[Pkg-golang-commits] [golang] 01/03: Imported Upstream version 1.3

Michael Stapelberg michael at stapelberg.de
Fri Jun 20 11:25:30 UTC 2014


This is an automated email from the git hooks/post-receive script.

stapelberg pushed a commit to branch debian-sid
in repository golang.

commit 8a39ee361feb9bf46d728ff1ba4f07ca1d9610b1
Author: Michael Stapelberg <stapelberg at debian.org>
Date:   Thu Jun 19 09:22:53 2014 +0200

    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/emacs/go-mode.el                              |    63 +-
 misc/goplay/Makefile                               |     6 -
 misc/goplay/README                                 |     1 -
 misc/goplay/doc.go                                 |    23 -
 misc/goplay/goplay.go                              |   288 -
 misc/{dist => makerelease}/darwin/Distribution     |     0
 misc/{dist => makerelease}/darwin/Resources/bg.png |   Bin
 misc/{dist => makerelease}/darwin/etc/paths.d/go   |     0
 .../darwin/scripts/postinstall                     |     0
 .../darwin/scripts/preinstall                      |     0
 misc/makerelease/makerelease.go                    |  1030 ++
 misc/{dist => makerelease}/windows/LICENSE.rtf     |   Bin
 misc/{dist => makerelease}/windows/README.txt      |     0
 .../windows/images/Banner.jpg                      |   Bin
 .../windows/images/Dialog.jpg                      |   Bin
 .../windows/images/DialogLeft.jpg                  |   Bin
 .../windows/images/gopher.ico                      |   Bin
 misc/{dist => makerelease}/windows/installer.wxs   |     0
 misc/nacl/README                                   |    63 +
 misc/nacl/go_nacl_386_exec                         |    10 +
 misc/nacl/go_nacl_amd64p32_exec                    |    10 +
 misc/nacl/mkzip.go                                 |   220 +
 api/next.txt => misc/nacl/testdata/bin/placeholder |     0
 api/next.txt => 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/syntaxerror/x.go => testonly/p_test.go}   |     0
 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 +-
 .../net/{sockopt_linux.go => sockopt_solaris.go}   |     0
 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_dragonfly.go => stat_solaris.go}  |     0
 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_386.s => asm_amd64p32.s}      |     0
 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 +-
 .../runtime/{signals_darwin.h => signals_nacl.h}   |     0
 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 +-
 1631 files changed, 134722 insertions(+), 74816 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index c3fd330..d4fbbd1 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -12,6 +12,7 @@ Aaron France <aaron.l.france at gmail.com>
 Abhinav Gupta <abhinav.g90 at gmail.com>
 Adrian Nos <nos.adrian at gmail.com>
 Adrian O'Grady <elpollouk at gmail.com>
+Adrien Bustany <adrien-xx-google at bustany.org>
 Akshat Kumar <seed at mail.nanosouffle.net>
 Albert Strasheim <fullung at gmail.com>
 Alberto García Hierro <alberto at garciahierro.com> <alberto.garcia.hierro at gmail.com>
@@ -19,12 +20,15 @@ Aleksandar Dezelin <dezelin at gmail.com>
 Alex A Skinner <alex at lx.lc>
 Alex Brainman <alex.brainman at gmail.com>
 Alex Jin <toalexjin at gmail.com>
+Alexander Larsson <alexander.larsson at gmail.com>
 Alexander Orlov <alexander.orlov at loxal.net>
 Alexander Reece <awreece at gmail.com>
 Alexander Surma <surma at surmair.de>
+Alexander Zhavnerchik <alex.vizor at gmail.com>
 Alexandre Normand <alexandre.normand at gmail.com>
 Alexei Sholik <alcosholik at gmail.com>
 Alexey Borzenkov <snaury at gmail.com>
+Alexey Palazhchenko <alexey.palazhchenko at gmail.com>
 Amir Mohammad Saied <amir at gluegadget.com>
 Amrut Joshi <amrut.joshi at gmail.com>
 Andrei Vieru <euvieru at gmail.com>
@@ -35,16 +39,21 @@ Andrew Lutomirski <andy at luto.us>
 Andrew Pritchard <awpritchard at gmail.com>
 Andrew Radev <andrey.radev at gmail.com>
 Andrew Skiba <skibaa at gmail.com>
+Andrew Szeto <andrew at jabagawee.com>
 Andrew Wilkins <axwalk at gmail.com>
 Andrey Mirtchovski <mirtchovski at gmail.com>
 Andriy Lytvynov <lytvynov.a.v at gmail.com>
 Andy Davis <andy at bigandian.com>
+Anfernee Yongkun Gui <anfernee.gui at gmail.com>
 Anh Hai Trinh <anh.hai.trinh at gmail.com>
 Anschel Schaffer-Cohen <anschelsc at gmail.com>
 Anthony Eufemio <anthony.eufemio at gmail.com>
 Anthony Martin <ality at pbrane.org>
 Anthony Starks <ajstarks at gmail.com>
+Apisak Darakananda <pongad at gmail.com>
+Aram Hăvărneanu <aram at mgk.ro>
 Arnaud Ysmal <arnaud.ysmal at gmail.com>
+Arne Hormann <arnehormann at gmail.com>
 Aron Nopanen <aron.nopanen at gmail.com>
 Arvindh Rajesh Tamilmani <art at a-30.net>
 Ato Araki <ato.araki at gmail.com>
@@ -53,18 +62,23 @@ Ben Olive <sionide21 at gmail.com>
 Benjamin Black <b at b3k.us>
 Benny Siegert <bsiegert at gmail.com>
 Berengar Lehr <berengar.lehr at gmx.de>
+Billie Harold Cleek <bhcleek at gmail.com>
 Bjorn Tillenius <bjorn at tillenius.me>
 Bjorn Tipling <bjorn.tipling at gmail.com>
 Blake Mizerany <blake.mizerany at gmail.com>
 Bobby Powers <bobbypowers at gmail.com>
+Brendan Daniel Tracey <tracey.brendan at gmail.com>
 Brian Dellisanti <briandellisanti at gmail.com>
 Brian G. Merrell <bgmerrell at gmail.com>
 Brian Gitonga Marete <marete at toshnix.com>
 Brian Ketelsen <bketelsen at gmail.com>
 Caine Tighe <arctanofyourface at gmail.com>
 Caleb Spare <cespare at gmail.com>
+Carl Chatfield <carlchatfield at gmail.com>
 Carlos Castillo <cookieo9 at gmail.com>
+Case Nelson <case.nelson at gmail.com>
 Casey Marshall <casey.marshall at gmail.com>
+Cezar Sá Espinola <cezarsa at gmail.com>
 ChaiShushan <chaishushan at gmail.com>
 Charles L. Dorian <cldorian at gmail.com>
 Charles Lee <zombie.fml at gmail.com>
@@ -75,6 +89,7 @@ Chris Jones <chris at cjones.org>
 Chris Lennert <calennert at gmail.com>
 Christian Himpel <chressie at googlemail.com>
 Christine Hansmann <chhansmann at gmail.com>
+Christoffer Buchholz <christoffer.buchholz at gmail.com>
 Christoph Hack <christoph at tux21b.org>
 Christopher Cahoon <chris.cahoon at gmail.com>
 Christopher Nielsen <m4dh4tt3r at gmail.com>
@@ -89,19 +104,25 @@ Dan Peterson <dpiddy at gmail.com>
 Dan Sinclair <dan.sinclair at gmail.com>
 Daniel Fleischman <danielfleischman at gmail.com>
 Daniel Krech <eikeon at eikeon.com>
+Daniel Lidén <daniel.liden.87 at gmail.com>
 Daniel Morsing <daniel.morsing at gmail.com>
 Daniel Theophanes <kardianos at gmail.com>
 Darren Elwood <darren at textnode.com>
 Dave Cheney <dave at cheney.net>
 David Bürgin <676c7473 at gmail.com>
+David Calavera <david.calavera at gmail.com>
 David du Colombier <0intro at gmail.com>
 David Forsythe <dforsythe at gmail.com>
 David G. Andersen <dave.andersen at gmail.com>
 David Jakob Fritz <david.jakob.fritz at gmail.com>
+David Thomas <davidthomas426 at gmail.com>
 David Titarenco <david.titarenco at gmail.com>
 Dean Prichard <dean.prichard at gmail.com>
+Denis Brandolini <denis.brandolini at gmail.com>
 Devon H. O'Dell <devon.odell at gmail.com>
+Dhiru Kholia <dhiru.kholia at gmail.com>
 Dimitri Tcaciuc <dtcaciuc at gmail.com>
+Dmitri Shuralyov <shurcooL at gmail.com>
 Dmitriy Shelenin <deemok at googlemail.com> <deemok at gmail.com>
 Dmitry Chestnykh <dchest at gmail.com>
 Dominik Honnef <dominik.honnef at gmail.com>
@@ -121,36 +142,46 @@ Eric Clark <zerohp at gmail.com>
 Eric Milliken <emilliken at gmail.com>
 Eric Roshan-Eisner <eric.d.eisner at gmail.com>
 Erik St. Martin <alakriti at gmail.com>
+Erik Westrup <erik.westrup at gmail.com>
 Esko Luontola <esko.luontola at gmail.com>
 Evan Shaw <chickencha at gmail.com>
 Ewan Chou <coocood at gmail.com>
+Fabrizio Milo <mistobaan at gmail.com>
 Fan Hongjian <fan.howard at gmail.com>
 Fazlul Shahriar <fshahriar at gmail.com>
+Felix Geisendörfer <haimuiba at gmail.com>
 Firmansyah Adiputra <frm.adiputra at gmail.com>
 Florian Uekermann <florian at uekermann-online.de>
 Florian Weimer <fw at deneb.enyo.de>
 Francisco Souza <franciscossouza at gmail.com>
 Frederick Kelly Mayle III <frederickmayle at gmail.com>
+Fredrik Enestad <fredrik.enestad at soundtrackyourbrand.com>
 Frithjof Schulze <schulze at math.uni-hannover.de> <sfrithjof at gmail.com>
 Gary Burd <gary at beagledreams.com>
+Gautham Thambidorai <gautham.dorai at gmail.com>
 Georg Reinke <guelfey at gmail.com>
 Gerasimos Dimitriadis <gedimitr at gmail.com>
 Gideon Jan-Wessel Redelinghuys <gjredelinghuys at gmail.com>
 Giles Lean <giles.lean at pobox.com>
 Google Inc.
+Gordon Klaus <gordon.klaus at gmail.com>
+Graham King <graham4king at gmail.com>
 Graham Miller <graham.miller at gmail.com>
 Greg Ward <greg at gerg.ca>
+Guillaume J. Charmes <guillaume at charmes.net>
 Gustav Paul <gustav.paul at gmail.com>
 Gustavo Niemeyer <gustavo at niemeyer.net>
 Gwenael Treguier <gwenn.kahz at gmail.com>
 Harley Laue <losinggeneration at gmail.com>
 Hector Chu <hectorchu at gmail.com>
+Henrik Edwards <henrik.edwards at gmail.com>
 Herbert Georg Fischer <herbert.fischer at gmail.com>
 Hong Ruiqi <hongruiqi at gmail.com>
 Icarus Sparry <golang at icarus.freeuk.com>
 Ingo Oeser <nightlyone at googlemail.com>
 Isaac Wagner <ibw at isaacwagner.me>
 Jakob Borg <jakob at nym.se>
+Jakub Ryszard Czarnowicz <j.czarnowicz at gmail.com>
 James David Chalfant <james.chalfant at gmail.com>
 James Fysh <james.fysh at gmail.com>
 James Gray <james at james4k.com>
@@ -165,7 +196,9 @@ Jan Newmarch <jan.newmarch at gmail.com>
 Jan Ziak <0xe2.0x9a.0x9b at gmail.com>
 Jani Monoses <jani.monoses at ubuntu.com>
 Jaroslavas Počepko <jp at webmaster.ms>
+Jason Del Ponte <delpontej at gmail.com>
 Jason Travis <infomaniac7 at gmail.com>
+Jay Weisskopf <jay at jayschwa.net>
 Jeff Hodges <jeff at somethingsimilar.com>
 Jeff R. Allen <jra at nella.org>
 Jeff Sickel <jas at corpus-callosum.com>
@@ -177,6 +210,7 @@ Jingcheng Zhang <diogin at gmail.com>
 Joakim Sernbrant <serbaut at gmail.com>
 Joe Poirier <jdpoirier at gmail.com>
 John Asmuth <jasmuth at gmail.com>
+John C Barstow <jbowtie at amathaine.com>
 John Graham-Cumming <jgc at jgc.org> <jgrahamc at gmail.com>
 John Howard Palevich <jack.palevich at gmail.com>
 John Shahid <jvshahid at gmail.com>
@@ -190,6 +224,7 @@ Joseph Holsten <joseph at josephholsten.com>
 Josh Bleecher Snyder <josharian at gmail.com>
 Josh Goebel <dreamer3 at gmail.com>
 Josh Holland <jrh at joshh.co.uk>
+Joshua Chase <jcjoshuachase at gmail.com>
 Jukka-Pekka Kekkonen <karatepekka at gmail.com>
 Julian Phillips <julian at quantumfyre.co.uk>
 Julien Schmidt <google at julienschmidt.com>
@@ -198,55 +233,75 @@ Kamil Kisiel <kamil at kamilkisiel.net> <kamil.kisiel at gmail.com>
 Katrina Owen <katrina.owen at gmail.com>
 Kei Son <hey.calmdown at gmail.com>
 Keith Rarick <kr at xph.us>
+Kelsey Hightower <kelsey.hightower at gmail.com>
+Kelvin Foo Chuan Lyi <vmirage at gmail.com>
 Ken Friedenbach <kenliz at cruzio.com>
 Ken Rockot <ken at oz.gs>
 Kevin Ballard <kevin at sb.org>
 Kyle Consalus <consalus at gmail.com>
+Kyle Isom <kyle at gokyle.net>
 Kyle Lemons <kyle at kylelemons.net>
 L Campbell <unpantsu at gmail.com>
 Lai Jiangshan <eag0628 at gmail.com>
+Linaro Limited
 Lorenzo Stoakes <lstoakes at gmail.com>
 Luca Greco <luca.greco at alcacoop.it>
 Lucio De Re <lucio.dere at gmail.com>
 Luit van Drongelen <luitvd at gmail.com>
+Luka Zakrajšek <tr00.g33k at gmail.com>
+Luke Curley <qpingu at gmail.com>
+Marc Weistroff <marc at weistroff.net>
 Marco Hennings <marco.hennings at freiheit.com>
 Marko Juhani Silokunnas <marko.silokunnas at gmail.com>
+Marko Tiikkaja <marko at joh.to>
 Markus Duft <markus.duft at salomon.at>
 Markus Sonderegger <marraison at gmail.com>
+Markus Zimmermann <zimmski at gmail.com>
 Martin Neubauer <m.ne at gmx.net>
+Martin Olsson <martin at minimum.se>
 Mateusz Czapliński <czapkofan at gmail.com>
 Mathieu Lonjaret <mathieu.lonjaret at gmail.com>
 Mats Lidell <mats.lidell at cag.se>
+Matt Aimonetti <mattaimonetti at gmail.com>
 Matt Jibson <matt.jibson at gmail.com>
 Matt Joiner <anacrolix at gmail.com>
 Matt Reiferson <mreiferson at gmail.com>
 Matthew Cottingham <mattcottingham at gmail.com>
 Matthew Horsnell <matthew.horsnell at gmail.com>
+Maxim Khitrov <max at mxcrypt.com>
 Micah Stetson <micah.stetson at gmail.com>
 Michael Chaten <mchaten at gmail.com>
 Michael Elkins <michael.elkins at gmail.com>
-Michael Gehring <mg at ebfe.org>
+Michael Fraenkel <michael.fraenkel at gmail.com>
+Michael Gehring <mg at ebfe.org> <gnirheg.leahcim at gmail.com>
 Michael Hoisie <hoisie at gmail.com>
 Michael Lewis <mikelikespie at gmail.com>
+Michael Pearson <mipearson at gmail.com>
 Michael Stapelberg <michael at stapelberg.de>
 Michael Teichgräber <mteichgraeber at gmx.de>
 Michał Derkacz <ziutek at lnet.pl>
 Miek Gieben <miek at miek.nl>
+Mihai Borobocea <MihaiBorobocea at gmail.com>
 Mikael Tillenius <mikti42 at gmail.com>
+Mike Andrews <mra at xoba.com>
 Mike Rosset <mike.rosset at gmail.com>
+Mikhail Panchenko <m at mihasya.com>
 Miki Tebeka <miki.tebeka at gmail.com>
 Mikio Hara <mikioh.mikioh at gmail.com>
 Mikkel Krautz <mikkel at krautz.dk>
 Miquel Sabaté Solà <mikisabate at gmail.com>
+Moov Corporation
 Moriyoshi Koizumi <mozo at mozo.jp>
 Môshe van der Sterre <moshevds at gmail.com>
 Nan Deng <monnand at gmail.com>
 Nathan John Youngman <nj at nathany.com>
 ngmoco, LLC
+Nicholas Katsaros <nick at nickkatsaros.com>
 Nicholas Presta <nick at nickpresta.ca> <nick1presta at gmail.com>
 Nicholas Sullivan <nicholas.sullivan at gmail.com>
 Nicholas Waples <nwaples at gmail.com>
 Nick Craig-Wood <nick at craig-wood.com> <nickcw at gmail.com>
+Nicolas Kaiser <nikai at nikai.net>
 Nicolas Owens <mischief at offblast.org>
 Nigel Kerr <nigel.kerr at gmail.com>
 Noah Campbell <noahcampbell at gmail.com>
@@ -261,24 +316,32 @@ Pascal S. de Kloe <pascal at quies.net>
 Patrick Crosby <patrick at stathat.com>
 Patrick Gavlin <pgavlin at gmail.com>
 Patrick Higgins <patrick.allen.higgins at gmail.com>
+Patrick Mézard <patrick at mezard.eu>
 Patrick Mylund Nielsen <patrick at patrickmn.com>
 Patrick Smith <pat42smith at gmail.com>
+Paul A Querna <paul.querna at gmail.com>
+Paul Hammond <paul at paulhammond.org>
 Paul Lalonde <paul.a.lalonde at gmail.com>
 Paul Sbarra <Sbarra.Paul at gmail.com>
 Paul van Brouwershaven <paul at vanbrouwershaven.com>
+Pavel Zinovkin <pavel.zinovkin at gmail.com>
 Petar Maymounkov <petarm at gmail.com>
 Peter Armitage <peter.armitage at gmail.com>
 Peter Froehlich <peter.hans.froehlich at gmail.com>
 Peter Kleiweg <pkleiweg at xs4all.nl>
 Peter Mundy <go.peter.90 at gmail.com>
 Péter Surányi <speter.go1 at gmail.com>
+Péter Szilágyi <peterke at gmail.com>
 Peter Waller <peter.waller at gmail.com>
 Peter Williams <pwil3058 at gmail.com>
 Philip K. Warren <pkwarren at gmail.com>
 Pieter Droogendijk <pieter at binky.org.uk>
+Pietro Gagliardi <pietro10 at mac.com>
+Preetam Jinka <pj at preet.am>
 Quan Yong Zhai <qyzhai at gmail.com>
 Raif S. Naffah <go at naffah-raif.name>
 Rémy Oudompheng <oudomphe at phare.normalesup.org>
+Richard Crowley <r at rcrowley.org>
 Richard Eric Gavaletz <gavaletz at gmail.com>
 Richard Musiol <mail at richard-musiol.de>
 Rick Arnold <rickarnoldjr at gmail.com>
@@ -295,8 +358,10 @@ Roger Pau Monné <royger at gmail.com>
 Roger Peppe <rogpeppe at gmail.com>
 Ron Minnich <rminnich at gmail.com>
 Ross Light <rlight2 at gmail.com>
+Rowan Worth <sqweek at gmail.com>
 Ryan Hitchman <hitchmanr at gmail.com>
 Ryan Slade <ryanslade at gmail.com>
+S.Çağlar Onur <caglar at 10ur.org>
 Sanjay Menakuru <balasanjay at gmail.com>
 Scott Ferguson <scottwferg at gmail.com>
 Scott Lawrence <bytbox at gmail.com>
@@ -311,12 +376,14 @@ Shenghou Ma <minux.ma at gmail.com>
 Shivakumar GN <shivakumar.gn at gmail.com>
 Sokolov Yura <funny.falcon at gmail.com>
 Spring Mc <heresy.mc at gmail.com>
+StalkR <stalkr at stalkr.net>
 Stefan Nilsson <snilsson at nada.kth.se> <trolleriprofessorn at gmail.com>
 Stéphane Travostino <stephane.travostino at gmail.com>
 Stephen McQuay <stephen at mcquay.me>
 Stephen Weinberg <stephen at q5comm.com>
 Steve McCoy <mccoyst at gmail.com>
 Steven Elliot Harris <seharris at gmail.com>
+Steven Hartland <steven.hartland at multiplay.co.uk>
 Sven Almgren <sven at tras.se>
 Szabolcs Nagy <nsz at port70.net>
 Tad Glines <tad.glines at gmail.com>
@@ -328,6 +395,8 @@ Thomas Kappler <tkappler at gmail.com>
 Timo Savola <timo.savola at gmail.com>
 Tobias Columbus <tobias.columbus at gmail.com>
 Tor Andersson <tor.andersson at gmail.com>
+Travis Cline <travis.cline at gmail.com>
+Tudor Golubenco <tudor.g at gmail.com>
 Tw <tw19881113 at gmail.com>
 Tyler Bunnell <tylerbunnell at gmail.com>
 Ugorji Nwoke <ugorji at gmail.com>
@@ -342,6 +411,7 @@ Volker Dobler <dr.volker.dobler at gmail.com>
 Wei Guangjing <vcc.163 at gmail.com>
 Willem van der Schyff <willemvds at gmail.com>
 William Josephson <wjosephson at gmail.com>
+William Orr <will at worrbase.com> <ay1244 at gmail.com>
 Xing Xing <mikespook at gmail.com>
 Yasuhiro Matsumoto <mattn.jp at gmail.com>
 Yissakhar Z. Beck <yissakhar.beck at gmail.com>
@@ -352,3 +422,4 @@ Yuusei Kuwana <kuwana at kumama.org>
 Yuval Pavel Zholkover <paulzhol at gmail.com>
 Ziad Hatahet <hatahet at gmail.com>
 Zorion Arrizabalaga <zorionk at gmail.com>
+申习之 <bronze1man at gmail.com>
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 4d4a73e..3722298 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -37,6 +37,7 @@ Abhinav Gupta <abhinav.g90 at gmail.com>
 Adam Langley <agl at golang.org>
 Adrian Nos <nos.adrian at gmail.com>
 Adrian O'Grady <elpollouk at gmail.com>
+Adrien Bustany <adrien-xx-google at bustany.org>
 Akshat Kumar <seed at mail.nanosouffle.net>
 Alan Donovan <adonovan at google.com>
 Albert Strasheim <fullung at gmail.com>
@@ -46,13 +47,16 @@ Alex A Skinner <alex at lx.lc>
 Alex Brainman <alex.brainman at gmail.com>
 Alex Bramley <abramley at google.com>
 Alex Jin <toalexjin at gmail.com>
+Alexander Larsson <alexander.larsson at gmail.com>
 Alexander Orlov <alexander.orlov at loxal.net>
 Alexander Reece <awreece at gmail.com>
 Alexander Surma <surma at surmair.de>
+Alexander Zhavnerchik <alex.vizor at gmail.com>
 Alexandre Normand <alexandre.normand at gmail.com>
 Alexandru Moșoi <brtzsnr at gmail.com>
 Alexei Sholik <alcosholik at gmail.com>
 Alexey Borzenkov <snaury at gmail.com>
+Alexey Palazhchenko <alexey.palazhchenko at gmail.com>
 Alexis Imperial-Legrand <ail at google.com>
 Amir Mohammad Saied <amir at gluegadget.com>
 Amrut Joshi <amrut.joshi at gmail.com>
@@ -67,16 +71,21 @@ Andrew Lutomirski <andy at luto.us>
 Andrew Pritchard <awpritchard at gmail.com>
 Andrew Radev <andrey.radev at gmail.com>
 Andrew Skiba <skibaa at gmail.com>
+Andrew Szeto <andrew at jabagawee.com>
 Andrew Wilkins <axwalk at gmail.com>
 Andrey Mirtchovski <mirtchovski at gmail.com>
 Andriy Lytvynov <lytvynov.a.v at gmail.com>
 Andy Davis <andy at bigandian.com>
+Anfernee Yongkun Gui <anfernee.gui at gmail.com>
 Anh Hai Trinh <anh.hai.trinh at gmail.com>
 Anschel Schaffer-Cohen <anschelsc at gmail.com>
 Anthony Eufemio <anthony.eufemio at gmail.com>
 Anthony Martin <ality at pbrane.org>
 Anthony Starks <ajstarks at gmail.com>
+Apisak Darakananda <pongad at gmail.com>
+Aram Hăvărneanu <aram at mgk.ro>
 Arnaud Ysmal <arnaud.ysmal at gmail.com>
+Arne Hormann <arnehormann at gmail.com>
 Aron Nopanen <aron.nopanen at gmail.com>
 Arvindh Rajesh Tamilmani <art at a-30.net>
 Asim Shankar <asimshankar at gmail.com>
@@ -93,25 +102,32 @@ Benny Siegert <bsiegert at gmail.com>
 Berengar Lehr <Berengar.Lehr at gmx.de>
 Bill Neubauer <wcn at golang.org> <wcn at google.com> <bill.neubauer at gmail.com>
 Bill Thiede <couchmoney at gmail.com>
+Billie Harold Cleek <bhcleek at gmail.com>
 Bjorn Tillenius <bjorn at tillenius.me>
 Bjorn Tipling <bjorn.tipling at gmail.com>
 Blake Mizerany <blake.mizerany at gmail.com>
 Bobby Powers <bobbypowers at gmail.com>
 Brad Fitzpatrick <bradfitz at golang.org> <bradfitz at gmail.com>
 Brad Garcia <bgarcia at golang.org>
+Brendan Daniel Tracey <tracey.brendan at gmail.com>
 Brendan O'Dea <bod at golang.org>
 Brian Dellisanti <briandellisanti at gmail.com>
 Brian G. Merrell <bgmerrell at gmail.com>
 Brian Gitonga Marete <marete at toshnix.com>
 Brian Ketelsen <bketelsen at gmail.com>
 Brian Slesinsky <skybrian at google.com>
+Burcu Dogan <jbd at google.com>
 Caine Tighe <arctanofyourface at gmail.com>
 Caleb Spare <cespare at gmail.com>
+Carl Chatfield <carlchatfield at gmail.com>
 Carl Mastrangelo <notcarl at google.com>
 Carl Shapiro <cshapiro at google.com> <cshapiro at golang.org>
 Carlos Castillo <cookieo9 at gmail.com>
 Cary Hull <chull at google.com>
+Case Nelson <case.nelson at gmail.com>
 Casey Marshall <casey.marshall at gmail.com>
+Catalin Patulea <catalinp at google.com>
+Cezar Sá Espinola <cezarsa at gmail.com>
 ChaiShushan <chaishushan at gmail.com>
 Charles L. Dorian <cldorian at gmail.com>
 Charles Lee <zombie.fml at gmail.com>
@@ -124,6 +140,7 @@ Chris Lennert <calennert at gmail.com>
 Chris Manghane <cmang at golang.org>
 Christian Himpel <chressie at googlemail.com> <chressie at gmail.com>
 Christine Hansmann <chhansmann at gmail.com>
+Christoffer Buchholz <christoffer.buchholz at gmail.com>
 Christoph Hack <christoph at tux21b.org>
 Christopher Cahoon <chris.cahoon at gmail.com>
 Christopher Nielsen <m4dh4tt3r at gmail.com>
@@ -141,6 +158,7 @@ Dan Peterson <dpiddy at gmail.com>
 Dan Sinclair <dan.sinclair at gmail.com>
 Daniel Fleischman <danielfleischman at gmail.com>
 Daniel Krech <eikeon at eikeon.com>
+Daniel Lidén <daniel.liden.87 at gmail.com>
 Daniel Morsing <daniel.morsing at gmail.com>
 Daniel Nadasi <dnadasi at google.com>
 Daniel Theophanes <kardianos at gmail.com>
@@ -150,8 +168,11 @@ Dave Cheney <dave at cheney.net>
 Dave Day <djd at golang.org>
 Dave Grijalva <dgrijalva at ngmoco.com>
 David Anderson <danderson at google.com>
+David Barnett <dbarnett at google.com>
 David Bürgin <676c7473 at gmail.com>
-David Crawshaw <david.crawshaw at zentus.com> <crawshaw at google.com>
+David Calavera <david.calavera at gmail.com>
+David Covert <davidhcovert at gmail.com>
+David Crawshaw <david.crawshaw at zentus.com> <crawshaw at google.com> <crawshaw at golang.org>
 David du Colombier <0intro at gmail.com>
 David Forsythe <dforsythe at gmail.com>
 David G. Andersen <dave.andersen at gmail.com>
@@ -159,10 +180,14 @@ David Jakob Fritz <david.jakob.fritz at gmail.com>
 David McLeish <davemc at google.com>
 David Presotto <presotto at gmail.com>
 David Symonds <dsymonds at golang.org>
+David Thomas <davidthomas426 at gmail.com>
 David Titarenco <david.titarenco at gmail.com>
 Dean Prichard <dean.prichard at gmail.com>
+Denis Brandolini <denis.brandolini at gmail.com>
 Devon H. O'Dell <devon.odell at gmail.com>
+Dhiru Kholia <dhiru.kholia at gmail.com>
 Dimitri Tcaciuc <dtcaciuc at gmail.com>
+Dmitri Shuralyov <shurcooL at gmail.com>
 Dmitriy Shelenin <deemok at googlemail.com> <deemok at gmail.com>
 Dmitriy Vyukov <dvyukov at google.com>
 Dmitry Chestnykh <dchest at gmail.com>
@@ -183,12 +208,15 @@ Eric Clark <zerohp at gmail.com>
 Eric Milliken <emilliken at gmail.com>
 Eric Roshan-Eisner <eric.d.eisner at gmail.com>
 Erik St. Martin <alakriti at gmail.com>
+Erik Westrup <erik.westrup at gmail.com>
 Esko Luontola <esko.luontola at gmail.com>
 Evan Martin <evan.martin at gmail.com>
 Evan Shaw <chickencha at gmail.com>
 Ewan Chou <coocood at gmail.com>
+Fabrizio Milo <mistobaan at gmail.com>
 Fan Hongjian <fan.howard at gmail.com>
 Fazlul Shahriar <fshahriar at gmail.com>
+Felix Geisendörfer <haimuiba at gmail.com>
 Firmansyah Adiputra <frm.adiputra at gmail.com>
 Florian Uekermann <florian at uekermann-online.de> <f1 at uekermann-online.de>
 Florian Weimer <fw at deneb.enyo.de>
@@ -196,16 +224,21 @@ Folke Behrens <folke at google.com>
 Francesc Campoy <campoy at golang.org>
 Francisco Souza <franciscossouza at gmail.com>
 Frederick Kelly Mayle III <frederickmayle at gmail.com>
+Fredrik Enestad <fredrik.enestad at soundtrackyourbrand.com>
 Frithjof Schulze <schulze at math.uni-hannover.de> <sfrithjof at gmail.com>
 Fumitoshi Ukai <ukai at google.com>
 Gaal Yahas <gaal at google.com>
 Gary Burd <gary at beagledreams.com> <gary.burd at gmail.com>
+Gautham Thambidorai <gautham.dorai at gmail.com>
 Georg Reinke <guelfey at gmail.com>
 Gerasimos Dimitriadis <gedimitr at gmail.com>
 Gideon Jan-Wessel Redelinghuys <gjredelinghuys at gmail.com>
 Giles Lean <giles.lean at pobox.com>
+Gordon Klaus <gordon.klaus at gmail.com>
+Graham King <graham4king at gmail.com>
 Graham Miller <graham.miller at gmail.com>
 Greg Ward <greg at gerg.ca>
+Guillaume J. Charmes <guillaume at charmes.net>
 Gustav Paul <gustav.paul at gmail.com>
 Gustavo Franco <gustavorfranco at gmail.com>
 Gustavo Niemeyer <gustavo at niemeyer.net> <n13m3y3r at gmail.com>
@@ -213,6 +246,7 @@ Gwenael Treguier <gwenn.kahz at gmail.com>
 Han-Wen Nienhuys <hanwen at google.com>
 Harley Laue <losinggeneration at gmail.com>
 Hector Chu <hectorchu at gmail.com>
+Henrik Edwards <henrik.edwards at gmail.com>
 Herbert Georg Fischer <herbert.fischer at gmail.com>
 Hong Ruiqi <hongruiqi at gmail.com>
 Hossein Sheikh Attar <hattar at google.com>
@@ -223,6 +257,7 @@ Isaac Wagner <ibw at isaacwagner.me>
 Ivan Krasin <krasin at golang.org>
 Jacob Baskin <jbaskin at google.com>
 Jakob Borg <jakob at nym.se>
+Jakub Ryszard Czarnowicz <j.czarnowicz at gmail.com>
 James Aguilar <jaguilar at google.com>
 James David Chalfant <james.chalfant at gmail.com>
 James Fysh <james.fysh at gmail.com>
@@ -242,7 +277,9 @@ Jan Newmarch <jan.newmarch at gmail.com>
 Jan Ziak <0xe2.0x9a.0x9b at gmail.com>
 Jani Monoses <jani.monoses at ubuntu.com> <jani.monoses at gmail.com>
 Jaroslavas Počepko <jp at webmaster.ms>
+Jason Del Ponte <delpontej at gmail.com>
 Jason Travis <infomaniac7 at gmail.com>
+Jay Weisskopf <jay at jayschwa.net>
 Jean-Marc Eurin <jmeurin at google.com>
 Jeff Hodges <jeff at somethingsimilar.com>
 Jeff R. Allen <jra at nella.org> <jeff.allen at gmail.com>
@@ -260,9 +297,11 @@ Joel Sing <jsing at google.com>
 Johan Euphrosine <proppy at google.com>
 John Asmuth <jasmuth at gmail.com>
 John Beisley <huin at google.com>
+John C Barstow <jbowtie at amathaine.com>
 John DeNero <denero at google.com>
 John Graham-Cumming <jgc at jgc.org> <jgrahamc at gmail.com>
 John Howard Palevich <jack.palevich at gmail.com>
+John Newlin <jnewlin at google.com>
 John Shahid <jvshahid at gmail.com>
 Jonathan Allie <jonallie at google.com>
 Jonathan Feinberg <feinberg at google.com>
@@ -282,6 +321,7 @@ Josh Bleecher Snyder <josharian at gmail.com>
 Josh Goebel <dreamer3 at gmail.com>
 Josh Hoak <jhoak at google.com>
 Josh Holland <jrh at joshh.co.uk>
+Joshua Chase <jcjoshuachase at gmail.com>
 JP Sugarbroad <jpsugar at google.com>
 Jukka-Pekka Kekkonen <karatepekka at gmail.com>
 Julian Phillips <julian at quantumfyre.co.uk>
@@ -289,9 +329,12 @@ Julien Schmidt <google at julienschmidt.com>
 Kai Backman <kaib at golang.org>
 Kamil Kisiel <kamil at kamilkisiel.net> <kamil.kisiel at gmail.com>
 Katrina Owen <katrina.owen at gmail.com>
+Kay Zhu <kayzhu at google.com>
 Kei Son <hey.calmdown at gmail.com>
 Keith Randall <khr at golang.org>
 Keith Rarick <kr at xph.us>
+Kelsey Hightower <kelsey.hightower at gmail.com>
+Kelvin Foo Chuan Lyi <vmirage at gmail.com>
 Ken Friedenbach <kenliz at cruzio.com>
 Ken Rockot <ken at oz.gs> <ken.rockot at gmail.com>
 Ken Thompson <ken at golang.org>
@@ -299,6 +342,7 @@ Kevin Ballard <kevin at sb.org>
 Kevin Klues <klueska at gmail.com> <klueska at google.com>
 Kirklin McDonald <kirklin.mcdonald at gmail.com>
 Kyle Consalus <consalus at gmail.com>
+Kyle Isom <kyle at gokyle.net>
 Kyle Lemons <kyle at kylelemons.net> <kevlar at google.com>
 L Campbell <unpantsu at gmail.com>
 Lai Jiangshan <eag0628 at gmail.com>
@@ -308,19 +352,27 @@ Louis Kruger <louisk at google.com>
 Luca Greco <luca.greco at alcacoop.it>
 Lucio De Re <lucio.dere at gmail.com>
 Luit van Drongelen <luitvd at gmail.com>
+Luka Zakrajšek <tr00.g33k at gmail.com>
+Luke Curley <qpingu at gmail.com>
 Luuk van Dijk <lvd at golang.org> <lvd at google.com>
+Manoj Dayaram <platform-dev at moovweb.com> <manoj.dayaram at moovweb.com>
 Manu Garg <manugarg at google.com>
+Marc Weistroff <marc at weistroff.net>
 Marcel van Lohuizen <mpvl at golang.org>
 Marco Hennings <marco.hennings at freiheit.com>
 Mark Zavislak <zavislak at google.com>
 Marko Juhani Silokunnas <marko.silokunnas at gmail.com>
 Marko Mikulicic <mkm at google.com>
+Marko Tiikkaja <marko at joh.to>
 Markus Duft <markus.duft at salomon.at>
 Markus Sonderegger <marraison at gmail.com>
+Markus Zimmermann <zimmski at gmail.com>
 Martin Neubauer <m.ne at gmx.net>
+Martin Olsson <martin at minimum.se>
 Mateusz Czapliński <czapkofan at gmail.com>
 Mathieu Lonjaret <mathieu.lonjaret at gmail.com>
 Mats Lidell <mats.lidell at cag.se> <mats.lidell at gmail.com>
+Matt Aimonetti <mattaimonetti at gmail.com>
 Matt Brown <mdbrown at google.com>
 Matt Jibson <matt.jibson at gmail.com>
 Matt Joiner <anacrolix at gmail.com>
@@ -329,15 +381,20 @@ Matt Reiferson <mreiferson at gmail.com>
 Matthew Cottingham <mattcottingham at gmail.com>
 Matthew Dempsky <mdempsky at google.com>
 Matthew Horsnell <matthew.horsnell at gmail.com>
+Maxim Khitrov <max at mxcrypt.com>
 Maxim Pimenov <mpimenov at google.com>
 Maxim Ushakov <ushakov at google.com>
 Micah Stetson <micah.stetson at gmail.com>
 Michael Chaten <mchaten at gmail.com>
 Michael Elkins <michael.elkins at gmail.com>
-Michael Gehring <mg at ebfe.org>
+Michael Fraenkel <michael.fraenkel at gmail.com>
+Michael Gehring <mg at ebfe.org> <gnirheg.leahcim at gmail.com>
 Michael Hoisie <hoisie at gmail.com>
+Michael Hudson-Doyle <michael.hudson at linaro.org>
+Michael Kelly <mjk at google.com>
 Michael Lewis <mikelikespie at gmail.com>
 Michael Matloob <matloob at google.com>
+Michael Pearson <mipearson at gmail.com>
 Michael Piatek <piatek at google.com>
 Michael Shields <mshields at google.com>
 Michael Stapelberg <michael at stapelberg.de> <mstplbrg at googlemail.com>
@@ -345,10 +402,13 @@ Michael T. Jones <mtj at google.com> <michael.jones at gmail.com>
 Michael Teichgräber <mteichgraeber at gmx.de> <mt4swm at googlemail.com>
 Michał Derkacz <ziutek at lnet.pl>
 Miek Gieben <miek at miek.nl> <remigius.gieben at gmail.com>
+Mihai Borobocea <MihaiBorobocea at gmail.com>
 Mikael Tillenius <mikti42 at gmail.com>
+Mike Andrews <mra at xoba.com>
 Mike Rosset <mike.rosset at gmail.com>
 Mike Samuel <mikesamuel at gmail.com>
 Mike Solomon <msolo at gmail.com>
+Mikhail Panchenko <m at mihasya.com>
 Miki Tebeka <miki.tebeka at gmail.com>
 Mikio Hara <mikioh.mikioh at gmail.com>
 Mikkel Krautz <mikkel at krautz.dk> <krautz at gmail.com>
@@ -357,10 +417,12 @@ Moriyoshi Koizumi <mozo at mozo.jp>
 Môshe van der Sterre <moshevds at gmail.com>
 Nan Deng <monnand at gmail.com>
 Nathan John Youngman <nj at nathany.com>
+Nicholas Katsaros <nick at nickkatsaros.com>
 Nicholas Presta <nick at nickpresta.ca> <nick1presta at gmail.com>
 Nicholas Sullivan <nicholas.sullivan at gmail.com>
 Nicholas Waples <nwaples at gmail.com>
 Nick Craig-Wood <nick at craig-wood.com> <nickcw at gmail.com>
+Nicolas Kaiser <nikai at nikai.net>
 Nicolas Owens <mischief at offblast.org>
 Nigel Kerr <nigel.kerr at gmail.com>
 Nigel Tao <nigeltao at golang.org>
@@ -376,32 +438,42 @@ Pascal S. de Kloe <pascal at quies.net>
 Patrick Crosby <patrick at stathat.com>
 Patrick Gavlin <pgavlin at gmail.com>
 Patrick Higgins <patrick.allen.higgins at gmail.com>
+Patrick Mézard <patrick at mezard.eu>
 Patrick Mylund Nielsen <patrick at patrickmn.com>
+Patrick Riley <pfr at google.com>
 Patrick Smith <pat42smith at gmail.com>
+Paul A Querna <paul.querna at gmail.com>
 Paul Borman <borman at google.com>
 Paul Chang <paulchang at google.com>
+Paul Hammond <paul at paulhammond.org>
 Paul Lalonde <paul.a.lalonde at gmail.com>
 Paul Sbarra <Sbarra.Paul at gmail.com>
 Paul van Brouwershaven <paul at vanbrouwershaven.com>
+Pavel Zinovkin <pavel.zinovkin at gmail.com>
 Pawel Szczur <filemon at google.com>
 Petar Maymounkov <petarm at gmail.com>
 Peter Armitage <peter.armitage at gmail.com>
+Peter Collingbourne <pcc at google.com>
 Peter Froehlich <peter.hans.froehlich at gmail.com>
 Peter Kleiweg <pkleiweg at xs4all.nl>
 Peter McKenzie <petermck at google.com>
 Peter Mundy <go.peter.90 at gmail.com>
 Péter Surányi <speter.go1 at gmail.com>
 Péter Szabó <pts at google.com>
+Péter Szilágyi <peterke at gmail.com>
 Peter Waller <peter.waller at gmail.com>
 Peter Weinberger <pjw at golang.org>
 Peter Williams <pwil3058 at gmail.com>
 Phil Pennock <pdp at golang.org>
 Philip K. Warren <pkwarren at gmail.com>
 Pieter Droogendijk <pieter at binky.org.uk>
+Pietro Gagliardi <pietro10 at mac.com>
+Preetam Jinka <pj at preet.am>
 Quan Yong Zhai <qyzhai at gmail.com>
 Raif S. Naffah <go at naffah-raif.name>
 Raph Levien <raph at google.com>
 Rémy Oudompheng <oudomphe at phare.normalesup.org> <remyoudompheng at gmail.com>
+Richard Crowley <r at rcrowley.org>
 Richard Eric Gavaletz <gavaletz at gmail.com>
 Richard Musiol <mail at richard-musiol.de> <neelance at gmail.com>
 Rick Arnold <rickarnoldjr at gmail.com>
@@ -413,6 +485,7 @@ Robert Figueiredo <robfig at gmail.com>
 Robert Griesemer <gri at golang.org>
 Robert Hencke <robert.hencke at gmail.com>
 Robert Obryk <robryk at gmail.com>
+Robert Sesek <rsesek at google.com>
 Robert Snedegar <roberts at google.com>
 Robin Eklind <r.eklind.87 at gmail.com>
 Rodrigo Moraes de Oliveira <rodrigo.moraes at gmail.com>
@@ -421,16 +494,20 @@ Roger Pau Monné <royger at gmail.com>
 Roger Peppe <rogpeppe at gmail.com>
 Ron Minnich <rminnich at gmail.com>
 Ross Light <rlight2 at gmail.com>
+Rowan Worth <sqweek at gmail.com>
+Rui Ueyama <ruiu at google.com>
 Russ Cox <rsc at golang.org>
 Ryan Barrett <ryanb at google.com>
 Ryan Hitchman <hitchmanr at gmail.com>
 Ryan Slade <ryanslade at gmail.com>
+S.Çağlar Onur <caglar at 10ur.org>
 Sam Thorogood <thorogood at google.com> <sam.thorogood at gmail.com>
 Sameer Ajmani <sameer at golang.org> <ajmani at gmail.com>
 Sanjay Menakuru <balasanjay at gmail.com>
 Scott Ferguson <scottwferg at gmail.com>
 Scott Lawrence <bytbox at gmail.com>
 Scott Schwartz <scotts at golang.org>
+Sean Burford <sburford at google.com>
 Sebastien Binet	<seb.binet at gmail.com>
 Sébastien Paolacci <sebastien.paolacci at gmail.com>
 Sergei Skorobogatov <skorobo at rambler.ru>
@@ -439,10 +516,11 @@ Sergio Luis O. B. Correia <sergio at correia.cc>
 Shane Hansen <shanemhansen at gmail.com>
 Shawn Ledbetter <sledbetter at google.com>
 Shawn Smith <shawn.p.smith at gmail.com>
-Shenghou Ma <minux.ma at gmail.com>
+Shenghou Ma <minux at golang.org> <minux.ma at gmail.com>
 Shivakumar GN <shivakumar.gn at gmail.com>
 Sokolov Yura <funny.falcon at gmail.com>
 Spring Mc <heresy.mc at gmail.com>
+StalkR <stalkr at stalkr.net>
 Stefan Nilsson <snilsson at nada.kth.se> <trolleriprofessorn at gmail.com>
 Stéphane Travostino <stephane.travostino at gmail.com>
 Stephen Ma <stephenm at golang.org>
@@ -450,6 +528,7 @@ Stephen McQuay <stephen at mcquay.me>
 Stephen Weinberg <stephen at q5comm.com>
 Steve McCoy <mccoyst at gmail.com>
 Steven Elliot Harris <seharris at gmail.com>
+Steven Hartland <steven.hartland at multiplay.co.uk>
 Sugu Sougoumarane <ssougou at gmail.com>
 Sven Almgren <sven at tras.se>
 Szabolcs Nagy <nsz at port70.net>
@@ -465,7 +544,9 @@ Tobias Columbus <tobias.columbus at gmail.com> <tobias.columbus at googlemail.com>
 Todd Wang <toddwang at gmail.com>
 Tom Szymanski <tgs at google.com>
 Tor Andersson <tor.andersson at gmail.com>
+Travis Cline <travis.cline at gmail.com>
 Trevor Strohman <trevor.strohman at gmail.com>
+Tudor Golubenco <tudor.g at gmail.com>
 Tw <tw19881113 at gmail.com>
 Tyler Bunnell <tylerbunnell at gmail.com>
 Ugorji Nwoke <ugorji at gmail.com>
@@ -484,7 +565,9 @@ Will Norris <willnorris at google.com>
 Willem van der Schyff <willemvds at gmail.com>
 William Chan <willchan at chromium.org>
 William Josephson <wjosephson at gmail.com>
+William Orr <will at worrbase.com> <ay1244 at gmail.com>
 Xing Xing <mikespook at gmail.com>
+Yan Zou <yzou at google.com>
 Yasuhiro Matsumoto <mattn.jp at gmail.com>
 Yissakhar Z. Beck <yissakhar.beck at gmail.com>
 Yongjian Xu <i3dmaster at gmail.com>
@@ -495,3 +578,4 @@ Yuval Pavel Zholkover <paulzhol at gmail.com>
 Yves Junqueira <yves.junqueira at gmail.com>
 Ziad Hatahet <hatahet at gmail.com>
 Zorion Arrizabalaga <zorionk at gmail.com>
+申习之 <bronze1man at gmail.com>
diff --git a/VERSION b/VERSION
index 39dbf64..9c3a7a1 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 92a5278..1a82966 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 0000000..0474277
--- /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 e69de29..5e49b3f 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 23262da..0000000
--- 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 0000000..282db8b
--- /dev/null
+++ b/doc/articles/race_detector.html
@@ -0,0 +1,388 @@
+<!--{
+	"Title": "Data Race Detector",
+	"Template": true
+}-->
+
+<h2 id="Introduction">Introduction</h2>
+
+<p>
+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 <a href="/ref/mem/">The Go Memory Model</a> for details.
+</p>
+
+<p>
+Here is an example of a data race that can lead to crashes and memory corruption:
+</p>
+
+<pre>
+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)
+	}
+}
+</pre>
+
+<h2 id="Usage">Usage</h2>
+
+<p>
+To help diagnose such bugs, Go includes a built-in data race detector.
+To use it, add the <code>-race</code> flag to the go command:
+</p>
+
+<pre>
+$ 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
+</pre>
+
+<h2 id="Report_Format">Report Format</h2>
+
+<p>
+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:
+</p>
+
+<pre>
+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
+</pre>
+
+<h2 id="Options">Options</h2>
+
+<p>
+The <code>GORACE</code> environment variable sets race detector options.
+The format is:
+</p>
+
+<pre>
+GORACE="option1=val1 option2=val2"
+</pre>
+
+<p>
+The options are:
+</p>
+
+<ul>
+<li>
+<code>log_path</code> (default <code>stderr</code>): The race detector writes
+its report to a file named <code>log_path.<em>pid</em></code>.
+The special names <code>stdout</code>
+and <code>stderr</code> cause reports to be written to standard output and
+standard error, respectively.
+</li>
+
+<li>
+<code>exitcode</code> (default <code>66</code>): The exit status to use when
+exiting after a detected race.
+</li>
+
+<li>
+<code>strip_path_prefix</code> (default <code>""</code>): Strip this prefix
+from all reported file paths, to make reports more concise.
+</li>
+
+<li>
+<code>history_size</code> (default <code>1</code>): The per-goroutine memory
+access history is <code>32K * 2**history_size elements</code>.
+Increasing this value can avoid a "failed to restore the stack" error in reports, at the
+cost of increased memory usage.
+</li>
+
+<li>
+<code>halt_on_error</code> (default <code>0</code>): Controls whether the program
+exits after reporting first data race.
+</li>
+</ul>
+
+<p>
+Example:
+</p>
+
+<pre>
+$ GORACE="log_path=/tmp/race/report strip_path_prefix=/my/go/sources/" go test -race
+</pre>
+
+<h2 id="Excluding_Tests">Excluding Tests</h2>
+
+<p>
+When you build with <code>-race</code> flag, the <code>go</code> command defines additional
+<a href="/pkg/go/build/#hdr-Build_Constraints">build tag</a> <code>race</code>.
+You can use the tag to exclude some code and tests when running the race detector.
+Some examples:
+</p>
+
+<pre>
+// +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) {
+	// ...
+}
+</pre>
+
+<h2 id="How_To_Use">How To Use</h2>
+
+<p>
+To start, run your tests using the race detector (<code>go test -race</code>).
+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 <code>-race</code> under a realistic
+workload.
+</p>
+
+<h2 id="Typical_Data_Races">Typical Data Races</h2>
+
+<p>
+Here are some typical data races.  All of them can be detected with the race detector.
+</p>
+
+<h3 id="Race_on_loop_counter">Race on loop counter</h3>
+
+<pre>
+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()
+}
+</pre>
+
+<p>
+The variable <code>i</code> 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:
+</p>
+
+<pre>
+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()
+}
+</pre>
+
+<h3 id="Accidentally_shared_variable">Accidentally shared variable</h3>
+
+<pre>
+// 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
+}
+</pre>
+
+<p>
+The fix is to introduce new variables in the goroutines (note the use of <code>:=</code>):
+</p>
+
+<pre>
+			...
+			_, err := f1.Write(data)
+			...
+			_, err := f2.Write(data)
+			...
+</pre>
+
+<h3 id="Unprotected_global_variable">Unprotected global variable</h3>
+
+<p>
+If the following code is called from several goroutines, it leads to races on the <code>service</code> map.
+Concurrent reads and writes of the same map are not safe:
+</p>
+
+<pre>
+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]
+}
+</pre>
+
+<p>
+To make the code safe, protect the accesses with a mutex:
+</p>
+
+<pre>
+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]
+}
+</pre>
+
+<h3 id="Primitive_unprotected_variable">Primitive unprotected variable</h3>
+
+<p>
+Data races can happen on variables of primitive types as well (<code>bool</code>, <code>int</code>, <code>int64</code>, etc.),
+as in this example:
+</p>
+
+<pre>
+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)
+			}
+		}
+	}()
+}
+</pre>
+
+<p>
+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 .
+</p>
+
+<p>
+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
+<a href="/pkg/sync/atomic/"><code>sync/atomic</code></a> package.
+</p>
+
+<pre>
+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)
+			}
+		}
+	}()
+}
+</pre>
+
+<h2 id="Supported_Systems">Supported Systems</h2>
+
+<p>
+The race detector runs on <code>darwin/amd64</code>, <code>linux/amd64</code>, and <code>windows/amd64</code>.
+</p>
+
+<h2 id="Runtime_Overheads">Runtime Overhead</h2>
+
+<p>
+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.
+</p>
diff --git a/doc/articles/wiki/Makefile b/doc/articles/wiki/Makefile
deleted file mode 100644
index e40b131..0000000
--- 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 f15794d..d84c1ff 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 7bf7213..b6b080d 100644
--- a/doc/articles/wiki/index.html
+++ b/doc/articles/wiki/index.html
@@ -466,7 +466,7 @@ header to the HTTP response.
 <p>
 The function <code>saveHandler</code> will handle the submission of forms
 located on the edit pages. After uncommenting the related line in
-<code>main</code>, let's implement the the handler:
+<code>main</code>, let's implement the handler:
 </p>
 
 {{code "doc/articles/wiki/final-template.go" `/^func saveHandler/` `/^}/`}}
diff --git a/doc/articles/wiki/test.bash b/doc/articles/wiki/test.bash
index 54a632c..2997f16 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 b855b9e..d44cb79 100644
--- a/doc/asm.html
+++ b/doc/asm.html
@@ -8,7 +8,11 @@
 <p>
 This document is a quick outline of the unusual form of assembly language used by the <code>gc</code>
 suite of Go compilers (<code>6g</code>, <code>8g</code>, etc.).
-It is based on the input to the Plan 9 assemblers, which is documented in detail
+The document is not comprehensive.
+</p>
+
+<p>
+The assembler is based on the input to the Plan 9 assemblers, which is documented in detail
 <a href="http://plan9.bell-labs.com/sys/doc/asm.html">on the Plan 9 site</a>.
 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 <code>FUNCDATA</code> and <code>PCDATA</code> directives contain information
 for use by the garbage collector; they are introduced by the compiler.
 </p> 
 
+<!-- Commenting out because the feature is gone but it's popular and may come back.
+
 <p>
 To see what gets put in the binary after linking, add the <code>-a</code> flag to the linker:
 </p>
@@ -98,6 +104,7 @@ codeblk [0x2000,0x1d059) at offset 0x1000
 ...
 </pre>
 
+-->
 
 <h3 id="symbols">Symbols</h3>
 
@@ -194,7 +201,7 @@ TEXT runtime·profileloop(SB),NOSPLIT,$8
 
 <p>
 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 <code>$24-8</code> 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 <code>NOSPLIT</code> is not specified for the <code>TEXT</code>,
diff --git a/doc/codewalk/sharemem.xml b/doc/codewalk/sharemem.xml
index d443e17..8b47f12 100644
--- a/doc/codewalk/sharemem.xml
+++ b/doc/codewalk/sharemem.xml
@@ -171,7 +171,7 @@ and/or writes to a shared map.
 
 <step title="Conclusion" src="doc/codewalk/urlpoll.go">
 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.
 <br/><br/>
 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 048a5d9..6529c91 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.
 </p>
 
-<h4 id="go1.1notes"><a href="/doc/go1.1">Go 1.1 Release Notes</a></h4>
+<h4 id="release notes"><a href="/doc/go1.1">Go 1.1 Release Notes</a></h4>
 <p>
-A list of significant changes in Go 1.1, with instructions for updating your
-code where necessary.
-</p>
-
-<h4 id="go1.2notes"><a href="/doc/go1.2">Go 1.2 Release Notes</a></h4>
-<p>
-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: <a href="/doc/go1.2">Go 1.2</a>, <a href="/doc/go1.3">Go 1.3</a>,
+and so on.
 </p>
 
 <h3 id="go1compat"><a href="/doc/go1compat">Go 1 and the Future of Go Programs</a></h3>
@@ -61,15 +58,22 @@ Go 1 matures.
 <h3 id="source"><a href="https://code.google.com/p/go/source">Source Code</a></h3>
 <p>Check out the Go source code.</p>
 
-<h3 id="golang-dev"><a href="http://groups.google.com/group/golang-dev">Developer Mailing List</a></h3>
-<p>The <a href="http://groups.google.com/group/golang-dev">golang-dev</a>
-mailing list is for discussing and reviewing code for the Go project.</p>
+<h3 id="golang-dev"><a href="https://groups.google.com/group/golang-dev">Developer</a> and
+<a href="https://groups.google.com/group/golang-codereviews">Code Review Mailing List</a></h3>
+<p>The <a href="https://groups.google.com/group/golang-dev">golang-dev</a>
+mailing list is for discussing code changes to the Go project.
+The <a href="https://groups.google.com/group/golang-codereviews">golang-codereviews</a>
+mailing list is for actual reviewing of the code changes (CLs).</p>
+
 <p>For general discussion of Go programming, see <a
-href="http://groups.google.com/group/golang-nuts">golang-nuts</a>.</p>
+href="https://groups.google.com/group/golang-nuts">golang-nuts</a>.</p>
 
-<h3 id="golang-checkins"><a href="http://groups.google.com/group/golang-checkins">Checkins Mailing List</a></h3>
+<h3 id="golang-checkins"><a href="https://groups.google.com/group/golang-checkins">Checkins Mailing List</a></h3>
 <p>A mailing list that receives a message summarizing each checkin to the Go repository.</p>
 
+<h3 id="golang-bugs"><a href="https://groups.google.com/group/golang-bugs">Bugs Mailing List</a></h3>
+<p>A mailing list that receives each update to the Go <a href="http://golang.org/issue">issue tracker</a>.</p>
+
 <h3 id="build_status"><a href="http://build.golang.org/">Build Status</a></h3>
 <p>View the status of Go builds across the supported operating
 systems and architectures.</p>
@@ -77,13 +81,13 @@ systems and architectures.</p>
 
 <h2 id="howto">How you can help</h2>
 
-<h3><a href="http://code.google.com/p/go/issues">Reporting issues</a></h3>
+<h3><a href="https://code.google.com/p/go/issues">Reporting issues</a></h3>
 
 <p>
 If you spot bugs, mistakes, or inconsistencies in the Go project's code or
 documentation, please let us know by
-<a href="http://code.google.com/p/go/issues/entry">filing a ticket</a>
-on our <a href="http://code.google.com/p/go/issues">issue tracker</a>.
+<a href="https://code.google.com/p/go/issues/entry">filing a ticket</a>
+on our <a href="https://code.google.com/p/go/issues">issue tracker</a>.
 (Of course, you should check it's not an existing issue before creating
 a new one.)
 </p>
@@ -102,8 +106,8 @@ To get started, read these <a href="/doc/contribute.html">contribution
 guidelines</a> for information on design, testing, and our code review process.
 </p>
 <p>
-Check <a href="http://code.google.com/p/go/issues">the tracker</a> for 
+Check <a href="https://code.google.com/p/go/issues">the tracker</a> for 
 open issues that interest you. Those labeled
-<a href="http://code.google.com/p/go/issues/list?q=status=HelpWanted">HelpWanted</a>
+<a href="https://code.google.com/p/go/issues/list?q=status=HelpWanted">HelpWanted</a>
 are particularly in need of outside help.
 </p>
diff --git a/doc/contribute.html b/doc/contribute.html
index 716a184..3927349 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.
 
 <p>
 Before undertaking to write something new for the Go project, send
-mail to the <a href="http://groups.google.com/group/golang-nuts">mailing
+mail to the <a href="https://groups.google.com/group/golang-nuts">mailing
 list</a> 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,11 +45,15 @@ tree to make sure the changes don't break other packages or programs:
 </p>
 
 <pre>
-cd $GOROOT/src
-./all.bash    # On Windows, run all.bat
+$ cd go/src
+$ ./all.bash
 </pre>
 
 <p>
+(To build under Windows use <code>all.bat</code>.)
+</p>
+
+<p>
 After running for a while, the command should print "<code>ALL TESTS PASSED</code>".
 </p>
 
@@ -95,11 +99,11 @@ command.
 
 <h3>Configure the extension</h3>
 
-<p>Edit <code>$GOROOT/.hg/hgrc</code> to add:</p>
+<p>Edit <code>.hg/hgrc</code> in the root of your Go checkout to add:</p>
 
 <pre>
 [extensions]
-codereview = $GOROOT/lib/codereview/codereview.py
+codereview = /path/to/go/lib/codereview/codereview.py
 
 [ui]
 username = Your Name <you at server.dom>
@@ -110,6 +114,16 @@ The <code>username</code> information will not be used unless
 you are a committer (see below), but Mercurial complains if it is missing.
 </p>
 
+<p>
+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.
+</p>
+
+<p>To contribute to subrepositories, edit the <code>.hg/hgrc</code> for each
+subrepository in the same way. For example, add the codereview extension to
+<code>code.google.com/p/go.tools/.hg/hgrc</code>.
+</p>
+
 <h3>Understanding the extension</h3>
 
 <p>After adding the code review extension, you can run</p>
@@ -126,16 +140,10 @@ $ hg help change
 </pre>
 
 <p>
-As the codereview extension is only enabled for your checkout
-in <code>$GOROOT</code>, the remainder of this document assumes you
-are inside <code>$GOROOT</code> when issuing commands.
-</p>
-
-<p>
-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
-<a href="https://code.google.com/p/go-wiki/wiki/CodeReview">CodeReview page</a> 
-on the <a href="http://code.google.com/p/go-wiki/wiki">Go Wiki</a> for details.
+<a href="https://code.google.com/p/go-wiki/wiki/CodeReview">CodeReview page</a>
+on the <a href="https://code.google.com/p/go-wiki/wiki">Go Wiki</a> for details.
 </p>
 
 <h3>Log in to the code review site.</h3>
@@ -146,7 +154,7 @@ The code review server uses a Google Account to authenticate.
 <a href="https://www.google.com/accounts/Login?hl=en&continue=http://www.google.com/">sign in at google.com</a>,
 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 <a href="http://code.google.com/p/go/source/list">Mercurial change log</a>
+will be recorded in the <a href="https://code.google.com/p/go/source/list">Mercurial change log</a>
 and in the <a href="/CONTRIBUTORS"><code>CONTRIBUTORS</code></a> file.
 You can <a href="https://www.google.com/accounts/NewAccount">create a Google Account</a>
 associated with any address where you receive email.
@@ -155,7 +163,6 @@ application-specific password and use that when prompted for a password.
 </p>
 
 <pre>
-$ cd $GOROOT
 $ hg code-login
 Email (login for uploading to codereview.appspot.com): rsc at golang.org
 Password for rsc at golang.org:
@@ -165,7 +172,7 @@ Saving authentication cookies to /Users/rsc/.codereview_upload_cookies_coderevie
 
 <h3>Configure your account settings.</h3>
 
-<p>Edit your <a href="http://codereview.appspot.com/settings">code review settings</a>.
+<p>Edit your <a href="https://codereview.appspot.com/settings">code review settings</a>.
 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
-<a href="http://groups.google.com/group/golang-dev">golang-dev at googlegroups.com</a>
+<a href="https://groups.google.com/group/golang-codereviews">golang-codereviews at googlegroups.com</a>
 mailing list will be used as the reviewer.
 </p>
 
@@ -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 at googlegroups.com
+Reviewer: golang-codereviews at googlegroups.com
 CC: math-nuts at swtch.com
 
 Description:
@@ -286,11 +293,11 @@ Files:
 
 <p>
 The special sentence “Fixes issue 159.” associates
-the change with issue 159 in the <a href="http://code.google.com/p/go/issues/list">Go issue tracker</a>.
+the change with issue 159 in the <a href="https://code.google.com/p/go/issues/list">Go issue tracker</a>.
 When this change is eventually submitted, the issue
 tracker will automatically mark the issue as fixed.
 (These conventions are described in detail by the
-<a href="http://code.google.com/p/support/wiki/IssueTracker#Integration_with_version_control">Google Project Hosting Issue Tracker documentation</a>.)
+<a href="https://code.google.com/p/support/wiki/IssueTracker#Integration_with_version_control">Google Project Hosting Issue Tracker documentation</a>.)
 </p>
 
 <p>
@@ -302,7 +309,7 @@ which <code>hg change</code> will print, something like:
 </p>
 
 <pre>
-CL created: http://codereview.appspot.com/99999
+CL created: https://codereview.appspot.com/99999
 </pre>
 
 <h3>Adding or removing files from an existing change</h3>
@@ -448,7 +455,7 @@ lines blank and then run:
 </p>
 
 <pre>
-$ hg mail -r golang-dev at googlegroups.com --cc math-nuts at swtch.com 99999
+$ hg mail -r golang-codereviews at googlegroups.com --cc math-nuts at swtch.com 99999
 </pre>
 
 <p>to achieve the same effect.</p>
@@ -473,31 +480,33 @@ to send comments back.
 <h3>Revise and upload</h3>
 
 <p>
-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 <code>hg upload</code> using the change
-list number assigned during <code>hg change</code>
+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 (<code>PTAL</code>). Use the change list number
+assigned during <code>hg change</code>
 </p>
 
 <pre>
-$ hg upload 99999
+$ hg mail 99999
 </pre>
 
+
 <p>
-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
 </p>
 
 <pre>
-$ hg mail 99999
+$ hg upload 99999
 </pre>
 
-<p>again to upload the latest copy and send mail asking the reviewers to please take another look
-(<code>PTAL</code>).
+<p>
+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.
 </p>
+
 <p>
 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
 </pre>
 
+<h3>More information</h3>
+
+<p>
+In addition to the information here, the Go community maintains a <a href="https://code.google.com/p/go-wiki/wiki/CodeReview">CodeReview</a> wiki page.
+Feel free to contribute to this page as you learn the review process.
+</p>
+
 <h2 id="copyright">Copyright</h2>
 
 <p>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 <a href="http://code.google.com/p/go/source/list">Mercurial change log</a>
+Instead, your name will appear in the <a href="https://code.google.com/p/go/source/list">Mercurial change log</a>
 and in the <a href="/CONTRIBUTORS"><code>CONTRIBUTORS</code></a> file
 and perhaps the <a href="/AUTHORS"><code>AUTHORS</code></a> file.
 </p>
@@ -616,13 +632,15 @@ In order for them to do that, you need to have completed one of the
 contributor license agreements:
 <ul>
 <li>
-If you are the copyright holder, you will need to agree to
-the <a href="http://code.google.com/legal/individual-cla-v1.0.html">individual
+If you are the copyright holder, you will need to agree to the
+<a href="https://developers.google.com/open-source/cla/individual">individual
 contributor license agreement</a>, which can be completed online.
 </li>
 <li>
 If your organization is the copyright holder, the organization
-will need to agree to the <a href="http://code.google.com/legal/corporate-cla-v1.0.html">corporate contributor license agreement</a>.
+will need to agree to the
+<a href="https://developers.google.com/open-source/cla/corporate">corporate
+contributor license agreement</a>.
 (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.
 <p>Code that you contribute should use the standard copyright header:</p>
 
 <pre>
-// 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.
 </pre>
diff --git a/doc/debugging_with_gdb.html b/doc/debugging_with_gdb.html
index b893f93..afaedf7 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
 <a href="http://sourceware.org/gdb/current/onlinedocs/gdb/">GDB manual</a>.
 </i></p>
 
+<p>
+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.
+</p>
+
+<p>
+In time, a more Go-centric debugging architecture may be required.
+</p>
+
 <h2 id="Introduction">Introduction</h2>
 
 <p>
@@ -19,8 +36,8 @@ use to inspect a live process or a core dump.
 </p>
 
 <p>
-Pass the <code>'-s'</code> flag to the linker to omit the debug information
-(for example, <code>go build -ldflags "-s" prog.go</code>).
+Pass the <code>'-w'</code> flag to the linker to omit the debug information
+(for example, <code>go build -ldflags "-w" prog.go</code>).
 </p>
 
 <p>
diff --git a/doc/devel/release.html b/doc/devel/release.html
index 5511db7..3a3d5bc 100644
--- a/doc/devel/release.html
+++ b/doc/devel/release.html
@@ -13,12 +13,38 @@ hg pull
 hg update <i>tag</i>
 </pre>
 
+<h2 id="go1.3">go1.3 (released 2014/06/18)</h2>
+
+<p>
+Go 1.3 is a major release of Go.
+Read the <a href="/doc/go1.3">Go 1.3 Release Notes</a> for more information.
+</p>
+
+<h2 id="go1.2">go1.2 (released 2013/12/01)</h2>
+
+<p>
+Go 1.2 is a major release of Go.
+Read the <a href="/doc/go1.2">Go 1.2 Release Notes</a> for more information.
+</p>
+
+<h3 id="go1.2.minor">Minor revisions</h3>
+
+<p>
+go1.2.1 (released 2014/03/02) includes bug fixes to the <code>runtime</code>, <code>net</code>, and <code>database/sql</code> packages.
+See the <a href="https://code.google.com/p/go/source/list?name=release-branch.go1.2&r=7ada9e760ce34e78aee5b476c9621556d0fa5d31">change history</a> for details.
+</p>
+
+<p>
+go1.2.2 (released 2014/05/05) includes a
+<a href="https://code.google.com/p/go/source/detail?r=bda3619e7a2c&repo=tools">security fix</a>
+that affects the tour binary included in the binary distributions (thanks to Guillaume T).
+</p>
+
 <h2 id="go1.1">go1.1 (released 2013/05/13)</h2>
 
 <p>
 Go 1.1 is a major release of Go.
-Read the <a href="/doc/go1.1.html">Go 1.1 Release Notes</a> for
-more information.
+Read the <a href="/doc/go1.1">Go 1.1 Release Notes</a> for more information.
 </p>
 
 <h3 id="go1.1.minor">Minor revisions</h3>
@@ -363,12 +389,6 @@ variable to build and install your own code and external libraries outside of
 the Go tree (and avoid writing Makefiles).
 </p>
 
-<h3 id="go1.2.minor">Minor revisions</h3>
-
-<p>
-go1.2.1 (released 2014/03/02) includes bug fixes to the <code>runtime</code>, <code>net</code>, and <code>database/sql</code> packages.
-See the <a href="https://code.google.com/p/go/source/list?name=release-branch.go1.2&r=7ada9e760ce34e78aee5b476c9621556d0fa5d31">change history</a> for details.
-</p>
 
 <h3 id="r58.minor">Minor revisions</h3>
 
diff --git a/doc/docs.html b/doc/docs.html
index 7aad8da..bb2d52d 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.
 </p>
 
+<h3 id="release"><a href="/doc/devel/release.html">Release History</a></h3>
+<p>A summary of the changes between Go releases.</p>
+
 
 <h2 id="articles">Articles</h2>
 
@@ -143,7 +146,9 @@ Guided tours of Go programs.
 <li><a href="/doc/gdb">Debugging Go Code with GDB</a></li>
 <li><a href="/blog/godoc-documenting-go-code">Godoc: documenting Go code</a> - writing good documentation for <a href="/cmd/godoc/">godoc</a>.</li>
 <li><a href="/blog/profiling-go-programs">Profiling Go Programs</a></li>
-<li><a href="/blog/race-detector">Data Race Detector</a> - testing Go programs for race conditions.</li>
+<li><a href="/doc/articles/race_detector.html">Data Race Detector</a> - a manual for the data race detector.</li>
+<li><a href="/blog/race-detector">Introducing the Go Race Detector</a> - an introduction to the race detector.
+<li><a href="/doc/asm">A Quick Guide to Go's Assembler</a> - an introduction to the assembler used by Go.
 </ul>
 
 <h4 id="articles_more">More</h4>
diff --git a/doc/effective_go.html b/doc/effective_go.html
index f919951..25266d6 100644
--- a/doc/effective_go.html
+++ b/doc/effective_go.html
@@ -214,7 +214,7 @@ not be used.
 One adjustment <code>godoc</code> does do is to display indented
 text in a fixed-width font, suitable for program snippets.
 The package comment for the
-<a href="http://golang.org/pkg/fmt/"><code>fmt</code> package</a> uses this to good effect.
+<a href="/pkg/fmt/"><code>fmt</code> package</a> uses this to good effect.
 </p>
 
 <p>
@@ -288,7 +288,7 @@ var (
 </pre>
 
 <p>
-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.
 </p>
 
@@ -350,7 +350,7 @@ not <code>encoding_base64</code> and not <code>encodingBase64</code>.
 </p>
 
 <p>
-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 <code>import .</code> notation, which can simplify
@@ -701,6 +701,7 @@ for _, value := range array {
 
 <p>
 The blank identifier has many uses, as described in <a href="#blank">a later section</a>.
+</p>
 
 <p>
 For strings, the <code>range</code> 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) <code>rune</code> is Go terminology for a
 single Unicode code point.
-See <a href="http://golang.org/ref/spec#Rune_literals">the language specification</a>
+See <a href="/ref/spec#Rune_literals">the language specification</a>
 for details.)
 The loop
 </p>
@@ -849,7 +850,7 @@ func Compare(a, b []byte) int {
 }
 </pre>
 
-<h2 id="type_switch">Type switch</h2>
+<h3 id="type_switch">Type switch</h3>
 
 <p>
 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)
 </pre>
 <p>
 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
-<code>b</code>, <i>slice</i> (here used as a verb) the buffer.
+any.
+To read into the first 32 bytes of a larger buffer
+<code>buf</code>, <i>slice</i> (here used as a verb) the buffer.
 </p>
 <pre>
     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:
 </p>
 
 <pre>
@@ -2054,10 +2056,22 @@ We pass the address of a <code>ByteSlice</code>
 because only <code>*ByteSlice</code> satisfies <code>io.Writer</code>.
 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.
 </p>
+
+<p>
+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 <code>b</code> is addressable, so we can call
+its <code>Write</code> method with just <code>b.Write</code>. The compiler
+will rewrite that to <code>(&b).Write</code> for us.
+</p>
+
 <p>
 By the way, the idea of using <code>Write</code> on a slice of bytes
 is central to the implementation of <code>bytes.Buffer</code>.
@@ -2173,6 +2187,7 @@ A one-case type switch would do, but so would a <em>type assertion</em>.
 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 <code>type</code> keyword:
+</p>
 
 <pre>
 value.(typeName)
@@ -2463,6 +2478,8 @@ It has uses beyond those we've seen already.
 <p>
 The use of a blank identifier in a <code>for</code> <code>range</code> loop is a
 special case of a general situation: multiple assignment.
+</p>
+
 <p>
 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.
 <p>
 A buffered channel can be used like a semaphore, for instance to
 limit throughput.  In this example, incoming requests are passed
-to <code>handle</code>, 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 <code>handle</code>, 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 <code>process</code>,
-so during initialization we prime the channel by filling it to capacity.
+simultaneous calls to <code>process</code>.
 </p>
 <pre>
 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) {
 </pre>
 
 <p>
-Because data synchronization occurs on a receive from a channel
-(that is, the send "happens before" the receive; see
-<a href="/ref/mem">The Go Memory Model</a>),
-acquisition of the semaphore must be on a channel receive, not a send.
+Once <code>MaxOutstanding</code> handlers are executing <code>process</code>,
+any more will block trying to send into the filled channel buffer,
+until one of the existing handlers finishes and receives from the buffer.
 </p>
 
 <p>
@@ -2988,10 +2997,10 @@ Here's an obvious solution, but beware it has a bug we'll fix subsequently:
 <pre>
 func Serve(queue chan *Request) {
     for req := range queue {
-        <-sem
+        sem <- 1
         go func() {
             process(req) // Buggy; see explanation below.
-            sem <- 1
+            <-sem
         }()
     }
 }</pre>
@@ -3009,10 +3018,10 @@ to the closure in the goroutine:
 <pre>
 func Serve(queue chan *Request) {
     for req := range queue {
-        <-sem
+        sem <- 1
         go func(req *Request) {
             process(req)
-            sem <- 1
+            <-sem
         }(req)
     }
 }</pre>
@@ -3027,11 +3036,11 @@ name, as in this example:
 <pre>
 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
         }()
     }
 }</pre>
@@ -3278,9 +3287,18 @@ the garbage collector for bookkeeping.
 
 <p>
 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 <code>error</code>,
+return value.
+It is good style to use this feature to provide detailed error information.
+For example, as we'll see, <code>os.Open</code> doesn't
+just return a <code>nil</code> pointer on failure, it also returns an
+error value that describes what went wrong.
+</p>
+
+<p>
+By convention, errors have type <code>error</code>,
 a simple built-in interface.
 </p>
 <pre>
@@ -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, <code>os.Open</code> returns an <code>os.PathError</code>.
+As mentioned, alongside the usual <code>*os.File</code>
+return value, <code>os.Open</code> also returns an
+error value.
+If the file is opened successfully, the error will be <code>nil</code>,
+but when there is a problem, it will hold an
+<code>os.PathError</code>:
 </p>
 <pre>
 // PathError records an error and the operation and
diff --git a/doc/gccgo_install.html b/doc/gccgo_install.html
index eef5ac2..4c1a8c2 100644
--- a/doc/gccgo_install.html
+++ b/doc/gccgo_install.html
@@ -291,9 +291,9 @@ first one that it finds.
 
 <ul>
 <li><code><var>FILE</var>.gox</code>
-<li><code><var>FILE</var>.o</code>
 <li><code>lib<var>FILE</var>.so</code>
 <li><code>lib<var>FILE</var>.a</code>
+<li><code><var>FILE</var>.o</code>
 </ul>
 
 <p>
@@ -522,4 +522,4 @@ port is for x86. The goal is to extend the port to most of the
 <a href="http://www.rtems.org/wiki/index.php/SupportedCPUs">
 architectures supported by <code>RTEMS</code></a>. For more information on the port,
 as well as instructions on how to install it, please see this
-<a href="http://www.rtems.com/wiki/index.php/GCCGoRTEMS"><code>RTEMS</code> Wiki page</a>.
+<a href="http://www.rtems.org/wiki/index.php/GCCGoRTEMS"><code>RTEMS</code> Wiki page</a>.
diff --git a/doc/go1.3.html b/doc/go1.3.html
new file mode 100644
index 0000000..ae5c025
--- /dev/null
+++ b/doc/go1.3.html
@@ -0,0 +1,599 @@
+<!--{
+	"Title": "Go 1.3 Release Notes",
+	"Path":  "/doc/go1.3",
+	"Template": true
+}-->
+
+<h2 id="introduction">Introduction to Go 1.3</h2>
+
+<p>
+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 <a href="/doc/go1compat.html">promise
+of compatibility</a>,
+and almost everything 
+will continue to compile and run without change when moved to 1.3.
+</p>
+
+<h2 id="os">Changes to the supported operating systems and architectures</h2>
+
+<h3 id="win2000">Removal of support for Windows 2000</h3>
+
+<p>
+Microsoft stopped supporting Windows 2000 in 2010.
+Since it has <a href="https://codereview.appspot.com/74790043">implementation difficulties</a>
+regarding exception handling (signals in Unix terminology),
+as of Go 1.3 it is not supported by Go either.
+</p>
+
+<h3 id="dragonfly">Support for DragonFly BSD</h3>
+
+<p>
+Go 1.3 now includes experimental support for DragonFly BSD on the <code>amd64</code> (64-bit x86) and <code>386</code> (32-bit x86) architectures.
+It uses DragonFly BSD 3.6 or above.
+</p>
+
+<h3 id="freebsd">Support for FreeBSD</h3>
+
+<p>
+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.
+</p>
+
+<p>
+As of Go 1.3, support for Go on FreeBSD requires that the kernel be compiled with the
+<code>COMPAT_FREEBSD32</code> flag configured.
+</p>
+
+<p>
+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.
+</p>
+
+<h3 id="nacl">Support for Native Client</h3>
+
+<p>
+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 (<code>GOARCH=386</code>) and also on 64-bit Intel, but using
+32-bit pointers (<code>GOARCH=amd64p32</code>).
+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 <a href="https://developers.google.com/native-client/dev/">here</a>;
+how to set up the Go version is described <a href="http://golang.org/wiki/NativeClient">here</a>.
+</p>
+
+<h3 id="netbsd">Support for NetBSD</h3>
+
+<p>
+As of Go 1.3, support for Go on NetBSD requires NetBSD 6.0 or above.
+</p>
+
+<h3 id="openbsd">Support for OpenBSD</h3>
+
+<p>
+As of Go 1.3, support for Go on OpenBSD requires OpenBSD 5.5 or above.
+</p>
+
+<h3 id="plan9">Support for Plan 9</h3>
+
+<p>
+Go 1.3 now includes experimental support for Plan 9 on the <code>386</code> (32-bit x86) architecture.
+It requires the <code>Tsemacquire</code> syscall, which has been in Plan 9 since June, 2012.
+</p>
+
+<h3 id="solaris">Support for Solaris</h3>
+
+<p>
+Go 1.3 now includes experimental support for Solaris on the <code>amd64</code> (64-bit x86) architecture.
+It requires illumos, Solaris 11 or above.
+</p>
+
+<h2 id="memory">Changes to the memory model</h2>
+
+<p>
+The Go 1.3 memory model <a href="https://codereview.appspot.com/75130045">adds a new rule</a>
+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.
+</p>
+
+<h2 id="impl">Changes to the implementations and tools</h2>
+
+<h3 id="stacks">Stack</h3>
+
+<p>
+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
+<a href="http://golang.org/s/contigstacks">design document</a>.
+</p>
+
+<h3 id="garbage_collector">Changes to the garbage collector</h3>
+
+<p>
+For a while now, the garbage collector has been <em>precise</em> 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.
+</p>
+
+<p>
+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 <a href="/pkg/unsafe/">package unsafe</a>
+to store integers in pointer-typed values are illegal and will crash if the runtime detects the behavior.
+Programs that use <a href="/pkg/unsafe/">package unsafe</a> 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
+<a href="http://en.wikipedia.org/wiki/Dangling_pointer">dangling pointers</a>.
+</p>
+
+<p>
+<em>Updating</em>: Code that uses <code>unsafe.Pointer</code> to convert
+an integer-typed value held in memory into a pointer is illegal and must be rewritten.
+Such code can be identified by <code>go vet</code>.
+</p>
+
+<h3 id="map">Map iteration</h3>
+
+<p>
+Iterations over small maps no longer happen in a consistent order.
+Go 1 defines that “<a href="http://golang.org/ref/spec#For_statements">The iteration order over maps
+is not specified and is not guaranteed to be the same from one iteration to the next.</a>”
+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.
+</p>
+
+<p>
+<em>Updating</em>: 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.
+</p>
+
+<h3 id="liblink">The linker</h3>
+
+<p>
+As part of the general <a href="http://golang.org/s/go13linker">overhaul</a> 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 <code>liblink</code>.
+By doing instruction selection only once, when the package is first compiled,
+this can speed up compilation of large projects significantly.
+</p>
+
+<p>
+<em>Updating</em>: Although this is a major internal change, it should have no
+effect on programs.
+</p>
+
+<h3 id="gccgo">Status of gccgo</h3>
+
+<p>
+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.
+</p>
+
+<h3 id="gocmd">Changes to the go command</h3>
+
+<p>
+The <a href="/cmd/go/"><code>cmd/go</code></a> command has several new
+features.
+The <a href="/cmd/go/"><code>go run</code></a> and
+<a href="/cmd/go/"><code>go test</code></a> subcommands
+support a new <code>-exec</code> option to specify an alternate
+way to run the resulting binary.
+Its immediate purpose is to support NaCl.
+</p>
+
+<p>
+The test coverage support of the <a href="/cmd/go/"><code>go test</code></a>
+subcommand now automatically sets the coverage mode to <code>-atomic</code>
+when the race detector is enabled, to eliminate false reports about unsafe
+access to coverage counters.
+</p>
+
+<p>
+The <a href="/cmd/go/"><code>go test</code></a> subcommand
+now always builds the package, even if it has no test files.
+Previously, it would do nothing if no test files were present.
+</p>
+
+<p>
+The <a href="/cmd/go/"><code>go build</code></a> subcommand
+supports a new <code>-i</code> option to install dependencies
+of the specified target, but not the target itself.
+</p>
+
+<p>
+Cross compiling with <a href="/cmd/cgo/"><code>cgo</code></a> 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.
+</p>
+
+<p>
+Finally, the go command now supports packages that import Objective-C
+files (suffixed <code>.m</code>) through cgo.
+</p>
+
+<h3 id="cgo">Changes to cgo</h3>
+
+<p>
+The <a href="/cmd/cgo/"><code>cmd/cgo</code></a> command,
+which processes <code>import "C"</code> 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 <code>*[0]byte</code>,
+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.
+</p>
+
+<p>
+Given the C declaration <code>typedef struct S T</code> for an incomplete <code>struct S</code>,
+some Go code used this bug to refer to the types <code>C.struct_S</code> and <code>C.T</code> 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 <code>*C.FILE</code>
+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.
+</p>
+
+<p>
+<em>Updating</em>: 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 <a href="/pkg/unsafe/#Pointer"><code>unsafe.Pointer</code></a>.
+</p>
+
+<h3 id="swig">SWIG 3.0 required for programs that use SWIG</h3>
+
+<p>
+For Go programs that use SWIG, SWIG version 3.0 is now required.
+The <a href="/cmd/go"><code>cmd/go</code></a> command will now link the
+SWIG generated object files directly into the binary, rather than
+building and linking with a shared library.
+</p>
+
+<h3 id="gc_flag">Command-line flag parsing</h3>
+
+<p>
+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,
+<code>go tool 6a -SDfoo</code> must now be written
+<code>go tool 6a -S -D foo</code>.
+(The same change was made to the compilers and linkers in <a href="/doc/go1.1#gc_flag">Go 1.1</a>.)
+</p>
+
+<h3 id="godoc">Changes to godoc</h3>
+<p>
+When invoked with the <code>-analysis</code> flag, 
+<a href="http://godoc.org/code.google.com/p/go.tools/cmd/godoc">godoc</a>
+now performs sophisticated <a href="/lib/godoc/analysis/help.html">static
+analysis</a> 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.
+</p>
+
+<h3 id="misc">Miscellany</h3>
+
+<p>
+The program <code>misc/benchcmp</code> 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 <code>go.tools</code> repo.
+Documentation is <a href="http://godoc.org/code.google.com/p/go.tools/cmd/benchcmp">here</a>.
+</p>
+
+<p>
+For the few of us that build Go distributions, the tool <code>misc/dist</code> has been
+moved and renamed; it now lives in <code>misc/makerelease</code>, still in the main repository.
+</p>
+
+<h2 id="performance">Performance</h2>
+
+<p>
+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:
+</p>
+
+<ul> 
+
+<li>
+The runtime handles defers more efficiently, reducing the memory footprint by about two kilobytes
+per goroutine that calls defer.
+</li>
+
+<li>
+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.
+</li>
+
+<li>
+The race detector (see <a href="/doc/articles/race_detector.html">this guide</a>)
+is now about 40% faster.
+</li>
+
+<li>
+The regular expression package <a href="/pkg/regexp/"><code>regexp</code></a>
+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.
+</li>
+
+</ul>
+
+<p>
+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.
+</p>
+
+<h2 id="library">Changes to the standard library</h2>
+
+<h3 id="new_packages">New packages</h3>
+
+<p>
+A new package <a href="/pkg/debug/plan9obj/"><code>debug/plan9obj</code></a> was added to the standard library.
+It implements access to Plan 9 <a href="http://plan9.bell-labs.com/magic/man2html/6/a.out">a.out</a> object files.
+</p>
+
+<h3 id="major_library_changes">Major changes to the library</h3>
+
+<p>
+A previous bug in <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a>
+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.
+</p>
+
+<p>
+There is an important new type added to the standard library: <a href="/pkg/sync/#Pool"><code>sync.Pool</code></a>.
+It provides an efficient mechanism for implementing certain types of caches whose memory
+can be reclaimed automatically by the system.
+</p>
+
+<p>
+The <a href="/pkg/testing/"><code>testing</code></a> package's benchmarking helper,
+<a href="/pkg/testing/#B"><code>B</code></a>, now has a
+<a href="/pkg/testing/#B.RunParallel"><code>RunParallel</code></a> method
+to make it easier to run benchmarks that exercise multiple CPUs.
+</p>
+
+<p>
+<em>Updating</em>: The crypto/tls fix may break existing code, but such
+code was erroneous and should be updated.
+</p>
+
+<h3 id="minor_library_changes">Minor changes to the library</h3>
+
+<p>
+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.
+</p>
+
+<ul>
+
+<li> In the <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> package,
+a new <a href="/pkg/crypto/tls/#DialWithDialer"><code>DialWithDialer</code></a>
+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
+<a href="/pkg/crypto/tls/#ConnectionState"><code>ConnectionState</code></a>
+struct.
+</li>
+
+<li> The <a href="/pkg/crypto/x509/#CreateCertificate"><code>CreateCertificate</code></a>
+function of the <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> package
+now supports parsing (and elsewhere, serialization) of PKCS #10 certificate
+signature requests.
+</li>
+
+<li>
+The formatted print functions of the <code>fmt</code> package now define <code>%F</code>
+as a synonym for <code>%f</code> when printing floating-point values.
+</li>
+
+<li>
+The <a href="/pkg/math/big/"><code>math/big</code></a> package's
+<a href="/pkg/math/big/#Int"><code>Int</code></a> and
+<a href="/pkg/math/big/#Rat"><code>Rat</code></a> types
+now implement
+<a href="/pkg/encoding/#TextMarshaler"><code>encoding.TextMarshaler</code></a> and
+<a href="/pkg/encoding/#TextUnmarshaler"><code>encoding.TextUnmarshaler</code></a>.
+</li>
+
+<li>
+The complex power function, <a href="/pkg/math/cmplx/#Pow"><code>Pow</code></a>,
+now specifies the behavior when the first argument is zero.
+It was undefined before.
+The details are in the <a href="/pkg/math/cmplx/#Pow">documentation for the function</a>.
+</li>
+
+<li>
+The <a href="/pkg/net/http/"><code>net/http</code></a> package now exposes the
+properties of a TLS connection used to make a client request in the new
+<a href="/pkg/net/http/#Response"><code>Response.TLS</code></a> field.
+</li>
+
+<li>
+The <a href="/pkg/net/http/"><code>net/http</code></a> package now
+allows setting an optional server error logger
+with <a href="/pkg/net/http/#Server"><code>Server.ErrorLog</code></a>.
+The default is still that all errors go to stderr.
+</li>
+
+<li>
+The <a href="/pkg/net/http/"><code>net/http</code></a> package now
+supports disabling HTTP keep-alive connections on the server
+with <a href="/pkg/net/http/#Server.SetKeepAlivesEnabled"><code>Server.SetKeepAlivesEnabled</code></a>.
+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.
+</li>
+
+<li>
+The <a href="/pkg/net/http/"><code>net/http</code></a> package adds an optional
+<a href="/pkg/net/http/#Transport"><code>Transport.TLSHandshakeTimeout</code></a>
+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 <a href="/pkg/net/http#DefaultTransport"><code>DefaultTransport</code></a>.
+</li>
+
+<li>
+The <a href="/pkg/net/http/"><code>net/http</code></a> package's
+<a href="/pkg/net/http/#DefaultTransport"><code>DefaultTransport</code></a>,
+used by the HTTP client code, now
+enables <a href="http://en.wikipedia.org/wiki/Keepalive#TCP_keepalive">TCP
+keep-alives</a> by default.
+Other <a href="/pkg/net/http/#Transport"><code>Transport</code></a>
+values with a nil <code>Dial</code> field continue to function the same
+as before: no TCP keep-alives are used.
+</li>
+
+<li>
+The <a href="/pkg/net/http/"><code>net/http</code></a> package
+now enables <a href="http://en.wikipedia.org/wiki/Keepalive#TCP_keepalive">TCP
+keep-alives</a> for incoming server requests when
+<a href="/pkg/net/http/#ListenAndServe"><code>ListenAndServe</code></a>
+or
+<a href="/pkg/net/http/#ListenAndServeTLS"><code>ListenAndServeTLS</code></a>
+are used.
+When a server is started otherwise, TCP keep-alives are not enabled.
+</li>
+
+<li>
+The <a href="/pkg/net/http/"><code>net/http</code></a> package now
+provides an
+optional <a href="/pkg/net/http/#Server"><code>Server.ConnState</code></a>
+callback to hook various phases of a server connection's lifecycle
+(see <a href="/pkg/net/http/#ConnState"><code>ConnState</code></a>).
+This can be used to implement rate limiting or graceful shutdown.
+</li>
+
+<li>
+The <a href="/pkg/net/http/"><code>net/http</code></a> package's HTTP
+client now has an
+optional <a href="/pkg/net/http/#Client"><code>Client.Timeout</code></a>
+field to specify an end-to-end timeout on requests made using the
+client.
+</li>
+
+<li> In the <a href="/pkg/net/"><code>net</code></a> package,
+the <a href="/pkg/net/#Dialer"><code>Dialer</code></a> struct now
+has a <code>KeepAlive</code> option to specify a keep-alive period for the connection.
+</li>
+
+<li>
+The <a href="/pkg/net/http/"><code>net/http</code></a> package's 
+<a href="/pkg/net/http/#Transport"><code>Transport</code></a>
+now closes <a href="/pkg/net/http/#Request"><code>Request.Body</code></a>
+consistently, even on error.
+</li>
+
+<li>
+The <a href="/pkg/os/exec/"><code>os/exec</code></a> package now implements
+what the documentation has always said with regard to relative paths for the binary.
+In particular, it only calls <a href="/pkg/os/exec/#LookPath"><code>LookPath</code></a>
+when the binary's file name contains no path separators.
+</li>
+
+<li>
+The <a href="/pkg/reflect/#Value.SetMapIndex"><code>SetMapIndex</code></a>
+function in the <a href="/pkg/reflect/"><code>reflect</code></a> package
+no longer panics when deleting from a <code>nil</code> map.
+</li>
+
+<li>
+If the main goroutine calls 
+<a href="/pkg/runtime/#Goexit"><code>runtime.Goexit</code></a>
+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.
+</li>
+
+<li>
+The runtime/debug package now has a new function
+<a href="/pkg/runtime/debug/#WriteHeapDump"><code>debug.WriteHeapDump</code></a>
+that writes out a description of the heap.
+</li>
+
+<li>
+The <a href="/pkg/strconv/#CanBackquote"><code>CanBackquote</code></a>
+function in the <a href="/pkg/strconv/"><code>strconv</code></a> package
+now considers the <code>DEL</code> character, <code>U+007F</code>, to be
+non-printing.
+</li>
+
+<li>
+The <a href="/pkg/syscall/"><code>syscall</code></a> package now provides
+<a href="/pkg/syscall/#SendmsgN"><code>SendmsgN</code></a>
+as an alternate version of
+<a href="/pkg/syscall/#Sendmsg"><code>Sendmsg</code></a>
+that returns the number of bytes written.
+</li>
+
+<li>
+On Windows, the <a href="/pkg/syscall/"><code>syscall</code></a> package now
+supports the cdecl calling convention through the addition of a new function
+<a href="/pkg/syscall/#NewCallbackCDecl"><code>NewCallbackCDecl</code></a>
+alongside the existing function
+<a href="/pkg/syscall/#NewCallback"><code>NewCallback</code></a>.
+</li>
+
+<li>
+The <a href="/pkg/testing/"><code>testing</code></a> package now
+diagnoses tests that call <code>panic(nil)</code>, which are almost always erroneous.
+Also, tests now write profiles (if invoked with profiling flags) even on failure.
+</li>
+
+<li>
+The <a href="/pkg/unicode/"><code>unicode</code></a> package and associated
+support throughout the system has been upgraded from
+Unicode 6.2.0 to <a href="http://www.unicode.org/versions/Unicode6.3.0/">Unicode 6.3.0</a>.
+</li>
+
+</ul>
diff --git a/doc/go1.html b/doc/go1.html
index 3bbe5d3..a664b65 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
 <a href="/doc/install">Getting Started</a> page, while
 the distributions themselves are listed on the
-<a href="http://code.google.com/p/go/downloads/list">downloads page</a>.
+<a href="/dl/">downloads page</a>.
diff --git a/doc/go_faq.html b/doc/go_faq.html
index f65dff7..b1945dd 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.
 </p>
 
 <p>
-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.
 </p>
 
@@ -446,7 +448,7 @@ Why are map operations not defined to be atomic?</h3>
 
 <p>
 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?</h3>
 There is a program, <code>godoc</code>, 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
-<a href="http://golang.org/pkg/">http://golang.org/pkg/</a>.
+<a href="/pkg/">http://golang.org/pkg/</a>.
 In fact, <code>godoc</code> implements the full site at
-<a href="http://golang.org/">http://golang.org/</a>.
+<a href="/">http://golang.org/</a>.
 </p>
 
 <h3 id="Is_there_a_Go_programming_style_guide">
@@ -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 <code>gofmt</code>.
 </p>
 
+<p>
+The document titled
+<a href="http://golang.org/s/comments">Go Code Review Comments</a>
+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.
+</p>
+
 <h3 id="How_do_I_submit_patches_to_the_Go_libraries">
 How do I submit patches to the Go libraries?</h3>
 
@@ -1427,7 +1437,7 @@ each closure shares that single variable. When the closure runs, it prints the
 value of <code>v</code> at the time <code>fmt.Println</code> is executed,
 but <code>v</code> may have been modified since the goroutine was launched.
 To help detect this and other problems before they happen, run
-<a href="http://golang.org/cmd/go/#hdr-Run_go_tool_vet_on_packages"><code>go vet</code></a>.
+<a href="/cmd/go/#hdr-Run_go_tool_vet_on_packages"><code>go vet</code></a>.
 </p>
 
 <p>
@@ -1606,9 +1616,10 @@ it now. <code>Gccgo</code>'s run-time support uses <code>glibc</code>.
 <code>Gc</code> 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 <code>gccgo</code> compiler implements segmented
-stacks on Linux only, supported by recent modifications to the gold linker.
+resizable stacks for goroutines.
+The <code>gccgo</code> compiler implements these on Linux only,
+using a technique called segmented stacks,
+supported by recent modifications to the gold linker.
 </p>
 
 <h3 id="Why_is_my_trivial_program_such_a_large_binary">
diff --git a/doc/go_mem.html b/doc/go_mem.html
index 3e769da..2ea1ded 100644
--- a/doc/go_mem.html
+++ b/doc/go_mem.html
@@ -1,6 +1,6 @@
 <!--{
 	"Title": "The Go Memory Model",
-	"Subtitle": "Version of March 6, 2012",
+	"Subtitle": "Version of May 31, 2014",
 	"Path": "/ref/mem"
 }-->
 
@@ -274,6 +274,41 @@ then the program would not be guaranteed to print
 crash, or do something else.)
 </p>
 
+<p class="rule">
+The <i>k</i>th receive on a channel with capacity <i>C</i> happens before the <i>k</i>+<i>C</i>th send from that channel completes.
+</p>
+
+<p>
+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.
+</p>
+
+<p>
+This program starts a goroutine for every entry in the work list, but the
+goroutines coordinate using the <code>limit</code> channel to ensure
+that at most three are running work functions at a time.
+</p>
+
+<pre>
+var limit = make(chan int, 3)
+
+func main() {
+	for _, w := range work {
+		go func() {
+			limit <- 1
+			w()
+			<-limit
+		}()
+	}
+	select{}
+}
+</pre>
+
 <h3>Locks</h3>
 
 <p>
diff --git a/doc/go_spec.html b/doc/go_spec.html
index bc9ec68..baa0ecf 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,6 +1,6 @@
 <!--{
 	"Title": "The Go Programming Language Specification",
-	"Subtitle": "Version of Nov 13, 2013",
+	"Subtitle": "Version of May 28, 2014",
 	"Path": "/ref/spec"
 }-->
 
@@ -23,7 +23,7 @@ TODO
 
 <p>
 This is a reference manual for the Go programming language. For
-more information and other documents, see <a href="http://golang.org/">http://golang.org</a>.
+more information and other documents, see <a href="/">http://golang.org</a>.
 </p>
 
 <p>
@@ -120,7 +120,7 @@ unicode_digit  = /* a Unicode code point classified as "Decimal Digit" */ .
 </pre>
 
 <p>
-In <a href="http://www.unicode.org/versions/Unicode6.2.0/">The Unicode Standard 6.2</a>,
+In <a href="http://www.unicode.org/versions/Unicode6.3.0/">The Unicode Standard 6.3</a>,
 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.
 </p>
 <p>
@@ -674,7 +674,8 @@ types, the dynamic type is always the static type.
 
 <p>
 Each type <code>T</code> has an <i>underlying type</i>: If <code>T</code>
-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 <code>T</code> itself. Otherwise, <code>T</code>'s underlying type
 is the underlying type of the type to which <code>T</code> refers in its
 <a href="#Type_declarations">type declaration</a>.
@@ -695,19 +696,19 @@ and <code>T4</code> is <code>[]T1</code>.
 
 <h3 id="Method_sets">Method sets</h3>
 <p>
-A type may have a <i>method set</i> associated with it
-(§<a href="#Interface_types">Interface types</a>, §<a href="#Method_declarations">Method declarations</a>).
+A type may have a <i>method set</i> associated with it.
 The method set of an <a href="#Interface_types">interface type</a> is its interface.
-The method set of any other type <code>T</code>
-consists of all methods with receiver type <code>T</code>.
-The method set of the corresponding pointer type <code>*T</code>
-is the set of all methods with receiver <code>*T</code> or <code>T</code>
+The method set of any other type <code>T</code> consists of all
+<a href="#Method_declarations">methods</a> declared with receiver type <code>T</code>.
+The method set of the corresponding <a href="#Pointer_types">pointer type</a> <code>*T</code>
+is the set of all methods declared with receiver <code>*T</code> or <code>T</code>
 (that is, it also contains the method set of <code>T</code>).
 Further rules apply to structs containing anonymous fields, as described
 in the section on <a href="#Struct_types">struct types</a>.
 Any other type has an empty method set.
 In a method set, each method must have a
-<a href="#Uniqueness_of_identifiers">unique</a> <a href="#MethodName">method name</a>.
+<a href="#Uniqueness_of_identifiers">unique</a>
+non-<a href="#Blank_identifier">blank</a> <a href="#MethodName">method name</a>.
 </p>
 
 <p>
@@ -817,8 +818,8 @@ ElementType = Type .
 </pre>
 
 <p>
-The length is part of the array's type; it must evaluate to a non-
-negative <a href="#Constants">constant</a> representable by a value
+The length is part of the array's type; it must evaluate to a
+non-negative <a href="#Constants">constant</a> representable by a value
 of type <code>int</code>.
 The length of array <code>a</code> can be discovered
 using the built-in function <a href="#Length_and_capacity"><code>len</code></a>.
@@ -1009,7 +1010,7 @@ A field declaration may be followed by an optional string literal <i>tag</i>,
 which becomes an attribute for all the fields in the corresponding
 field declaration. The tags are made
 visible through a <a href="/pkg/reflect/#StructTag">reflection interface</a>
-and take part in <a href="Type_identity">type identity</a> for structs
+and take part in <a href="#Type_identity">type identity</a> for structs
 but are otherwise ignored.
 </p>
 
@@ -1108,7 +1109,8 @@ InterfaceTypeName  = TypeName .
 
 <p>
 As with all method sets, in an interface type, each method must have a
-<a href="#Uniqueness_of_identifiers">unique</a> name.
+<a href="#Uniqueness_of_identifiers">unique</a>
+non-<a href="#Blank_identifier">blank</a> name.
 </p>
 
 <pre>
@@ -1277,20 +1279,23 @@ may be added.
 <h3 id="Channel_types">Channel types</h3>
 
 <p>
-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
+<a href="#Go_statements">concurrently executing functions</a>
+to communicate by
+<a href="#Send_statements">sending</a> and
+<a href="#Receive_operator">receiving</a>
+values of a specified element type.
 The value of an uninitialized channel is <code>nil</code>.
 </p>
 
 <pre class="ebnf">
-ChannelType = ( "chan" [ "<-" ] | "<-" "chan" ) ElementType .
+ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) ElementType .
 </pre>
 
 <p>
-The <code><-</code> operator specifies the channel <i>direction</i>,
+The optional <code><-</code> operator specifies the channel <i>direction</i>,
 <i>send</i> or <i>receive</i>. If no direction is given, the channel is
-<i>bi-directional</i>.
+<i>bidirectional</i>.
 A channel may be constrained only to send or only to receive by
 <a href="#Conversions">conversion</a> or <a href="#Assignments">assignment</a>.
 </p>
@@ -1317,7 +1322,7 @@ chan (<-chan int)
 A new, initialized channel
 value can be made using the built-in function
 <a href="#Making_slices_maps_and_channels"><code>make</code></a>,
-which takes the channel type and an optional capacity as arguments:
+which takes the channel type and an optional <i>capacity</i> as arguments:
 </p>
 
 <pre>
@@ -1325,21 +1330,35 @@ make(chan int, 100)
 </pre>
 
 <p>
-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 <code>nil</code> channel is never ready for communication.
 </p>
 
 <p>
 A channel may be closed with the built-in function
-<a href="#Close"><code>close</code></a>; the
-multi-valued assignment form of the
+<a href="#Close"><code>close</code></a>.
+The multi-valued assignment form of the
 <a href="#Receive_operator">receive operator</a>
-tests whether a channel has been closed.
+reports whether a received value was sent before
+the channel was closed.
+</p>
+
+<p>
+A single channel may be used in
+<a href="#Send_statements">send statements</a>,
+<a href="#Receive_operator">receive operations</a>,
+and calls to the built-in functions
+<a href="#Length_and_capacity"><code>cap</code></a> and
+<a href="#Length_and_capacity"><code>len</code></a>
+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.
 </p>
 
 <h2 id="Properties_of_types_and_values">Properties of types and values</h2>
@@ -1515,6 +1534,9 @@ no identifier may be declared in both the file and package block.
 <p>
 The <a href="#Blank_identifier">blank identifier</a> 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 <code>init</code> may only be used for
+<a href="#Package_initialization"><code>init</code> function</a> declarations,
+and like the blank identifier it does not introduce a new binding.
 </p>
 
 <pre class="ebnf">
@@ -1770,9 +1792,9 @@ last non-empty expression list.
 
 <p>
 A type declaration binds an identifier, the <i>type name</i>, to a new type
-that has the same <a href="#Types">underlying type</a> as
-an existing type.  The new type is <a href="#Type_identity">different</a> from
-the existing type.
+that has the same <a href="#Types">underlying type</a> as an existing type,
+and operations defined for the existing type are also defined for the new type.
+The new type is <a href="#Type_identity">different</a> from the existing type.
 </p>
 
 <pre class="ebnf">
@@ -2267,8 +2289,6 @@ Similarly, elements that are addresses of composite literals may elide
 the <code>&T</code> when the element type is <code>*T</code>.
 </p>
 
-
-
 <pre>
 [...]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 <code>&T</code> when the element type is <code>*T</code>.
 
 <p>
 A parsing ambiguity arises when a composite literal using the
-TypeName form of the LiteralType appears between the
-<a href="#Keywords">keyword</a> 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
+<a href="#Keywords">keyword</a> 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.
 </p>
 
 <pre>
@@ -2692,7 +2712,7 @@ For arrays or strings, the indices are <i>in range</i> if
 otherwise they are <i>out of range</i>.
 For slices, the upper index bound is the slice capacity <code>cap(a)</code> rather than the length.
 A <a href="#Constants">constant</a> index must be non-negative and representable by a value of type
-<code>int</code>.
+<code>int</code>; for arrays or constant strings, constant indices must also be in range.
 If both indices are constant, they must satisfy <code>low <= high</code>.
 If the indices are out of range at run time, a <a href="#Run_time_panics">run-time panic</a> occurs.
 </p>
@@ -2752,7 +2772,7 @@ If the sliced operand is an array, it must be <a href="#Address_operators">addre
 The indices are <i>in range</i> if <code>0 <= low <= high <= max <= cap(a)</code>,
 otherwise they are <i>out of range</i>.
 A <a href="#Constants">constant</a> index must be non-negative and representable by a value of type
-<code>int</code>.
+<code>int</code>; 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 <a href="#Run_time_panics">run-time panic</a> occurs.
@@ -2916,27 +2936,32 @@ There is no distinct method type and there are no method literals.
 <h3 id="Passing_arguments_to_..._parameters">Passing arguments to <code>...</code> parameters</h3>
 
 <p>
-If <code>f</code> is variadic with final parameter type <code>...T</code>,
-then within the function the argument is equivalent to a parameter of type
-<code>[]T</code>.  At each call of <code>f</code>, the argument
-passed to the final parameter is
-a new slice of type <code>[]T</code> whose successive elements are
-the actual arguments, which all must be <a href="#Assignability">assignable</a>
-to the type <code>T</code>. The length of the slice is therefore the number of
-arguments bound to the final parameter and may differ for each call site.
+If <code>f</code> is <a href="#Function_types">variadic</a> with a final
+parameter <code>p</code> of type <code>...T</code>, then within <code>f</code>
+the type of <code>p</code> is equivalent to type <code>[]T</code>.
+If <code>f</code> is invoked with no actual arguments for <code>p</code>,
+the value passed to <code>p</code> is <code>nil</code>.
+Otherwise, the value passed is a new slice
+of type <code>[]T</code> with a new underlying array whose successive elements
+are the actual arguments, which all must be <a href="#Assignability">assignable</a>
+to <code>T</code>. The length and capacity of the slice is therefore
+the number of arguments bound to <code>p</code> and may differ for each
+call site.
 </p>
 
 <p>
-Given the function and call
+Given the function and calls
 </p>
 <pre>
 func Greeting(prefix string, who ...string)
+Greeting("nobody")
 Greeting("hello:", "Joe", "Anna", "Eileen")
 </pre>
 
 <p>
 within <code>Greeting</code>, <code>who</code> will have the value
-<code>[]string{"Joe", "Anna", "Eileen"}</code>
+<code>nil</code> in the first call, and
+<code>[]string{"Joe", "Anna", "Eileen"}</code> in the second.
 </p>
 
 <p>
@@ -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 <code>nil</code> channel blocks forever.
 A receive operation on a <a href="#Close">closed</a> channel can always proceed
-immediately, yielding the element type's <a href="#The_zero_value">zero value</a>.
+immediately, yielding the element type's <a href="#The_zero_value">zero value</a>
+after any previously sent values have been received.
 </p>
 
 <pre>
@@ -3929,7 +3955,7 @@ an untyped complex constant.
 
 <pre>
 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)
 </pre>
 
 <p>
@@ -3992,8 +4018,11 @@ precision.
 <h3 id="Order_of_evaluation">Order of evaluation</h3>
 
 <p>
-When evaluating the <a href="#Operands">operands</a> of an expression,
-<a href="#Assignments">assignment</a>, or
+At package level, <a href="#Package_initialization">initialization dependencies</a>
+determine the evaluation order of individual initialization expressions in
+<a href="#Variable_declarations">variable declarations</a>.
+Otherwise, when evaluating the <a href="#Operands">operands</a> of an
+expression, assignment, or
 <a href="#Return_statements">return statement</a>,
 all function calls, method calls, and
 communication operations are evaluated in lexical left-to-right
@@ -4001,7 +4030,7 @@ order.
 </p>
 
 <p>
-For example, in the assignment
+For example, in the (function-local) assignment
 </p>
 <pre>
 y[f()], ok = g(h(), i()+x[j()], <-c), k()
@@ -4018,12 +4047,34 @@ of <code>y</code> is not specified.
 <pre>
 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
 </pre>
 
 <p>
+At package level, initialization dependencies override the left-to-right rule
+for individual initialization expressions, but not for operands within each
+expression: 
+</p>
+
+<pre>
+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
+</pre>
+
+<p>
+The function calls happen in the order
+<code>u()</code>, <code>sqr()</code>, <code>v()</code>,
+<code>f()</code>, <code>v()</code>, and <code>g()</code>.
+</p>
+
+<p>
 Floating-point operations within a single expression are evaluated according to
 the associativity of the operators.  Explicit parentheses affect the evaluation
 by overriding the default associativity.
@@ -4209,22 +4260,8 @@ A send on a closed channel proceeds by causing a <a href="#Run_time_panics">run-
 A send on a <code>nil</code> channel blocks forever.
 </p>
 
-<p>
-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.
-</p>
-
-<p>
-A single channel may be used for send and receive
-operations and calls to the built-in functions
-<a href="#Length_and_capacity"><code>cap</code></a> and
-<a href="#Length_and_capacity"><code>len</code></a>
-by any number of goroutines without further synchronization.
-</p>
-
 <pre>
-ch <- 3
+ch <- 3  // send value 3 to channel ch
 </pre>
 
 
@@ -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 <code>true</code>.
+A missing switch expression is equivalent to the boolean value
+<code>true</code>.
 </p>
 
 <pre class="ebnf">
@@ -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 <code>true</code>.
+If the condition is absent, it is equivalent to the boolean value
+<code>true</code>.
 </p>
 
 <pre>
@@ -4662,7 +4700,8 @@ only if the block was executed).
 Any element of the ForClause may be empty but the
 <a href="#Semicolons">semicolons</a> are
 required unless there is only a condition.
-If the condition is absent, it is equivalent to <code>true</code>.
+If the condition is absent, it is equivalent to the boolean value
+<code>true</code>.
 </p>
 
 <pre>
@@ -4844,8 +4883,12 @@ go func(ch chan<- bool) { for { sleep(10); ch <- true; }} (c)
 <h3 id="Select_statements">Select statements</h3>
 
 <p>
-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
+<a href="#Send_statements">send</a> or
+<a href="#Receive_operator">receive</a>
+operations will proceed.
+It looks similar to a
+<a href="#Switch_statements">"switch"</a> statement but with the
 cases all referring to communication operations.
 </p>
 
@@ -4858,41 +4901,63 @@ RecvExpr   = Expression .
 </pre>
 
 <p>
-RecvExpr must be a <a href="#Receive_operator">receive operation</a>.
-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 <code>nil</code>,
-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-<code>nil</code> 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
+<a href="#Short_variable_declarations">short variable declaration</a>.
+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.
 </p>
+
 <p>
-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:
 </p>
+
+<ol>
+<li>
+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.
+</li>
+
+<li>
+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.
+</li>
+
+<li>
+Unless the selected case is the default case, the respective communication
+operation is executed.
+</li>
+
+<li>
+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.
+</li>
+
+<li>
+The statement list of the selected case is executed.
+</li>
+</ol>
+
 <p>
-If multiple cases can proceed, a uniform pseudo-random choice is made to decide
-which single communication will execute.
-<p>
-The receive case may declare one or two new variables using a
-<a href="#Short_variable_declarations">short variable declaration</a>.
+Since communication on <code>nil</code> channels can never proceed,
+a select with only <code>nil</code> channels and no default case blocks forever.
 </p>
 
 <pre>
-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.
 </p>
 
+<p>
+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
+<a href="#Declarations_and_scope">scope</a> at the place of the return.
+</p>
+
+<pre>
+func f(n int) (res int, err error) {
+	if _, err := f(n-1); err != nil {
+		return  // invalid return statement: err is shadowed
+	}
+	return
+}
+</pre>
 
 <h3 id="Break_statements">Break statements</h3>
 
@@ -5009,7 +5093,8 @@ any deferred functions are executed.
 A "break" statement terminates execution of the innermost
 <a href="#For_statements">"for"</a>,
 <a href="#Switch_statements">"switch"</a>, or
-<a href="#Select_statements">"select"</a> statement.
+<a href="#Select_statements">"select"</a> statement
+within the same function.
 </p>
 
 <pre class="ebnf">
@@ -5043,6 +5128,7 @@ OuterLoop:
 <p>
 A "continue" statement begins the next iteration of the
 innermost <a href="#For_statements">"for" loop</a> at its post statement.
+The "for" loop must be within the same function.
 </p>
 
 <pre class="ebnf">
@@ -5070,7 +5156,8 @@ RowLoop:
 <h3 id="Goto_statements">Goto statements</h3>
 
 <p>
-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.
 </p>
 
 <pre class="ebnf">
@@ -5263,7 +5350,7 @@ At any time the following relationship holds:
 
 <p>
 The length of a <code>nil</code> slice, map or channel is 0.
-The capacity of a <code>nil</code> slice and channel is 0.
+The capacity of a <code>nil</code> slice or channel is 0.
 </p>
 
 <p>
@@ -5271,12 +5358,22 @@ The expression <code>len(s)</code> is <a href="#Constants">constant</a> if
 <code>s</code> is a string constant. The expressions <code>len(s)</code> and
 <code>cap(s)</code> are constants if the type of <code>s</code> is an array
 or pointer to an array and the expression <code>s</code> does not contain
-<a href="#Receive_operator">channel receives</a> or
+<a href="#Receive_operator">channel receives</a> or (non-constant)
 <a href="#Calls">function calls</a>; in this case <code>s</code> is not evaluated.
 Otherwise, invocations of <code>len</code> and <code>cap</code> are not
 constant and <code>s</code> is evaluated.
 </p>
 
+<pre>
+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
+</pre>
 
 <h3 id="Allocation">Allocation</h3>
 
@@ -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
 </pre>
 
 
@@ -5669,7 +5766,7 @@ If the PackageName is omitted, it defaults to the identifier specified in the
 If an explicit period (<code>.</code>) appears instead of a name, all the
 package's exported identifiers declared in that package's
 <a href="#Blocks">package block</a> 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.
 </p>
 
 <p>
@@ -5681,7 +5778,7 @@ package and may be relative to a repository of installed packages.
 <p>
 Implementation restriction: A compiler may restrict ImportPaths to
 non-empty strings using only characters belonging to
-<a href="http://www.unicode.org/versions/Unicode6.2.0/">Unicode's</a>
+<a href="http://www.unicode.org/versions/Unicode6.3.0/">Unicode's</a>
 L, M, N, P, and S general categories (the Graphic characters without
 spaces) and may also exclude the characters
 <code>!"#$%&'()*,:;<=>?[\]^`{|}</code>
@@ -5693,7 +5790,7 @@ Assume we have compiled a package containing the package clause
 <code>package math</code>, which exports function <code>Sin</code>, and
 installed the compiled package in the file identified by
 <code>"lib/math"</code>.
-This table illustrates how <code>Sin</code> may be accessed in files
+This table illustrates how <code>Sin</code> is accessed in files
 that import the package after the
 various types of import declaration.
 </p>
@@ -5817,62 +5914,126 @@ The same would also be true after
 var t T
 </pre>
 
-<h3 id="Program_execution">Program execution</h3>
+<h3 id="Package_initialization">Package initialization</h3>
 <p>
-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
-</p>
-<pre>
-func init()
-</pre>
-<p>
-defined in its source.
-A package-scope or file-scope identifier
-with name <code>init</code> 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.
-</p>
-<p>
-Within a package, package-level variables are initialized,
-and constant values are determined, according to
-order of reference: if the initializer of <code>A</code>
-depends on <code>B</code>, <code>A</code>
-will be set after <code>B</code>.
-Dependency analysis does not depend on the actual values
-of the items being initialized, only on their appearance
-in the source.
-<code>A</code>
-depends on <code>B</code> if the value of <code>A</code>
-contains a mention of <code>B</code>, contains a value
-whose initializer
-mentions <code>B</code>, or mentions a function that
-mentions <code>B</code>, 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 <code>A</code>'s initializer calls a function defined
-in another package that refers to <code>B</code>.
+Within a package, package-level variables are initialized according
+to their <i>dependencies</i>: if a variable <code>x</code> depends on
+a variable <code>y</code>, <code>x</code> will be initialized after
+<code>y</code>.
+</p>
+
+<p>
+Dependency analysis does not rely on the actual values of the
+variables, only on lexical <i>references</i> to them in the source,
+analyzed transitively. For instance, a variable <code>x</code>'s
+<a href="#Variable_declarations">initialization expression</a>
+may refer to a function whose body refers to variable <code>y</code>;
+if so, <code>x</code> depends on <code>y</code>.
+Specifically:
+</p>
+
+<ul>
+<li>
+A reference to a variable or function is an identifier denoting that
+variable or function.
+</li>
+
+<li>
+A reference to a method <code>m</code> is a
+<a href="#Method_values">method value</a> or
+<a href="#Method_expressions">method expression</a> of the form 
+<code>t.m</code>, where the (static) type of <code>t</code> is
+not an interface type, and the method <code>m</code> is in the
+<a href="#Method_sets">method set</a> of <code>t</code>.
+It is immaterial whether the resulting function value
+<code>t.m</code> is invoked.
+</li>
+
+<li>
+A variable, function, or method <code>x</code> depends on a variable 
+<code>y</code> if <code>x</code>'s initialization expression or body
+(for functions and methods) contains a reference to <code>y</code>
+or to a function or method that depends on <code>y</code>.
+</li>
+</ul>
+
+<p>
+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.
+</p>
+
+<p>
+For example, given the declarations
+</p>
+
+<pre>
+var (
+	a = c + b
+	b = f()
+	c = f()
+	d = 3
+)
+
+func f() int {
+	d++
+	return d
+}
+</pre>
+
+<p>
+the initialization order is <code>d</code>, <code>b</code>, <code>c</code>, <code>a</code>.
+Since <code>b</code> and <code>c</code> are independent of each other, they are
+initialized in declaration order (<code>b</code> before <code>c</code>).
+</p>
+
+<p>
+Variables may also be initialized using functions named <code>init</code>
+declared in the package block, with no arguments and no result parameters.
 </p>
+
+<pre>
+func init() { … }
+</pre>
+
 <p>
-An <code>init</code> function cannot be referred to from anywhere
-in a program. In particular, <code>init</code> cannot be called explicitly,
-nor can a pointer to <code>init</code> be assigned to a function variable.
+Multiple such functions may be defined, even within a single 
+source file. The <code>init</code> identifier is not
+<a href="#Declarations_and_scope">declared</a> and thus
+<code>init</code> functions cannot be referred to from anywhere
+in a program.
 </p>
+
 <p>
+A package with no imports is initialized by assigning initial values
+to all its package-level variables followed by calling all <code>init</code>
+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 <code>P</code>, <code>P</code> 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.
 </p>
+
 <p>
-The importing of packages, by construction, guarantees that there can
-be no cyclic dependencies in initialization.
+Package initialization—variable initialization and the invocation of
+<code>init</code> functions—happens in a single goroutine,
+sequentially, one package at a time.
+An <code>init</code> function may launch other goroutines, which can run
+concurrently with the initialization code. However, initialization
+always sequences
+the <code>init</code> functions: it will not invoke the next one
+until the previous one has returned.
 </p>
+
+
+<h3 id="Program_execution">Program execution</h3>
 <p>
 A complete program is created by linking a single, unimported package
 called the <i>main package</i> with all the packages it imports, transitively.
@@ -5889,22 +6050,10 @@ func main() { … }
 <p>
 Program execution begins by initializing the main package and then
 invoking the function <code>main</code>.
-When the function <code>main</code> returns, the program exits.
+When that function invocation returns, the program exits.
 It does not wait for other (non-<code>main</code>) goroutines to complete.
 </p>
 
-<p>
-Package initialization—variable initialization and the invocation of
-<code>init</code> functions—happens in a single goroutine,
-sequentially, one package at a time.
-An <code>init</code> function may launch other goroutines, which can run
-concurrently with the initialization code. However, initialization
-always sequences
-the <code>init</code> functions: it will not start the next
-<code>init</code> until
-the previous one has returned.
-</p>
-
 <h2 id="Errors">Errors</h2>
 
 <p>
diff --git a/doc/gopher/README b/doc/gopher/README
new file mode 100644
index 0000000..936a24c
--- /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 3de5206..ad92c56 100644
--- a/doc/help.html
+++ b/doc/help.html
@@ -39,7 +39,7 @@ Go IRC channel.</p>
 
 <h3 id="twitter"><a href="http://twitter.com/golang">@golang at Twitter</a></h3>
 <p>The Go project's official Twitter account.</p>
-<p>Tweeting your about problem with the <code>#golang</code> hashtag usually
+<p>Tweeting about your problem with the <code>#golang</code> hashtag usually
 generates some helpful responses.</p>
 
 <h3 id="go_user_groups"><a href="/wiki/GoUserGroups">Go User Groups</a></h3>
diff --git a/doc/install-source.html b/doc/install-source.html
index b99360c..6f6a15a 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.
 </p>
 
 <p>
-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
 <a href="#environment">environment variables</a> below.
 </p>
@@ -95,7 +95,7 @@ have an <code>hg</code> command.)
 <p>
 If you do not have a working Mercurial installation,
 follow the instructions on the
-<a href="http://mercurial.selenic.com/downloads/">Mercurial downloads</a> page.
+<a href="http://mercurial.selenic.com/downloads">Mercurial downloads</a> page.
 </p>
 
 <p>
@@ -176,6 +176,10 @@ architecture, and root directory used during the install.
 <p>
 For more information about ways to control the build, see the discussion of
 <a href="#environment">environment variables</a> below.
+<code>all.bash</code> (or <code>all.bat</code>) 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 <code>make.bash</code> (or <code>make.bat</code>)
+instead.
 </p>
 </div>
 
@@ -354,9 +358,9 @@ These default to the values of <code>$GOHOSTOS</code> and
 
 <p>
 Choices for <code>$GOOS</code> are
-<code>darwin</code> (Mac OS X 10.6 and above), <code>freebsd</code>,
+<code>darwin</code> (Mac OS X 10.6 and above), <code>dragonfly</code>, <code>freebsd</code>,
 <code>linux</code>, <code>netbsd</code>, <code>openbsd</code>, 
-<code>plan9</code>, and <code>windows</code>.
+<code>plan9</code>, <code>solaris</code> and <code>windows</code>.
 Choices for <code>$GOARCH</code> are
 <code>amd64</code> (64-bit x86, the most mature port),
 <code>386</code> (32-bit x86), and <code>arm</code> (32-bit ARM).
@@ -372,6 +376,12 @@ The valid combinations of <code>$GOOS</code> and <code>$GOARCH</code> are:
 <td></td><td><code>darwin</code></td> <td><code>amd64</code></td>
 </tr>
 <tr>
+<td></td><td><code>dragonfly</code></td> <td><code>386</code></td>
+</tr>
+<tr>
+<td></td><td><code>dragonfly</code></td> <td><code>amd64</code></td>
+</tr>
+<tr>
 <td></td><td><code>freebsd</code></td> <td><code>386</code></td>
 </tr>
 <tr>
@@ -411,6 +421,9 @@ The valid combinations of <code>$GOOS</code> and <code>$GOARCH</code> are:
 <td></td><td><code>plan9</code></td> <td><code>amd64</code></td>
 </tr>
 <tr>
+<td></td><td><code>solaris</code></td> <td><code>amd64</code></td>
+</tr>
+<tr>
 <td></td><td><code>windows</code></td> <td><code>386</code></td>
 </tr>
 <tr>
@@ -444,7 +457,7 @@ installs all commands there.
 </p>
 
 <li><code>$GO386</code> (for <code>386</code> only, default is auto-detected
-if built natively, <code>387</code> if not)
+if built on either <code>386</code> or <code>amd64</code>, <code>387</code> otherwise)
 <p>
 This controls the code generated by 8g to use either the 387 floating-point unit
 (set to <code>387</code>) or SSE2 instructions (set to <code>sse2</code>) for
diff --git a/doc/install.html b/doc/install.html
index af4c8f3..7282ae9 100644
--- a/doc/install.html
+++ b/doc/install.html
@@ -6,15 +6,15 @@
 <h2 id="download">Download the Go distribution</h2>
 
 <p>
-<a href="http://code.google.com/p/go/downloads" id="start" class="download" target="_blank">
+<a href="/dl/" id="start" class="download" target="_blank">
 <span class="big">Download Go</span>
 <span class="desc">Click here to visit the downloads page</span>
 </a>
 </p>
 
 <p>
-<a href="http://code.google.com/p/go/downloads" target="_blank">Official binary
-distributions</a> are available for the FreeBSD, Linux, Mac OS X (Snow Leopard
+<a href="https://code.google.com/p/go/wiki/Downloads?tm=2" target="_blank">Official binary
+distributions</a> 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 (<code>386</code>) and
 64-bit (<code>amd64</code>) x86 processor architectures.
 </p>
@@ -39,15 +39,15 @@ proceeding. If your OS or architecture is not on the list, it's possible that
 
 <table class="codetable" frame="border" summary="requirements">
 <tr>
-<th align="middle">Operating system</th>
-<th align="middle">Architectures</th>
-<th align="middle">Notes</th>
+<th align="center">Operating system</th>
+<th align="center">Architectures</th>
+<th align="center">Notes</th>
 </tr>
 <tr><td colspan="3"><hr></td></tr>
-<tr><td>FreeBSD 7 or later</td> <td>amd64, 386, arm</td> <td>Debian GNU/kFreeBSD not supported; FreeBSD/ARM needs FreeBSD 10 or later</td></tr>
+<tr><td>FreeBSD 8 or later</td> <td>amd64, 386, arm</td> <td>Debian GNU/kFreeBSD not supported; FreeBSD/ARM needs FreeBSD 10 or later</td></tr>
 <tr><td>Linux 2.6.23 or later with glibc</td> <td>amd64, 386, arm</td> <td>CentOS/RHEL 5.x not supported; no binary distribution for ARM yet</td></tr>
 <tr><td>Mac OS X 10.6 or later</td> <td>amd64, 386</td> <td>use the gcc<sup>†</sup> that comes with Xcode<sup>‡</sup></td></tr>
-<tr><td>Windows 2000 or later</td> <td>amd64, 386</td> <td>use mingw gcc<sup>†</sup>; cygwin or msys is not needed</td></tr>
+<tr><td>Windows XP or later</td> <td>amd64, 386</td> <td>use MinGW gcc<sup>†</sup>. No need for cgywin or msys.</td></tr>
 </table>
 
 <p>
@@ -70,18 +70,19 @@ first <a href="#uninstall">remove the existing version</a>.
 <h3 id="tarball">Linux, Mac OS X, and FreeBSD tarballs</h3>
 
 <p>
-<a href="http://code.google.com/p/go/downloads/list?q=OpSys-FreeBSD+OR+OpSys-Linux+OR+OpSys-OSX+Type-Archive">Download the archive</a>
+<a href="https://code.google.com/p/go/wiki/Downloads?tm=2">Download the archive</a>
 and extract it into <code>/usr/local</code>, creating a Go tree in
 <code>/usr/local/go</code>. For example:
 </p>
 
 <pre>
-tar -C /usr/local -xzf go1.2.1.linux-amd64.tar.gz
+tar -C /usr/local -xzf go$VERSION.$OS-$ARCH.tar.gz
 </pre>
 
 <p>
-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 <code>go1.2.1.linux-amd64.tar.gz</code>.
 </p>
 
 <p>
@@ -126,7 +127,7 @@ location.
 <h3 id="osx">Mac OS X package installer</h3>
 
 <p>
-<a href="http://code.google.com/p/go/downloads/list?q=OpSys-OSX+Type-Installer">Download the package file</a>,
+<a href="https://code.google.com/p/go/wiki/Downloads?tm=2">Download the package file</a>,
 open it, and follow the prompts to install the Go tools.
 The package installs the Go distribution to <code>/usr/local/go</code>.
 </p>
@@ -149,7 +150,7 @@ MSI installer that configures your installation automatically.
 <h4 id="windows_msi">MSI installer</h4>
 
 <p>
-Open the <a href="http://code.google.com/p/go/downloads/list?q=OpSys-Windows+Type%3DInstaller">MSI file</a>
+Open the <a href="https://code.google.com/p/go/wiki/Downloads?tm=2">MSI file</a>
 and follow the prompts to install the Go tools.
 By default, the installer puts the Go distribution in <code>c:\Go</code>.
 </p>
@@ -163,7 +164,7 @@ command prompts for the change to take effect.
 <h4 id="windows_zip">Zip archive</h4>
 
 <p>
-<a href="http://code.google.com/p/go/downloads/list?q=OpSys-Windows+Type%3DArchive">Download the zip file</a> and extract it into the directory of your choice (we suggest <code>c:\Go</code>).
+<a href="https://code.google.com/p/go/wiki/Downloads?tm=2">Download the zip file</a> and extract it into the directory of your choice (we suggest <code>c:\Go</code>).
 </p>
 
 <p>
@@ -227,7 +228,7 @@ You just need to do a little more setup.
 </p>
 
 <p>
-<a href="/doc/code.html" class="download" id="start">
+<a href="/doc/code.html" class="download" id="writing">
 <span class="big">How to Write Go Code</span>
 <span class="desc">Learn how to set up and use the Go tools</span>
 </a>
diff --git a/doc/root.html b/doc/root.html
index 48280ac..4363793 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 5506c7c..f61409b 100644
--- a/include/bio.h
+++ b/include/bio.h
@@ -33,8 +33,6 @@ extern "C" {
 AUTOLIB(bio)
 #endif
 
-#include <fcntl.h>	/* 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 49721ea..0000000
--- 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 at 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 0000000..2484978
--- /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 at 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 at 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 cf7151c..0000000
--- 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 at 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 4736b8e..1c4076b 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 090b2fa..c2d4999 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 0000000..13d5e0e
--- /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 0000000..1ed572a
--- /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 0000000..b4a4fe7
--- /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 798e470..773edee 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 0000000..f65971e
--- /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 636f44f..0000000
--- 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 0000000..449e15f
--- /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 0000000..b562a3a
--- /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 8aaa83f..0000000
--- 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 f83c19a..0000000
--- 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 7d73a48..0000000
--- 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 0000000..03c26d6
--- /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 44bfcd6..6b2d50c 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 2c39f17..0000000
--- 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 at 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 c740b03..0000000
--- 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 at 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 c20fe4e..0000000
--- 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 at 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 f24ef82..8e1662a 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 c918115..e0d3afe 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 f5d79e4..50f4f72 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 3180f57..28a3739 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<n; i++) {
-		what = name[i]
-		printf("%-*s %12d %12d  %6s%%\n", len, what, old[what], new[what],
-			sprintf("%+.2f", 100*new[what]/old[what]-100))
-	}
-
-	# print mb/s
-	anymb = 0
-	for(i=0; i<n; i++) {
-		what = name[i]
-		if(!(what in newmb))
-			continue
-		if(anymb++ == 0)
-			printf("\n%-*s %12s %12s  %7s\n", len, "benchmark", "old MB/s", "new MB/s", "speedup")
-		printf("%-*s %12s %12s  %6sx\n", len, what,
-			sprintf("%.2f", oldmb[what]),
-			sprintf("%.2f", newmb[what]),
-			sprintf("%.2f", newmb[what]/oldmb[what]))
-	}
-
-	# print allocs
-	anyalloc = 0
-	for(i=0; i<n; i++) {
-		what = name[i]
-		if(!(what in newalloc))
-			continue
-		if(anyalloc++ == 0)
-			printf("\n%-*s %12s %12s  %7s\n", len, "benchmark", "old allocs", "new allocs", "delta")
-		if(oldalloc[what] == 0)
-			delta="n/a"
-		else
-			delta=sprintf("%.2f", 100*newalloc[what]/oldalloc[what]-100)
-		printf("%-*s %12d %12d  %6s%%\n", len, what,
-			oldalloc[what], newalloc[what], delta)
-	}
-
-	# print alloc bytes
-	anybytes = 0
-	for(i=0; i<n; i++) {
-		what = name[i]
-		if(!(what in newbytes))
-			continue
-		if(anybytes++ == 0)
-			printf("\n%-*s %12s %12s  %7s\n", len, "benchmark", "old bytes", "new bytes", "delta")
-		if(oldbytes[what] == 0)
-			delta="n/a"
-		else
-			delta=sprintf("%.2f", 100*newbytes[what]/oldbytes[what]-100)
-		printf("%-*s %12d %12d  %6s%%\n", len, what,
-			oldbytes[what], newbytes[what], delta)
-	}
-}
-' "$@"
+echo 'misc/benchcmp has moved:' >&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 0000000..3680a4a
--- /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 697ae2f..f0f60c8 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 0000000..00ae5e9
--- /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 0000000..45d247c
--- /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 efe4f01..7398772 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 0000000..514f76e
--- /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 194a9c8..7e6b448 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 056d67c..0a405c7 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 b7c6d28..eb23772 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 0000000..e12d534
--- /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 0000000..a77b425
--- /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 0000000..897cdd0
--- /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 <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+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 0000000..871bd51
--- /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 0000000..713dade
--- /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 0000000..4bea6e3
--- /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 <stdint.h>
+
+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 0000000..4f36dce
--- /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 0000000..4bd6f8e
--- /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 0000000..b927637
--- /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 0000000..8e41908
--- /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 0000000..936ae9d
--- /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 0000000..7fa55be
--- /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 0000000..d52aed6
--- /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 1a14ad3..01621a4 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 27155c2..7a38022 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 0000000..7d5444c
--- /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 a9546a6..8e9ee70 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 223d2dc..0000000
--- 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/emacs/go-mode.el b/misc/emacs/go-mode.el
index 75b28ac..6333ff9 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 a6db75a..0000000
--- 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 e8a1d29..0000000
--- 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 61e74a0..0000000
--- 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 9cb7d7b..0000000
--- 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 = `<pre>{{printf "%s" . |html}}</pre>`
-
-var frontPageText = `<!doctype html>
-<html>
-<head>
-<style>
-pre, textarea {
-	font-family: Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
-	font-size: 100%;
-}
-.hints {
-	font-size: 0.8em;
-	text-align: right;
-}
-#edit, #output, #errors { width: 100%; text-align: left; }
-#edit { height: 500px; }
-#output { color: #00c; }
-#errors { color: #c00; }
-</style>
-<script>
-
-function insertTabs(n) {
-	// find the selection start and end
-	var cont  = document.getElementById("edit");
-	var start = cont.selectionStart;
-	var end   = cont.selectionEnd;
-	// split the textarea content into two, and insert n tabs
-	var v = cont.value;
-	var u = v.substr(0, start);
-	for (var i=0; i<n; i++) {
-		u += "\t";
-	}
-	u += v.substr(end);
-	// set revised content
-	cont.value = u;
-	// reset caret position after inserted tabs
-	cont.selectionStart = start+n;
-	cont.selectionEnd = start+n;
-}
-
-function autoindent(el) {
-	var curpos = el.selectionStart;
-	var tabs = 0;
-	while (curpos > 0) {
-		curpos--;
-		if (el.value[curpos] == "\t") {
-			tabs++;
-		} else if (tabs > 0 || el.value[curpos] == "\n") {
-			break;
-		}
-	}
-	setTimeout(function() {
-		insertTabs(tabs);
-	}, 1);
-}
-
-function preventDefault(e) {
-	if (e.preventDefault) {
-		e.preventDefault();
-	} else {
-		e.cancelBubble = true;
-	}
-}
-
-function keyHandler(event) {
-	var e = window.event || event;
-	if (e.keyCode == 9) { // tab
-		insertTabs(1);
-		preventDefault(e);
-		return false;
-	}
-	if (e.keyCode == 13) { // enter
-		if (e.shiftKey) { // +shift
-			compile(e.target);
-			preventDefault(e);
-			return false;
-		} else {
-			autoindent(e.target);
-		}
-	}
-	return true;
-}
-
-var xmlreq;
-
-function autocompile() {
-	if(!document.getElementById("autocompile").checked) {
-		return;
-	}
-	compile();
-}
-
-function compile() {
-	var prog = document.getElementById("edit").value;
-	var req = new XMLHttpRequest();
-	xmlreq = req;
-	req.onreadystatechange = compileUpdate;
-	req.open("POST", "/compile", true);
-	req.setRequestHeader("Content-Type", "text/plain; charset=utf-8");
-	req.send(prog);	
-}
-
-function compileUpdate() {
-	var req = xmlreq;
-	if(!req || req.readyState != 4) {
-		return;
-	}
-	if(req.status == 200) {
-		document.getElementById("output").innerHTML = req.responseText;
-		document.getElementById("errors").innerHTML = "";
-	} else {
-		document.getElementById("errors").innerHTML = req.responseText;
-		document.getElementById("output").innerHTML = "";
-	}
-}
-</script>
-</head>
-<body>
-<table width="100%"><tr><td width="60%" valign="top">
-<textarea autofocus="true" id="edit" spellcheck="false" onkeydown="keyHandler(event);" onkeyup="autocompile();">{{printf "%s" . |html}}</textarea>
-<div class="hints">
-(Shift-Enter to compile and run.)    
-<input type="checkbox" id="autocompile" value="checked" /> Compile and run after each keystroke
-</div>
-<td width="3%">
-<td width="27%" align="right" valign="top">
-<div id="output"></div>
-</table>
-<div id="errors"></div>
-</body>
-</html>
-`
-
-var helloWorld = []byte(`package main
-
-import "fmt"
-
-func main() {
-	fmt.Println("hello, world")
-}
-`)
diff --git a/misc/dist/darwin/Distribution b/misc/makerelease/darwin/Distribution
similarity index 100%
rename from misc/dist/darwin/Distribution
rename to misc/makerelease/darwin/Distribution
diff --git a/misc/dist/darwin/Resources/bg.png b/misc/makerelease/darwin/Resources/bg.png
similarity index 100%
rename from misc/dist/darwin/Resources/bg.png
rename to misc/makerelease/darwin/Resources/bg.png
diff --git a/misc/dist/darwin/etc/paths.d/go b/misc/makerelease/darwin/etc/paths.d/go
similarity index 100%
rename from misc/dist/darwin/etc/paths.d/go
rename to misc/makerelease/darwin/etc/paths.d/go
diff --git a/misc/dist/darwin/scripts/postinstall b/misc/makerelease/darwin/scripts/postinstall
similarity index 100%
rename from misc/dist/darwin/scripts/postinstall
rename to misc/makerelease/darwin/scripts/postinstall
diff --git a/misc/dist/darwin/scripts/preinstall b/misc/makerelease/darwin/scripts/preinstall
similarity index 100%
rename from misc/dist/darwin/scripts/preinstall
rename to misc/makerelease/darwin/scripts/preinstall
diff --git a/misc/makerelease/makerelease.go b/misc/makerelease/makerelease.go
new file mode 100644
index 0000000..2496a86
--- /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/dist/windows/LICENSE.rtf b/misc/makerelease/windows/LICENSE.rtf
similarity index 100%
rename from misc/dist/windows/LICENSE.rtf
rename to misc/makerelease/windows/LICENSE.rtf
diff --git a/misc/dist/windows/README.txt b/misc/makerelease/windows/README.txt
similarity index 100%
rename from misc/dist/windows/README.txt
rename to misc/makerelease/windows/README.txt
diff --git a/misc/dist/windows/images/Banner.jpg b/misc/makerelease/windows/images/Banner.jpg
similarity index 100%
rename from misc/dist/windows/images/Banner.jpg
rename to misc/makerelease/windows/images/Banner.jpg
diff --git a/misc/dist/windows/images/Dialog.jpg b/misc/makerelease/windows/images/Dialog.jpg
similarity index 100%
rename from misc/dist/windows/images/Dialog.jpg
rename to misc/makerelease/windows/images/Dialog.jpg
diff --git a/misc/dist/windows/images/DialogLeft.jpg b/misc/makerelease/windows/images/DialogLeft.jpg
similarity index 100%
rename from misc/dist/windows/images/DialogLeft.jpg
rename to misc/makerelease/windows/images/DialogLeft.jpg
diff --git a/misc/dist/windows/images/gopher.ico b/misc/makerelease/windows/images/gopher.ico
similarity index 100%
rename from misc/dist/windows/images/gopher.ico
rename to misc/makerelease/windows/images/gopher.ico
diff --git a/misc/dist/windows/installer.wxs b/misc/makerelease/windows/installer.wxs
similarity index 100%
rename from misc/dist/windows/installer.wxs
rename to misc/makerelease/windows/installer.wxs
diff --git a/misc/nacl/README b/misc/nacl/README
new file mode 100644
index 0000000..9cc2bda
--- /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 0000000..9cff635
--- /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 0000000..0a5ed65
--- /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 0000000..7b2de7d
--- /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/api/next.txt b/misc/nacl/testdata/bin/placeholder
similarity index 100%
copy from api/next.txt
copy to misc/nacl/testdata/bin/placeholder
diff --git a/api/next.txt b/misc/nacl/testdata/empty
similarity index 100%
copy from api/next.txt
copy to misc/nacl/testdata/empty
diff --git a/misc/nacl/testdata/group b/misc/nacl/testdata/group
new file mode 100644
index 0000000..eb7f9a3
--- /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 0000000..75721cd
--- /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 0000000..2c41bd2
--- /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 <http://www.iana.org/assignments/media-types/>.
+#
+# 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 0000000..2701ff4
--- /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 ca949f0..7c605db 100644
--- a/misc/notepadplus/functionList.xml
+++ b/misc/notepadplus/functionList.xml
@@ -1,8 +1,15 @@
 <!-- <NotepadPlus> -->
 	<!-- <functionList> -->
 		<!-- <associationMap> -->
+
+		<!--
+			if npp version == 6.4:
 			<association ext=".go" id="go"/>
 
+			if npp version >= 6.5:
+			<association userDefinedLangName="go" id="go"/>
+		-->
+
 		<!-- </associationMap> -->
 		<!-- <parsers> -->
 			<parser id="go" displayName="Go" commentExpr="((/\*.*?\*)/|(//.*?$))">
diff --git a/misc/pprof b/misc/pprof
index 1fc8d36..ad3f1eb 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 8dd43de..a4fa6b6 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 8066733..532fb17 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 5f7976f..359545b 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 faf4d79..e3d6e84 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 b8469f9..9a9e228 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 18bcaaf..066cf40 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 488ca46..5d994d3 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 8b39d61..bb60fe7 100644
--- a/src/cmd/5a/a.h
+++ b/src/cmd/5a/a.h
@@ -29,6 +29,7 @@
 // THE SOFTWARE.
 
 #include <bio.h>
+#include <link.h>
 #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 c506ff9..56d0c56 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	<sym>	LNAME LLAB LVAR
 %type	<lval>	con expr oexpr pointer offset sreg spreg creg
 %type	<lval>	rcon cond reglist
-%type	<gen>	gen rel reg regreg freg shift fcon frcon
-%type	<gen>	imm ximm name oreg ireg nireg ioreg imsr
+%type	<addr>	gen rel reg regreg freg shift fcon frcon
+%type	<addr>	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 c1b54e5..571fdf7 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; i<nDlist; i++)
-		dodefine(Dlist[i]);
-	yyparse();
-	if(nerrors) {
+	Bprint(&obuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
+	Bprint(&obuf, "!\n");
+
+	for(pass = 1; pass <= 2; pass++) {
+		pinit(file);
+		for(i=0; i<nDlist; i++)
+			dodefine(Dlist[i]);
+		yyparse();
 		cclean();
-		return nerrors;
+		if(nerrors)
+			return nerrors;
 	}
 
-	Bprint(&obuf, "\n!\n");
-
-	pass = 2;
-	outhist();
-	pinit(file);
-	for(i=0; i<nDlist; i++)
-		dodefine(Dlist[i]);
-	yyparse();
-	cclean();
-	return nerrors;
+	writeobj(ctxt, &obuf);
+	Bflush(&obuf);
+	return 0;
 }
 
 struct
@@ -426,15 +434,9 @@ cinit(void)
 	Sym *s;
 	int i;
 
-	nullgen.sym = S;
-	nullgen.offset = 0;
 	nullgen.type = D_NONE;
 	nullgen.name = D_NONE;
 	nullgen.reg = NREG;
-	if(FPCHIP)
-		nullgen.dval = 0;
-	for(i=0; i<sizeof(nullgen.sval); i++)
-		nullgen.sval[i] = 0;
 
 	nerrors = 0;
 	iostack = I;
@@ -448,13 +450,6 @@ cinit(void)
 		s->type = 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; i<NSNAME; i++) {
-			BPUTC(&obuf, *n);
-			n++;
-		}
-		break;
-
-	case D_FCONST:
-		ieeedtod(&e, a->dval);
-		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 dd102a0..0bc8c34 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 <u.h>
@@ -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 <libintl.h> /* 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 <stdlib.h> /* 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 92230a2..f11fb85 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 084da7e..40d3a2b 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 30b8840..98da424 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; i<NREG; i++) {
-			if(v & (1<<i)) {
-				if(str[0] == 0)
-					strcat(str, "[R");
-				else
-					strcat(str, ",R");
-				sprint(strchr(str, 0), "%d", i);
-			}
-		}
-		strcat(str, "]");
-	}
-	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<NSNAME; i++) {
-		c = a[i] & 0xff;
-		if(c >= '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 22328c1..143400a 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 3d67872..b9ac21a 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; z<BITS; z++)
 			addrs.b[z] |= bit.b[z];
 	if(t == D_CONST) {
-		if(s == S) {
+		if(s == nil) {
 			for(z=0; z<BITS; z++)
 				consts.b[z] |= bit.b[z];
 			return bit;
@@ -1135,7 +1137,7 @@ paint3(Reg *r, int bn, int32 rb, int rn)
 }
 
 void
-addreg(Adr *a, int rn)
+addreg(Addr *a, int rn)
 {
 
 	a->sym = 0;
diff --git a/src/cmd/5c/swt.c b/src/cmd/5c/swt.c
index 0f0c457..fd81a4e 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; sym<NSYM; sym++) {
-		h[sym].sym = S;
-		h[sym].type = 0;
-	}
-	sym = 1;
-	for(p = firstp; p != P; p = p->link) {
-	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 6d9b69d..a753510 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 2d260e7..9011b20 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 1fbf633..a62102e 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 860817f..413e93c 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 040c3d2..fb32c2f 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; i<stkzerosize; i+=widthptr) {
-			if(bvget(bv, j) || bvget(bv, j+1)) {
-				if(first) {
-					p = appendp(p, AMOVW, D_CONST, NREG, 0, D_REG, 0, 0);
-					first = 0;
-				}
-				p = appendp(p, AMOVW, D_REG, 0, 0, D_OREG, REGSP, 4+frame-stkzerosize+i);
-			}
-			j += 2;
-		}
 	}
+	return p;
 }
 
-static Prog*
-appendp(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;
+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 212ffc2..5e98887 100644
--- a/src/cmd/5g/gobj.c
+++ b/src/cmd/5g/gobj.c
@@ -32,235 +32,6 @@
 #include <libc.h>
 #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; i<NSNAME; i++) {
-			BPUTC(b, *n);
-			n++;
-		}
-		break;
-
-	case D_REGREG:
-	case D_REGREG2:
-		BPUTC(b, a->offset);
-		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.sym<NSYM; z.sym++) {
-		z.h[z.sym].sym = S;
-		z.h[z.sym].type = 0;
-	}
-	z.sym = 1;
-}
-
-static int
-zsym(Sym *s, int t, int *new)
-{
-	int i;
-
-	*new = 0;
-	if(s == S)
-		return 0;
-
-	i = s->sym;
-	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);
@@ -453,27 +224,6 @@ dgostringptr(Sym *s, int off, char *str)
 }
 
 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)
 {
 	Prog *p;
@@ -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 27749b7..f66c87b 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 6c3f1d7..0000000
--- 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 at 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 at 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 <u.h>
-#include <libc.h>
-#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, "<nil>");
-		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<sconsize; i++) {
-		c = a[i] & 0xff;
-		if((c >= '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 15b9d14..e3e3f78 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 c78fb3d..4aa6452 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<n; i++)
-			if(copyu(p, &a[i], A) > 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<<v->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<<v->reg))
 				return 1;
 		} else {			/* read/rar, write reglist */
-			if(s != A) {
+			if(s != nil) {
 				if(p->to.offset&(1<<v->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 5aa6163..797bc07 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 d2a8cc4..4762df5 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; z<BITS; z++)
-			ovar.b[z] |= bit.b[z];
-		t = structnext(&save);
-	}
-//if(bany(&ovar))
-//print("ovar = %Q\n", ovar);
-}
-
 void
 excise(Flow *r)
 {
@@ -153,13 +129,15 @@ static char* regname[] = {
 
 static Node* regnodes[NREGVAR];
 
+static void walkvardef(Node *n, Reg *r, int active);
+
 void
 regopt(Prog *firstp)
 {
 	Reg *r, *r1;
 	Prog *p;
 	Graph *g;
-	int i, z;
+	int i, z, active;
 	uint32 vreg;
 	Bits bit;
 	ProgInfo info;
@@ -168,8 +146,7 @@ regopt(Prog *firstp)
 		fmtinstall('Q', Qconv);
 		first = 0;
 	}
-	
-	fixjmp(firstp);
+
 	mergetemp(firstp);
 
 	/*
@@ -191,12 +168,10 @@ regopt(Prog *firstp)
 		params.b[z] = 0;
 		consts.b[z] = 0;
 		addrs.b[z] = 0;
+		ivar.b[z] = 0;
 		ovar.b[z] = 0;
 	}
 
-	// build list of return variables
-	setoutvar();
-
 	/*
 	 * pass 1
 	 * build aux data structure
@@ -204,12 +179,18 @@ regopt(Prog *firstp)
 	 * find use and set of variables
 	 */
 	g = flowstart(firstp, sizeof(Reg));
-	if(g == nil)
+	if(g == nil) {
+		for(i=0; i<nvar; i++)
+			var[i].node->opt = 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.
@@ -271,6 +252,26 @@ regopt(Prog *firstp)
 		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
 	 * 	back until flow graph is complete
@@ -471,6 +472,14 @@ brk:
 		dumpit("pass6", &firstr->f, 1);
 
 	/*
+	 * free aux structures. peep allocates new ones.
+	 */
+	for(i=0; i<nvar; i++)
+		var[i].node->opt = 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; i<nvar; i++) {
+			v = var+i;
+			if(v->node == 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; z<BITS; z++)
@@ -815,6 +866,45 @@ mkvar(Reg *r, Adr *a)
 		for(z=0; z<BITS; z++)
 			params.b[z] |= bit.b[z];
 
+	if(node->class == PPARAM)
+		for(z=0; z<BITS; z++)
+			ivar.b[z] |= bit.b[z];
+	if(node->class == PPARAMOUT)
+		for(z=0; z<BITS; z++)
+			ovar.b[z] |= bit.b[z];
+
+	// Treat values with their address taken as live at calls,
+	// because the garbage collector's liveness analysis in ../gc/plive.c does.
+	// These must be consistent or else we will elide stores and the garbage
+	// collector will see uninitialized data.
+	// The typical case where our own analysis is out of sync is when the
+	// node appears to have its address taken but that code doesn't actually
+	// get generated and therefore doesn't show up as an address being
+	// taken when we analyze the instruction stream.
+	// One instance of this case is when a closure uses the same name as
+	// an outer variable for one of its own variables declared with :=.
+	// The parser flags the outer variable as possibly shared, and therefore
+	// sets addrtaken, even though it ends up not being actually shared.
+	// If we were better about _ elision, _ = &x would suffice too.
+	// The broader := in a closure problem is mentioned in a comment in
+	// closure.c:/^typecheckclosure and dcl.c:/^oldname.
+	if(node->addrtaken)
+		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; z<BITS; z++) {
@@ -844,10 +935,61 @@ prop(Reg *r, Bits ref, Bits cal)
 		case ABL:
 			if(noreturn(r1->f.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; z<BITS; z++) {
-				cal.b[z] |= ref.b[z] | externs.b[z];
+				cal.b[z] |= ref.b[z] | externs.b[z] | ivar.b[z] | r1->act.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<BITS; z++) {
+				if(cal.b[z] == 0)
+					continue;
+				for(i=0; i<32; i++) {
+					if(z*32+i >= 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; z<BITS; z++) {
-				cal.b[z] |= externs.b[z];
-				// issue 4066: flush modified return variables in case of panic
-				if(hasdefer)
-					cal.b[z] |= ovar.b[z];
-			}
-			break;
 		}
 		for(z=0; z<BITS; z++) {
 			ref.b[z] = (ref.b[z] & ~r1->set.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 e8cf83d..9e8acee 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 33cdf80..5e9267b 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<<R),R */
-		o1 = oprrr(p->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<<I(R),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 ae4b05b..761bc86 100644
--- a/src/cmd/5l/l.h
+++ b/src/cmd/5l/l.h
@@ -31,6 +31,7 @@
 #include	<u.h>
 #include	<libc.h>
 #include	<bio.h>
+#include	<link.h>
 #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 7502a3b..875fc3e 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<sizeof(int32); i++) {
-		c = a[i] & 0xff;
-		if(c >= '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 305ed68..d42c862 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, <reg>, 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, <reg>
-						//
-						// 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, <reg>
-						// SUB -tlsoffset, <reg>
-						//
-						// 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 80f5787..86a0ece 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	<ar.h>
 
-#ifndef	DEFAULT
-#define	DEFAULT	'9'
-#endif
-
-char	*noname		= "<none>";
-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 3d05d6d..0000000
--- 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 at 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 at 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 cd88979..0000000
--- 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 at 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 at 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 225a524..0000000
--- 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 at 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 at 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 de6481c..0000000
--- 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 e7cc0b4..0000000
--- 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 at 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 at 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; i<o->size/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(; o<e; o++)
-		if(o->a2 == 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<C_GOK; i++)
-		for(n=0; n<C_GOK; n++)
-			xcmp[i][n] = cmp(n, i);
-	for(n=0; optab[n].as != AXXX; n++) {
-		if((optab[n].flag & LPCREL) != 0) {
-			if(flag_shared)
-				optab[n].size += optab[n].pcrelsiz;
-			else
-				optab[n].flag &= ~LPCREL;
-		}
-	}
-	qsort(optab, n, sizeof(optab[0]), ocmp);
-	for(i=0; i<n; i++) {
-		r = optab[i].as;
-		oprange[r].start = optab+i;
-		while(optab[i].as == r)
-			i++;
-		oprange[r].stop = optab+i;
-		i--;
-
-		switch(r)
-		{
-		default:
-			diag("unknown op in build: %A", r);
-			errorexit();
-		case AADD:
-			oprange[AAND] = oprange[r];
-			oprange[AEOR] = oprange[r];
-			oprange[ASUB] = oprange[r];
-			oprange[ARSB] = oprange[r];
-			oprange[AADC] = oprange[r];
-			oprange[ASBC] = oprange[r];
-			oprange[ARSC] = oprange[r];
-			oprange[AORR] = oprange[r];
-			oprange[ABIC] = oprange[r];
-			break;
-		case ACMP:
-			oprange[ATEQ] = oprange[r];
-			oprange[ACMN] = oprange[r];
-			break;
-		case AMVN:
-			break;
-		case ABEQ:
-			oprange[ABNE] = oprange[r];
-			oprange[ABCS] = oprange[r];
-			oprange[ABHS] = oprange[r];
-			oprange[ABCC] = oprange[r];
-			oprange[ABLO] = oprange[r];
-			oprange[ABMI] = oprange[r];
-			oprange[ABPL] = oprange[r];
-			oprange[ABVS] = oprange[r];
-			oprange[ABVC] = oprange[r];
-			oprange[ABHI] = oprange[r];
-			oprange[ABLS] = oprange[r];
-			oprange[ABGE] = oprange[r];
-			oprange[ABLT] = oprange[r];
-			oprange[ABGT] = oprange[r];
-			oprange[ABLE] = oprange[r];
-			break;
-		case ASLL:
-			oprange[ASRL] = oprange[r];
-			oprange[ASRA] = oprange[r];
-			break;
-		case AMUL:
-			oprange[AMULU] = oprange[r];
-			break;
-		case ADIV:
-			oprange[AMOD] = oprange[r];
-			oprange[AMODU] = oprange[r];
-			oprange[ADIVU] = oprange[r];
-			break;
-		case AMOVW:
-		case AMOVB:
-		case AMOVBS:
-		case AMOVBU:
-		case AMOVH:
-		case AMOVHS:
-		case AMOVHU:
-			break;
-		case ASWPW:
-			oprange[ASWPBU] = oprange[r];
-			break;
-		case AB:
-		case ABL:
-		case ABX:
-		case ABXRET:
-		case ASWI:
-		case AWORD:
-		case AMOVM:
-		case ARFE:
-		case ATEXT:
-		case AUSEFIELD:
-		case ACASE:
-		case ABCASE:
-		case ATYPE:
-			break;
-		case AADDF:
-			oprange[AADDD] = oprange[r];
-			oprange[ASUBF] = oprange[r];
-			oprange[ASUBD] = oprange[r];
-			oprange[AMULF] = oprange[r];
-			oprange[AMULD] = oprange[r];
-			oprange[ADIVF] = oprange[r];
-			oprange[ADIVD] = oprange[r];
-			oprange[ASQRTF] = oprange[r];
-			oprange[ASQRTD] = oprange[r];
-			oprange[AMOVFD] = oprange[r];
-			oprange[AMOVDF] = oprange[r];
-			oprange[AABSF] = oprange[r];
-			oprange[AABSD] = oprange[r];
-			break;
-
-		case ACMPF:
-			oprange[ACMPD] = oprange[r];
-			break;
-
-		case AMOVF:
-			oprange[AMOVD] = oprange[r];
-			break;
-
-		case AMOVFW:
-			oprange[AMOVDW] = oprange[r];
-			break;
-
-		case AMOVWF:
-			oprange[AMOVWD] = oprange[r];
-			break;
-
-		case AMULL:
-			oprange[AMULAL] = oprange[r];
-			oprange[AMULLU] = oprange[r];
-			oprange[AMULALU] = oprange[r];
-			break;
-
-		case AMULWT:
-			oprange[AMULWB] = oprange[r];
-			break;
-
-		case AMULAWT:
-			oprange[AMULAWB] = oprange[r];
-			break;
-
-		case AMULA:
-		case ALDREX:
-		case ASTREX:
-		case ALDREXD:
-		case ASTREXD:
-		case ATST:
-		case APLD:
-		case AUNDEF:
-		case ACLZ:
-		case AFUNCDATA:
-		case APCDATA:
-			break;
-		}
-	}
-}
-
-/*
-void
-buildrep(int x, int as)
-{
-	Opcross *p;
-	Optab *e, *s, *o;
-	int a1, a2, a3, n;
-
-	if(C_NONE != 0 || C_REG != 1 || C_GOK >= 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 5c78680..b3fb0bb 100644
--- a/src/cmd/6a/a.h
+++ b/src/cmd/6a/a.h
@@ -29,9 +29,9 @@
 // THE SOFTWARE.
 
 #include <bio.h>
+#include <link.h>
 #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 ed72916..6fd4910 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	<sval>	LSCONST LSP
 %token	<sym>	LNAME LLAB LVAR
 %type	<lval>	con con2 expr pointer offset
-%type	<gen>	mem imm imm2 reg nam rel rem rim rom omem nmem
-%type	<gen2>	nonnon nonrel nonrem rimnon rimrem remrim
-%type	<gen2>	spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9
-%type	<gen2>	spec10 spec11 spec12 spec13
+%type	<addr>	mem imm imm2 reg nam rel rem rim rom omem nmem
+%type	<addr2>	nonnon nonrel nonrem rimnon rimrem remrim
+%type	<addr2>	spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9
+%type	<addr2>	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 ab34e82..167e6b6 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; i<nDlist; i++)
-		dodefine(Dlist[i]);
-	yyparse();
-	if(nerrors) {
+	for(pass = 1; pass <= 2; pass++) {
+		pinit(file);
+		for(i=0; i<nDlist; i++)
+			dodefine(Dlist[i]);
+		yyparse();
 		cclean();
-		return nerrors;
+		if(nerrors)
+			return nerrors;
 	}
 
-	Bprint(&obuf, "\n!\n");
-
-	pass = 2;
-	outhist();
-	pinit(file);
-	for(i=0; i<nDlist; i++)
-		dodefine(Dlist[i]);
-	yyparse();
-	cclean();
-	return nerrors;
+	writeobj(ctxt, &obuf);
+	Bflush(&obuf);
+	return 0;
 }
 
 struct
@@ -313,6 +329,7 @@ struct
 	"TR5",		LBREG,	D_TR+5,
 	"TR6",		LBREG,	D_TR+6,
 	"TR7",		LBREG,	D_TR+7,
+	"TLS",		LSREG,	D_TLS,
 
 	"AAA",		LTYPE0,	AAAA,
 	"AAD",		LTYPE0,	AAAD,
@@ -503,6 +520,7 @@ struct
 	"MOVLQZX",	LTYPE3, AMOVLQZX,
 	"MOVNTIL",	LTYPE3,	AMOVNTIL,
 	"MOVNTIQ",	LTYPE3,	AMOVNTIQ,
+	"MOVQL",	LTYPE3, AMOVQL,
 	"MOVWLSX",	LTYPE3, AMOVWLSX,
 	"MOVWLZX",	LTYPE3, AMOVWLZX,
 	"MOVWQSX",	LTYPE3,	AMOVWQSX,
@@ -1031,15 +1049,8 @@ cinit(void)
 	Sym *s;
 	int i;
 
-	nullgen.sym = S;
-	nullgen.offset = 0;
-	if(FPCHIP)
-		nullgen.dval = 0;
-	for(i=0; i<sizeof(nullgen.sval); i++)
-		nullgen.sval[i] = 0;
 	nullgen.type = D_NONE;
 	nullgen.index = D_NONE;
-	nullgen.scale = 0;
 
 	nerrors = 0;
 	iostack = I;
@@ -1055,13 +1066,6 @@ cinit(void)
 		s->type = 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; i<NSNAME; i++) {
-			BPUTC(&obuf, *n);
-			n++;
-		}
-		return;
-	}
-	if(t & T_TYPE)
-		BPUTC(&obuf, a->type);
-}
-
-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 3e5058b..a4f0f74 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 <http://www.gnu.org/licenses/>.  */
+   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 <u.h>
-#include <stdio.h>	/* if we don't, bison will, and a.h re-#defines getc */
-#include <libc.h>
-#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 <u.h>
+#include <stdio.h>	/* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
+#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 <stdlib.h> /* 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 <stdlib.h> /* 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
-       <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
-       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 bba6081..e0eb5e1 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 <http://www.gnu.org/licenses/>.  */
+   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 c466a3a..a196e55 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 b5a60ac..28f5b8d 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<sizeof(double); i++) {
-		c = a[i] & 0xff;
-		if(c >= '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 0a3bd84..a11067c 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 edd93a0..348d747 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 744a602..ba1c1f6 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 2496da4..d771364 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; sym<NSYM; sym++) {
-		h[sym].sym = S;
-		h[sym].type = 0;
-	}
-	sym = 1;
-	for(p = firstp; p != P; p = p->link) {
-	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; i<NSNAME; i++) {
-			BPUTC(b, *n);
-			n++;
-		}
-		return;
-	}
-	if(t & T_TYPE)
-		BPUTC(b, a->type);
-}
-
 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 6f5d42d..4d07436 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 ada2baa..4dd505b 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 526c04c..1d32c5a 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 3ef59c7..a5da17d 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 9fad9f7..c385798 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; i<stkzerosize; i+=widthptr) {
-			if(bvget(bv, j) || bvget(bv, j+1))
-				p = appendp(p, AMOVQ, D_CONST, 0, D_SP+D_INDIR, frame-stkzerosize+i);
-			j += 2;
+	lo = hi = 0;
+	ax = 0;
+	// iterate through declarations - they are sorted in decreasing xoffset order.
+	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*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(&reg, 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(&reg, types[TINT64], D_CX);
+			nodconst(&r1, types[TINT64], 32);
+			gins(ASHLQ, &r1, &reg);
+			gins(AORQ, &con, &reg);
+			gins(APUSHQ, &reg, N);
 		} else {
-			gins(APUSHQ, f, N);
+			nodreg(&reg, types[TINT64], D_CX);
+			gmove(f, &reg);
+			gins(APUSHQ, &reg, 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(&reg, types[TINT64], D_CX);
 		gins(APOPQ, N, &reg);
-		gins(APOPQ, N, &reg);
+		if(widthptr == 8)
+			gins(APOPQ, N, &reg);
 		if(proc == 2) {
 			nodreg(&reg, types[TINT64], D_AX);
 			gins(ATESTQ, &reg, &reg);
-			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 a9bd5e8..04e837b 100644
--- a/src/cmd/6g/gobj.c
+++ b/src/cmd/6g/gobj.c
@@ -32,231 +32,6 @@
 #include <libc.h>
 #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; i<NSNAME; i++) {
-			BPUTC(b, *n);
-			n++;
-		}
-		return;
-	}
-	if(t & T_TYPE)
-		BPUTC(b, a->type);
-	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.sym<NSYM; z.sym++) {
-		z.h[z.sym].sym = S;
-		z.h[z.sym].type = 0;
-	}
-	z.sym = 1;
-}
-
-static int
-zsym(Sym *s, int t, int *new)
-{
-	int i;
-
-	*new = 0;
-	if(s == S)
-		return 0;
-
-	i = s->sym;
-	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);
@@ -431,27 +206,6 @@ dgostringptr(Sym *s, int off, char *str)
 }
 
 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)
 {
 	Prog *p;
@@ -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 7318909..e4d00bf 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; i<nelem(resvd); i++)
 		reg[resvd[i]]++;
+	
+	if(nacl) {
+		reg[D_BP]++;
+		reg[D_R15]++;
+	}
 }
 
 void
@@ -310,6 +310,11 @@ gclean(void)
 
 	for(i=0; i<nelem(resvd); i++)
 		reg[resvd[i]]--;
+	if(nacl) {
+		reg[D_BP]--;
+		reg[D_R15]--;
+	}
+
 
 	for(i=D_AX; i<=D_R15; i++)
 		if(reg[i])
@@ -457,6 +462,7 @@ Node*
 nodarg(Type *t, int fp)
 {
 	Node *n;
+	NodeList *l;
 	Type *first;
 	Iter savet;
 
@@ -477,6 +483,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;
@@ -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<o; i++) {
 		if(oary[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 9d27a6a..0000000
--- 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 at 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 at 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 <u.h>
-#include <libc.h>
-#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), "<nil>");
-		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<sconsize; i++) {
-		c = a[i] & 0xff;
-		if((c >= '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 3dcc3d7..bf356af 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 5ccf901..0f27204 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 90571a2..ee68399 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 63fd0de..f3b1e55 100644
--- a/src/cmd/6g/reg.c
+++ b/src/cmd/6g/reg.c
@@ -55,30 +55,6 @@ rcmp(const void *a1, const void *a2)
 }
 
 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; z<BITS; z++)
-			ovar.b[z] |= bit.b[z];
-		t = structnext(&save);
-	}
-//if(bany(&ovar))
-//print("ovars = %Q\n", ovar);
-}
-
-static void
 setaddrs(Bits bit)
 {
 	int i, n;
@@ -138,6 +114,8 @@ static char* regname[] = {
 
 static Node* regnodes[NREGVAR];
 
+static void walkvardef(Node *n, Reg *r, int active);
+
 void
 regopt(Prog *firstp)
 {
@@ -145,7 +123,7 @@ regopt(Prog *firstp)
 	Prog *p;
 	Graph *g;
 	ProgInfo info;
-	int i, z;
+	int i, z, active;
 	uint32 vreg;
 	Bits bit;
 
@@ -155,9 +133,8 @@ regopt(Prog *firstp)
 		first = 0;
 	}
 
-	fixjmp(firstp);
 	mergetemp(firstp);
-	
+
 	/*
 	 * control flow is more complicated in generated go code
 	 * than in generated c code.  define pseudo-variables for
@@ -177,12 +154,10 @@ regopt(Prog *firstp)
 		params.b[z] = 0;
 		consts.b[z] = 0;
 		addrs.b[z] = 0;
+		ivar.b[z] = 0;
 		ovar.b[z] = 0;
 	}
 
-	// build list of return variables
-	setoutvar();
-
 	/*
 	 * pass 1
 	 * build aux data structure
@@ -190,12 +165,18 @@ regopt(Prog *firstp)
 	 * find use and set of variables
 	 */
 	g = flowstart(firstp, sizeof(Reg));
-	if(g == nil)
+	if(g == nil) {
+		for(i=0; i<nvar; i++)
+			var[i].node->opt = 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.
@@ -256,6 +237,26 @@ regopt(Prog *firstp)
 		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
 	 * 	back until flow graph is complete
@@ -406,6 +407,8 @@ brk:
 	/*
 	 * free aux structures. peep allocates new ones.
 	 */
+	for(i=0; i<nvar; i++)
+		var[i].node->opt = 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; i<nvar; i++) {
+			v = var+i;
+			if(v->node == 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; z<BITS; z++)
 			params.b[z] |= bit.b[z];
 
+	if(node->class == PPARAM)
+		for(z=0; z<BITS; z++)
+			ivar.b[z] |= bit.b[z];
+	if(node->class == PPARAMOUT)
+		for(z=0; z<BITS; z++)
+			ovar.b[z] |= bit.b[z];
+
+	// Treat values with their address taken as live at calls,
+	// because the garbage collector's liveness analysis in ../gc/plive.c does.
+	// These must be consistent or else we will elide stores and the garbage
+	// collector will see uninitialized data.
+	// The typical case where our own analysis is out of sync is when the
+	// node appears to have its address taken but that code doesn't actually
+	// get generated and therefore doesn't show up as an address being
+	// taken when we analyze the instruction stream.
+	// One instance of this case is when a closure uses the same name as
+	// an outer variable for one of its own variables declared with :=.
+	// The parser flags the outer variable as possibly shared, and therefore
+	// sets addrtaken, even though it ends up not being actually shared.
+	// If we were better about _ elision, _ = &x would suffice too.
+	// The broader := in a closure problem is mentioned in a comment in
+	// closure.c:/^typecheckclosure and dcl.c:/^oldname.
+	if(node->addrtaken)
+		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; z<BITS; z++) {
@@ -710,10 +789,61 @@ prop(Reg *r, Bits ref, Bits cal)
 		case ACALL:
 			if(noreturn(r1->f.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; z<BITS; z++) {
-				cal.b[z] |= ref.b[z] | externs.b[z];
+				cal.b[z] |= ref.b[z] | externs.b[z] | ivar.b[z] | r1->act.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<BITS; z++) {
+				if(cal.b[z] == 0)
+					continue;
+				for(i=0; i<32; i++) {
+					if(z*32+i >= 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; z<BITS; z++) {
-				cal.b[z] |= externs.b[z];
-				// issue 4066: flush modified return variables in case of panic
-				if(hasdefer)
-					cal.b[z] |= ovar.b[z];
-			}
-			break;
 		}
 		for(z=0; z<BITS; z++) {
 			ref.b[z] = (ref.b[z] & ~r1->set.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 5fa73a6..1e2a148 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 a09cc97..e251e32 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 ecab867..7303910 100644
--- a/src/cmd/6l/l.h
+++ b/src/cmd/6l/l.h
@@ -31,6 +31,7 @@
 #include	<u.h>
 #include	<libc.h>
 #include	<bio.h>
+#include	<link.h>
 #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 5040e43..d960fcc 100644
--- a/src/cmd/6l/list.c
+++ b/src/cmd/6l/list.c
@@ -33,371 +33,14 @@
 #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<sizeof(double); i++) {
-		c = a[i] & 0xff;
-		if(c >= '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)
 {
 	int i, n;
@@ -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 ae649a7..3b8e8f4 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	<ar.h>
 
-char	*noname		= "<none>";
 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 46603ad..0000000
--- 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 at 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 at 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 1be3c18..0000000
--- 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 at 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 at 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 : "<nil>");
-			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; i<nelem(morename); i++) {
-		symmorestack[i] = lookup(morename[i], 0);
-		if(symmorestack[i]->type != 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 862ce08..0000000
--- 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 at 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 at 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 74f11d6..0000000
--- 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 at 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 at 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; i<s->np; i++) {
-			print(" %.2ux", s->p[i]);
-			if(i%16 == 15)
-				print("\n  %.6ux", i+1);
-		}
-		if(i%16)
-			print("\n");
-	
-		for(i=0; i<s->nr; i++) {
-			Reloc *r;
-			
-			r = &s->r[i];
-			print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add);
-		}
-	}
-}
-
-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<Ymax; i++)
-		ycover[i*Ymax + i] = 1;
-
-	ycover[Yi0*Ymax + Yi8] = 1;
-	ycover[Yi1*Ymax + Yi8] = 1;
-
-	ycover[Yi0*Ymax + Ys32] = 1;
-	ycover[Yi1*Ymax + Ys32] = 1;
-	ycover[Yi8*Ymax + Ys32] = 1;
-
-	ycover[Yi0*Ymax + Yi32] = 1;
-	ycover[Yi1*Ymax + Yi32] = 1;
-	ycover[Yi8*Ymax + Yi32] = 1;
-	ycover[Ys32*Ymax + Yi32] = 1;
-
-	ycover[Yi0*Ymax + Yi64] = 1;
-	ycover[Yi1*Ymax + Yi64] = 1;
-	ycover[Yi8*Ymax + Yi64] = 1;
-	ycover[Ys32*Ymax + Yi64] = 1;
-	ycover[Yi32*Ymax + Yi64] = 1;
-
-	ycover[Yal*Ymax + Yrb] = 1;
-	ycover[Ycl*Ymax + Yrb] = 1;
-	ycover[Yax*Ymax + Yrb] = 1;
-	ycover[Ycx*Ymax + Yrb] = 1;
-	ycover[Yrx*Ymax + Yrb] = 1;
-	ycover[Yrl*Ymax + Yrb] = 1;
-
-	ycover[Ycl*Ymax + Ycx] = 1;
-
-	ycover[Yax*Ymax + Yrx] = 1;
-	ycover[Ycx*Ymax + Yrx] = 1;
-
-	ycover[Yax*Ymax + Yrl] = 1;
-	ycover[Ycx*Ymax + Yrl] = 1;
-	ycover[Yrx*Ymax + Yrl] = 1;
-
-	ycover[Yf0*Ymax + Yrf] = 1;
-
-	ycover[Yal*Ymax + Ymb] = 1;
-	ycover[Ycl*Ymax + Ymb] = 1;
-	ycover[Yax*Ymax + Ymb] = 1;
-	ycover[Ycx*Ymax + Ymb] = 1;
-	ycover[Yrx*Ymax + Ymb] = 1;
-	ycover[Yrb*Ymax + Ymb] = 1;
-	ycover[Yrl*Ymax + Ymb] = 1;
-	ycover[Ym*Ymax + Ymb] = 1;
-
-	ycover[Yax*Ymax + Yml] = 1;
-	ycover[Ycx*Ymax + Yml] = 1;
-	ycover[Yrx*Ymax + Yml] = 1;
-	ycover[Yrl*Ymax + Yml] = 1;
-	ycover[Ym*Ymax + Yml] = 1;
-
-	ycover[Yax*Ymax + Ymm] = 1;
-	ycover[Ycx*Ymax + Ymm] = 1;
-	ycover[Yrx*Ymax + Ymm] = 1;
-	ycover[Yrl*Ymax + Ymm] = 1;
-	ycover[Ym*Ymax + Ymm] = 1;
-	ycover[Ymr*Ymax + Ymm] = 1;
-
-	ycover[Ym*Ymax + Yxm] = 1;
-	ycover[Yxr*Ymax + Yxm] = 1;
-
-	for(i=0; i<D_NONE; i++) {
-		reg[i] = -1;
-		if(i >= D_AL && i <= D_R15B) {
-			reg[i] = (i-D_AL) & 7;
-			if(i >= D_SPB && i <= D_DIB)
-				regrex[i] = 0x40;
-			if(i >= D_R8B && i <= D_R15B)
-				regrex[i] = Rxr | Rxx | Rxb;
-		}
-		if(i >= D_AH && i<= D_BH)
-			reg[i] = 4 + ((i-D_AH) & 7);
-		if(i >= D_AX && i <= D_R15) {
-			reg[i] = (i-D_AX) & 7;
-			if(i >= D_R8)
-				regrex[i] = Rxr | Rxx | Rxb;
-		}
-		if(i >= D_F0 && i <= D_F0+7)
-			reg[i] = (i-D_F0) & 7;
-		if(i >= D_M0 && i <= D_M0+7)
-			reg[i] = (i-D_M0) & 7;
-		if(i >= D_X0 && i <= D_X0+15) {
-			reg[i] = (i-D_X0) & 7;
-			if(i >= D_X0+8)
-				regrex[i] = Rxr | Rxx | Rxb;
-		}
-		if(i >= D_CR+8 && i <= D_CR+15)
-			regrex[i] = Rxr;
-	}
-}
-
-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 c5c22d7..adc388c 100644
--- a/src/cmd/8a/a.h
+++ b/src/cmd/8a/a.h
@@ -29,9 +29,9 @@
 // THE SOFTWARE.
 
 #include <bio.h>
+#include <link.h>
 #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 13ccc98..d7ff623 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	<sym>	LNAME LLAB LVAR
 %type	<lval>	con expr pointer offset
 %type	<con2>	con2
-%type	<gen>	mem imm imm2 reg nam rel rem rim rom omem nmem
-%type	<gen2>	nonnon nonrel nonrem rimnon rimrem remrim
-%type	<gen2>	spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9 spec10 spec11 spec12
+%type	<addr>	mem imm imm2 reg nam rel rem rim rom omem nmem
+%type	<addr2>	nonnon nonrel nonrem rimnon rimrem remrim
+%type	<addr2>	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 f2ccc33..32c099b 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; i<nDlist; i++)
-		dodefine(Dlist[i]);
-	yyparse();
-	if(nerrors) {
+	Bprint(&obuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
+	Bprint(&obuf, "!\n");
+
+	for(pass = 1; pass <= 2; pass++) {
+		pinit(file);
+		for(i=0; i<nDlist; i++)
+			dodefine(Dlist[i]);
+		yyparse();
 		cclean();
-		return nerrors;
+		if(nerrors)
+			return nerrors;
 	}
 
-	Bprint(&obuf, "\n!\n");
-
-	pass = 2;
-	outhist();
-	pinit(file);
-	for(i=0; i<nDlist; i++)
-		dodefine(Dlist[i]);
-	yyparse();
-	cclean();
-	return nerrors;
+	writeobj(ctxt, &obuf);
+	Bflush(&obuf);
+	return 0;
 }
 
 struct
@@ -225,6 +236,7 @@ struct
 	"ES",		LSREG,	D_ES,
 	"FS",		LSREG,	D_FS,
 	"GS",		LSREG,	D_GS,
+	"TLS",		LSREG,	D_TLS,
 
 	"GDTR",		LBREG,	D_GDTR,
 	"IDTR",		LBREG,	D_IDTR,
@@ -778,6 +790,7 @@ struct
 	"PSUBW",	LTYPE3,	APSUBW,
 	"PUNPCKHQDQ",	LTYPE3,	APUNPCKHQDQ,
 	"PUNPCKLQDQ",	LTYPE3,	APUNPCKLQDQ,
+	"PXOR",		LTYPE3, APXOR,
 	"RCPPS",	LTYPE3,	ARCPPS,
 	"RCPSS",	LTYPE3,	ARCPSS,
 	"RSQRTPS",	LTYPE3,	ARSQRTPS,
@@ -810,15 +823,8 @@ cinit(void)
 	Sym *s;
 	int i;
 
-	nullgen.sym = S;
-	nullgen.offset = 0;
-	if(FPCHIP)
-		nullgen.dval = 0;
-	for(i=0; i<sizeof(nullgen.sval); i++)
-		nullgen.sval[i] = 0;
 	nullgen.type = D_NONE;
 	nullgen.index = D_NONE;
-	nullgen.scale = 0;
 
 	nerrors = 0;
 	iostack = I;
@@ -834,13 +840,6 @@ cinit(void)
 		s->type = 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; i<NSNAME; i++) {
-			BPUTC(&obuf, *n);
-			n++;
-		}
-		return;
-	}
-	if(t & T_TYPE)
-		BPUTC(&obuf, a->type);
-}
-
-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 aec4856..f48c9fe 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 <http://www.gnu.org/licenses/>.  */
+   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 <u.h>
-#include <stdio.h>	/* if we don't, bison will, and a.h re-#defines getc */
-#include <libc.h>
-#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 <u.h>
+#include <stdio.h>	/* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
+#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 <stdlib.h> /* 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 <stdlib.h> /* 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
-       <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
-       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 14637cb..d191455 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 <http://www.gnu.org/licenses/>.  */
+   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 b668b4c..87b8e22 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 8506e08..1730ecc 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<sizeof(double); i++) {
-		c = a[i] & 0xff;
-		if(c >= '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 da0127d..4f58fc05 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 a3d5d61..e6ba8bc 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 b681974..ae36f84 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; sym<NSYM; sym++) {
-		h[sym].sym = S;
-		h[sym].type = 0;
-	}
-	sym = 1;
-	for(p = firstp; p != P; p = p->link) {
-	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; i<NSNAME; i++) {
-			BPUTC(b, *n);
-			n++;
-		}
-		return;
-	}
-	if(t & T_TYPE)
-		BPUTC(b, a->type);
-}
-
 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 5c486af..25082de 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 cc28a31..d626c2e 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 2c8aaa0..fbd2e9a 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 55fdded..bdefa93 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 fa5ed00..2285a04 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; i<stkzerosize; i+=widthptr) {
-			if(bvget(bv, j) || bvget(bv, j+1))
-				p = appendp(p, AMOVL, D_CONST, 0, D_SP+D_INDIR, frame-stkzerosize+i);
-			j += 2;
+	hi = 0;
+	lo = hi;
+	ax = 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 = 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(&reg, types[TINT64], D_AX);
 			gins(ATESTL, &reg, &reg);
-			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 0517824..fa0605e 100644
--- a/src/cmd/8g/gobj.c
+++ b/src/cmd/8g/gobj.c
@@ -32,229 +32,6 @@
 #include <libc.h>
 #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; i<NSNAME; i++) {
-			BPUTC(b, *n);
-			n++;
-		}
-		return;
-	}
-	if(t & T_TYPE)
-		BPUTC(b, a->type);
-	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.sym<NSYM; z.sym++) {
-		z.h[z.sym].sym = S;
-		z.h[z.sym].type = 0;
-	}
-	z.sym = 1;
-}
-
-static int
-zsym(Sym *s, int t, int *new)
-{
-	int i;
-
-	*new = 0;
-	if(s == S)
-		return 0;
-
-	i = s->sym;
-	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 34703ba..2f3cb28 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 ec02ba5..0000000
--- 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 at 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 at 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 <u.h>
-#include <libc.h>
-#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<sconsize; i++) {
-		c = a[i] & 0xff;
-		if((c >= '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 0d99bdb..77a69e1 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 966c042..a4e516d 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 14f197b..8eed67f 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 a85c660..fd610f8 100644
--- a/src/cmd/8g/reg.c
+++ b/src/cmd/8g/reg.c
@@ -55,30 +55,6 @@ rcmp(const void *a1, const void *a2)
 }
 
 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; z<BITS; z++)
-			ovar.b[z] |= bit.b[z];
-		t = structnext(&save);
-	}
-//if(bany(ovar))
-//print("ovars = %Q\n", ovar);
-}
-
-static void
 setaddrs(Bits bit)
 {
 	int i, n;
@@ -108,6 +84,8 @@ static char* regname[] = {
 
 static Node* regnodes[NREGVAR];
 
+static void walkvardef(Node *n, Reg *r, int active);
+
 void
 regopt(Prog *firstp)
 {
@@ -115,7 +93,7 @@ regopt(Prog *firstp)
 	Prog *p;
 	Graph *g;
 	ProgInfo info;
-	int i, z;
+	int i, z, active;
 	uint32 vreg;
 	Bits bit;
 
@@ -124,8 +102,7 @@ regopt(Prog *firstp)
 		exregoffset = D_DI;	// no externals
 		first = 0;
 	}
-	
-	fixjmp(firstp);
+
 	mergetemp(firstp);
 
 	/*
@@ -147,12 +124,10 @@ regopt(Prog *firstp)
 		params.b[z] = 0;
 		consts.b[z] = 0;
 		addrs.b[z] = 0;
+		ivar.b[z] = 0;
 		ovar.b[z] = 0;
 	}
 
-	// build list of return variables
-	setoutvar();
-
 	/*
 	 * pass 1
 	 * build aux data structure
@@ -160,12 +135,18 @@ regopt(Prog *firstp)
 	 * find use and set of variables
 	 */
 	g = flowstart(firstp, sizeof(Reg));
-	if(g == nil)
+	if(g == nil) {
+		for(i=0; i<nvar; i++)
+			var[i].node->opt = 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.
@@ -228,6 +209,26 @@ regopt(Prog *firstp)
 		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
 	 * 	back until flow graph is complete
@@ -367,6 +368,8 @@ brk:
 	/*
 	 * free aux structures. peep allocates new ones.
 	 */
+	for(i=0; i<nvar; i++)
+		var[i].node->opt = 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; i<nvar; i++) {
+			v = var+i;
+			if(v->node == 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; z<BITS; z++)
 			params.b[z] |= bit.b[z];
+		
+	if(node->class == PPARAM)
+		for(z=0; z<BITS; z++)
+			ivar.b[z] |= bit.b[z];
+	if(node->class == PPARAMOUT)
+		for(z=0; z<BITS; z++)
+			ovar.b[z] |= bit.b[z];
+
+	// Treat values with their address taken as live at calls,
+	// because the garbage collector's liveness analysis in ../gc/plive.c does.
+	// These must be consistent or else we will elide stores and the garbage
+	// collector will see uninitialized data.
+	// The typical case where our own analysis is out of sync is when the
+	// node appears to have its address taken but that code doesn't actually
+	// get generated and therefore doesn't show up as an address being
+	// taken when we analyze the instruction stream.
+	// One instance of this case is when a closure uses the same name as
+	// an outer variable for one of its own variables declared with :=.
+	// The parser flags the outer variable as possibly shared, and therefore
+	// sets addrtaken, even though it ends up not being actually shared.
+	// If we were better about _ elision, _ = &x would suffice too.
+	// The broader := in a closure problem is mentioned in a comment in
+	// closure.c:/^typecheckclosure and dcl.c:/^oldname.
+	if(node->addrtaken)
+		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; z<BITS; z++) {
@@ -672,10 +755,61 @@ prop(Reg *r, Bits ref, Bits cal)
 		case ACALL:
 			if(noreturn(r1->f.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; z<BITS; z++) {
-				cal.b[z] |= ref.b[z] | externs.b[z];
+				cal.b[z] |= ref.b[z] | externs.b[z] | ivar.b[z] | r1->act.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<BITS; z++) {
+				if(cal.b[z] == 0)
+					continue;
+				for(i=0; i<32; i++) {
+					if(z*32+i >= 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; z<BITS; z++) {
-				cal.b[z] |= externs.b[z];
-				// issue 4066: flush modified return variables in case of panic
-				if(hasdefer)
-					cal.b[z] |= ovar.b[z];
-			}
-			break;
 		}
 		for(z=0; z<BITS; z++) {
 			ref.b[z] = (ref.b[z] & ~r1->set.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 988e50f..8e642d3 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 3be37ea..114a3eb 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 814aa14..c9695ad 100644
--- a/src/cmd/8l/l.h
+++ b/src/cmd/8l/l.h
@@ -31,6 +31,7 @@
 #include	<u.h>
 #include	<libc.h>
 #include	<bio.h>
+#include	<link.h>
 #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 e2a2ec5..0a75340 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<sizeof(double); i++) {
-		c = a[i] & 0xff;
-		if(c >= '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 3fdc413..1b65c5e 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	<ar.h>
 
-#ifndef	DEFAULT
-#define	DEFAULT	'9'
-#endif
-
-char	*noname		= "<none>";
-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 a4c40e8..0000000
--- 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 at 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 at 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 1eaf78f..0000000
--- 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 at 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 at 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 : "<nil>");
-				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 d99c5e4..0000000
--- 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 at 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 at 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 acf973c..0000000
--- 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 at 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 at 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; i<s->np; i++) {
-			print(" %.2ux", s->p[i]);
-			if(i%16 == 15)
-				print("\n  %.6ux", i+1);
-		}
-		if(i%16)
-			print("\n");
-	
-		for(i=0; i<s->nr; i++) {
-			Reloc *r;
-			
-			r = &s->r[i];
-			print(" rel %#.4ux/%d %s%+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<Ymax; i++)
-		ycover[i*Ymax + i] = 1;
-
-	ycover[Yi0*Ymax + Yi8] = 1;
-	ycover[Yi1*Ymax + Yi8] = 1;
-
-	ycover[Yi0*Ymax + Yi32] = 1;
-	ycover[Yi1*Ymax + Yi32] = 1;
-	ycover[Yi8*Ymax + Yi32] = 1;
-
-	ycover[Yal*Ymax + Yrb] = 1;
-	ycover[Ycl*Ymax + Yrb] = 1;
-	ycover[Yax*Ymax + Yrb] = 1;
-	ycover[Ycx*Ymax + Yrb] = 1;
-	ycover[Yrx*Ymax + Yrb] = 1;
-
-	ycover[Yax*Ymax + Yrx] = 1;
-	ycover[Ycx*Ymax + Yrx] = 1;
-
-	ycover[Yax*Ymax + Yrl] = 1;
-	ycover[Ycx*Ymax + Yrl] = 1;
-	ycover[Yrx*Ymax + Yrl] = 1;
-
-	ycover[Yf0*Ymax + Yrf] = 1;
-
-	ycover[Yal*Ymax + Ymb] = 1;
-	ycover[Ycl*Ymax + Ymb] = 1;
-	ycover[Yax*Ymax + Ymb] = 1;
-	ycover[Ycx*Ymax + Ymb] = 1;
-	ycover[Yrx*Ymax + Ymb] = 1;
-	ycover[Yrb*Ymax + Ymb] = 1;
-	ycover[Ym*Ymax + Ymb] = 1;
-
-	ycover[Yax*Ymax + Yml] = 1;
-	ycover[Ycx*Ymax + Yml] = 1;
-	ycover[Yrx*Ymax + Yml] = 1;
-	ycover[Yrl*Ymax + Yml] = 1;
-	ycover[Ym*Ymax + Yml] = 1;
-
-	ycover[Yax*Ymax + Ymm] = 1;
-	ycover[Ycx*Ymax + Ymm] = 1;
-	ycover[Yrx*Ymax + Ymm] = 1;
-	ycover[Yrl*Ymax + Ymm] = 1;
-	ycover[Ym*Ymax + Ymm] = 1;
-	ycover[Ymr*Ymax + Ymm] = 1;
-
-	ycover[Ym*Ymax + Yxm] = 1;
-	ycover[Yxr*Ymax + Yxm] = 1;
-
-	for(i=0; i<D_NONE; i++) {
-		reg[i] = -1;
-		if(i >= D_AL && i <= D_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 0000000..b278d08
--- /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 54c4d90..0000000
--- 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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-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 0000000..b94ba12
--- /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 a62c874..4bde794 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 1e10dc6..896b2b4 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 af2339c..c8aac12 100644
--- a/src/cmd/cc/cc.h
+++ b/src/cmd/cc/cc.h
@@ -30,6 +30,7 @@
 
 #include <libc.h>
 #include <bio.h>
+#include <link.h>
 
 #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 049dc51..4248437 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, "<eof>");
-	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 9d293b0..e24db1b 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; i<NSYM; i++) {
-		h[i].type = 0;
-		h[i].sym = S;
-	}
 	for(i=0; i<NHASH; i++)
 		for(s = hash[i]; s != S; s = s->link)
 			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<n; i++)
-				a[i].line += d;
-		}
-	}
-	if(n > HISTSZ)
-		n = HISTSZ;
-	for(i=0; i<n; i++)
-		print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1));
-}
-
-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 = (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 f0a5076..f6927b2 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: <pop>\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 b82872b..10bebc1 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 cc9c227..bae57c6 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 bed9891..94c11d0 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 605bab6..69c7ce8 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 3e1837e..7a80210 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 83ab952..76c7247 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 9de9318..6222e50 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 dafc5c1..52a621c 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 e6e5f0c..6884e0a 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<nelem(unreleased); i++)
 			if(isdir(bpathf(&b, "%s/%s", goroot, unreleased[i])))
 				fatal("%s should not exist in release build", bstr(&b));
@@ -435,7 +457,6 @@ static char *proto_gccargs[] = {
 	"-Wstrict-prototypes",
 	"-Wextra",
 	"-Wunused",
-	"-Wuninitialized",
 	"-Wno-sign-compare",
 	"-Wno-missing-braces",
 	"-Wno-parentheses",
@@ -447,6 +468,15 @@ static char *proto_gccargs[] = {
 	"-fno-common",
 	"-ggdb",
 	"-pipe",
+};
+
+// gccargs2 is the second part of gccargs.
+// it is used if the environment isn't defining CFLAGS.
+static char *proto_gccargs2[] = {
+	// on older versions of GCC, -Wuninitialized is not supported
+	// without -O, so put it here together with -O settings in case
+	// the user's $CFLAGS doesn't include -O.
+	"-Wuninitialized",
 #if defined(__NetBSD__) && defined(__arm__)
 	// GCC 4.5.4 (NetBSD nb1 20120916) on ARM is known to mis-optimize gc/mparith3.c
 	// Fix available at http://patchwork.ozlabs.org/patch/64562/.
@@ -456,7 +486,7 @@ static char *proto_gccargs[] = {
 #endif
 };
 
-static Vec gccargs;
+static Vec gccargs, ldargs;
 
 // deptab lists changes to the default dependencies for a given prefix.
 // deps ending in /* read the whole directory; deps beginning with -
@@ -480,18 +510,17 @@ static struct {
 		"$GOROOT/include/libc.h",
 		"$GOROOT/include/bio.h",
 	}},
-	{"libmach", {
+	{"liblink", {
 		"$GOROOT/include/u.h",
 		"$GOROOT/include/utf.h",
 		"$GOROOT/include/fmt.h",
 		"$GOROOT/include/libc.h",
 		"$GOROOT/include/bio.h",
 		"$GOROOT/include/ar.h",
-		"$GOROOT/include/bootexec.h",
-		"$GOROOT/include/mach.h",
-		"$GOROOT/include/ureg_amd64.h",
-		"$GOROOT/include/ureg_arm.h",
-		"$GOROOT/include/ureg_x86.h",
+		"$GOROOT/include/link.h",
+		"anames5.c",
+		"anames6.c",
+		"anames8.c",
 	}},
 	{"cmd/cc", {
 		"-pgen.c",
@@ -500,6 +529,7 @@ static struct {
 	{"cmd/gc", {
 		"-cplx.c",
 		"-pgen.c",
+		"-plive.c",
 		"-popt.c",
 		"-y1.tab.c",  // makefile dreg
 		"opnames.h",
@@ -507,64 +537,58 @@ static struct {
 	{"cmd/5c", {
 		"../cc/pgen.c",
 		"../cc/pswt.c",
-		"../5l/enam.c",
-		"$GOROOT/pkg/obj/$GOOS_$GOARCH/libcc.a",
+		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libcc.a",
 	}},
 	{"cmd/6c", {
 		"../cc/pgen.c",
 		"../cc/pswt.c",
-		"../6l/enam.c",
-		"$GOROOT/pkg/obj/$GOOS_$GOARCH/libcc.a",
+		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libcc.a",
 	}},
 	{"cmd/8c", {
 		"../cc/pgen.c",
 		"../cc/pswt.c",
-		"../8l/enam.c",
-		"$GOROOT/pkg/obj/$GOOS_$GOARCH/libcc.a",
+		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libcc.a",
 	}},
 	{"cmd/5g", {
 		"../gc/cplx.c",
 		"../gc/pgen.c",
+		"../gc/plive.c",
 		"../gc/popt.c",
 		"../gc/popt.h",
-		"../5l/enam.c",
-		"$GOROOT/pkg/obj/$GOOS_$GOARCH/libgc.a",
+		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
 	}},
 	{"cmd/6g", {
 		"../gc/cplx.c",
 		"../gc/pgen.c",
+		"../gc/plive.c",
 		"../gc/popt.c",
 		"../gc/popt.h",
-		"../6l/enam.c",
-		"$GOROOT/pkg/obj/$GOOS_$GOARCH/libgc.a",
+		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
 	}},
 	{"cmd/8g", {
 		"../gc/cplx.c",
 		"../gc/pgen.c",
+		"../gc/plive.c",
 		"../gc/popt.c",
 		"../gc/popt.h",
-		"../8l/enam.c",
-		"$GOROOT/pkg/obj/$GOOS_$GOARCH/libgc.a",
+		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
 	}},
 	{"cmd/5l", {
 		"../ld/*",
-		"enam.c",
 	}},
 	{"cmd/6l", {
 		"../ld/*",
-		"enam.c",
 	}},
 	{"cmd/8l", {
 		"../ld/*",
-		"enam.c",
 	}},
 	{"cmd/go", {
 		"zdefaultcc.go",
 	}},
 	{"cmd/", {
-		"$GOROOT/pkg/obj/$GOOS_$GOARCH/libmach.a",
-		"$GOROOT/pkg/obj/$GOOS_$GOARCH/libbio.a",
-		"$GOROOT/pkg/obj/$GOOS_$GOARCH/lib9.a",
+		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/liblink.a",
+		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libbio.a",
+		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/lib9.a",
 	}},
 	{"pkg/runtime", {
 		"zaexperiment.h", // must sort above zasm
@@ -592,7 +616,9 @@ static struct {
 	void (*gen)(char*, char*);
 } gentab[] = {
 	{"opnames.h", gcopnames},
-	{"enam.c", mkenam},
+	{"anames5.c", mkanames},
+	{"anames6.c", mkanames},
+	{"anames8.c", mkanames},
 	{"zasm_", mkzasm},
 	{"zdefaultcc.go", mkzdefaultcc},
 	{"zsys_", mkzsys},
@@ -601,6 +627,9 @@ static struct {
 	{"zruntime_defs_", mkzruntimedefs},
 	{"zversion.go", mkzversion},
 	{"zaexperiment.h", mkzexperiment},
+
+	// not generated anymore, but delete the file if we see it
+	{"enam.c", nil},
 };
 
 // install installs the library, package, or binary associated with dir,
@@ -609,11 +638,11 @@ static void
 install(char *dir)
 {
 	char *name, *p, *elem, *prefix, *exe;
-	bool islib, ispkg, isgo, stale;
+	bool islib, ispkg, isgo, stale, ispackcmd;
 	Buf b, b1, path;
 	Vec compile, files, link, go, missing, clean, lib, extra;
 	Time ttarg, t;
-	int i, j, k, n, doclean, targ, usecpp;
+	int i, j, k, n, doclean, targ;
 
 	if(vflag) {
 		if(!streq(goos, gohostos) || !streq(goarch, gohostarch))
@@ -646,30 +675,33 @@ install(char *dir)
 		goto out;
 	}
 
-	// For release, cmd/prof is not included.
-	if((streq(dir, "cmd/prof")) && !isdir(bstr(&path))) {
-		if(vflag > 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<nelem(proto_gccargs); i++)
 			vadd(&gccargs, proto_gccargs[i]);
+		if(defaultcflags[0] == '\0') {
+			for(i=0; i<nelem(proto_gccargs2); i++)
+				vadd(&gccargs, proto_gccargs2[i]);
+		}
 		if(contains(gccargs.p[0], "clang")) {
 			// disable ASCII art in clang errors, if possible
 			vadd(&gccargs, "-fno-caret-diagnostics");
 			// clang is too smart about unused command-line arguments
 			vadd(&gccargs, "-Qunused-arguments");
 		}
+		// disable word wrapping in error messages
+		vadd(&gccargs, "-fmessage-length=0");
 		if(streq(gohostos, "darwin")) {
 			// golang.org/issue/5261
 			vadd(&gccargs, "-mmacosx-version-min=10.6");
 		}
 	}
+	if(ldargs.len == 0 && defaultldflags[0] != '\0') {
+		bprintf(&b, "%s", defaultldflags);
+		splitfields(&ldargs, bstr(&b));
+	}
 
 	islib = hasprefix(dir, "lib") || streq(dir, "cmd/cc") || streq(dir, "cmd/gc");
 	ispkg = hasprefix(dir, "pkg");
@@ -681,6 +713,7 @@ install(char *dir)
 
 	// Start final link command line.
 	// Note: code below knows that link.p[targ] is the target.
+	ispackcmd = 0;
 	if(islib) {
 		// C library.
 		vadd(&link, "ar");
@@ -695,8 +728,8 @@ install(char *dir)
 		vadd(&link, bpathf(&b, "%s/pkg/obj/%s_%s/%s%s.a", goroot, gohostos, gohostarch, prefix, name));
 	} else if(ispkg) {
 		// Go library (package).
-		vadd(&link, bpathf(&b, "%s/pack", tooldir));
-		vadd(&link, "grc");
+		ispackcmd = 1;
+		vadd(&link, "pack"); // program name - unused here, but all the other cases record one
 		p = bprintf(&b, "%s/pkg/%s_%s/%s", goroot, goos, goarch, dir+4);
 		*xstrrchr(p, '/') = '\0';
 		xmkdirall(p);
@@ -712,7 +745,7 @@ install(char *dir)
 		targ = link.len;
 		vadd(&link, bpathf(&b, "%s/%s%s", tooldir, elem, exe));
 	} else {
-		// C command. Use gccargs.
+		// C command. Use gccargs and ldargs.
 		if(streq(gohostos, "plan9")) {
 			vadd(&link, bprintf(&b, "%sl", gohostchar));
 			vadd(&link, "-o");
@@ -720,6 +753,7 @@ install(char *dir)
 			vadd(&link, bpathf(&b, "%s/%s", tooldir, name));
 		} else {
 			vcopy(&link, gccargs.p, gccargs.len);
+			vcopy(&link, ldargs.p, ldargs.len);
 			if(sflag)
 				vadd(&link, "-static");
 			vadd(&link, "-o");
@@ -754,17 +788,18 @@ install(char *dir)
 	files.len = n;
 
 	for(i=0; i<nelem(deptab); i++) {
-		if(hasprefix(dir, deptab[i].prefix)) {
+		if(streq(dir, deptab[i].prefix) ||
+		   (hassuffix(deptab[i].prefix, "/") && hasprefix(dir, deptab[i].prefix))) {
 			for(j=0; (p=deptab[i].dep[j])!=nil; j++) {
 				breset(&b1);
 				bwritestr(&b1, p);
 				bsubst(&b1, "$GOROOT", goroot);
 				bsubst(&b1, "$GOOS", goos);
 				bsubst(&b1, "$GOARCH", goarch);
+				bsubst(&b1, "$GOHOSTOS", gohostos);
+				bsubst(&b1, "$GOHOSTARCH", gohostarch);
 				p = bstr(&b1);
 				if(hassuffix(p, ".a")) {
-					if(streq(gohostos, "plan9") && hassuffix(p, "libbio.a"))
-						continue;
 					vadd(&lib, bpathf(&b, "%s", p));
 					continue;
 				}
@@ -865,6 +900,8 @@ install(char *dir)
 		p = files.p[i];
 		elem = lastelem(p);
 		for(j=0; j<nelem(gentab); j++) {
+			if(gentab[j].gen == nil)
+				continue;
 			if(hasprefix(elem, gentab[j].nameprefix)) {
 				if(vflag > 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<files.len; i++) {
-			p = files.p[i];
-			if(hassuffix(p, "y.tab.c") || hassuffix(p, "y.tab.h")){
-				usecpp = 1;
-				break;
-			}
-		}
-	}
-
 	// Compile the files.
 	for(i=0; i<files.len; i++) {
 		if(!hassuffix(files.p[i], ".c") && !hassuffix(files.p[i], ".s"))
@@ -941,13 +964,12 @@ install(char *dir)
 			// C library or tool.
 			if(streq(gohostos, "plan9")) {
 				vadd(&compile, bprintf(&b, "%sc", gohostchar));
-				vadd(&compile, "-FTVw");
-				if(usecpp)
-					vadd(&compile, "-Bp+");
+				vadd(&compile, "-FTVwp");
+				vadd(&compile, "-DPLAN9");
+				vadd(&compile, "-D__STDC__=1");
+				vadd(&compile, "-D__SIZE_TYPE__=ulong"); // for GNU Bison
 				vadd(&compile, bpathf(&b, "-I%s/include/plan9", goroot));
 				vadd(&compile, bpathf(&b, "-I%s/include/plan9/%s", goroot, gohostarch));
-				// Work around Plan 9 C compiler's handling of #include with .. path.
-				vadd(&compile, bpathf(&b, "-I%s/src/cmd/ld", goroot));
 			} else {
 				vcopy(&compile, gccargs.p, gccargs.len);
 				vadd(&compile, "-c");
@@ -955,13 +977,15 @@ install(char *dir)
 					vadd(&compile, "-m64");
 				else if(streq(gohostarch, "386"))
 					vadd(&compile, "-m32");
-				if(streq(dir, "lib9"))
-					vadd(&compile, "-DPLAN9PORT");
 	
 				vadd(&compile, "-I");
 				vadd(&compile, bpathf(&b, "%s/include", goroot));
 			}
 
+			if(streq(dir, "lib9"))
+				vadd(&compile, "-DPLAN9PORT");
+
+
 			vadd(&compile, "-I");
 			vadd(&compile, bstr(&path));
 
@@ -1048,11 +1072,13 @@ install(char *dir)
 		vreset(&compile);
 		vadd(&compile, bpathf(&b, "%s/%sg", tooldir, gochar));
 
-		bpathf(&b, "%s/_go_.%s", workdir, gochar);
+		bpathf(&b, "%s/_go_.a", workdir);
+		vadd(&compile, "-pack");
 		vadd(&compile, "-o");
 		vadd(&compile, bstr(&b));
 		vadd(&clean, bstr(&b));
-		vadd(&link, bstr(&b));
+		if(!ispackcmd)
+			vadd(&link, bstr(&b));
 
 		vadd(&compile, "-p");
 		if(hasprefix(dir, "pkg/"))
@@ -1066,6 +1092,12 @@ install(char *dir)
 		vcopy(&compile, go.p, go.len);
 
 		runv(nil, bstr(&path), CheckExit, &compile);
+
+		if(ispackcmd) {
+			xremove(link.p[targ]);
+			dopack(link.p[targ], bstr(&b), &link.p[targ+1], link.len - (targ+1));
+			goto nobuild;
+		}
 	}
 
 	if(!islib && !isgo) {
@@ -1138,21 +1170,6 @@ shouldbuild(char *file, char *dir)
 	int i, j, ret;
 	Buf b;
 	Vec lines, fields;
-
-	// On Plan 9, most of the libraries are already present.
-	// The main exception is libmach which has been modified
-	// in various places to support Go object files.
-	if(streq(gohostos, "plan9")) {
-		if(streq(dir, "lib9")) {
-			name = lastelem(file);
-			if(streq(name, "goos.c") || streq(name, "flag.c"))
-				return 1;
-			if(!contains(name, "plan9"))
-				return 0;
-		}
-		if(streq(dir, "libbio"))
-			return 0;
-	}
 	
 	// Check file name for GOOS or GOARCH.
 	name = lastelem(file);
@@ -1238,20 +1255,56 @@ copy(char *dst, char *src, int exec)
 	bfree(&b);
 }
 
+// dopack copies the package src to dst,
+// appending the files listed in extra.
+// The archive format is the traditional Unix ar format.
+static void
+dopack(char *dst, char *src, char **extra, int nextra)
+{
+	int i;
+	char c, *p, *q;
+	Buf b, bdst;
+	
+	binit(&b);
+	binit(&bdst);
+
+	readfile(&bdst, src);
+	for(i=0; i<nextra; i++) {
+		readfile(&b, extra[i]);
+		// find last path element for archive member name
+		p = xstrrchr(extra[i], '/');
+		if(p)
+			p++;
+		q = xstrrchr(extra[i], '\\');
+		if(q) {
+			q++;
+			if(p == nil || q > 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; i<nelem(cleantab); i++) {
-		if((streq(cleantab[i], "cmd/prof")) && !isdir(cleantab[i]))
-			continue;
 		bpathf(&path, "%s/src/%s", goroot, cleantab[i]);
 		xreaddir(&dir, bstr(&path));
 		// Remove generated files.
@@ -1488,6 +1534,7 @@ cmdenv(int argc, char **argv)
 		usage();
 
 	xprintf(format, "CC", defaultcc);
+	xprintf(format, "CC_FOR_TARGET", defaultcctarget);
 	xprintf(format, "GOROOT", goroot);
 	xprintf(format, "GOBIN", gobin);
 	xprintf(format, "GOARCH", goarch);
diff --git a/src/cmd/dist/buildgc.c b/src/cmd/dist/buildgc.c
index 03a797f..1f0625d 100644
--- a/src/cmd/dist/buildgc.c
+++ b/src/cmd/dist/buildgc.c
@@ -63,10 +63,10 @@ gcopnames(char *dir, char *file)
 	vfree(&fields);
 }
 
-// mkenam reads [568].out.h and writes enam.c
+// mkanames reads [568].out.h and writes anames[568].c
 // The format is much the same as the Go opcodes above.
 void
-mkenam(char *dir, char *file)
+mkanames(char *dir, char *file)
 {
 	int i, ch;
 	Buf in, b, out;
@@ -78,11 +78,11 @@ mkenam(char *dir, char *file)
 	binit(&out);
 	vinit(&lines);
 
-	ch = dir[xstrlen(dir)-2];
-	bprintf(&b, "%s/../%cl/%c.out.h", dir, ch, ch);
+	ch = file[xstrlen(file)-3];
+	bprintf(&b, "%s/../cmd/%cl/%c.out.h", dir, ch, ch);
 	readfile(&in, bstr(&b));
 	splitlines(&lines, bstr(&in));
-	bwritestr(&out, "char*	anames[] = {\n");
+	bprintf(&out, "char*	anames%c[] = {\n", ch);
 	for(i=0; i<lines.len; i++) {
 		if(hasprefix(lines.p[i], "\tA")) {
 			p = xstrstr(lines.p[i], ",");
diff --git a/src/cmd/dist/buildgo.c b/src/cmd/dist/buildgo.c
index a340252..41208fa 100644
--- a/src/cmd/dist/buildgo.c
+++ b/src/cmd/dist/buildgo.c
@@ -31,7 +31,7 @@ mkzdefaultcc(char *dir, char *file)
 		"\n"
 		"const defaultCC = `%s`\n"
 		"const defaultCXX = `%s`\n",
-		defaultcc, defaultcxx);
+		defaultcctarget, defaultcxxtarget);
 
 	writefile(&out, file, 0);
 
diff --git a/src/cmd/dist/buildruntime.c b/src/cmd/dist/buildruntime.c
index e6e309d..ba5993b 100644
--- a/src/cmd/dist/buildruntime.c
+++ b/src/cmd/dist/buildruntime.c
@@ -127,83 +127,22 @@ static struct {
 	char *goos;
 	char *hdr;
 } zasmhdr[] = {
-	{"386", "windows",
-		"#define	get_tls(r)	MOVL 0x14(FS), r\n"
-		"#define	g(r)	0(r)\n"
-		"#define	m(r)	4(r)\n"
-	},
-	{"386", "plan9",
-		"// Plan 9 does not have per-process segment descriptors with\n"
-		"// which to do thread-local storage. Instead, we will use a\n"
-		"// fixed offset from the per-process TOS struct address for\n"
-		"// the local storage. Since the process ID is contained in the\n"
-		"// TOS struct, we specify an offset for that here as well.\n"
-		"#define	get_tls(r)	MOVL _tos(SB), r \n"
-		"#define	g(r)	-8(r)\n"
-		"#define	m(r)	-4(r)\n"
-		"#define	procid(r)	48(r)\n"
-	},
-	{"386", "linux",
-		"// On Linux systems, what we call 0(GS) and 4(GS) for g and m\n"
-		"// turn into %gs:-8 and %gs:-4 (using gcc syntax to denote\n"
-		"// what the machine sees as opposed to 8l input).\n"
-		"// 8l rewrites 0(GS) and 4(GS) into these.\n"
-		"//\n"
-		"// On Linux Xen, it is not allowed to use %gs:-8 and %gs:-4\n"
-		"// directly.  Instead, we have to store %gs:0 into a temporary\n"
-		"// register and then use -8(%reg) and -4(%reg).  This kind\n"
-		"// of addressing is correct even when not running Xen.\n"
-		"//\n"
-		"// 8l can rewrite MOVL 0(GS), CX into the appropriate pair\n"
-		"// of mov instructions, using CX as the intermediate register\n"
-		"// (safe because CX is about to be written to anyway).\n"
-		"// But 8l cannot handle other instructions, like storing into 0(GS),\n"
-		"// which is where these macros come into play.\n"
-		"// get_tls sets up the temporary and then g and r use it.\n"
-		"//\n"
-		"// Another wrinkle is that get_tls needs to read from %gs:0,\n"
-		"// but in 8l input it's called 8(GS), because 8l is going to\n"
-		"// subtract 8 from all the offsets, as described above.\n"
-		"//\n"
-		"// The final wrinkle is that when generating an ELF .o file for\n"
-		"// external linking mode, we need to be able to relocate the\n"
-		"// -8(r) and -4(r) instructions. Tag them with an extra (GS*1)\n"
-		"// that is ignored by the linker except for that identification.\n"
-		"#define	get_tls(r)	MOVL 8(GS), r\n"
-		"#define	g(r)	-8(r)(GS*1)\n"
-		"#define	m(r)	-4(r)(GS*1)\n"
-	},
 	{"386", "",
-		"#define	get_tls(r)\n"
-		"#define	g(r)	0(GS)\n"
-		"#define	m(r)	4(GS)\n"
-	},
-	
-	{"amd64", "windows",
-		"#define	get_tls(r) MOVQ 0x28(GS), r\n"
-		"#define	g(r) 0(r)\n"
-		"#define	m(r) 8(r)\n"
+		"#define	get_tls(r)	MOVL TLS, r\n"
+		"#define	g(r)	0(r)(TLS*1)\n"
+		"#define	m(r)	4(r)(TLS*1)\n"
 	},
-	{"amd64", "plan9",
-		"#define	get_tls(r)\n"
-		"#define	g(r) 0(GS)\n"
-		"#define	m(r) 8(GS)\n"
-		"#define	procid(r) 16(GS)\n"
-	},
-	// The TLS accessors here are defined here to use initial exec model.
-	// If the linker is not outputting a shared library, it will reduce
-	// the TLS accessors to the local exec model, effectively removing
-	// get_tls().
-	{"amd64", "linux",
-		"#define	get_tls(r) MOVQ runtime·tlsgm(SB), r\n"
-		"#define	g(r) 0(r)(GS*1)\n"
-		"#define	m(r) 8(r)(GS*1)\n"
+	{"amd64p32", "",
+		"#define	get_tls(r)	MOVL TLS, r\n"
+		"#define	g(r)	0(r)(TLS*1)\n"
+		"#define	m(r)	4(r)(TLS*1)\n"
 	},
 	{"amd64", "",
-		"#define get_tls(r)\n"
-		"#define g(r) 0(GS)\n"
-		"#define m(r) 8(GS)\n"
+		"#define	get_tls(r)	MOVQ TLS, r\n"
+		"#define	g(r)	0(r)(TLS*1)\n"
+		"#define	m(r)	8(r)(TLS*1)\n"
 	},	
+
 	{"arm", "",
 	"#define	LR	R14\n"
 	},
@@ -243,7 +182,8 @@ mkzasm(char *dir, char *file)
 ok:
 
 	// Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -a -n -o workdir/proc.acid proc.c
-	// to get acid [sic] output.
+	// to get acid [sic] output. Run once without the -a -o workdir/proc.acid in order to
+	// report compilation failures (the -o redirects all messages, unfortunately).
 	vreset(&argv);
 	vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar));
 	vadd(&argv, "-D");
@@ -252,8 +192,8 @@ ok:
 	vadd(&argv, bprintf(&b, "GOARCH_%s", goarch));
 	vadd(&argv, "-I");
 	vadd(&argv, bprintf(&b, "%s", workdir));
-	vadd(&argv, "-a");
 	vadd(&argv, "-n");
+	vadd(&argv, "-a");
 	vadd(&argv, "-o");
 	vadd(&argv, bpathf(&b, "%s/proc.acid", workdir));
 	vadd(&argv, "proc.c");
@@ -284,8 +224,8 @@ ok:
 				aggr = "p";
 			else if(streq(fields.p[1], "Gobuf"))
 				aggr = "gobuf";
-			else if(streq(fields.p[1], "WinCall"))
-				aggr = "wincall";
+			else if(streq(fields.p[1], "LibCall"))
+				aggr = "libcall";
 			else if(streq(fields.p[1], "WinCallbackContext"))
 				aggr = "cbctxt";
 			else if(streq(fields.p[1], "SEH"))
@@ -329,7 +269,7 @@ ok:
 	vfree(&fields);
 }
 
-// mkzsys writes zsys_$GOOS_$GOARCH.h,
+// mkzsys writes zsys_$GOOS_$GOARCH.s,
 // which contains arch or os specific asm code.
 // 
 void
@@ -365,10 +305,8 @@ mkzsys(char *dir, char *file)
 }
 
 static char *runtimedefs[] = {
+	"defs.c",
 	"proc.c",
-	"iface.c",
-	"hashmap.c",
-	"chan.c",
 	"parfor.c",
 };
 
diff --git a/src/cmd/dist/goc2c.c b/src/cmd/dist/goc2c.c
index f0fa043..3862765 100644
--- a/src/cmd/dist/goc2c.c
+++ b/src/cmd/dist/goc2c.c
@@ -85,11 +85,15 @@ enum {
 	String,
 	Slice,
 	Eface,
+	Complex128,
+	Float32,
+	Float64,
 };
 
 static struct {
 	char *name;
 	int size;
+	int rnd; // alignment
 } type_table[] = {
 	/* 
 	 * variable sized first, for easy replacement.
@@ -105,6 +109,7 @@ static struct {
 	{"String",	8},
 	{"Slice",	12},
 	{"Eface",	8},
+	{"Complex128", 16},
 
 	/* fixed size */
 	{"float32",	4},
@@ -130,7 +135,7 @@ int structround = 4;
 static void
 bad_eof(void)
 {
-	fatal("%s:%ud: unexpected EOF\n", file, lineno);
+	fatal("%s:%d: unexpected EOF\n", file, lineno);
 }
 
 /* Free a list of parameters.  */
@@ -295,9 +300,9 @@ read_package(void)
 
 	token = read_token_no_eof();
 	if (token == nil)
-		fatal("%s:%ud: no token\n", file, lineno);
+		fatal("%s:%d: no token\n", file, lineno);
 	if (!streq(token, "package")) {
-		fatal("%s:%ud: expected \"package\", got \"%s\"\n",
+		fatal("%s:%d: expected \"package\", got \"%s\"\n",
 			file, lineno, token);
 	}
 	return read_token_no_eof();
@@ -307,6 +312,9 @@ read_package(void)
 static void
 read_preprocessor_lines(void)
 {
+	int first;
+	
+	first = 1;
 	while (1) {
 		int c;
 
@@ -317,6 +325,10 @@ read_preprocessor_lines(void)
 			xungetc();
 			break;
 		}
+		if(first) {
+			first = 0;
+			xputchar('\n');
+		}
 		xputchar(c);
 		do {
 			c = getchar_update_lineno();
@@ -365,17 +377,24 @@ read_type(void)
 
 /* Return the size of the given type. */
 static int
-type_size(char *p)
+type_size(char *p, int *rnd)
 {
 	int i;
 
-	if(p[xstrlen(p)-1] == '*')
+	if(p[xstrlen(p)-1] == '*') {
+		*rnd = type_table[Uintptr].rnd;
 		return type_table[Uintptr].size;
+	}
+
+	if(streq(p, "Iface"))
+		p = "Eface";
 
 	for(i=0; type_table[i].name; i++)
-		if(streq(type_table[i].name, p))
+		if(streq(type_table[i].name, p)) {
+			*rnd = type_table[i].rnd;
 			return type_table[i].size;
-	fatal("%s:%ud: unknown type %s\n", file, lineno, p);
+		}
+	fatal("%s:%d: unknown type %s\n", file, lineno, p);
 	return 0;
 }
 
@@ -398,18 +417,22 @@ read_params(int *poffset)
 		while (1) {
 			p = xmalloc(sizeof(struct params));
 			p->name = 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<nelem(type_table); i++)
+			type_table[i].rnd = type_table[i].size;
+
+		type_table[String].rnd = type_table[Uintptr].rnd;
+		type_table[Slice].rnd = type_table[Uintptr].rnd;
+		type_table[Eface].rnd = type_table[Uintptr].rnd;
+		type_table[Complex128].rnd = type_table[Float64].rnd;
 	}
 
 	bprintf(&out, "// auto generated by go tool dist\n// goos=%s goarch=%s\n\n", goos, goarch);
diff --git a/src/cmd/dist/unix.c b/src/cmd/dist/unix.c
index fa388e0..8b943a2 100644
--- a/src/cmd/dist/unix.c
+++ b/src/cmd/dist/unix.c
@@ -24,6 +24,7 @@
 #include <errno.h>
 #include <stdarg.h>
 #include <setjmp.h>
+#include <signal.h>
 
 // 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 7d03989..2839c4b 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 8e9677e..b809640 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 0000000..5e53c1f
--- /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 <u.h>
+#include <libc.h>
+#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 c0fd4d8..2e79f6f 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 309dc1e..5ca5aeb 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 92834a9..2efbbc5 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 5a84dfb..ad4e5bd 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 cfb1f0a..143c173 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 c7d13ef..73c2581 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 7919677..03df93a 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 b84b66e..78624d7 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 31bcdf8..da5984c 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 9cd3448..b5f8a83 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, "<unknown line number>");
-
-	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, "<S>");
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
index ada16ea..cf630f3 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 562f168..413e710 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	<bio.h>
+#include	<link.h>
 
 #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<<EscBits) - 1,
+	EscContentEscapes = 1<<EscBits, // value obtained by indirect of parameter escapes to some returned result
+	EscReturnBits = EscBits+1,
 };
 
 struct	Node
@@ -277,6 +285,7 @@ struct	Node
 	schar	likely; // likeliness of if statement
 	uchar	hasbreak;	// has break statement
 	uchar	needzero; // if it contains pointers, needs to be zeroed on function entry
+	uchar	needctxt;	// function uses context register (has closure variables)
 	uint	esc;		// EscXXX
 	int	funcdepth;
 
@@ -392,6 +401,7 @@ struct	Sym
 	int32	block;		// blocknumber to catch redeclaration
 	int32	lastlineno;	// last declaration for diagnostic
 	Pkg*	origpkg;	// original package for . import
+	LSym*	lsym;
 };
 #define	S	((Sym*)0)
 
@@ -420,16 +430,6 @@ struct	Iter
 	Node*	n;
 };
 
-typedef	struct	Hist	Hist;
-struct	Hist
-{
-	Hist*	link;
-	char*	name;
-	int32	line;
-	int32	offset;
-};
-#define	H	((Hist*)0)
-
 // Node ops.
 enum
 {
@@ -447,11 +447,13 @@ enum
 	OSUB,	// x - y
 	OOR,	// x | y
 	OXOR,	// x ^ y
+	OADDPTR,	// ptr + uintptr, inserted by compiler only, used to avoid unsafe type changes during codegen
 	OADDSTR,	// s + "foo"
 	OADDR,	// &x
 	OANDAND,	// b0 && b1
 	OAPPEND,	// append
 	OARRAYBYTESTR,	// string(bytes)
+	OARRAYBYTESTRTMP, // string(bytes) ephemeral
 	OARRAYRUNESTR,	// string(runes)
 	OSTRARRAYBYTE,	// []byte(s)
 	OSTRARRAYRUNE,	// []rune(s)
@@ -506,7 +508,7 @@ enum
 	OKEY,	// The x:3 in t{x:3, y:4}, the 1:2 in a[1:2], the 2:20 in [3]int{2:20}, etc.
 	OPARAM,	// The on-stack copy of a parameter or return value that escapes.
 	OLEN,	// len
-	OMAKE,	// make, typechecking may convert to a more specfic OMAKEXXX.
+	OMAKE,	// make, typechecking may convert to a more specific OMAKEXXX.
 	OMAKECHAN,	// make(chan int)
 	OMAKEMAP,	// make(map[string]int)
 	OMAKESLICE,	// make([]int, 0)
@@ -528,7 +530,7 @@ enum
 	OPRINTN,	// println
 	OPAREN,	// (x)
 	OSEND,	// c <- x
-	OSLICE,	// v[1:2], typechecking may convert to a more specfic OSLICEXXX.
+	OSLICE,	// v[1:2], typechecking may convert to a more specific OSLICEXXX.
 	OSLICEARR,	// a[1:2]
 	OSLICESTR,	// s[1:2]
 	OSLICE3,	// v[1:2:3], typechecking may convert to OSLICE3ARR.
@@ -583,6 +585,7 @@ enum
 	OCLOSUREVAR, // variable reference at beginning of closure function
 	OCFUNC,	// reference to c function pointer (not go func value)
 	OCHECKNIL, // emit code to ensure pointer/interface not nil
+	OVARKILL, // variable is dead
 
 	// arch-specific registers
 	OREGISTER,	// a register, such as AX.
@@ -724,6 +727,7 @@ struct	Var
 {
 	vlong	offset;
 	Node*	node;
+	Var*	nextinnode;
 	int	width;
 	char	name;
 	char	etype;
@@ -804,9 +808,6 @@ struct	Magic
 	int	ua;	// output - adder
 };
 
-typedef struct	Prog Prog;
-#pragma incomplete Prog
-
 struct	Label
 {
 	uchar	used;
@@ -859,9 +860,6 @@ EXTERN	Io	pushedio;
 EXTERN	int32	lexlineno;
 EXTERN	int32	lineno;
 EXTERN	int32	prevlineno;
-EXTERN	char*	pathname;
-EXTERN	Hist*	hist;
-EXTERN	Hist*	ehist;
 
 EXTERN	char*	infile;
 EXTERN	char*	outfile;
@@ -870,6 +868,7 @@ EXTERN	int	nerrors;
 EXTERN	int	nsavederrors;
 EXTERN	int	nsyntaxerrors;
 EXTERN	int	safemode;
+EXTERN	int	nolocalimports;
 EXTERN	char	namebuf[NSYMB];
 EXTERN	char	lexbuf[NSYMB];
 EXTERN	char	litbuf[NSYMB];
@@ -950,7 +949,6 @@ EXTERN	Node*	lasttype;
 EXTERN	vlong	maxarg;
 EXTERN	vlong	stksize;		// stack size for current frame
 EXTERN	vlong	stkptrsize;		// prefix of stack containing pointers
-EXTERN	vlong	stkzerosize;		// prefix of stack that must be zeroed on entry
 EXTERN	int32	blockgen;		// max block number
 EXTERN	int32	block;			// current block number
 EXTERN	int	hasdefer;		// flag that curfn has defer statetment
@@ -959,12 +957,14 @@ EXTERN	Node*	curfn;
 
 EXTERN	int	widthptr;
 EXTERN	int	widthint;
+EXTERN	int	widthreg;
 
 EXTERN	Node*	typesw;
 EXTERN	Node*	nblank;
 
 extern	int	thechar;
 extern	char*	thestring;
+extern	LinkArch*	thelinkarch;
 EXTERN	int  	use_sse;
 
 EXTERN	char*	hunk;
@@ -980,10 +980,17 @@ EXTERN	char*	flag_installsuffix;
 EXTERN	int	flag_race;
 EXTERN	int	flag_largemodel;
 EXTERN	int	noescape;
+EXTERN	int	debuglive;
+EXTERN	Link*	ctxt;
 
 EXTERN	int	nointerface;
 EXTERN	int	fieldtrack_enabled;
 EXTERN	int	precisestack_enabled;
+EXTERN	int	writearchive;
+
+EXTERN	Biobuf	bstdout;
+
+EXTERN	int	nacl;
 
 /*
  *	y.tab.c
@@ -1002,6 +1009,18 @@ vlong	rnd(vlong o, vlong r);
 void	typeinit(void);
 
 /*
+ *	array.c
+ */
+Array*	arraynew(int32 capacity, int32 size);
+void	arrayfree(Array *array);
+int32	arraylength(Array *array);
+void*	arrayget(Array *array, int32 index);
+void	arrayset(Array *array, int32 index, void *element);
+void	arrayadd(Array *array, void *element);
+int32	arrayindexof(Array* array, void *element);
+void	arraysort(Array* array, int (*cmp)(const void*, const void*));
+
+/*
  *	bits.c
  */
 int	Qconv(Fmt *fp);
@@ -1019,11 +1038,19 @@ int	bset(Bits a, uint n);
  *	bv.c
  */
 Bvec*	bvalloc(int32 n);
-void	bvset(Bvec *bv, int32 i);
-void	bvres(Bvec *bv, int32 i);
+void	bvandnot(Bvec *dst, Bvec *src1, Bvec *src2);
+int	bvcmp(Bvec *bv1, Bvec *bv2);
+void	bvcopy(Bvec *dst, Bvec *src);
+Bvec*	bvconcat(Bvec *src1, Bvec *src2);
 int	bvget(Bvec *bv, int32 i);
 int	bvisempty(Bvec *bv);
-int	bvcmp(Bvec *bv1, Bvec *bv2);
+void	bvnot(Bvec *bv);
+void	bvor(Bvec *dst, Bvec *src1, Bvec *src2);
+void	bvand(Bvec *dst, Bvec *src1, Bvec *src2);
+void	bvprint(Bvec *bv);
+void	bvreset(Bvec *bv, int32 i);
+void	bvresetall(Bvec *bv);
+void	bvset(Bvec *bv, int32 i);
 
 /*
  *	closure.c
@@ -1173,7 +1200,6 @@ char*	expstring(void);
 void	mkpackage(char* pkgname);
 void	unimportfile(void);
 int32	yylex(void);
-extern	int	windows;
 extern	int	yylast;
 extern	int	yyprev;
 
@@ -1230,17 +1256,19 @@ void	mpxorfixfix(Mpint *a, Mpint *b);
 void	mpaddfltflt(Mpflt *a, Mpflt *b);
 void	mpdivfltflt(Mpflt *a, Mpflt *b);
 double	mpgetflt(Mpflt *a);
+double	mpgetflt32(Mpflt *a);
 void	mpmovecflt(Mpflt *a, double c);
 void	mpmulfltflt(Mpflt *a, Mpflt *b);
 void	mpnegflt(Mpflt *a);
 void	mpnorm(Mpflt *a);
+void	mpsetexp(Mpflt *a, int exp);
 int	mptestflt(Mpflt *a);
 int	sigfig(Mpflt *a);
 
 /*
  *	obj.c
  */
-void	Bputname(Biobuf *b, Sym *s);
+void	Bputname(Biobuf *b, LSym *s);
 int	duint16(Sym *s, int off, uint16 v);
 int	duint32(Sym *s, int off, uint32 v);
 int	duint64(Sym *s, int off, uint64 v);
@@ -1248,8 +1276,9 @@ int	duint8(Sym *s, int off, uint8 v);
 int	duintptr(Sym *s, int off, uint64 v);
 int	dsname(Sym *s, int off, char *dat, int ndat);
 void	dumpobj(void);
-void	ieeedtod(uint64 *ieee, double native);
 Sym*	stringsym(char*, int);
+void	slicebytes(Node*, char*, int);
+LSym*	linksym(Sym*);
 
 /*
  *	order.c
@@ -1274,6 +1303,7 @@ Sym*	tracksym(Type *t);
 Sym*	typesymprefix(char *prefix, Type *t);
 int	haspointers(Type *t);
 void	usefield(Node*);
+Type*	hiter(Type* t);
 
 /*
  *	select.c
@@ -1434,32 +1464,21 @@ void	walkstmt(Node **np);
 void	walkstmtlist(NodeList *l);
 Node*	conv(Node*, Type*);
 int	candiscard(Node*);
+Node*	outervalue(Node*);
 
 /*
- *	arch-specific ggen.c/gsubr.c/gobj.c/pgen.c
+ *	arch-specific ggen.c/gsubr.c/gobj.c/pgen.c/plive.c
  */
 #define	P	((Prog*)0)
 
-typedef	struct	Plist	Plist;
-struct	Plist
-{
-	Node*	name;
-	Prog*	firstpc;
-	int	recur;
-	Plist*	link;
-};
-
-EXTERN	Plist*	plist;
-EXTERN	Plist*	plast;
-
 EXTERN	Prog*	continpc;
 EXTERN	Prog*	breakpc;
 EXTERN	Prog*	pc;
 EXTERN	Prog*	firstpc;
-EXTERN	Prog*	retpc;
 
 EXTERN	Node*	nodfp;
 EXTERN	int	disable_checknil;
+EXTERN	vlong	zerosize;
 
 int	anyregalloc(void);
 void	betypeinit(void);
@@ -1474,59 +1493,52 @@ void	cgen_checknil(Node*);
 void	cgen_ret(Node *n);
 void	clearfat(Node *n);
 void	compile(Node*);
-void	defframe(Prog*, Bvec*);
+void	defframe(Prog*);
 int	dgostringptr(Sym*, int off, char *str);
 int	dgostrlitptr(Sym*, int off, Strlit*);
 int	dstringptr(Sym *s, int off, char *str);
 int	dsymptr(Sym *s, int off, Sym *x, int xoff);
 int	duintxx(Sym *s, int off, uint64 v, int wid);
 void	dumpdata(void);
-void	dumpfuncs(void);
 void	fixautoused(Prog*);
 void	gdata(Node*, Node*, int);
 void	gdatacomplex(Node*, Mpcplx*);
 void	gdatastring(Node*, Strlit*);
 void	ggloblnod(Node *nam);
 void	ggloblsym(Sym *s, int32 width, int dupok, int rodata);
+void	gvardef(Node*);
+void	gvarkill(Node*);
 Prog*	gjmp(Prog*);
 void	gused(Node*);
 void	movelarge(NodeList*);
 int	isfat(Type*);
+void	linkarchinit(void);
+void	liveness(Node*, Prog*, Sym*, Sym*);
 void	markautoused(Prog*);
 Plist*	newplist(void);
 Node*	nodarg(Type*, int);
 void	nopout(Prog*);
 void	patch(Prog*, Prog*);
 Prog*	unpatch(Prog*);
-void	zfile(Biobuf *b, char *p, int n);
-void	zhist(Biobuf *b, int line, vlong offset);
-void	zname(Biobuf *b, Sym *s, int t);
 
-#pragma	varargck	type	"A"	int
 #pragma	varargck	type	"B"	Mpint*
-#pragma	varargck	type	"D"	Addr*
-#pragma	varargck	type	"lD"	Addr*
 #pragma	varargck	type	"E"	int
 #pragma	varargck	type	"E"	uint
 #pragma	varargck	type	"F"	Mpflt*
 #pragma	varargck	type	"H"	NodeList*
 #pragma	varargck	type	"J"	Node*
-#pragma	varargck	type	"lL"	int
-#pragma	varargck	type	"lL"	uint
-#pragma	varargck	type	"L"	int
-#pragma	varargck	type	"L"	uint
+#pragma	varargck	type	"lL"	int32
+#pragma	varargck	type	"L"	int32
 #pragma	varargck	type	"N"	Node*
 #pragma	varargck	type	"lN"	Node*
+#pragma	varargck	type	"O"	int
 #pragma	varargck	type	"O"	uint
-#pragma	varargck	type	"P"	Prog*
 #pragma	varargck	type	"Q"	Bits
-#pragma	varargck	type	"R"	int
 #pragma	varargck	type	"S"	Sym*
-#pragma	varargck	type	"lS"	Sym*
+#pragma	varargck	type	"lS"	LSym*
 #pragma	varargck	type	"T"	Type*
 #pragma	varargck	type	"lT"	Type*
 #pragma	varargck	type	"V"	Val*
-#pragma	varargck	type	"Y"	char*
 #pragma	varargck	type	"Z"	Strlit*
 
 /*
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index 5432eca..2f354f7 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -557,6 +557,7 @@ caseblock:
 		// This is so that the stmt_list action doesn't look at
 		// the case tokens if the stmt_list is empty.
 		yylast = yychar;
+		$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 6800884..cf89b00 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 8c73939..a50101c 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<nf; i++)
 		addexp(f[i]);
@@ -165,6 +166,21 @@ fault(int s)
 	fatal("fault");
 }
 
+#ifdef	PLAN9
+void
+catcher(void *v, char *s)
+{
+	USED(v);
+
+	if(strncmp(s, "sys: trap: fault read", 21) == 0) {
+		if(nsavederrors + nerrors > 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, "!<arch>\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 bbd4e29..0051ac9 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 f153e30..5a60106 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 e25044a..1519cae 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 9b2f664..5cf98c6 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<na; i++) {
 		x = *a1++;
 		for(j=0; j<Mpscale; j++) {
-			if(x & 1)
+			if(x & 1) {
+				if(s.ovf) {
+					q.ovf = 1;
+					goto out;
+				}
 				mpaddfixfix(&q, &s, 1);
+				if(q.ovf)
+					goto out;
+			}
 			mplsh(&s, 1);
 			x >>= 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 f8344c9..95618f1 100644
--- a/src/cmd/gc/mparith3.c
+++ b/src/cmd/gc/mparith3.c
@@ -23,6 +23,27 @@ sigfig(Mpflt *a)
 }
 
 /*
+ * 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<<Mpscale) | a->val.a[i];
 		s -= Mpscale;
 	}
-	vm = v;
-	if(s > 0)
-		vm = (vm<<s) | (a->val.a[i]>>(Mpscale-s));
-
-	// continue with 64 more bits
-	s += 64;
-	for(; s>=Mpscale; i--) {
-		v = (v<<Mpscale) | a->val.a[i];
-		s -= Mpscale;
-	}
-	if(s > 0)
+	if(s > 0) {
 		v = (v<<s) | (a->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) - 1);
-		vm >>= 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)-1)) != 0)
+			v |= 1<<s;
+		v >>= 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 4cad089..4eeb03a 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, "!<arch>\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) {
+		m = 8;
+		if(m > 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 7552510..30dbc7d 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	<u.h>
 #include	<libc.h>
 #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 2850af6..40620c3 100644
--- a/src/cmd/gc/pgen.c
+++ b/src/cmd/gc/pgen.c
@@ -8,30 +8,159 @@
 
 #include	<u.h>
 #include	<libc.h>
+#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(&reg, types[tptr], n);
 		cgen(n, &reg);
 		gins(ACHECKNIL, &reg, N);
diff --git a/src/cmd/gc/plive.c b/src/cmd/gc/plive.c
new file mode 100644
index 0000000..eb89017
--- /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 <u.h>
+#include <libc.h>
+#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; j<nmsg; j++)
+				msg[j] = nil;
+		}
+
+		// walk backward, emit pcdata and populate the maps
+		pos = bb->lastbitmapindex;
+		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; j<nmsg; j++) 
+				if(msg[j] != nil)
+					print("%s", msg[j]);
+			free(msg);
+			msg = nil;
+			nmsg = 0;
+			startmsg = 0;
+		}
+	}
+
+	free(livein);
+	free(liveout);
+	free(uevar);
+	free(varkill);
+	free(avarinit);
+	free(any);
+	free(all);
+	free(ambig);
+	
+	flusherrors();
+}
+
+// FNV-1 hash function constants.
+#define H0 2166136261UL
+#define Hp 16777619UL
+
+static uint32
+hashbitmap(uint32 h, Bvec *bv)
+{
+	uchar *p, *ep;
+	
+	p = (uchar*)bv->b;
+	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; i<n; i++) {
+		local = *(Bvec**)arrayget(lv->livepointers, 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; j<n; j++) {
+		*(Bvec**)arrayget(lv->livepointers, 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; i<arraylength(vars); i++) {
+		if(!bvget(bits, i))
+			continue;
+		if(!started) {
+			if(!printed)
+				print("\t");
+			else
+				print(" ");
+			started = 1;
+			printed = 1;
+			print("%s=", name);
+		} else {
+			print(",");
+		}
+		n = *(Node**)arrayget(vars, i);
+		print("%s", n->sym->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 8d7afa0..ea88b94 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; i<nvar; i++) {
 		v = bystart[i];
-		if(v->addr || 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; j<nvar; j++) {
 			v1 = inuse[j];
-			if(eqtype(t, v1->node->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; v<var+nvar; v++) {
-			print("var %#N %T %d-%d", v->node, 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 d6a5b3c..285bd78 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 bd271da..45aa521 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 0a8aa8d..dbb447e 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 c8d57ab..fb5c2a1 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 cd3de8c..58a1206 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 446b111..59804cd 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 bea90b8..72a9ac2 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("<autogenerated>", 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 d6aa021..ce01905 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 31a2f2c..c50b228 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<<k.
-	defaultlit(&n, types[TINT]);
 
-	if(!isint[n->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<<k.
+	defaultlit(&n, types[TINT]);
+
 	return 0;
 }
 
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 66409d5..1cb2551 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -21,7 +21,7 @@ static	NodeList*	reorder3(NodeList*);
 static	Node*	addstr(Node*, NodeList**);
 static	Node*	appendslice(Node*, NodeList**);
 static	Node*	append(Node*, NodeList**);
-static	Node*	copyany(Node*, NodeList**);
+static	Node*	copyany(Node*, NodeList**, int);
 static	Node*	sliceany(Node*, NodeList**);
 static	void	walkcompare(Node**, NodeList**);
 static	void	walkrotate(Node**);
@@ -163,7 +163,6 @@ walkstmt(Node **np)
 	case OCALLFUNC:
 	case ODELETE:
 	case OSEND:
-	case ORECV:
 	case OPRINT:
 	case OPRINTN:
 	case OPANIC:
@@ -179,6 +178,21 @@ walkstmt(Node **np)
 			n->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; i<count; i++)
-		in = list(in, nod(ODCLFIELD, N, typstr));
-	cat->ntype->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 390ad80..08d8ecf 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 <http://www.gnu.org/licenses/>.  */
+   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 <u.h>
-#include <stdio.h>	/* if we don't, bison will, and go.h re-#defines getc */
-#include <libc.h>
-#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 <u.h>
+#include <stdio.h>	/* if we don't, bison will, and go.h re-#defines getc */
+#include <libc.h>
+#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 <stdlib.h> /* 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 <stdlib.h> /* 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
-       <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
-       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 6eeb831..d01fbe1 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 <http://www.gnu.org/licenses/>.  */
+   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 f70f778..3645f1c 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 16687f7..16054a5 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 0000000..68e5182
--- /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 75228b5..b9f4279 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 ebb2f37..9840804 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 2db8217..26d37df 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 e61da7e..e708fcf 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 71e5517..40da7e1 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 f56ebed..0ead435 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 df0cf1b..5b1194a 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 71f14c7..d45df26 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 0000000..06b9f0a
--- /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
+}{
+	{
+		`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
+		[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
+	},
+	{
+		`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
+		<meta name="go-import" content="baz/quux git http://github.com/rsc/baz/quux">`,
+		[]metaImport{
+			{"foo/bar", "git", "https://github.com/rsc/foo/bar"},
+			{"baz/quux", "git", "http://github.com/rsc/baz/quux"},
+		},
+	},
+	{
+		`<head>
+		<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
+		</head>`,
+		[]metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}},
+	},
+	{
+		`<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
+		<body>`,
+		[]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 e6dadd2..ef8aa95 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 00c7165..e86cd46 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 f71d678..0060ce2 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 <<EOF
 package p
 import (
-	_ "math/rand"
-	_ "math/Rand"
+	_ "example/a/pkg"
+	_ "example/a/Pkg"
 )
 EOF
+cat >$d/src/example/a/pkg/pkg.go <<EOF
+package pkg
+EOF
+cat >$d/src/example/a/Pkg/pkg.go <<EOF
+package pkg
+EOF
 if ./testgo list example/a 2>$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 06ac9d2..5935c98 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, "<lost path to cycle>")
+		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 0000000..a6a3891
--- /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 0000000..a8f057e
--- /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 0000000..0c53ac4
--- /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 0000000..7c42c32
--- /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 0000000..65ab76d
--- /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 0000000..75abb13
--- /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 0000000..7e26cdf
--- /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 0000000..bb0a2f4
--- /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 0000000..9b4b075
--- /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 0000000..dac039e
--- /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 0000000..01f6e83
--- /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 0000000..59cf918
--- /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/src/syntaxerror/x.go b/src/cmd/go/testdata/testonly/p_test.go
similarity index 100%
copy from src/cmd/go/testdata/src/syntaxerror/x.go
copy to src/cmd/go/testdata/testonly/p_test.go
diff --git a/src/cmd/go/testflag.go b/src/cmd/go/testflag.go
index aea81d8..73f311e 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 22d5ebc..8f0bae0 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 94e67fd..8f73ef5 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 861ff93..576cae5 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 75a322a..b9335b8 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 862e9d9..108278b 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 66d2331..fb6c6fc 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 87e9161..2b1905e 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 f90f289..8f8cba9 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 30d7c81..55d0207 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; r<s->r+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 : "<nil>", (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 : "<nil>", (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; r<s->r+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; r<s->r+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; i<siz; i++)
-			s->p[off+i] = p->to.scon[i];
-		break;
-
-	case D_CONST:
-		if(p->to.sym)
-			goto Addr;
-		o = p->to.offset;
-		fl = o;
-		cast = (uchar*)&fl;
-		switch(siz) {
-		default:
-			diag("bad nuxi %d\n%P", siz, p);
-			break;
-		case 1:
-			s->p[off] = cast[inuxi1[0]];
-			break;
-		case 2:
-			for(i=0; i<2; i++)
-				s->p[off+i] = cast[inuxi2[i]];
-			break;
-		case 4:
-			for(i=0; i<4; i++)
-				s->p[off+i] = cast[inuxi4[i]];
-			break;
-		case 8:
-			cast = (uchar*)&o;
-			for(i=0; i<8; i++)
-				s->p[off+i] = cast[inuxi8[i]];
-			break;
-		}
-		break;
-
-	case D_ADDR:
-	case D_SIZE:
-	Addr:
-		r = addrel(s);
-		r->off = off;
-		r->siz = siz;
-		r->sym = p->to.sym;
-		r->type = p->to.type;
-		if(r->type != D_SIZE)
-			r->type = D_ADDR;
-		r->add = p->to.offset;
-		break;
-	}
-}
-
 static void
-blk(Sym *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    <unknown type>\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 ab3f4fb..da48d37 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 2adda25..8135bd5 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 c832bcc..cc77b45 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 "<eof>", 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 "<eof>"
-	for (i = 1; i < histfilesize; i++)
-		free(histfile[i]);
-	histfilesize = 0;
-}
-
-static int
-addhistfile(char *zentry)
-{
-	char *fname;
-
-	if (histfilesize == histfilecap) {
-		histfilecap = 2 * histfilecap + 2;
-		histfile = erealloc(histfile, histfilecap * sizeof(char*));
-	}
-	if (histfilesize == 0)
-		histfile[histfilesize++] = "<eof>";
-
-	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; i<s->pcln->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; i<ctxt->nhistfile; 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 f0df2f9..32db36d 100644
--- a/src/cmd/ld/dwarf.h
+++ b/src/cmd/ld/dwarf.h
@@ -3,12 +3,6 @@
 // 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 6b3638e..0555cf4 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; i<nbucket; i++)
-		adduint32(s, buckets[i]);
+		adduint32(ctxt, s, buckets[i]);
 	for(i = 0; i<nsym; i++)
-		adduint32(s, chain[i]);
+		adduint32(ctxt, s, chain[i]);
 
 	free(chain);
 	free(buckets);
 	
 	// version symbols
-	dynstr = lookup(".dynstr", 0);
-	s = lookup(".gnu.version_r", 0);
+	dynstr = linklookup(ctxt, ".dynstr", 0);
+	s = linklookup(ctxt, ".gnu.version_r", 0);
 	i = 2;
 	nfile = 0;
 	for(l=needlib; l; l=l->next) {
 		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; i<nsym; i++) {
 		if(i == 0)
-			adduint16(s, 0); // first entry - no symbol
+			adduint16(ctxt, s, 0); // first entry - no symbol
 		else if(need[i] == nil)
-			adduint16(s, 1); // global
+			adduint16(ctxt, s, 1); // global
 		else
-			adduint16(s, need[i]->num);
+			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 5b2ff04..e84d996 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 39ffa3d..9c296b7 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; i<s->nr; i++)
 			mark1(s->r[i].sym, s);
+		if(s->pcln) {
+			for(i=0; i<s->pcln->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; i<nelem(markextra); i++)
-		mark(lookup(markextra[i], 0));
+		mark(linklookup(ctxt, markextra[i], 0));
 
 	for(i=0; i<ndynexp; i++)
 		mark(dynexp[i]);
@@ -691,37 +608,29 @@ deadcode(void)
 	markflood();
 	
 	// keep each beginning with 'typelink.' if the symbol it points at is being kept.
-	for(s = allsym; s != S; s = s->allsym) {
+	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; i<ndynexp; i++)
-		adddynsym(dynexp[i]);
+		adddynsym(ctxt, dynexp[i]);
 }
 
 /* %Z from gc, for quoting import paths */
diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c
index 27041bc..1d7c4c1 100644
--- a/src/cmd/ld/ldelf.c
+++ b/src/cmd/ld/ldelf.c
@@ -258,7 +258,7 @@ struct ElfSect
 	uint64	align;
 	uint64	entsize;
 	uchar	*base;
-	Sym	*sym;
+	LSym	*sym;
 };
 
 struct ElfObj
@@ -301,7 +301,7 @@ struct ElfSym
 	uchar	type;
 	uchar	other;
 	uint16	shndx;
-	Sym*	sym;
+	LSym*	sym;
 };
 
 uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' };
@@ -312,7 +312,7 @@ static int	readsym(ElfObj*, int i, ElfSym*, int);
 static int	reltype(char*, int, uchar*);
 
 int
-valuecmp(Sym *a, Sym *b)
+valuecmp(LSym *a, LSym *b)
 {
 	if(a->value < 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 e0f5405..413deda 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; i<ncmd; i++){
 		ty = e->e32(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 6bcda2c..f6eda90 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 da522dc..da6194e 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	<ar.h>
+#if !(defined(_WIN32) || defined(PLAN9))
+#include	<sys/stat.h>
+#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,165 +146,25 @@ 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(; i<histfrogp; i++) {
-		snprint(comp, sizeof comp, "%s", histfrog[i]->name+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<libraryp; i++)
-		if(strcmp(library[i].pkg, name) == 0)
-			return;
-	
-	// runtime -> runtime.a for search
-	if(p != nil)
-		*p = '.';
-
-	if(search) {
-		// try dot, -L "libdir", and then goroot.
-		for(i=0; i<nlibdir; i++) {
-			snprint(pname, sizeof pname, "%s/%s", libdir[i], name);
-			if(access(pname, AEXIST) >= 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<libraryp; i++)
-		if(strcmp(file, library[i].file) == 0)
-			return;
-
-	if(debug['v'] > 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)
 {
 	char pname[1024];
 	int i, found;
 
 	found = 0;
-	for(i=0; i<nlibdir; i++) {
-		snprint(pname, sizeof pname, "%s/%s.a", libdir[i], name);
+	for(i=0; i<ctxt->nlibdir; 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; i<ctxt->libraryp; 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<libraryp; i++) {
-		if(debug['v'] > 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; i<nhostobj; i++) {
 		h = &hostobj[i];
 		f = Bopen(h->file, 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; i<argc; i++) {
+				if(strcmp(argv[i], "-rdynamic") == 0)
+					argv[i] = "-static";
+			}
+		}
+
 		p = strchr(p + 1, ' ');
 	}
 
@@ -798,7 +692,7 @@ hostlink(void)
 	}
 
 	if(runcmd(argv) < 0) {
-		cursym = S;
+		ctxt->cursym = 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; i<histfrogp; i++) {
-		p = seprint(p, ep, "%s", histfrog[i]->name+1);
-		if(i+1<histfrogp && (p == buf || p[-1] != '/'))
-			p = seprint(p, ep, "/");
-	}
-}
-
-void
-addhist(int32 line, int type)
-{
-	Auto *u;
-	Sym *s;
-	int i, j, k;
-
-	u = mal(sizeof(Auto));
-	s = mal(sizeof(Sym));
-	s->name = 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; i<histfrogp; i++) {
-		k = histfrog[i]->value;
-		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; i<histfrogp; i++)
-		if(strcmp(histfrog[i]->name+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; i<histfrogp; i++)
-		if(strcmp(histfrog[i]->name+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; i<dst->np; 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; i<LOG; i++) {
-		if(i == 0)
-			cnt[i] = 1;
-		else
-			cnt[i] = LOG * cnt[i-1];
-		dwn[i] = 1;
-		lst[i] = P;
-	}
-	i = 0;
-	for(cursym = textp; cursym != nil; cursym = cursym->next) {
-		for(p = cursym->text; p != P; p = p->link) {
-			if(p->link == P) {
-				if(cursym->next)
-					p->forwd = cursym->next->text;
-				break;
-			}
-			i--;
-			if(i < 0)
-				i = LOG-1;
-			p->forwd = P;
-			dwn[i]--;
-			if(dwn[i] <= 0) {
-				dwn[i] = cnt[i];
-				if(lst[i] != P)
-					lst[i]->forwd = p;
-				lst[i] = p;
-			}
-		}
-	}
-}
-
 uint16
 le16(uchar *b)
 {
@@ -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);
@@ -1828,52 +1210,14 @@ stkprint(Chain *ch, int 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, "<nil>");
 	} 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; i<s->nr; 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<npcdata; i++) {
-			if(!(havepc[i/32]>>(i%32))&1) {
-				off = setuint32(ftab, off, 0);
+	for(s = ctxt->textp; s != nil; s = s->next) {
+		for(i=0; i<s->nr; 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 be95bb4..7267c63 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 d135a92..61306bb 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; i<nsortsym; i++) {
 		s = sortsym[i];
-		adduint32(symtab, symstr->size);
+		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 0000000..788b7c7
--- /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 at 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 at 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 0000000..4c2ffa7
--- /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; i<nfiles; i++) {
+		f = files[i];
+		if(f->type != 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; i<pcln->npcdata; 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; i<pcln->nfuncdata; 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 7b9a596..c26cd52 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;
@@ -455,40 +475,97 @@ newPEDWARFSection(char *name, vlong size)
 }
 
 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; i<fh.NumberOfSymbols; i++) {
-		s = rlookup(symlabels[i], 0);
-		strnput(s->name, 8);
-		lputl(datoff(s->value));
-		wputl(textsect);
+	for (i=0; i<ncoffsym; i++) {
+		s = &coffsym[i];
+		if(s->strtbloff == 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; i<nextsymoff; i++)
-		cput(symnames[i]);
+	lputl(strtblnextoff + 4);
+	for (i=0; i<strtblnextoff; i++)
+		cput(strtbl[i]);
 	strnput("", h->SizeOfRawData - 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 7aa9388..03ed8d8 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 0000000..819c379
--- /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 at 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 at 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	<ar.h>
+
+char	*noname		= "<none>";
+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 c9b4657..6d321c0 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 1d62db7..2a76e76 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 3f528d7..0000000
--- 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 0000000..9a067e2
--- /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("!<arch>\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 8e88e2e..b62da47 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 0000000..5aaa194
--- /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 0000000..5e0817d
--- /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 0000000..c60bde5
--- /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 8209424..0000000
--- 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 at 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 at 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 <u.h>
-#include <libc.h>
-#include <ar.h>
-#include <bio.h>
-#include <mach.h>
-
-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<argc; i++){
-		filename = argv[i];
-		bin = Bopen(filename, OREAD);
-		if(bin == 0){
-			error("cannot open %s", filename);
-			continue;
-		}
-		if (isar(bin))
-			doar(bin);
-		else{
-			Bseek(bin, 0, 0);
-			dofile(bin);
-		}
-		Bterm(bin);
-	}
-	exits(errs);
-}
-
-/*
- * read an archive file,
- * processing the symbols for each intermediate file in it.
- */
-void
-doar(Biobuf *bp)
-{
-	int offset, size, obj;
-	char name[SARNAME];
-
-	multifile = 1;
-	for (offset = Boffset(bp);;offset += size) {
-		size = nextar(bp, offset, name);
-		if (size < 0) {
-			error("phase error on ar header %d", offset);
-			return;
-		}
-		if (size == 0)
-			return;
-		if (strcmp(name, symname) == 0)
-			continue;
-		obj = objtype(bp, 0);
-		if (obj < 0) {
-			// perhaps foreign object
-			if(strlen(name) > 2 && strcmp(name+strlen(name)-2, ".o") == 0)
-				return;
-			error("inconsistent file %s in %s",
-					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; i<nelem(skipnames); i++)
-		if(strcmp(skipnames[i], name) == 0)
-			return 1;
-	return 0;
-}
-
-void
-printsyms(Sym **symptr, long nsym)
-{
-	int i, j, wid;
-	Sym *s;
-	char *cp;
-	char path[512];
-
-	qsort(symptr, nsym, sizeof(*symptr), (void*)cmp);
-
-	wid = 0;
-	for (i=0; i<nsym; i++) {
-		s = symptr[i];
-		if (s->value && wid == 0)
-			wid = 8;
-		else if (s->value >= 0x100000000LL && wid == 8)
-			wid = 16;
-	}
-	for (i=0; i<nsym; i++) {
-		s = symptr[i];
-		if (multifile && !hflag)
-			Bprint(&bout, "%s:", filename);
-		if (s->type == '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; j<nsym; j++) {
-				if(!skipsize(symptr[j]->name) && 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 0000000..a403618
--- /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("!<arch>\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 0000000..f4e47a4
--- /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 0000000..52d05e5
--- /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 0000000..006c66e
--- /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 0000000..1b66c26
--- /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 0000000..764a368
--- /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<<n - 1) << deltaShift
+			deltaShift += n
+		}
+		op := f.op + arm_Op(delta)
+
+		// Special case: BKPT encodes with condition but cannot have one.
+		if op&^15 == arm_BKPT_EQ && op != arm_BKPT {
+			continue Search
+		}
+
+		var args arm_Args
+		for j, aop := range f.args {
+			if aop == 0 {
+				break
+			}
+			arg := arm_decodeArg(aop, x)
+			if arg == nil { // cannot decode argument
+				continue Search
+			}
+			args[j] = arg
+		}
+
+		arm_decoderCover[i] = true
+
+		inst = arm_Inst{
+			Op:   op,
+			Args: args,
+			Enc:  x,
+			Len:  4,
+		}
+		priority = f.priority
+		continue Search
+	}
+	if inst.Op != 0 {
+		return inst, nil
+	}
+	return arm_Inst{}, arm_errUnknown
+}
+
+// An instArg describes the encoding of a single argument.
+// In the names used for arguments, _p_ means +, _m_ means -,
+// _pm_ means ± (usually keyed by the U bit).
+// The _W suffix indicates a general addressing mode based on the P and W bits.
+// The _offset and _postindex suffixes force the given addressing mode.
+// The rest should be somewhat self-explanatory, at least given
+// the decodeArg function.
+type arm_instArg uint8
+
+const (
+	_ arm_instArg = iota
+	arm_arg_APSR
+	arm_arg_FPSCR
+	arm_arg_Dn_half
+	arm_arg_R1_0
+	arm_arg_R1_12
+	arm_arg_R2_0
+	arm_arg_R2_12
+	arm_arg_R_0
+	arm_arg_R_12
+	arm_arg_R_12_nzcv
+	arm_arg_R_16
+	arm_arg_R_16_WB
+	arm_arg_R_8
+	arm_arg_R_rotate
+	arm_arg_R_shift_R
+	arm_arg_R_shift_imm
+	arm_arg_SP
+	arm_arg_Sd
+	arm_arg_Sd_Dd
+	arm_arg_Dd_Sd
+	arm_arg_Sm
+	arm_arg_Sm_Dm
+	arm_arg_Sn
+	arm_arg_Sn_Dn
+	arm_arg_const
+	arm_arg_endian
+	arm_arg_fbits
+	arm_arg_fp_0
+	arm_arg_imm24
+	arm_arg_imm5
+	arm_arg_imm5_32
+	arm_arg_imm5_nz
+	arm_arg_imm_12at8_4at0
+	arm_arg_imm_4at16_12at0
+	arm_arg_imm_vfp
+	arm_arg_label24
+	arm_arg_label24H
+	arm_arg_label_m_12
+	arm_arg_label_p_12
+	arm_arg_label_pm_12
+	arm_arg_label_pm_4_4
+	arm_arg_lsb_width
+	arm_arg_mem_R
+	arm_arg_mem_R_pm_R_W
+	arm_arg_mem_R_pm_R_postindex
+	arm_arg_mem_R_pm_R_shift_imm_W
+	arm_arg_mem_R_pm_R_shift_imm_offset
+	arm_arg_mem_R_pm_R_shift_imm_postindex
+	arm_arg_mem_R_pm_imm12_W
+	arm_arg_mem_R_pm_imm12_offset
+	arm_arg_mem_R_pm_imm12_postindex
+	arm_arg_mem_R_pm_imm8_W
+	arm_arg_mem_R_pm_imm8_postindex
+	arm_arg_mem_R_pm_imm8at0_offset
+	arm_arg_option
+	arm_arg_registers
+	arm_arg_registers1
+	arm_arg_registers2
+	arm_arg_satimm4
+	arm_arg_satimm5
+	arm_arg_satimm4m1
+	arm_arg_satimm5m1
+	arm_arg_widthm1
+)
+
+// decodeArg decodes the arg described by aop from the instruction bits x.
+// It returns nil if x cannot be decoded according to aop.
+func arm_decodeArg(aop arm_instArg, x uint32) arm_Arg {
+	switch aop {
+	default:
+		return nil
+
+	case arm_arg_APSR:
+		return arm_APSR
+	case arm_arg_FPSCR:
+		return arm_FPSCR
+
+	case arm_arg_R_0:
+		return arm_Reg(x & (1<<4 - 1))
+	case arm_arg_R_8:
+		return arm_Reg((x >> 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 [<Rn>],+/-<Rm> like [<Rn>,+/-<Rm>{,<shift>}]{!}
+		// 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 [<Rn>,+/-<Rm>]{!} like [<Rn>,+/-<Rm>{,<shift>}]{!}
+		// 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 [<Rn>],+/-<Rm>{,<shift>} like [<Rn>,+/-<Rm>{,<shift>}]{!}
+		// 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 [<Rn>],+/-<Rm>{,<shift>} like [<Rn>,+/-<Rm>{,<shift>}]{!}
+		// 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 [<Rn>,#+/-<imm12>] like [<Rn>{,#+/-<imm12>}]{!}
+		// 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 [<Rn>],#+/-<imm12> like [<Rn>{,#+/-<imm12>}]{!}
+		// 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 [<Rn>],#+/-<imm8> like [<Rn>{,#+/-<imm8>}]{!}
+		// 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<<uint(i)) != 0 {
+				fmt.Fprintf(&buf, "%s%s", sep, arm_gnuArg(inst, -1, arm_Reg(i)))
+				sep = ", "
+			}
+		}
+		fmt.Fprintf(&buf, "}")
+		return buf.String()
+
+	case arm_RegShift:
+		if arg.Shift == arm_ShiftLeft && arg.Count == 0 {
+			return arm_gnuArg(inst, -1, arg.Reg)
+		}
+		if arg.Shift == arm_RotateRightExt {
+			return arm_gnuArg(inst, -1, arg.Reg) + ", rrx"
+		}
+		return fmt.Sprintf("%s, %s #%d", arm_gnuArg(inst, -1, arg.Reg), strings.ToLower(arg.Shift.String()), arg.Count)
+
+	case arm_RegShiftReg:
+		return fmt.Sprintf("%s, %s %s", arm_gnuArg(inst, -1, arg.Reg), strings.ToLower(arg.Shift.String()), arm_gnuArg(inst, -1, arg.RegCount))
+
+	}
+	return strings.ToLower(arg.String())
+}
+
+/* inst.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.
+
+// A Mode is an instruction execution mode.
+type arm_Mode int
+
+const (
+	_ arm_Mode = iota
+	arm_ModeARM
+	arm_ModeThumb
+)
+
+func (m arm_Mode) String() string {
+	switch m {
+	case arm_ModeARM:
+		return "ARM"
+	case arm_ModeThumb:
+		return "Thumb"
+	}
+	return fmt.Sprintf("Mode(%d)", int(m))
+}
+
+// An Op is an ARM opcode.
+type arm_Op uint16
+
+// NOTE: The actual Op values are defined in tables.go.
+// They are chosen to simplify instruction decoding and
+// are not a dense packing from 0 to N, although the
+// density is high, probably at least 90%.
+
+func (op arm_Op) String() string {
+	if op >= 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<<uint(i)) != 0 {
+			fmt.Fprintf(&buf, "%s%s", sep, arm_Reg(i).String())
+			sep = ","
+		}
+	}
+	fmt.Fprintf(&buf, "}")
+	return buf.String()
+}
+
+// An Endian is the argument to the SETEND instruction.
+type arm_Endian uint8
+
+const (
+	arm_LittleEndian arm_Endian = 0
+	arm_BigEndian    arm_Endian = 1
+)
+
+func (arm_Endian) IsArg() {}
+
+func (e arm_Endian) String() string {
+	if e != 0 {
+		return "BE"
+	}
+	return "LE"
+}
+
+// A Shift describes an ARM shift operation.
+type arm_Shift uint8
+
+const (
+	arm_ShiftLeft        arm_Shift = 0 // left shift
+	arm_ShiftRight       arm_Shift = 1 // logical (unsigned) right shift
+	arm_ShiftRightSigned arm_Shift = 2 // arithmetic (signed) right shift
+	arm_RotateRight      arm_Shift = 3 // right rotate
+	arm_RotateRightExt   arm_Shift = 4 // right rotate through carry (Count will always be 1)
+)
+
+var arm_shiftName = [...]string{
+	"LSL", "LSR", "ASR", "ROR", "RRX",
+}
+
+func (s arm_Shift) String() string {
+	if s < 5 {
+		return arm_shiftName[s]
+	}
+	return fmt.Sprintf("Shift(%d)", int(s))
+}
+
+// A RegShift is a register shifted by a constant.
+type arm_RegShift struct {
+	Reg   arm_Reg
+	Shift arm_Shift
+	Count uint8
+}
+
+func (arm_RegShift) IsArg() {}
+
+func (r arm_RegShift) String() string {
+	return fmt.Sprintf("%s %s #%d", r.Reg, r.Shift, r.Count)
+}
+
+// A RegShiftReg is a register shifted by a register.
+type arm_RegShiftReg struct {
+	Reg      arm_Reg
+	Shift    arm_Shift
+	RegCount arm_Reg
+}
+
+func (arm_RegShiftReg) IsArg() {}
+
+func (r arm_RegShiftReg) String() string {
+	return fmt.Sprintf("%s %s %s", r.Reg, r.Shift, r.RegCount)
+}
+
+// A PCRel describes a memory address (usually a code label)
+// as a distance relative to the program counter.
+// TODO(rsc): Define which program counter (PC+4? PC+8? PC?).
+type arm_PCRel int32
+
+func (arm_PCRel) IsArg() {}
+
+func (r arm_PCRel) String() string {
+	return fmt.Sprintf("PC%+#x", int32(r))
+}
+
+// An AddrMode is an ARM addressing mode.
+type arm_AddrMode uint8
+
+const (
+	_                 arm_AddrMode = iota
+	arm_AddrPostIndex              // [R], X – use address R, set R = R + X
+	arm_AddrPreIndex               // [R, X]! – use address R + X, set R = R + X
+	arm_AddrOffset                 // [R, X] – use address R + X
+	arm_AddrLDM                    // R – [R] but formats as R, for LDM/STM only
+	arm_AddrLDM_WB                 // R! - [R], X where X is instruction-specific amount, for LDM/STM only
+)
+
+// A Mem is a memory reference made up of a base R and index expression X.
+// The effective memory address is R or R+X depending on AddrMode.
+// The index expression is X = Sign*(Index Shift Count) + Offset,
+// but in any instruction either Sign = 0 or Offset = 0.
+type arm_Mem struct {
+	Base   arm_Reg
+	Mode   arm_AddrMode
+	Sign   int8
+	Index  arm_Reg
+	Shift  arm_Shift
+	Count  uint8
+	Offset int16
+}
+
+func (arm_Mem) IsArg() {}
+
+func (m arm_Mem) String() string {
+	R := m.Base.String()
+	X := ""
+	if m.Sign != 0 {
+		X = "+"
+		if m.Sign < 0 {
+			X = "-"
+		}
+		X += m.Index.String()
+		if m.Shift != arm_ShiftLeft || m.Count != 0 {
+			X += fmt.Sprintf(", %s #%d", m.Shift, m.Count)
+		}
+	} else {
+		X = fmt.Sprintf("#%d", m.Offset)
+	}
+
+	switch m.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(m.Mode), X)
+}
+
+/* plan9x.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.
+
+// plan9Syntax returns the Go assembler syntax for the instruction.
+// The syntax was originally defined by Plan 9.
+// The pc is the program counter of the instruction, used for expanding
+// PC-relative addresses into absolute ones.
+// The symname function queries the symbol table for the program
+// being disassembled. Given a target address it returns the name and base
+// address of the symbol containing the target, if any; otherwise it returns "", 0.
+// The reader r should read from the text segment using text addresses
+// as offsets; it is used to display pc-relative loads as constant loads.
+func arm_plan9Syntax(inst arm_Inst, pc uint64, symname func(uint64) (string, uint64), text io.ReaderAt) string {
+	if symname == nil {
+		symname = func(uint64) (string, uint64) { return "", 0 }
+	}
+
+	var args []string
+	for _, a := range inst.Args {
+		if a == nil {
+			break
+		}
+		args = append(args, arm_plan9Arg(&inst, pc, symname, a))
+	}
+
+	op := inst.Op.String()
+
+	switch inst.Op &^ 15 {
+	case arm_LDR_EQ, arm_LDRB_EQ, arm_LDRH_EQ:
+		// Check for RET
+		reg, _ := inst.Args[0].(arm_Reg)
+		mem, _ := inst.Args[1].(arm_Mem)
+		if inst.Op&^15 == arm_LDR_EQ && reg == arm_R15 && mem.Base == arm_SP && mem.Sign == 0 && mem.Mode == arm_AddrPostIndex {
+			return fmt.Sprintf("RET%s #%d", op[3:], mem.Offset)
+		}
+
+		// Check for PC-relative load.
+		if mem.Base == arm_PC && mem.Sign == 0 && mem.Mode == arm_AddrOffset && text != nil {
+			addr := uint32(pc) + 8 + uint32(mem.Offset)
+			buf := make([]byte, 4)
+			switch inst.Op &^ 15 {
+			case arm_LDRB_EQ:
+				if _, err := text.ReadAt(buf[:1], int64(addr)); err != nil {
+					break
+				}
+				args[1] = fmt.Sprintf("$%#x", buf[0])
+
+			case arm_LDRH_EQ:
+				if _, err := text.ReadAt(buf[:2], int64(addr)); err != nil {
+					break
+				}
+				args[1] = fmt.Sprintf("$%#x", binary.LittleEndian.Uint16(buf))
+
+			case arm_LDR_EQ:
+				if _, err := text.ReadAt(buf, int64(addr)); err != nil {
+					break
+				}
+				x := binary.LittleEndian.Uint32(buf)
+				if s, base := symname(uint64(x)); s != "" && uint64(x) == base {
+					args[1] = fmt.Sprintf("$%s(SB)", s)
+				} else {
+					args[1] = fmt.Sprintf("$%#x", x)
+				}
+			}
+		}
+	}
+
+	// Move addressing mode into opcode suffix.
+	suffix := ""
+	switch inst.Op &^ 15 {
+	case arm_LDR_EQ, arm_LDRB_EQ, arm_LDRH_EQ, arm_STR_EQ, arm_STRB_EQ, arm_STRH_EQ:
+		mem, _ := inst.Args[1].(arm_Mem)
+		switch mem.Mode {
+		case arm_AddrOffset, arm_AddrLDM:
+			// no suffix
+		case arm_AddrPreIndex, arm_AddrLDM_WB:
+			suffix = ".W"
+		case arm_AddrPostIndex:
+			suffix = ".P"
+		}
+		off := ""
+		if mem.Offset != 0 {
+			off = fmt.Sprintf("%#x", mem.Offset)
+		}
+		base := fmt.Sprintf("(R%d)", int(mem.Base))
+		index := ""
+		if mem.Sign != 0 {
+			sign := ""
+			if mem.Sign < 0 {
+				sign = ""
+			}
+			shift := ""
+			if mem.Count != 0 {
+				shift = fmt.Sprintf("%s%d", arm_plan9Shift[mem.Shift], mem.Count)
+			}
+			index = fmt.Sprintf("(%sR%d%s)", sign, int(mem.Index), shift)
+		}
+		args[1] = off + base + index
+	}
+
+	// Reverse args, placing dest last.
+	for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
+		args[i], args[j] = args[j], args[i]
+	}
+
+	switch inst.Op &^ 15 {
+	case arm_MOV_EQ:
+		op = "MOVW" + op[3:]
+
+	case arm_LDR_EQ:
+		op = "MOVW" + op[3:] + suffix
+	case arm_LDRB_EQ:
+		op = "MOVB" + op[4:] + suffix
+	case arm_LDRH_EQ:
+		op = "MOVH" + op[4:] + suffix
+
+	case arm_STR_EQ:
+		op = "MOVW" + op[3:] + suffix
+		args[0], args[1] = args[1], args[0]
+	case arm_STRB_EQ:
+		op = "MOVB" + op[4:] + suffix
+		args[0], args[1] = args[1], args[0]
+	case arm_STRH_EQ:
+		op = "MOVH" + op[4:] + suffix
+		args[0], args[1] = args[1], args[0]
+	}
+
+	if args != nil {
+		op += " " + strings.Join(args, ", ")
+	}
+
+	return op
+}
+
+// assembler syntax for the various shifts.
+// @x> 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<<uint(i)) != 0 {
+				if i == end+1 {
+					end++
+					continue
+				}
+				start = i
+				end = i
+			}
+		}
+		flush()
+		fmt.Fprintf(&buf, "]")
+		return buf.String()
+
+	case arm_RegShift:
+		return fmt.Sprintf("R%d%s$%d", int(a.Reg), arm_plan9Shift[a.Shift], int(a.Count))
+
+	case arm_RegShiftReg:
+		return fmt.Sprintf("R%d%sR%d", int(a.Reg), arm_plan9Shift[a.Shift], int(a.RegCount))
+	}
+	return strings.ToUpper(arg.String())
+}
+
+/* tables.go */
+
+const (
+	_ arm_Op = iota
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	arm_ADC_EQ
+	arm_ADC_NE
+	arm_ADC_CS
+	arm_ADC_CC
+	arm_ADC_MI
+	arm_ADC_PL
+	arm_ADC_VS
+	arm_ADC_VC
+	arm_ADC_HI
+	arm_ADC_LS
+	arm_ADC_GE
+	arm_ADC_LT
+	arm_ADC_GT
+	arm_ADC_LE
+	arm_ADC
+	arm_ADC_ZZ
+	arm_ADC_S_EQ
+	arm_ADC_S_NE
+	arm_ADC_S_CS
+	arm_ADC_S_CC
+	arm_ADC_S_MI
+	arm_ADC_S_PL
+	arm_ADC_S_VS
+	arm_ADC_S_VC
+	arm_ADC_S_HI
+	arm_ADC_S_LS
+	arm_ADC_S_GE
+	arm_ADC_S_LT
+	arm_ADC_S_GT
+	arm_ADC_S_LE
+	arm_ADC_S
+	arm_ADC_S_ZZ
+	arm_ADD_EQ
+	arm_ADD_NE
+	arm_ADD_CS
+	arm_ADD_CC
+	arm_ADD_MI
+	arm_ADD_PL
+	arm_ADD_VS
+	arm_ADD_VC
+	arm_ADD_HI
+	arm_ADD_LS
+	arm_ADD_GE
+	arm_ADD_LT
+	arm_ADD_GT
+	arm_ADD_LE
+	arm_ADD
+	arm_ADD_ZZ
+	arm_ADD_S_EQ
+	arm_ADD_S_NE
+	arm_ADD_S_CS
+	arm_ADD_S_CC
+	arm_ADD_S_MI
+	arm_ADD_S_PL
+	arm_ADD_S_VS
+	arm_ADD_S_VC
+	arm_ADD_S_HI
+	arm_ADD_S_LS
+	arm_ADD_S_GE
+	arm_ADD_S_LT
+	arm_ADD_S_GT
+	arm_ADD_S_LE
+	arm_ADD_S
+	arm_ADD_S_ZZ
+	arm_AND_EQ
+	arm_AND_NE
+	arm_AND_CS
+	arm_AND_CC
+	arm_AND_MI
+	arm_AND_PL
+	arm_AND_VS
+	arm_AND_VC
+	arm_AND_HI
+	arm_AND_LS
+	arm_AND_GE
+	arm_AND_LT
+	arm_AND_GT
+	arm_AND_LE
+	arm_AND
+	arm_AND_ZZ
+	arm_AND_S_EQ
+	arm_AND_S_NE
+	arm_AND_S_CS
+	arm_AND_S_CC
+	arm_AND_S_MI
+	arm_AND_S_PL
+	arm_AND_S_VS
+	arm_AND_S_VC
+	arm_AND_S_HI
+	arm_AND_S_LS
+	arm_AND_S_GE
+	arm_AND_S_LT
+	arm_AND_S_GT
+	arm_AND_S_LE
+	arm_AND_S
+	arm_AND_S_ZZ
+	arm_ASR_EQ
+	arm_ASR_NE
+	arm_ASR_CS
+	arm_ASR_CC
+	arm_ASR_MI
+	arm_ASR_PL
+	arm_ASR_VS
+	arm_ASR_VC
+	arm_ASR_HI
+	arm_ASR_LS
+	arm_ASR_GE
+	arm_ASR_LT
+	arm_ASR_GT
+	arm_ASR_LE
+	arm_ASR
+	arm_ASR_ZZ
+	arm_ASR_S_EQ
+	arm_ASR_S_NE
+	arm_ASR_S_CS
+	arm_ASR_S_CC
+	arm_ASR_S_MI
+	arm_ASR_S_PL
+	arm_ASR_S_VS
+	arm_ASR_S_VC
+	arm_ASR_S_HI
+	arm_ASR_S_LS
+	arm_ASR_S_GE
+	arm_ASR_S_LT
+	arm_ASR_S_GT
+	arm_ASR_S_LE
+	arm_ASR_S
+	arm_ASR_S_ZZ
+	arm_B_EQ
+	arm_B_NE
+	arm_B_CS
+	arm_B_CC
+	arm_B_MI
+	arm_B_PL
+	arm_B_VS
+	arm_B_VC
+	arm_B_HI
+	arm_B_LS
+	arm_B_GE
+	arm_B_LT
+	arm_B_GT
+	arm_B_LE
+	arm_B
+	arm_B_ZZ
+	arm_BFC_EQ
+	arm_BFC_NE
+	arm_BFC_CS
+	arm_BFC_CC
+	arm_BFC_MI
+	arm_BFC_PL
+	arm_BFC_VS
+	arm_BFC_VC
+	arm_BFC_HI
+	arm_BFC_LS
+	arm_BFC_GE
+	arm_BFC_LT
+	arm_BFC_GT
+	arm_BFC_LE
+	arm_BFC
+	arm_BFC_ZZ
+	arm_BFI_EQ
+	arm_BFI_NE
+	arm_BFI_CS
+	arm_BFI_CC
+	arm_BFI_MI
+	arm_BFI_PL
+	arm_BFI_VS
+	arm_BFI_VC
+	arm_BFI_HI
+	arm_BFI_LS
+	arm_BFI_GE
+	arm_BFI_LT
+	arm_BFI_GT
+	arm_BFI_LE
+	arm_BFI
+	arm_BFI_ZZ
+	arm_BIC_EQ
+	arm_BIC_NE
+	arm_BIC_CS
+	arm_BIC_CC
+	arm_BIC_MI
+	arm_BIC_PL
+	arm_BIC_VS
+	arm_BIC_VC
+	arm_BIC_HI
+	arm_BIC_LS
+	arm_BIC_GE
+	arm_BIC_LT
+	arm_BIC_GT
+	arm_BIC_LE
+	arm_BIC
+	arm_BIC_ZZ
+	arm_BIC_S_EQ
+	arm_BIC_S_NE
+	arm_BIC_S_CS
+	arm_BIC_S_CC
+	arm_BIC_S_MI
+	arm_BIC_S_PL
+	arm_BIC_S_VS
+	arm_BIC_S_VC
+	arm_BIC_S_HI
+	arm_BIC_S_LS
+	arm_BIC_S_GE
+	arm_BIC_S_LT
+	arm_BIC_S_GT
+	arm_BIC_S_LE
+	arm_BIC_S
+	arm_BIC_S_ZZ
+	arm_BKPT_EQ
+	arm_BKPT_NE
+	arm_BKPT_CS
+	arm_BKPT_CC
+	arm_BKPT_MI
+	arm_BKPT_PL
+	arm_BKPT_VS
+	arm_BKPT_VC
+	arm_BKPT_HI
+	arm_BKPT_LS
+	arm_BKPT_GE
+	arm_BKPT_LT
+	arm_BKPT_GT
+	arm_BKPT_LE
+	arm_BKPT
+	arm_BKPT_ZZ
+	arm_BL_EQ
+	arm_BL_NE
+	arm_BL_CS
+	arm_BL_CC
+	arm_BL_MI
+	arm_BL_PL
+	arm_BL_VS
+	arm_BL_VC
+	arm_BL_HI
+	arm_BL_LS
+	arm_BL_GE
+	arm_BL_LT
+	arm_BL_GT
+	arm_BL_LE
+	arm_BL
+	arm_BL_ZZ
+	arm_BLX_EQ
+	arm_BLX_NE
+	arm_BLX_CS
+	arm_BLX_CC
+	arm_BLX_MI
+	arm_BLX_PL
+	arm_BLX_VS
+	arm_BLX_VC
+	arm_BLX_HI
+	arm_BLX_LS
+	arm_BLX_GE
+	arm_BLX_LT
+	arm_BLX_GT
+	arm_BLX_LE
+	arm_BLX
+	arm_BLX_ZZ
+	arm_BX_EQ
+	arm_BX_NE
+	arm_BX_CS
+	arm_BX_CC
+	arm_BX_MI
+	arm_BX_PL
+	arm_BX_VS
+	arm_BX_VC
+	arm_BX_HI
+	arm_BX_LS
+	arm_BX_GE
+	arm_BX_LT
+	arm_BX_GT
+	arm_BX_LE
+	arm_BX
+	arm_BX_ZZ
+	arm_BXJ_EQ
+	arm_BXJ_NE
+	arm_BXJ_CS
+	arm_BXJ_CC
+	arm_BXJ_MI
+	arm_BXJ_PL
+	arm_BXJ_VS
+	arm_BXJ_VC
+	arm_BXJ_HI
+	arm_BXJ_LS
+	arm_BXJ_GE
+	arm_BXJ_LT
+	arm_BXJ_GT
+	arm_BXJ_LE
+	arm_BXJ
+	arm_BXJ_ZZ
+	arm_CLREX
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	arm_CLZ_EQ
+	arm_CLZ_NE
+	arm_CLZ_CS
+	arm_CLZ_CC
+	arm_CLZ_MI
+	arm_CLZ_PL
+	arm_CLZ_VS
+	arm_CLZ_VC
+	arm_CLZ_HI
+	arm_CLZ_LS
+	arm_CLZ_GE
+	arm_CLZ_LT
+	arm_CLZ_GT
+	arm_CLZ_LE
+	arm_CLZ
+	arm_CLZ_ZZ
+	arm_CMN_EQ
+	arm_CMN_NE
+	arm_CMN_CS
+	arm_CMN_CC
+	arm_CMN_MI
+	arm_CMN_PL
+	arm_CMN_VS
+	arm_CMN_VC
+	arm_CMN_HI
+	arm_CMN_LS
+	arm_CMN_GE
+	arm_CMN_LT
+	arm_CMN_GT
+	arm_CMN_LE
+	arm_CMN
+	arm_CMN_ZZ
+	arm_CMP_EQ
+	arm_CMP_NE
+	arm_CMP_CS
+	arm_CMP_CC
+	arm_CMP_MI
+	arm_CMP_PL
+	arm_CMP_VS
+	arm_CMP_VC
+	arm_CMP_HI
+	arm_CMP_LS
+	arm_CMP_GE
+	arm_CMP_LT
+	arm_CMP_GT
+	arm_CMP_LE
+	arm_CMP
+	arm_CMP_ZZ
+	arm_DBG_EQ
+	arm_DBG_NE
+	arm_DBG_CS
+	arm_DBG_CC
+	arm_DBG_MI
+	arm_DBG_PL
+	arm_DBG_VS
+	arm_DBG_VC
+	arm_DBG_HI
+	arm_DBG_LS
+	arm_DBG_GE
+	arm_DBG_LT
+	arm_DBG_GT
+	arm_DBG_LE
+	arm_DBG
+	arm_DBG_ZZ
+	arm_DMB
+	arm_DSB
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	arm_EOR_EQ
+	arm_EOR_NE
+	arm_EOR_CS
+	arm_EOR_CC
+	arm_EOR_MI
+	arm_EOR_PL
+	arm_EOR_VS
+	arm_EOR_VC
+	arm_EOR_HI
+	arm_EOR_LS
+	arm_EOR_GE
+	arm_EOR_LT
+	arm_EOR_GT
+	arm_EOR_LE
+	arm_EOR
+	arm_EOR_ZZ
+	arm_EOR_S_EQ
+	arm_EOR_S_NE
+	arm_EOR_S_CS
+	arm_EOR_S_CC
+	arm_EOR_S_MI
+	arm_EOR_S_PL
+	arm_EOR_S_VS
+	arm_EOR_S_VC
+	arm_EOR_S_HI
+	arm_EOR_S_LS
+	arm_EOR_S_GE
+	arm_EOR_S_LT
+	arm_EOR_S_GT
+	arm_EOR_S_LE
+	arm_EOR_S
+	arm_EOR_S_ZZ
+	arm_ISB
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	arm_LDM_EQ
+	arm_LDM_NE
+	arm_LDM_CS
+	arm_LDM_CC
+	arm_LDM_MI
+	arm_LDM_PL
+	arm_LDM_VS
+	arm_LDM_VC
+	arm_LDM_HI
+	arm_LDM_LS
+	arm_LDM_GE
+	arm_LDM_LT
+	arm_LDM_GT
+	arm_LDM_LE
+	arm_LDM
+	arm_LDM_ZZ
+	arm_LDMDA_EQ
+	arm_LDMDA_NE
+	arm_LDMDA_CS
+	arm_LDMDA_CC
+	arm_LDMDA_MI
+	arm_LDMDA_PL
+	arm_LDMDA_VS
+	arm_LDMDA_VC
+	arm_LDMDA_HI
+	arm_LDMDA_LS
+	arm_LDMDA_GE
+	arm_LDMDA_LT
+	arm_LDMDA_GT
+	arm_LDMDA_LE
+	arm_LDMDA
+	arm_LDMDA_ZZ
+	arm_LDMDB_EQ
+	arm_LDMDB_NE
+	arm_LDMDB_CS
+	arm_LDMDB_CC
+	arm_LDMDB_MI
+	arm_LDMDB_PL
+	arm_LDMDB_VS
+	arm_LDMDB_VC
+	arm_LDMDB_HI
+	arm_LDMDB_LS
+	arm_LDMDB_GE
+	arm_LDMDB_LT
+	arm_LDMDB_GT
+	arm_LDMDB_LE
+	arm_LDMDB
+	arm_LDMDB_ZZ
+	arm_LDMIB_EQ
+	arm_LDMIB_NE
+	arm_LDMIB_CS
+	arm_LDMIB_CC
+	arm_LDMIB_MI
+	arm_LDMIB_PL
+	arm_LDMIB_VS
+	arm_LDMIB_VC
+	arm_LDMIB_HI
+	arm_LDMIB_LS
+	arm_LDMIB_GE
+	arm_LDMIB_LT
+	arm_LDMIB_GT
+	arm_LDMIB_LE
+	arm_LDMIB
+	arm_LDMIB_ZZ
+	arm_LDR_EQ
+	arm_LDR_NE
+	arm_LDR_CS
+	arm_LDR_CC
+	arm_LDR_MI
+	arm_LDR_PL
+	arm_LDR_VS
+	arm_LDR_VC
+	arm_LDR_HI
+	arm_LDR_LS
+	arm_LDR_GE
+	arm_LDR_LT
+	arm_LDR_GT
+	arm_LDR_LE
+	arm_LDR
+	arm_LDR_ZZ
+	arm_LDRB_EQ
+	arm_LDRB_NE
+	arm_LDRB_CS
+	arm_LDRB_CC
+	arm_LDRB_MI
+	arm_LDRB_PL
+	arm_LDRB_VS
+	arm_LDRB_VC
+	arm_LDRB_HI
+	arm_LDRB_LS
+	arm_LDRB_GE
+	arm_LDRB_LT
+	arm_LDRB_GT
+	arm_LDRB_LE
+	arm_LDRB
+	arm_LDRB_ZZ
+	arm_LDRBT_EQ
+	arm_LDRBT_NE
+	arm_LDRBT_CS
+	arm_LDRBT_CC
+	arm_LDRBT_MI
+	arm_LDRBT_PL
+	arm_LDRBT_VS
+	arm_LDRBT_VC
+	arm_LDRBT_HI
+	arm_LDRBT_LS
+	arm_LDRBT_GE
+	arm_LDRBT_LT
+	arm_LDRBT_GT
+	arm_LDRBT_LE
+	arm_LDRBT
+	arm_LDRBT_ZZ
+	arm_LDRD_EQ
+	arm_LDRD_NE
+	arm_LDRD_CS
+	arm_LDRD_CC
+	arm_LDRD_MI
+	arm_LDRD_PL
+	arm_LDRD_VS
+	arm_LDRD_VC
+	arm_LDRD_HI
+	arm_LDRD_LS
+	arm_LDRD_GE
+	arm_LDRD_LT
+	arm_LDRD_GT
+	arm_LDRD_LE
+	arm_LDRD
+	arm_LDRD_ZZ
+	arm_LDREX_EQ
+	arm_LDREX_NE
+	arm_LDREX_CS
+	arm_LDREX_CC
+	arm_LDREX_MI
+	arm_LDREX_PL
+	arm_LDREX_VS
+	arm_LDREX_VC
+	arm_LDREX_HI
+	arm_LDREX_LS
+	arm_LDREX_GE
+	arm_LDREX_LT
+	arm_LDREX_GT
+	arm_LDREX_LE
+	arm_LDREX
+	arm_LDREX_ZZ
+	arm_LDREXB_EQ
+	arm_LDREXB_NE
+	arm_LDREXB_CS
+	arm_LDREXB_CC
+	arm_LDREXB_MI
+	arm_LDREXB_PL
+	arm_LDREXB_VS
+	arm_LDREXB_VC
+	arm_LDREXB_HI
+	arm_LDREXB_LS
+	arm_LDREXB_GE
+	arm_LDREXB_LT
+	arm_LDREXB_GT
+	arm_LDREXB_LE
+	arm_LDREXB
+	arm_LDREXB_ZZ
+	arm_LDREXD_EQ
+	arm_LDREXD_NE
+	arm_LDREXD_CS
+	arm_LDREXD_CC
+	arm_LDREXD_MI
+	arm_LDREXD_PL
+	arm_LDREXD_VS
+	arm_LDREXD_VC
+	arm_LDREXD_HI
+	arm_LDREXD_LS
+	arm_LDREXD_GE
+	arm_LDREXD_LT
+	arm_LDREXD_GT
+	arm_LDREXD_LE
+	arm_LDREXD
+	arm_LDREXD_ZZ
+	arm_LDREXH_EQ
+	arm_LDREXH_NE
+	arm_LDREXH_CS
+	arm_LDREXH_CC
+	arm_LDREXH_MI
+	arm_LDREXH_PL
+	arm_LDREXH_VS
+	arm_LDREXH_VC
+	arm_LDREXH_HI
+	arm_LDREXH_LS
+	arm_LDREXH_GE
+	arm_LDREXH_LT
+	arm_LDREXH_GT
+	arm_LDREXH_LE
+	arm_LDREXH
+	arm_LDREXH_ZZ
+	arm_LDRH_EQ
+	arm_LDRH_NE
+	arm_LDRH_CS
+	arm_LDRH_CC
+	arm_LDRH_MI
+	arm_LDRH_PL
+	arm_LDRH_VS
+	arm_LDRH_VC
+	arm_LDRH_HI
+	arm_LDRH_LS
+	arm_LDRH_GE
+	arm_LDRH_LT
+	arm_LDRH_GT
+	arm_LDRH_LE
+	arm_LDRH
+	arm_LDRH_ZZ
+	arm_LDRHT_EQ
+	arm_LDRHT_NE
+	arm_LDRHT_CS
+	arm_LDRHT_CC
+	arm_LDRHT_MI
+	arm_LDRHT_PL
+	arm_LDRHT_VS
+	arm_LDRHT_VC
+	arm_LDRHT_HI
+	arm_LDRHT_LS
+	arm_LDRHT_GE
+	arm_LDRHT_LT
+	arm_LDRHT_GT
+	arm_LDRHT_LE
+	arm_LDRHT
+	arm_LDRHT_ZZ
+	arm_LDRSB_EQ
+	arm_LDRSB_NE
+	arm_LDRSB_CS
+	arm_LDRSB_CC
+	arm_LDRSB_MI
+	arm_LDRSB_PL
+	arm_LDRSB_VS
+	arm_LDRSB_VC
+	arm_LDRSB_HI
+	arm_LDRSB_LS
+	arm_LDRSB_GE
+	arm_LDRSB_LT
+	arm_LDRSB_GT
+	arm_LDRSB_LE
+	arm_LDRSB
+	arm_LDRSB_ZZ
+	arm_LDRSBT_EQ
+	arm_LDRSBT_NE
+	arm_LDRSBT_CS
+	arm_LDRSBT_CC
+	arm_LDRSBT_MI
+	arm_LDRSBT_PL
+	arm_LDRSBT_VS
+	arm_LDRSBT_VC
+	arm_LDRSBT_HI
+	arm_LDRSBT_LS
+	arm_LDRSBT_GE
+	arm_LDRSBT_LT
+	arm_LDRSBT_GT
+	arm_LDRSBT_LE
+	arm_LDRSBT
+	arm_LDRSBT_ZZ
+	arm_LDRSH_EQ
+	arm_LDRSH_NE
+	arm_LDRSH_CS
+	arm_LDRSH_CC
+	arm_LDRSH_MI
+	arm_LDRSH_PL
+	arm_LDRSH_VS
+	arm_LDRSH_VC
+	arm_LDRSH_HI
+	arm_LDRSH_LS
+	arm_LDRSH_GE
+	arm_LDRSH_LT
+	arm_LDRSH_GT
+	arm_LDRSH_LE
+	arm_LDRSH
+	arm_LDRSH_ZZ
+	arm_LDRSHT_EQ
+	arm_LDRSHT_NE
+	arm_LDRSHT_CS
+	arm_LDRSHT_CC
+	arm_LDRSHT_MI
+	arm_LDRSHT_PL
+	arm_LDRSHT_VS
+	arm_LDRSHT_VC
+	arm_LDRSHT_HI
+	arm_LDRSHT_LS
+	arm_LDRSHT_GE
+	arm_LDRSHT_LT
+	arm_LDRSHT_GT
+	arm_LDRSHT_LE
+	arm_LDRSHT
+	arm_LDRSHT_ZZ
+	arm_LDRT_EQ
+	arm_LDRT_NE
+	arm_LDRT_CS
+	arm_LDRT_CC
+	arm_LDRT_MI
+	arm_LDRT_PL
+	arm_LDRT_VS
+	arm_LDRT_VC
+	arm_LDRT_HI
+	arm_LDRT_LS
+	arm_LDRT_GE
+	arm_LDRT_LT
+	arm_LDRT_GT
+	arm_LDRT_LE
+	arm_LDRT
+	arm_LDRT_ZZ
+	arm_LSL_EQ
+	arm_LSL_NE
+	arm_LSL_CS
+	arm_LSL_CC
+	arm_LSL_MI
+	arm_LSL_PL
+	arm_LSL_VS
+	arm_LSL_VC
+	arm_LSL_HI
+	arm_LSL_LS
+	arm_LSL_GE
+	arm_LSL_LT
+	arm_LSL_GT
+	arm_LSL_LE
+	arm_LSL
+	arm_LSL_ZZ
+	arm_LSL_S_EQ
+	arm_LSL_S_NE
+	arm_LSL_S_CS
+	arm_LSL_S_CC
+	arm_LSL_S_MI
+	arm_LSL_S_PL
+	arm_LSL_S_VS
+	arm_LSL_S_VC
+	arm_LSL_S_HI
+	arm_LSL_S_LS
+	arm_LSL_S_GE
+	arm_LSL_S_LT
+	arm_LSL_S_GT
+	arm_LSL_S_LE
+	arm_LSL_S
+	arm_LSL_S_ZZ
+	arm_LSR_EQ
+	arm_LSR_NE
+	arm_LSR_CS
+	arm_LSR_CC
+	arm_LSR_MI
+	arm_LSR_PL
+	arm_LSR_VS
+	arm_LSR_VC
+	arm_LSR_HI
+	arm_LSR_LS
+	arm_LSR_GE
+	arm_LSR_LT
+	arm_LSR_GT
+	arm_LSR_LE
+	arm_LSR
+	arm_LSR_ZZ
+	arm_LSR_S_EQ
+	arm_LSR_S_NE
+	arm_LSR_S_CS
+	arm_LSR_S_CC
+	arm_LSR_S_MI
+	arm_LSR_S_PL
+	arm_LSR_S_VS
+	arm_LSR_S_VC
+	arm_LSR_S_HI
+	arm_LSR_S_LS
+	arm_LSR_S_GE
+	arm_LSR_S_LT
+	arm_LSR_S_GT
+	arm_LSR_S_LE
+	arm_LSR_S
+	arm_LSR_S_ZZ
+	arm_MLA_EQ
+	arm_MLA_NE
+	arm_MLA_CS
+	arm_MLA_CC
+	arm_MLA_MI
+	arm_MLA_PL
+	arm_MLA_VS
+	arm_MLA_VC
+	arm_MLA_HI
+	arm_MLA_LS
+	arm_MLA_GE
+	arm_MLA_LT
+	arm_MLA_GT
+	arm_MLA_LE
+	arm_MLA
+	arm_MLA_ZZ
+	arm_MLA_S_EQ
+	arm_MLA_S_NE
+	arm_MLA_S_CS
+	arm_MLA_S_CC
+	arm_MLA_S_MI
+	arm_MLA_S_PL
+	arm_MLA_S_VS
+	arm_MLA_S_VC
+	arm_MLA_S_HI
+	arm_MLA_S_LS
+	arm_MLA_S_GE
+	arm_MLA_S_LT
+	arm_MLA_S_GT
+	arm_MLA_S_LE
+	arm_MLA_S
+	arm_MLA_S_ZZ
+	arm_MLS_EQ
+	arm_MLS_NE
+	arm_MLS_CS
+	arm_MLS_CC
+	arm_MLS_MI
+	arm_MLS_PL
+	arm_MLS_VS
+	arm_MLS_VC
+	arm_MLS_HI
+	arm_MLS_LS
+	arm_MLS_GE
+	arm_MLS_LT
+	arm_MLS_GT
+	arm_MLS_LE
+	arm_MLS
+	arm_MLS_ZZ
+	arm_MOV_EQ
+	arm_MOV_NE
+	arm_MOV_CS
+	arm_MOV_CC
+	arm_MOV_MI
+	arm_MOV_PL
+	arm_MOV_VS
+	arm_MOV_VC
+	arm_MOV_HI
+	arm_MOV_LS
+	arm_MOV_GE
+	arm_MOV_LT
+	arm_MOV_GT
+	arm_MOV_LE
+	arm_MOV
+	arm_MOV_ZZ
+	arm_MOV_S_EQ
+	arm_MOV_S_NE
+	arm_MOV_S_CS
+	arm_MOV_S_CC
+	arm_MOV_S_MI
+	arm_MOV_S_PL
+	arm_MOV_S_VS
+	arm_MOV_S_VC
+	arm_MOV_S_HI
+	arm_MOV_S_LS
+	arm_MOV_S_GE
+	arm_MOV_S_LT
+	arm_MOV_S_GT
+	arm_MOV_S_LE
+	arm_MOV_S
+	arm_MOV_S_ZZ
+	arm_MOVT_EQ
+	arm_MOVT_NE
+	arm_MOVT_CS
+	arm_MOVT_CC
+	arm_MOVT_MI
+	arm_MOVT_PL
+	arm_MOVT_VS
+	arm_MOVT_VC
+	arm_MOVT_HI
+	arm_MOVT_LS
+	arm_MOVT_GE
+	arm_MOVT_LT
+	arm_MOVT_GT
+	arm_MOVT_LE
+	arm_MOVT
+	arm_MOVT_ZZ
+	arm_MOVW_EQ
+	arm_MOVW_NE
+	arm_MOVW_CS
+	arm_MOVW_CC
+	arm_MOVW_MI
+	arm_MOVW_PL
+	arm_MOVW_VS
+	arm_MOVW_VC
+	arm_MOVW_HI
+	arm_MOVW_LS
+	arm_MOVW_GE
+	arm_MOVW_LT
+	arm_MOVW_GT
+	arm_MOVW_LE
+	arm_MOVW
+	arm_MOVW_ZZ
+	arm_MRS_EQ
+	arm_MRS_NE
+	arm_MRS_CS
+	arm_MRS_CC
+	arm_MRS_MI
+	arm_MRS_PL
+	arm_MRS_VS
+	arm_MRS_VC
+	arm_MRS_HI
+	arm_MRS_LS
+	arm_MRS_GE
+	arm_MRS_LT
+	arm_MRS_GT
+	arm_MRS_LE
+	arm_MRS
+	arm_MRS_ZZ
+	arm_MUL_EQ
+	arm_MUL_NE
+	arm_MUL_CS
+	arm_MUL_CC
+	arm_MUL_MI
+	arm_MUL_PL
+	arm_MUL_VS
+	arm_MUL_VC
+	arm_MUL_HI
+	arm_MUL_LS
+	arm_MUL_GE
+	arm_MUL_LT
+	arm_MUL_GT
+	arm_MUL_LE
+	arm_MUL
+	arm_MUL_ZZ
+	arm_MUL_S_EQ
+	arm_MUL_S_NE
+	arm_MUL_S_CS
+	arm_MUL_S_CC
+	arm_MUL_S_MI
+	arm_MUL_S_PL
+	arm_MUL_S_VS
+	arm_MUL_S_VC
+	arm_MUL_S_HI
+	arm_MUL_S_LS
+	arm_MUL_S_GE
+	arm_MUL_S_LT
+	arm_MUL_S_GT
+	arm_MUL_S_LE
+	arm_MUL_S
+	arm_MUL_S_ZZ
+	arm_MVN_EQ
+	arm_MVN_NE
+	arm_MVN_CS
+	arm_MVN_CC
+	arm_MVN_MI
+	arm_MVN_PL
+	arm_MVN_VS
+	arm_MVN_VC
+	arm_MVN_HI
+	arm_MVN_LS
+	arm_MVN_GE
+	arm_MVN_LT
+	arm_MVN_GT
+	arm_MVN_LE
+	arm_MVN
+	arm_MVN_ZZ
+	arm_MVN_S_EQ
+	arm_MVN_S_NE
+	arm_MVN_S_CS
+	arm_MVN_S_CC
+	arm_MVN_S_MI
+	arm_MVN_S_PL
+	arm_MVN_S_VS
+	arm_MVN_S_VC
+	arm_MVN_S_HI
+	arm_MVN_S_LS
+	arm_MVN_S_GE
+	arm_MVN_S_LT
+	arm_MVN_S_GT
+	arm_MVN_S_LE
+	arm_MVN_S
+	arm_MVN_S_ZZ
+	arm_NOP_EQ
+	arm_NOP_NE
+	arm_NOP_CS
+	arm_NOP_CC
+	arm_NOP_MI
+	arm_NOP_PL
+	arm_NOP_VS
+	arm_NOP_VC
+	arm_NOP_HI
+	arm_NOP_LS
+	arm_NOP_GE
+	arm_NOP_LT
+	arm_NOP_GT
+	arm_NOP_LE
+	arm_NOP
+	arm_NOP_ZZ
+	arm_ORR_EQ
+	arm_ORR_NE
+	arm_ORR_CS
+	arm_ORR_CC
+	arm_ORR_MI
+	arm_ORR_PL
+	arm_ORR_VS
+	arm_ORR_VC
+	arm_ORR_HI
+	arm_ORR_LS
+	arm_ORR_GE
+	arm_ORR_LT
+	arm_ORR_GT
+	arm_ORR_LE
+	arm_ORR
+	arm_ORR_ZZ
+	arm_ORR_S_EQ
+	arm_ORR_S_NE
+	arm_ORR_S_CS
+	arm_ORR_S_CC
+	arm_ORR_S_MI
+	arm_ORR_S_PL
+	arm_ORR_S_VS
+	arm_ORR_S_VC
+	arm_ORR_S_HI
+	arm_ORR_S_LS
+	arm_ORR_S_GE
+	arm_ORR_S_LT
+	arm_ORR_S_GT
+	arm_ORR_S_LE
+	arm_ORR_S
+	arm_ORR_S_ZZ
+	arm_PKHBT_EQ
+	arm_PKHBT_NE
+	arm_PKHBT_CS
+	arm_PKHBT_CC
+	arm_PKHBT_MI
+	arm_PKHBT_PL
+	arm_PKHBT_VS
+	arm_PKHBT_VC
+	arm_PKHBT_HI
+	arm_PKHBT_LS
+	arm_PKHBT_GE
+	arm_PKHBT_LT
+	arm_PKHBT_GT
+	arm_PKHBT_LE
+	arm_PKHBT
+	arm_PKHBT_ZZ
+	arm_PKHTB_EQ
+	arm_PKHTB_NE
+	arm_PKHTB_CS
+	arm_PKHTB_CC
+	arm_PKHTB_MI
+	arm_PKHTB_PL
+	arm_PKHTB_VS
+	arm_PKHTB_VC
+	arm_PKHTB_HI
+	arm_PKHTB_LS
+	arm_PKHTB_GE
+	arm_PKHTB_LT
+	arm_PKHTB_GT
+	arm_PKHTB_LE
+	arm_PKHTB
+	arm_PKHTB_ZZ
+	arm_PLD_W
+	arm_PLD
+	arm_PLI
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	arm_POP_EQ
+	arm_POP_NE
+	arm_POP_CS
+	arm_POP_CC
+	arm_POP_MI
+	arm_POP_PL
+	arm_POP_VS
+	arm_POP_VC
+	arm_POP_HI
+	arm_POP_LS
+	arm_POP_GE
+	arm_POP_LT
+	arm_POP_GT
+	arm_POP_LE
+	arm_POP
+	arm_POP_ZZ
+	arm_PUSH_EQ
+	arm_PUSH_NE
+	arm_PUSH_CS
+	arm_PUSH_CC
+	arm_PUSH_MI
+	arm_PUSH_PL
+	arm_PUSH_VS
+	arm_PUSH_VC
+	arm_PUSH_HI
+	arm_PUSH_LS
+	arm_PUSH_GE
+	arm_PUSH_LT
+	arm_PUSH_GT
+	arm_PUSH_LE
+	arm_PUSH
+	arm_PUSH_ZZ
+	arm_QADD_EQ
+	arm_QADD_NE
+	arm_QADD_CS
+	arm_QADD_CC
+	arm_QADD_MI
+	arm_QADD_PL
+	arm_QADD_VS
+	arm_QADD_VC
+	arm_QADD_HI
+	arm_QADD_LS
+	arm_QADD_GE
+	arm_QADD_LT
+	arm_QADD_GT
+	arm_QADD_LE
+	arm_QADD
+	arm_QADD_ZZ
+	arm_QADD16_EQ
+	arm_QADD16_NE
+	arm_QADD16_CS
+	arm_QADD16_CC
+	arm_QADD16_MI
+	arm_QADD16_PL
+	arm_QADD16_VS
+	arm_QADD16_VC
+	arm_QADD16_HI
+	arm_QADD16_LS
+	arm_QADD16_GE
+	arm_QADD16_LT
+	arm_QADD16_GT
+	arm_QADD16_LE
+	arm_QADD16
+	arm_QADD16_ZZ
+	arm_QADD8_EQ
+	arm_QADD8_NE
+	arm_QADD8_CS
+	arm_QADD8_CC
+	arm_QADD8_MI
+	arm_QADD8_PL
+	arm_QADD8_VS
+	arm_QADD8_VC
+	arm_QADD8_HI
+	arm_QADD8_LS
+	arm_QADD8_GE
+	arm_QADD8_LT
+	arm_QADD8_GT
+	arm_QADD8_LE
+	arm_QADD8
+	arm_QADD8_ZZ
+	arm_QASX_EQ
+	arm_QASX_NE
+	arm_QASX_CS
+	arm_QASX_CC
+	arm_QASX_MI
+	arm_QASX_PL
+	arm_QASX_VS
+	arm_QASX_VC
+	arm_QASX_HI
+	arm_QASX_LS
+	arm_QASX_GE
+	arm_QASX_LT
+	arm_QASX_GT
+	arm_QASX_LE
+	arm_QASX
+	arm_QASX_ZZ
+	arm_QDADD_EQ
+	arm_QDADD_NE
+	arm_QDADD_CS
+	arm_QDADD_CC
+	arm_QDADD_MI
+	arm_QDADD_PL
+	arm_QDADD_VS
+	arm_QDADD_VC
+	arm_QDADD_HI
+	arm_QDADD_LS
+	arm_QDADD_GE
+	arm_QDADD_LT
+	arm_QDADD_GT
+	arm_QDADD_LE
+	arm_QDADD
+	arm_QDADD_ZZ
+	arm_QDSUB_EQ
+	arm_QDSUB_NE
+	arm_QDSUB_CS
+	arm_QDSUB_CC
+	arm_QDSUB_MI
+	arm_QDSUB_PL
+	arm_QDSUB_VS
+	arm_QDSUB_VC
+	arm_QDSUB_HI
+	arm_QDSUB_LS
+	arm_QDSUB_GE
+	arm_QDSUB_LT
+	arm_QDSUB_GT
+	arm_QDSUB_LE
+	arm_QDSUB
+	arm_QDSUB_ZZ
+	arm_QSAX_EQ
+	arm_QSAX_NE
+	arm_QSAX_CS
+	arm_QSAX_CC
+	arm_QSAX_MI
+	arm_QSAX_PL
+	arm_QSAX_VS
+	arm_QSAX_VC
+	arm_QSAX_HI
+	arm_QSAX_LS
+	arm_QSAX_GE
+	arm_QSAX_LT
+	arm_QSAX_GT
+	arm_QSAX_LE
+	arm_QSAX
+	arm_QSAX_ZZ
+	arm_QSUB_EQ
+	arm_QSUB_NE
+	arm_QSUB_CS
+	arm_QSUB_CC
+	arm_QSUB_MI
+	arm_QSUB_PL
+	arm_QSUB_VS
+	arm_QSUB_VC
+	arm_QSUB_HI
+	arm_QSUB_LS
+	arm_QSUB_GE
+	arm_QSUB_LT
+	arm_QSUB_GT
+	arm_QSUB_LE
+	arm_QSUB
+	arm_QSUB_ZZ
+	arm_QSUB16_EQ
+	arm_QSUB16_NE
+	arm_QSUB16_CS
+	arm_QSUB16_CC
+	arm_QSUB16_MI
+	arm_QSUB16_PL
+	arm_QSUB16_VS
+	arm_QSUB16_VC
+	arm_QSUB16_HI
+	arm_QSUB16_LS
+	arm_QSUB16_GE
+	arm_QSUB16_LT
+	arm_QSUB16_GT
+	arm_QSUB16_LE
+	arm_QSUB16
+	arm_QSUB16_ZZ
+	arm_QSUB8_EQ
+	arm_QSUB8_NE
+	arm_QSUB8_CS
+	arm_QSUB8_CC
+	arm_QSUB8_MI
+	arm_QSUB8_PL
+	arm_QSUB8_VS
+	arm_QSUB8_VC
+	arm_QSUB8_HI
+	arm_QSUB8_LS
+	arm_QSUB8_GE
+	arm_QSUB8_LT
+	arm_QSUB8_GT
+	arm_QSUB8_LE
+	arm_QSUB8
+	arm_QSUB8_ZZ
+	arm_RBIT_EQ
+	arm_RBIT_NE
+	arm_RBIT_CS
+	arm_RBIT_CC
+	arm_RBIT_MI
+	arm_RBIT_PL
+	arm_RBIT_VS
+	arm_RBIT_VC
+	arm_RBIT_HI
+	arm_RBIT_LS
+	arm_RBIT_GE
+	arm_RBIT_LT
+	arm_RBIT_GT
+	arm_RBIT_LE
+	arm_RBIT
+	arm_RBIT_ZZ
+	arm_REV_EQ
+	arm_REV_NE
+	arm_REV_CS
+	arm_REV_CC
+	arm_REV_MI
+	arm_REV_PL
+	arm_REV_VS
+	arm_REV_VC
+	arm_REV_HI
+	arm_REV_LS
+	arm_REV_GE
+	arm_REV_LT
+	arm_REV_GT
+	arm_REV_LE
+	arm_REV
+	arm_REV_ZZ
+	arm_REV16_EQ
+	arm_REV16_NE
+	arm_REV16_CS
+	arm_REV16_CC
+	arm_REV16_MI
+	arm_REV16_PL
+	arm_REV16_VS
+	arm_REV16_VC
+	arm_REV16_HI
+	arm_REV16_LS
+	arm_REV16_GE
+	arm_REV16_LT
+	arm_REV16_GT
+	arm_REV16_LE
+	arm_REV16
+	arm_REV16_ZZ
+	arm_REVSH_EQ
+	arm_REVSH_NE
+	arm_REVSH_CS
+	arm_REVSH_CC
+	arm_REVSH_MI
+	arm_REVSH_PL
+	arm_REVSH_VS
+	arm_REVSH_VC
+	arm_REVSH_HI
+	arm_REVSH_LS
+	arm_REVSH_GE
+	arm_REVSH_LT
+	arm_REVSH_GT
+	arm_REVSH_LE
+	arm_REVSH
+	arm_REVSH_ZZ
+	arm_ROR_EQ
+	arm_ROR_NE
+	arm_ROR_CS
+	arm_ROR_CC
+	arm_ROR_MI
+	arm_ROR_PL
+	arm_ROR_VS
+	arm_ROR_VC
+	arm_ROR_HI
+	arm_ROR_LS
+	arm_ROR_GE
+	arm_ROR_LT
+	arm_ROR_GT
+	arm_ROR_LE
+	arm_ROR
+	arm_ROR_ZZ
+	arm_ROR_S_EQ
+	arm_ROR_S_NE
+	arm_ROR_S_CS
+	arm_ROR_S_CC
+	arm_ROR_S_MI
+	arm_ROR_S_PL
+	arm_ROR_S_VS
+	arm_ROR_S_VC
+	arm_ROR_S_HI
+	arm_ROR_S_LS
+	arm_ROR_S_GE
+	arm_ROR_S_LT
+	arm_ROR_S_GT
+	arm_ROR_S_LE
+	arm_ROR_S
+	arm_ROR_S_ZZ
+	arm_RRX_EQ
+	arm_RRX_NE
+	arm_RRX_CS
+	arm_RRX_CC
+	arm_RRX_MI
+	arm_RRX_PL
+	arm_RRX_VS
+	arm_RRX_VC
+	arm_RRX_HI
+	arm_RRX_LS
+	arm_RRX_GE
+	arm_RRX_LT
+	arm_RRX_GT
+	arm_RRX_LE
+	arm_RRX
+	arm_RRX_ZZ
+	arm_RRX_S_EQ
+	arm_RRX_S_NE
+	arm_RRX_S_CS
+	arm_RRX_S_CC
+	arm_RRX_S_MI
+	arm_RRX_S_PL
+	arm_RRX_S_VS
+	arm_RRX_S_VC
+	arm_RRX_S_HI
+	arm_RRX_S_LS
+	arm_RRX_S_GE
+	arm_RRX_S_LT
+	arm_RRX_S_GT
+	arm_RRX_S_LE
+	arm_RRX_S
+	arm_RRX_S_ZZ
+	arm_RSB_EQ
+	arm_RSB_NE
+	arm_RSB_CS
+	arm_RSB_CC
+	arm_RSB_MI
+	arm_RSB_PL
+	arm_RSB_VS
+	arm_RSB_VC
+	arm_RSB_HI
+	arm_RSB_LS
+	arm_RSB_GE
+	arm_RSB_LT
+	arm_RSB_GT
+	arm_RSB_LE
+	arm_RSB
+	arm_RSB_ZZ
+	arm_RSB_S_EQ
+	arm_RSB_S_NE
+	arm_RSB_S_CS
+	arm_RSB_S_CC
+	arm_RSB_S_MI
+	arm_RSB_S_PL
+	arm_RSB_S_VS
+	arm_RSB_S_VC
+	arm_RSB_S_HI
+	arm_RSB_S_LS
+	arm_RSB_S_GE
+	arm_RSB_S_LT
+	arm_RSB_S_GT
+	arm_RSB_S_LE
+	arm_RSB_S
+	arm_RSB_S_ZZ
+	arm_RSC_EQ
+	arm_RSC_NE
+	arm_RSC_CS
+	arm_RSC_CC
+	arm_RSC_MI
+	arm_RSC_PL
+	arm_RSC_VS
+	arm_RSC_VC
+	arm_RSC_HI
+	arm_RSC_LS
+	arm_RSC_GE
+	arm_RSC_LT
+	arm_RSC_GT
+	arm_RSC_LE
+	arm_RSC
+	arm_RSC_ZZ
+	arm_RSC_S_EQ
+	arm_RSC_S_NE
+	arm_RSC_S_CS
+	arm_RSC_S_CC
+	arm_RSC_S_MI
+	arm_RSC_S_PL
+	arm_RSC_S_VS
+	arm_RSC_S_VC
+	arm_RSC_S_HI
+	arm_RSC_S_LS
+	arm_RSC_S_GE
+	arm_RSC_S_LT
+	arm_RSC_S_GT
+	arm_RSC_S_LE
+	arm_RSC_S
+	arm_RSC_S_ZZ
+	arm_SADD16_EQ
+	arm_SADD16_NE
+	arm_SADD16_CS
+	arm_SADD16_CC
+	arm_SADD16_MI
+	arm_SADD16_PL
+	arm_SADD16_VS
+	arm_SADD16_VC
+	arm_SADD16_HI
+	arm_SADD16_LS
+	arm_SADD16_GE
+	arm_SADD16_LT
+	arm_SADD16_GT
+	arm_SADD16_LE
+	arm_SADD16
+	arm_SADD16_ZZ
+	arm_SADD8_EQ
+	arm_SADD8_NE
+	arm_SADD8_CS
+	arm_SADD8_CC
+	arm_SADD8_MI
+	arm_SADD8_PL
+	arm_SADD8_VS
+	arm_SADD8_VC
+	arm_SADD8_HI
+	arm_SADD8_LS
+	arm_SADD8_GE
+	arm_SADD8_LT
+	arm_SADD8_GT
+	arm_SADD8_LE
+	arm_SADD8
+	arm_SADD8_ZZ
+	arm_SASX_EQ
+	arm_SASX_NE
+	arm_SASX_CS
+	arm_SASX_CC
+	arm_SASX_MI
+	arm_SASX_PL
+	arm_SASX_VS
+	arm_SASX_VC
+	arm_SASX_HI
+	arm_SASX_LS
+	arm_SASX_GE
+	arm_SASX_LT
+	arm_SASX_GT
+	arm_SASX_LE
+	arm_SASX
+	arm_SASX_ZZ
+	arm_SBC_EQ
+	arm_SBC_NE
+	arm_SBC_CS
+	arm_SBC_CC
+	arm_SBC_MI
+	arm_SBC_PL
+	arm_SBC_VS
+	arm_SBC_VC
+	arm_SBC_HI
+	arm_SBC_LS
+	arm_SBC_GE
+	arm_SBC_LT
+	arm_SBC_GT
+	arm_SBC_LE
+	arm_SBC
+	arm_SBC_ZZ
+	arm_SBC_S_EQ
+	arm_SBC_S_NE
+	arm_SBC_S_CS
+	arm_SBC_S_CC
+	arm_SBC_S_MI
+	arm_SBC_S_PL
+	arm_SBC_S_VS
+	arm_SBC_S_VC
+	arm_SBC_S_HI
+	arm_SBC_S_LS
+	arm_SBC_S_GE
+	arm_SBC_S_LT
+	arm_SBC_S_GT
+	arm_SBC_S_LE
+	arm_SBC_S
+	arm_SBC_S_ZZ
+	arm_SBFX_EQ
+	arm_SBFX_NE
+	arm_SBFX_CS
+	arm_SBFX_CC
+	arm_SBFX_MI
+	arm_SBFX_PL
+	arm_SBFX_VS
+	arm_SBFX_VC
+	arm_SBFX_HI
+	arm_SBFX_LS
+	arm_SBFX_GE
+	arm_SBFX_LT
+	arm_SBFX_GT
+	arm_SBFX_LE
+	arm_SBFX
+	arm_SBFX_ZZ
+	arm_SEL_EQ
+	arm_SEL_NE
+	arm_SEL_CS
+	arm_SEL_CC
+	arm_SEL_MI
+	arm_SEL_PL
+	arm_SEL_VS
+	arm_SEL_VC
+	arm_SEL_HI
+	arm_SEL_LS
+	arm_SEL_GE
+	arm_SEL_LT
+	arm_SEL_GT
+	arm_SEL_LE
+	arm_SEL
+	arm_SEL_ZZ
+	arm_SETEND
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	arm_SEV_EQ
+	arm_SEV_NE
+	arm_SEV_CS
+	arm_SEV_CC
+	arm_SEV_MI
+	arm_SEV_PL
+	arm_SEV_VS
+	arm_SEV_VC
+	arm_SEV_HI
+	arm_SEV_LS
+	arm_SEV_GE
+	arm_SEV_LT
+	arm_SEV_GT
+	arm_SEV_LE
+	arm_SEV
+	arm_SEV_ZZ
+	arm_SHADD16_EQ
+	arm_SHADD16_NE
+	arm_SHADD16_CS
+	arm_SHADD16_CC
+	arm_SHADD16_MI
+	arm_SHADD16_PL
+	arm_SHADD16_VS
+	arm_SHADD16_VC
+	arm_SHADD16_HI
+	arm_SHADD16_LS
+	arm_SHADD16_GE
+	arm_SHADD16_LT
+	arm_SHADD16_GT
+	arm_SHADD16_LE
+	arm_SHADD16
+	arm_SHADD16_ZZ
+	arm_SHADD8_EQ
+	arm_SHADD8_NE
+	arm_SHADD8_CS
+	arm_SHADD8_CC
+	arm_SHADD8_MI
+	arm_SHADD8_PL
+	arm_SHADD8_VS
+	arm_SHADD8_VC
+	arm_SHADD8_HI
+	arm_SHADD8_LS
+	arm_SHADD8_GE
+	arm_SHADD8_LT
+	arm_SHADD8_GT
+	arm_SHADD8_LE
+	arm_SHADD8
+	arm_SHADD8_ZZ
+	arm_SHASX_EQ
+	arm_SHASX_NE
+	arm_SHASX_CS
+	arm_SHASX_CC
+	arm_SHASX_MI
+	arm_SHASX_PL
+	arm_SHASX_VS
+	arm_SHASX_VC
+	arm_SHASX_HI
+	arm_SHASX_LS
+	arm_SHASX_GE
+	arm_SHASX_LT
+	arm_SHASX_GT
+	arm_SHASX_LE
+	arm_SHASX
+	arm_SHASX_ZZ
+	arm_SHSAX_EQ
+	arm_SHSAX_NE
+	arm_SHSAX_CS
+	arm_SHSAX_CC
+	arm_SHSAX_MI
+	arm_SHSAX_PL
+	arm_SHSAX_VS
+	arm_SHSAX_VC
+	arm_SHSAX_HI
+	arm_SHSAX_LS
+	arm_SHSAX_GE
+	arm_SHSAX_LT
+	arm_SHSAX_GT
+	arm_SHSAX_LE
+	arm_SHSAX
+	arm_SHSAX_ZZ
+	arm_SHSUB16_EQ
+	arm_SHSUB16_NE
+	arm_SHSUB16_CS
+	arm_SHSUB16_CC
+	arm_SHSUB16_MI
+	arm_SHSUB16_PL
+	arm_SHSUB16_VS
+	arm_SHSUB16_VC
+	arm_SHSUB16_HI
+	arm_SHSUB16_LS
+	arm_SHSUB16_GE
+	arm_SHSUB16_LT
+	arm_SHSUB16_GT
+	arm_SHSUB16_LE
+	arm_SHSUB16
+	arm_SHSUB16_ZZ
+	arm_SHSUB8_EQ
+	arm_SHSUB8_NE
+	arm_SHSUB8_CS
+	arm_SHSUB8_CC
+	arm_SHSUB8_MI
+	arm_SHSUB8_PL
+	arm_SHSUB8_VS
+	arm_SHSUB8_VC
+	arm_SHSUB8_HI
+	arm_SHSUB8_LS
+	arm_SHSUB8_GE
+	arm_SHSUB8_LT
+	arm_SHSUB8_GT
+	arm_SHSUB8_LE
+	arm_SHSUB8
+	arm_SHSUB8_ZZ
+	arm_SMLABB_EQ
+	arm_SMLABB_NE
+	arm_SMLABB_CS
+	arm_SMLABB_CC
+	arm_SMLABB_MI
+	arm_SMLABB_PL
+	arm_SMLABB_VS
+	arm_SMLABB_VC
+	arm_SMLABB_HI
+	arm_SMLABB_LS
+	arm_SMLABB_GE
+	arm_SMLABB_LT
+	arm_SMLABB_GT
+	arm_SMLABB_LE
+	arm_SMLABB
+	arm_SMLABB_ZZ
+	arm_SMLABT_EQ
+	arm_SMLABT_NE
+	arm_SMLABT_CS
+	arm_SMLABT_CC
+	arm_SMLABT_MI
+	arm_SMLABT_PL
+	arm_SMLABT_VS
+	arm_SMLABT_VC
+	arm_SMLABT_HI
+	arm_SMLABT_LS
+	arm_SMLABT_GE
+	arm_SMLABT_LT
+	arm_SMLABT_GT
+	arm_SMLABT_LE
+	arm_SMLABT
+	arm_SMLABT_ZZ
+	arm_SMLATB_EQ
+	arm_SMLATB_NE
+	arm_SMLATB_CS
+	arm_SMLATB_CC
+	arm_SMLATB_MI
+	arm_SMLATB_PL
+	arm_SMLATB_VS
+	arm_SMLATB_VC
+	arm_SMLATB_HI
+	arm_SMLATB_LS
+	arm_SMLATB_GE
+	arm_SMLATB_LT
+	arm_SMLATB_GT
+	arm_SMLATB_LE
+	arm_SMLATB
+	arm_SMLATB_ZZ
+	arm_SMLATT_EQ
+	arm_SMLATT_NE
+	arm_SMLATT_CS
+	arm_SMLATT_CC
+	arm_SMLATT_MI
+	arm_SMLATT_PL
+	arm_SMLATT_VS
+	arm_SMLATT_VC
+	arm_SMLATT_HI
+	arm_SMLATT_LS
+	arm_SMLATT_GE
+	arm_SMLATT_LT
+	arm_SMLATT_GT
+	arm_SMLATT_LE
+	arm_SMLATT
+	arm_SMLATT_ZZ
+	arm_SMLAD_EQ
+	arm_SMLAD_NE
+	arm_SMLAD_CS
+	arm_SMLAD_CC
+	arm_SMLAD_MI
+	arm_SMLAD_PL
+	arm_SMLAD_VS
+	arm_SMLAD_VC
+	arm_SMLAD_HI
+	arm_SMLAD_LS
+	arm_SMLAD_GE
+	arm_SMLAD_LT
+	arm_SMLAD_GT
+	arm_SMLAD_LE
+	arm_SMLAD
+	arm_SMLAD_ZZ
+	arm_SMLAD_X_EQ
+	arm_SMLAD_X_NE
+	arm_SMLAD_X_CS
+	arm_SMLAD_X_CC
+	arm_SMLAD_X_MI
+	arm_SMLAD_X_PL
+	arm_SMLAD_X_VS
+	arm_SMLAD_X_VC
+	arm_SMLAD_X_HI
+	arm_SMLAD_X_LS
+	arm_SMLAD_X_GE
+	arm_SMLAD_X_LT
+	arm_SMLAD_X_GT
+	arm_SMLAD_X_LE
+	arm_SMLAD_X
+	arm_SMLAD_X_ZZ
+	arm_SMLAL_EQ
+	arm_SMLAL_NE
+	arm_SMLAL_CS
+	arm_SMLAL_CC
+	arm_SMLAL_MI
+	arm_SMLAL_PL
+	arm_SMLAL_VS
+	arm_SMLAL_VC
+	arm_SMLAL_HI
+	arm_SMLAL_LS
+	arm_SMLAL_GE
+	arm_SMLAL_LT
+	arm_SMLAL_GT
+	arm_SMLAL_LE
+	arm_SMLAL
+	arm_SMLAL_ZZ
+	arm_SMLAL_S_EQ
+	arm_SMLAL_S_NE
+	arm_SMLAL_S_CS
+	arm_SMLAL_S_CC
+	arm_SMLAL_S_MI
+	arm_SMLAL_S_PL
+	arm_SMLAL_S_VS
+	arm_SMLAL_S_VC
+	arm_SMLAL_S_HI
+	arm_SMLAL_S_LS
+	arm_SMLAL_S_GE
+	arm_SMLAL_S_LT
+	arm_SMLAL_S_GT
+	arm_SMLAL_S_LE
+	arm_SMLAL_S
+	arm_SMLAL_S_ZZ
+	arm_SMLALBB_EQ
+	arm_SMLALBB_NE
+	arm_SMLALBB_CS
+	arm_SMLALBB_CC
+	arm_SMLALBB_MI
+	arm_SMLALBB_PL
+	arm_SMLALBB_VS
+	arm_SMLALBB_VC
+	arm_SMLALBB_HI
+	arm_SMLALBB_LS
+	arm_SMLALBB_GE
+	arm_SMLALBB_LT
+	arm_SMLALBB_GT
+	arm_SMLALBB_LE
+	arm_SMLALBB
+	arm_SMLALBB_ZZ
+	arm_SMLALBT_EQ
+	arm_SMLALBT_NE
+	arm_SMLALBT_CS
+	arm_SMLALBT_CC
+	arm_SMLALBT_MI
+	arm_SMLALBT_PL
+	arm_SMLALBT_VS
+	arm_SMLALBT_VC
+	arm_SMLALBT_HI
+	arm_SMLALBT_LS
+	arm_SMLALBT_GE
+	arm_SMLALBT_LT
+	arm_SMLALBT_GT
+	arm_SMLALBT_LE
+	arm_SMLALBT
+	arm_SMLALBT_ZZ
+	arm_SMLALTB_EQ
+	arm_SMLALTB_NE
+	arm_SMLALTB_CS
+	arm_SMLALTB_CC
+	arm_SMLALTB_MI
+	arm_SMLALTB_PL
+	arm_SMLALTB_VS
+	arm_SMLALTB_VC
+	arm_SMLALTB_HI
+	arm_SMLALTB_LS
+	arm_SMLALTB_GE
+	arm_SMLALTB_LT
+	arm_SMLALTB_GT
+	arm_SMLALTB_LE
+	arm_SMLALTB
+	arm_SMLALTB_ZZ
+	arm_SMLALTT_EQ
+	arm_SMLALTT_NE
+	arm_SMLALTT_CS
+	arm_SMLALTT_CC
+	arm_SMLALTT_MI
+	arm_SMLALTT_PL
+	arm_SMLALTT_VS
+	arm_SMLALTT_VC
+	arm_SMLALTT_HI
+	arm_SMLALTT_LS
+	arm_SMLALTT_GE
+	arm_SMLALTT_LT
+	arm_SMLALTT_GT
+	arm_SMLALTT_LE
+	arm_SMLALTT
+	arm_SMLALTT_ZZ
+	arm_SMLALD_EQ
+	arm_SMLALD_NE
+	arm_SMLALD_CS
+	arm_SMLALD_CC
+	arm_SMLALD_MI
+	arm_SMLALD_PL
+	arm_SMLALD_VS
+	arm_SMLALD_VC
+	arm_SMLALD_HI
+	arm_SMLALD_LS
+	arm_SMLALD_GE
+	arm_SMLALD_LT
+	arm_SMLALD_GT
+	arm_SMLALD_LE
+	arm_SMLALD
+	arm_SMLALD_ZZ
+	arm_SMLALD_X_EQ
+	arm_SMLALD_X_NE
+	arm_SMLALD_X_CS
+	arm_SMLALD_X_CC
+	arm_SMLALD_X_MI
+	arm_SMLALD_X_PL
+	arm_SMLALD_X_VS
+	arm_SMLALD_X_VC
+	arm_SMLALD_X_HI
+	arm_SMLALD_X_LS
+	arm_SMLALD_X_GE
+	arm_SMLALD_X_LT
+	arm_SMLALD_X_GT
+	arm_SMLALD_X_LE
+	arm_SMLALD_X
+	arm_SMLALD_X_ZZ
+	arm_SMLAWB_EQ
+	arm_SMLAWB_NE
+	arm_SMLAWB_CS
+	arm_SMLAWB_CC
+	arm_SMLAWB_MI
+	arm_SMLAWB_PL
+	arm_SMLAWB_VS
+	arm_SMLAWB_VC
+	arm_SMLAWB_HI
+	arm_SMLAWB_LS
+	arm_SMLAWB_GE
+	arm_SMLAWB_LT
+	arm_SMLAWB_GT
+	arm_SMLAWB_LE
+	arm_SMLAWB
+	arm_SMLAWB_ZZ
+	arm_SMLAWT_EQ
+	arm_SMLAWT_NE
+	arm_SMLAWT_CS
+	arm_SMLAWT_CC
+	arm_SMLAWT_MI
+	arm_SMLAWT_PL
+	arm_SMLAWT_VS
+	arm_SMLAWT_VC
+	arm_SMLAWT_HI
+	arm_SMLAWT_LS
+	arm_SMLAWT_GE
+	arm_SMLAWT_LT
+	arm_SMLAWT_GT
+	arm_SMLAWT_LE
+	arm_SMLAWT
+	arm_SMLAWT_ZZ
+	arm_SMLSD_EQ
+	arm_SMLSD_NE
+	arm_SMLSD_CS
+	arm_SMLSD_CC
+	arm_SMLSD_MI
+	arm_SMLSD_PL
+	arm_SMLSD_VS
+	arm_SMLSD_VC
+	arm_SMLSD_HI
+	arm_SMLSD_LS
+	arm_SMLSD_GE
+	arm_SMLSD_LT
+	arm_SMLSD_GT
+	arm_SMLSD_LE
+	arm_SMLSD
+	arm_SMLSD_ZZ
+	arm_SMLSD_X_EQ
+	arm_SMLSD_X_NE
+	arm_SMLSD_X_CS
+	arm_SMLSD_X_CC
+	arm_SMLSD_X_MI
+	arm_SMLSD_X_PL
+	arm_SMLSD_X_VS
+	arm_SMLSD_X_VC
+	arm_SMLSD_X_HI
+	arm_SMLSD_X_LS
+	arm_SMLSD_X_GE
+	arm_SMLSD_X_LT
+	arm_SMLSD_X_GT
+	arm_SMLSD_X_LE
+	arm_SMLSD_X
+	arm_SMLSD_X_ZZ
+	arm_SMLSLD_EQ
+	arm_SMLSLD_NE
+	arm_SMLSLD_CS
+	arm_SMLSLD_CC
+	arm_SMLSLD_MI
+	arm_SMLSLD_PL
+	arm_SMLSLD_VS
+	arm_SMLSLD_VC
+	arm_SMLSLD_HI
+	arm_SMLSLD_LS
+	arm_SMLSLD_GE
+	arm_SMLSLD_LT
+	arm_SMLSLD_GT
+	arm_SMLSLD_LE
+	arm_SMLSLD
+	arm_SMLSLD_ZZ
+	arm_SMLSLD_X_EQ
+	arm_SMLSLD_X_NE
+	arm_SMLSLD_X_CS
+	arm_SMLSLD_X_CC
+	arm_SMLSLD_X_MI
+	arm_SMLSLD_X_PL
+	arm_SMLSLD_X_VS
+	arm_SMLSLD_X_VC
+	arm_SMLSLD_X_HI
+	arm_SMLSLD_X_LS
+	arm_SMLSLD_X_GE
+	arm_SMLSLD_X_LT
+	arm_SMLSLD_X_GT
+	arm_SMLSLD_X_LE
+	arm_SMLSLD_X
+	arm_SMLSLD_X_ZZ
+	arm_SMMLA_EQ
+	arm_SMMLA_NE
+	arm_SMMLA_CS
+	arm_SMMLA_CC
+	arm_SMMLA_MI
+	arm_SMMLA_PL
+	arm_SMMLA_VS
+	arm_SMMLA_VC
+	arm_SMMLA_HI
+	arm_SMMLA_LS
+	arm_SMMLA_GE
+	arm_SMMLA_LT
+	arm_SMMLA_GT
+	arm_SMMLA_LE
+	arm_SMMLA
+	arm_SMMLA_ZZ
+	arm_SMMLA_R_EQ
+	arm_SMMLA_R_NE
+	arm_SMMLA_R_CS
+	arm_SMMLA_R_CC
+	arm_SMMLA_R_MI
+	arm_SMMLA_R_PL
+	arm_SMMLA_R_VS
+	arm_SMMLA_R_VC
+	arm_SMMLA_R_HI
+	arm_SMMLA_R_LS
+	arm_SMMLA_R_GE
+	arm_SMMLA_R_LT
+	arm_SMMLA_R_GT
+	arm_SMMLA_R_LE
+	arm_SMMLA_R
+	arm_SMMLA_R_ZZ
+	arm_SMMLS_EQ
+	arm_SMMLS_NE
+	arm_SMMLS_CS
+	arm_SMMLS_CC
+	arm_SMMLS_MI
+	arm_SMMLS_PL
+	arm_SMMLS_VS
+	arm_SMMLS_VC
+	arm_SMMLS_HI
+	arm_SMMLS_LS
+	arm_SMMLS_GE
+	arm_SMMLS_LT
+	arm_SMMLS_GT
+	arm_SMMLS_LE
+	arm_SMMLS
+	arm_SMMLS_ZZ
+	arm_SMMLS_R_EQ
+	arm_SMMLS_R_NE
+	arm_SMMLS_R_CS
+	arm_SMMLS_R_CC
+	arm_SMMLS_R_MI
+	arm_SMMLS_R_PL
+	arm_SMMLS_R_VS
+	arm_SMMLS_R_VC
+	arm_SMMLS_R_HI
+	arm_SMMLS_R_LS
+	arm_SMMLS_R_GE
+	arm_SMMLS_R_LT
+	arm_SMMLS_R_GT
+	arm_SMMLS_R_LE
+	arm_SMMLS_R
+	arm_SMMLS_R_ZZ
+	arm_SMMUL_EQ
+	arm_SMMUL_NE
+	arm_SMMUL_CS
+	arm_SMMUL_CC
+	arm_SMMUL_MI
+	arm_SMMUL_PL
+	arm_SMMUL_VS
+	arm_SMMUL_VC
+	arm_SMMUL_HI
+	arm_SMMUL_LS
+	arm_SMMUL_GE
+	arm_SMMUL_LT
+	arm_SMMUL_GT
+	arm_SMMUL_LE
+	arm_SMMUL
+	arm_SMMUL_ZZ
+	arm_SMMUL_R_EQ
+	arm_SMMUL_R_NE
+	arm_SMMUL_R_CS
+	arm_SMMUL_R_CC
+	arm_SMMUL_R_MI
+	arm_SMMUL_R_PL
+	arm_SMMUL_R_VS
+	arm_SMMUL_R_VC
+	arm_SMMUL_R_HI
+	arm_SMMUL_R_LS
+	arm_SMMUL_R_GE
+	arm_SMMUL_R_LT
+	arm_SMMUL_R_GT
+	arm_SMMUL_R_LE
+	arm_SMMUL_R
+	arm_SMMUL_R_ZZ
+	arm_SMUAD_EQ
+	arm_SMUAD_NE
+	arm_SMUAD_CS
+	arm_SMUAD_CC
+	arm_SMUAD_MI
+	arm_SMUAD_PL
+	arm_SMUAD_VS
+	arm_SMUAD_VC
+	arm_SMUAD_HI
+	arm_SMUAD_LS
+	arm_SMUAD_GE
+	arm_SMUAD_LT
+	arm_SMUAD_GT
+	arm_SMUAD_LE
+	arm_SMUAD
+	arm_SMUAD_ZZ
+	arm_SMUAD_X_EQ
+	arm_SMUAD_X_NE
+	arm_SMUAD_X_CS
+	arm_SMUAD_X_CC
+	arm_SMUAD_X_MI
+	arm_SMUAD_X_PL
+	arm_SMUAD_X_VS
+	arm_SMUAD_X_VC
+	arm_SMUAD_X_HI
+	arm_SMUAD_X_LS
+	arm_SMUAD_X_GE
+	arm_SMUAD_X_LT
+	arm_SMUAD_X_GT
+	arm_SMUAD_X_LE
+	arm_SMUAD_X
+	arm_SMUAD_X_ZZ
+	arm_SMULBB_EQ
+	arm_SMULBB_NE
+	arm_SMULBB_CS
+	arm_SMULBB_CC
+	arm_SMULBB_MI
+	arm_SMULBB_PL
+	arm_SMULBB_VS
+	arm_SMULBB_VC
+	arm_SMULBB_HI
+	arm_SMULBB_LS
+	arm_SMULBB_GE
+	arm_SMULBB_LT
+	arm_SMULBB_GT
+	arm_SMULBB_LE
+	arm_SMULBB
+	arm_SMULBB_ZZ
+	arm_SMULBT_EQ
+	arm_SMULBT_NE
+	arm_SMULBT_CS
+	arm_SMULBT_CC
+	arm_SMULBT_MI
+	arm_SMULBT_PL
+	arm_SMULBT_VS
+	arm_SMULBT_VC
+	arm_SMULBT_HI
+	arm_SMULBT_LS
+	arm_SMULBT_GE
+	arm_SMULBT_LT
+	arm_SMULBT_GT
+	arm_SMULBT_LE
+	arm_SMULBT
+	arm_SMULBT_ZZ
+	arm_SMULTB_EQ
+	arm_SMULTB_NE
+	arm_SMULTB_CS
+	arm_SMULTB_CC
+	arm_SMULTB_MI
+	arm_SMULTB_PL
+	arm_SMULTB_VS
+	arm_SMULTB_VC
+	arm_SMULTB_HI
+	arm_SMULTB_LS
+	arm_SMULTB_GE
+	arm_SMULTB_LT
+	arm_SMULTB_GT
+	arm_SMULTB_LE
+	arm_SMULTB
+	arm_SMULTB_ZZ
+	arm_SMULTT_EQ
+	arm_SMULTT_NE
+	arm_SMULTT_CS
+	arm_SMULTT_CC
+	arm_SMULTT_MI
+	arm_SMULTT_PL
+	arm_SMULTT_VS
+	arm_SMULTT_VC
+	arm_SMULTT_HI
+	arm_SMULTT_LS
+	arm_SMULTT_GE
+	arm_SMULTT_LT
+	arm_SMULTT_GT
+	arm_SMULTT_LE
+	arm_SMULTT
+	arm_SMULTT_ZZ
+	arm_SMULL_EQ
+	arm_SMULL_NE
+	arm_SMULL_CS
+	arm_SMULL_CC
+	arm_SMULL_MI
+	arm_SMULL_PL
+	arm_SMULL_VS
+	arm_SMULL_VC
+	arm_SMULL_HI
+	arm_SMULL_LS
+	arm_SMULL_GE
+	arm_SMULL_LT
+	arm_SMULL_GT
+	arm_SMULL_LE
+	arm_SMULL
+	arm_SMULL_ZZ
+	arm_SMULL_S_EQ
+	arm_SMULL_S_NE
+	arm_SMULL_S_CS
+	arm_SMULL_S_CC
+	arm_SMULL_S_MI
+	arm_SMULL_S_PL
+	arm_SMULL_S_VS
+	arm_SMULL_S_VC
+	arm_SMULL_S_HI
+	arm_SMULL_S_LS
+	arm_SMULL_S_GE
+	arm_SMULL_S_LT
+	arm_SMULL_S_GT
+	arm_SMULL_S_LE
+	arm_SMULL_S
+	arm_SMULL_S_ZZ
+	arm_SMULWB_EQ
+	arm_SMULWB_NE
+	arm_SMULWB_CS
+	arm_SMULWB_CC
+	arm_SMULWB_MI
+	arm_SMULWB_PL
+	arm_SMULWB_VS
+	arm_SMULWB_VC
+	arm_SMULWB_HI
+	arm_SMULWB_LS
+	arm_SMULWB_GE
+	arm_SMULWB_LT
+	arm_SMULWB_GT
+	arm_SMULWB_LE
+	arm_SMULWB
+	arm_SMULWB_ZZ
+	arm_SMULWT_EQ
+	arm_SMULWT_NE
+	arm_SMULWT_CS
+	arm_SMULWT_CC
+	arm_SMULWT_MI
+	arm_SMULWT_PL
+	arm_SMULWT_VS
+	arm_SMULWT_VC
+	arm_SMULWT_HI
+	arm_SMULWT_LS
+	arm_SMULWT_GE
+	arm_SMULWT_LT
+	arm_SMULWT_GT
+	arm_SMULWT_LE
+	arm_SMULWT
+	arm_SMULWT_ZZ
+	arm_SMUSD_EQ
+	arm_SMUSD_NE
+	arm_SMUSD_CS
+	arm_SMUSD_CC
+	arm_SMUSD_MI
+	arm_SMUSD_PL
+	arm_SMUSD_VS
+	arm_SMUSD_VC
+	arm_SMUSD_HI
+	arm_SMUSD_LS
+	arm_SMUSD_GE
+	arm_SMUSD_LT
+	arm_SMUSD_GT
+	arm_SMUSD_LE
+	arm_SMUSD
+	arm_SMUSD_ZZ
+	arm_SMUSD_X_EQ
+	arm_SMUSD_X_NE
+	arm_SMUSD_X_CS
+	arm_SMUSD_X_CC
+	arm_SMUSD_X_MI
+	arm_SMUSD_X_PL
+	arm_SMUSD_X_VS
+	arm_SMUSD_X_VC
+	arm_SMUSD_X_HI
+	arm_SMUSD_X_LS
+	arm_SMUSD_X_GE
+	arm_SMUSD_X_LT
+	arm_SMUSD_X_GT
+	arm_SMUSD_X_LE
+	arm_SMUSD_X
+	arm_SMUSD_X_ZZ
+	arm_SSAT_EQ
+	arm_SSAT_NE
+	arm_SSAT_CS
+	arm_SSAT_CC
+	arm_SSAT_MI
+	arm_SSAT_PL
+	arm_SSAT_VS
+	arm_SSAT_VC
+	arm_SSAT_HI
+	arm_SSAT_LS
+	arm_SSAT_GE
+	arm_SSAT_LT
+	arm_SSAT_GT
+	arm_SSAT_LE
+	arm_SSAT
+	arm_SSAT_ZZ
+	arm_SSAT16_EQ
+	arm_SSAT16_NE
+	arm_SSAT16_CS
+	arm_SSAT16_CC
+	arm_SSAT16_MI
+	arm_SSAT16_PL
+	arm_SSAT16_VS
+	arm_SSAT16_VC
+	arm_SSAT16_HI
+	arm_SSAT16_LS
+	arm_SSAT16_GE
+	arm_SSAT16_LT
+	arm_SSAT16_GT
+	arm_SSAT16_LE
+	arm_SSAT16
+	arm_SSAT16_ZZ
+	arm_SSAX_EQ
+	arm_SSAX_NE
+	arm_SSAX_CS
+	arm_SSAX_CC
+	arm_SSAX_MI
+	arm_SSAX_PL
+	arm_SSAX_VS
+	arm_SSAX_VC
+	arm_SSAX_HI
+	arm_SSAX_LS
+	arm_SSAX_GE
+	arm_SSAX_LT
+	arm_SSAX_GT
+	arm_SSAX_LE
+	arm_SSAX
+	arm_SSAX_ZZ
+	arm_SSUB16_EQ
+	arm_SSUB16_NE
+	arm_SSUB16_CS
+	arm_SSUB16_CC
+	arm_SSUB16_MI
+	arm_SSUB16_PL
+	arm_SSUB16_VS
+	arm_SSUB16_VC
+	arm_SSUB16_HI
+	arm_SSUB16_LS
+	arm_SSUB16_GE
+	arm_SSUB16_LT
+	arm_SSUB16_GT
+	arm_SSUB16_LE
+	arm_SSUB16
+	arm_SSUB16_ZZ
+	arm_SSUB8_EQ
+	arm_SSUB8_NE
+	arm_SSUB8_CS
+	arm_SSUB8_CC
+	arm_SSUB8_MI
+	arm_SSUB8_PL
+	arm_SSUB8_VS
+	arm_SSUB8_VC
+	arm_SSUB8_HI
+	arm_SSUB8_LS
+	arm_SSUB8_GE
+	arm_SSUB8_LT
+	arm_SSUB8_GT
+	arm_SSUB8_LE
+	arm_SSUB8
+	arm_SSUB8_ZZ
+	arm_STM_EQ
+	arm_STM_NE
+	arm_STM_CS
+	arm_STM_CC
+	arm_STM_MI
+	arm_STM_PL
+	arm_STM_VS
+	arm_STM_VC
+	arm_STM_HI
+	arm_STM_LS
+	arm_STM_GE
+	arm_STM_LT
+	arm_STM_GT
+	arm_STM_LE
+	arm_STM
+	arm_STM_ZZ
+	arm_STMDA_EQ
+	arm_STMDA_NE
+	arm_STMDA_CS
+	arm_STMDA_CC
+	arm_STMDA_MI
+	arm_STMDA_PL
+	arm_STMDA_VS
+	arm_STMDA_VC
+	arm_STMDA_HI
+	arm_STMDA_LS
+	arm_STMDA_GE
+	arm_STMDA_LT
+	arm_STMDA_GT
+	arm_STMDA_LE
+	arm_STMDA
+	arm_STMDA_ZZ
+	arm_STMDB_EQ
+	arm_STMDB_NE
+	arm_STMDB_CS
+	arm_STMDB_CC
+	arm_STMDB_MI
+	arm_STMDB_PL
+	arm_STMDB_VS
+	arm_STMDB_VC
+	arm_STMDB_HI
+	arm_STMDB_LS
+	arm_STMDB_GE
+	arm_STMDB_LT
+	arm_STMDB_GT
+	arm_STMDB_LE
+	arm_STMDB
+	arm_STMDB_ZZ
+	arm_STMIB_EQ
+	arm_STMIB_NE
+	arm_STMIB_CS
+	arm_STMIB_CC
+	arm_STMIB_MI
+	arm_STMIB_PL
+	arm_STMIB_VS
+	arm_STMIB_VC
+	arm_STMIB_HI
+	arm_STMIB_LS
+	arm_STMIB_GE
+	arm_STMIB_LT
+	arm_STMIB_GT
+	arm_STMIB_LE
+	arm_STMIB
+	arm_STMIB_ZZ
+	arm_STR_EQ
+	arm_STR_NE
+	arm_STR_CS
+	arm_STR_CC
+	arm_STR_MI
+	arm_STR_PL
+	arm_STR_VS
+	arm_STR_VC
+	arm_STR_HI
+	arm_STR_LS
+	arm_STR_GE
+	arm_STR_LT
+	arm_STR_GT
+	arm_STR_LE
+	arm_STR
+	arm_STR_ZZ
+	arm_STRB_EQ
+	arm_STRB_NE
+	arm_STRB_CS
+	arm_STRB_CC
+	arm_STRB_MI
+	arm_STRB_PL
+	arm_STRB_VS
+	arm_STRB_VC
+	arm_STRB_HI
+	arm_STRB_LS
+	arm_STRB_GE
+	arm_STRB_LT
+	arm_STRB_GT
+	arm_STRB_LE
+	arm_STRB
+	arm_STRB_ZZ
+	arm_STRBT_EQ
+	arm_STRBT_NE
+	arm_STRBT_CS
+	arm_STRBT_CC
+	arm_STRBT_MI
+	arm_STRBT_PL
+	arm_STRBT_VS
+	arm_STRBT_VC
+	arm_STRBT_HI
+	arm_STRBT_LS
+	arm_STRBT_GE
+	arm_STRBT_LT
+	arm_STRBT_GT
+	arm_STRBT_LE
+	arm_STRBT
+	arm_STRBT_ZZ
+	arm_STRD_EQ
+	arm_STRD_NE
+	arm_STRD_CS
+	arm_STRD_CC
+	arm_STRD_MI
+	arm_STRD_PL
+	arm_STRD_VS
+	arm_STRD_VC
+	arm_STRD_HI
+	arm_STRD_LS
+	arm_STRD_GE
+	arm_STRD_LT
+	arm_STRD_GT
+	arm_STRD_LE
+	arm_STRD
+	arm_STRD_ZZ
+	arm_STREX_EQ
+	arm_STREX_NE
+	arm_STREX_CS
+	arm_STREX_CC
+	arm_STREX_MI
+	arm_STREX_PL
+	arm_STREX_VS
+	arm_STREX_VC
+	arm_STREX_HI
+	arm_STREX_LS
+	arm_STREX_GE
+	arm_STREX_LT
+	arm_STREX_GT
+	arm_STREX_LE
+	arm_STREX
+	arm_STREX_ZZ
+	arm_STREXB_EQ
+	arm_STREXB_NE
+	arm_STREXB_CS
+	arm_STREXB_CC
+	arm_STREXB_MI
+	arm_STREXB_PL
+	arm_STREXB_VS
+	arm_STREXB_VC
+	arm_STREXB_HI
+	arm_STREXB_LS
+	arm_STREXB_GE
+	arm_STREXB_LT
+	arm_STREXB_GT
+	arm_STREXB_LE
+	arm_STREXB
+	arm_STREXB_ZZ
+	arm_STREXD_EQ
+	arm_STREXD_NE
+	arm_STREXD_CS
+	arm_STREXD_CC
+	arm_STREXD_MI
+	arm_STREXD_PL
+	arm_STREXD_VS
+	arm_STREXD_VC
+	arm_STREXD_HI
+	arm_STREXD_LS
+	arm_STREXD_GE
+	arm_STREXD_LT
+	arm_STREXD_GT
+	arm_STREXD_LE
+	arm_STREXD
+	arm_STREXD_ZZ
+	arm_STREXH_EQ
+	arm_STREXH_NE
+	arm_STREXH_CS
+	arm_STREXH_CC
+	arm_STREXH_MI
+	arm_STREXH_PL
+	arm_STREXH_VS
+	arm_STREXH_VC
+	arm_STREXH_HI
+	arm_STREXH_LS
+	arm_STREXH_GE
+	arm_STREXH_LT
+	arm_STREXH_GT
+	arm_STREXH_LE
+	arm_STREXH
+	arm_STREXH_ZZ
+	arm_STRH_EQ
+	arm_STRH_NE
+	arm_STRH_CS
+	arm_STRH_CC
+	arm_STRH_MI
+	arm_STRH_PL
+	arm_STRH_VS
+	arm_STRH_VC
+	arm_STRH_HI
+	arm_STRH_LS
+	arm_STRH_GE
+	arm_STRH_LT
+	arm_STRH_GT
+	arm_STRH_LE
+	arm_STRH
+	arm_STRH_ZZ
+	arm_STRHT_EQ
+	arm_STRHT_NE
+	arm_STRHT_CS
+	arm_STRHT_CC
+	arm_STRHT_MI
+	arm_STRHT_PL
+	arm_STRHT_VS
+	arm_STRHT_VC
+	arm_STRHT_HI
+	arm_STRHT_LS
+	arm_STRHT_GE
+	arm_STRHT_LT
+	arm_STRHT_GT
+	arm_STRHT_LE
+	arm_STRHT
+	arm_STRHT_ZZ
+	arm_STRT_EQ
+	arm_STRT_NE
+	arm_STRT_CS
+	arm_STRT_CC
+	arm_STRT_MI
+	arm_STRT_PL
+	arm_STRT_VS
+	arm_STRT_VC
+	arm_STRT_HI
+	arm_STRT_LS
+	arm_STRT_GE
+	arm_STRT_LT
+	arm_STRT_GT
+	arm_STRT_LE
+	arm_STRT
+	arm_STRT_ZZ
+	arm_SUB_EQ
+	arm_SUB_NE
+	arm_SUB_CS
+	arm_SUB_CC
+	arm_SUB_MI
+	arm_SUB_PL
+	arm_SUB_VS
+	arm_SUB_VC
+	arm_SUB_HI
+	arm_SUB_LS
+	arm_SUB_GE
+	arm_SUB_LT
+	arm_SUB_GT
+	arm_SUB_LE
+	arm_SUB
+	arm_SUB_ZZ
+	arm_SUB_S_EQ
+	arm_SUB_S_NE
+	arm_SUB_S_CS
+	arm_SUB_S_CC
+	arm_SUB_S_MI
+	arm_SUB_S_PL
+	arm_SUB_S_VS
+	arm_SUB_S_VC
+	arm_SUB_S_HI
+	arm_SUB_S_LS
+	arm_SUB_S_GE
+	arm_SUB_S_LT
+	arm_SUB_S_GT
+	arm_SUB_S_LE
+	arm_SUB_S
+	arm_SUB_S_ZZ
+	arm_SVC_EQ
+	arm_SVC_NE
+	arm_SVC_CS
+	arm_SVC_CC
+	arm_SVC_MI
+	arm_SVC_PL
+	arm_SVC_VS
+	arm_SVC_VC
+	arm_SVC_HI
+	arm_SVC_LS
+	arm_SVC_GE
+	arm_SVC_LT
+	arm_SVC_GT
+	arm_SVC_LE
+	arm_SVC
+	arm_SVC_ZZ
+	arm_SWP_EQ
+	arm_SWP_NE
+	arm_SWP_CS
+	arm_SWP_CC
+	arm_SWP_MI
+	arm_SWP_PL
+	arm_SWP_VS
+	arm_SWP_VC
+	arm_SWP_HI
+	arm_SWP_LS
+	arm_SWP_GE
+	arm_SWP_LT
+	arm_SWP_GT
+	arm_SWP_LE
+	arm_SWP
+	arm_SWP_ZZ
+	arm_SWP_B_EQ
+	arm_SWP_B_NE
+	arm_SWP_B_CS
+	arm_SWP_B_CC
+	arm_SWP_B_MI
+	arm_SWP_B_PL
+	arm_SWP_B_VS
+	arm_SWP_B_VC
+	arm_SWP_B_HI
+	arm_SWP_B_LS
+	arm_SWP_B_GE
+	arm_SWP_B_LT
+	arm_SWP_B_GT
+	arm_SWP_B_LE
+	arm_SWP_B
+	arm_SWP_B_ZZ
+	arm_SXTAB_EQ
+	arm_SXTAB_NE
+	arm_SXTAB_CS
+	arm_SXTAB_CC
+	arm_SXTAB_MI
+	arm_SXTAB_PL
+	arm_SXTAB_VS
+	arm_SXTAB_VC
+	arm_SXTAB_HI
+	arm_SXTAB_LS
+	arm_SXTAB_GE
+	arm_SXTAB_LT
+	arm_SXTAB_GT
+	arm_SXTAB_LE
+	arm_SXTAB
+	arm_SXTAB_ZZ
+	arm_SXTAB16_EQ
+	arm_SXTAB16_NE
+	arm_SXTAB16_CS
+	arm_SXTAB16_CC
+	arm_SXTAB16_MI
+	arm_SXTAB16_PL
+	arm_SXTAB16_VS
+	arm_SXTAB16_VC
+	arm_SXTAB16_HI
+	arm_SXTAB16_LS
+	arm_SXTAB16_GE
+	arm_SXTAB16_LT
+	arm_SXTAB16_GT
+	arm_SXTAB16_LE
+	arm_SXTAB16
+	arm_SXTAB16_ZZ
+	arm_SXTAH_EQ
+	arm_SXTAH_NE
+	arm_SXTAH_CS
+	arm_SXTAH_CC
+	arm_SXTAH_MI
+	arm_SXTAH_PL
+	arm_SXTAH_VS
+	arm_SXTAH_VC
+	arm_SXTAH_HI
+	arm_SXTAH_LS
+	arm_SXTAH_GE
+	arm_SXTAH_LT
+	arm_SXTAH_GT
+	arm_SXTAH_LE
+	arm_SXTAH
+	arm_SXTAH_ZZ
+	arm_SXTB_EQ
+	arm_SXTB_NE
+	arm_SXTB_CS
+	arm_SXTB_CC
+	arm_SXTB_MI
+	arm_SXTB_PL
+	arm_SXTB_VS
+	arm_SXTB_VC
+	arm_SXTB_HI
+	arm_SXTB_LS
+	arm_SXTB_GE
+	arm_SXTB_LT
+	arm_SXTB_GT
+	arm_SXTB_LE
+	arm_SXTB
+	arm_SXTB_ZZ
+	arm_SXTB16_EQ
+	arm_SXTB16_NE
+	arm_SXTB16_CS
+	arm_SXTB16_CC
+	arm_SXTB16_MI
+	arm_SXTB16_PL
+	arm_SXTB16_VS
+	arm_SXTB16_VC
+	arm_SXTB16_HI
+	arm_SXTB16_LS
+	arm_SXTB16_GE
+	arm_SXTB16_LT
+	arm_SXTB16_GT
+	arm_SXTB16_LE
+	arm_SXTB16
+	arm_SXTB16_ZZ
+	arm_SXTH_EQ
+	arm_SXTH_NE
+	arm_SXTH_CS
+	arm_SXTH_CC
+	arm_SXTH_MI
+	arm_SXTH_PL
+	arm_SXTH_VS
+	arm_SXTH_VC
+	arm_SXTH_HI
+	arm_SXTH_LS
+	arm_SXTH_GE
+	arm_SXTH_LT
+	arm_SXTH_GT
+	arm_SXTH_LE
+	arm_SXTH
+	arm_SXTH_ZZ
+	arm_TEQ_EQ
+	arm_TEQ_NE
+	arm_TEQ_CS
+	arm_TEQ_CC
+	arm_TEQ_MI
+	arm_TEQ_PL
+	arm_TEQ_VS
+	arm_TEQ_VC
+	arm_TEQ_HI
+	arm_TEQ_LS
+	arm_TEQ_GE
+	arm_TEQ_LT
+	arm_TEQ_GT
+	arm_TEQ_LE
+	arm_TEQ
+	arm_TEQ_ZZ
+	arm_TST_EQ
+	arm_TST_NE
+	arm_TST_CS
+	arm_TST_CC
+	arm_TST_MI
+	arm_TST_PL
+	arm_TST_VS
+	arm_TST_VC
+	arm_TST_HI
+	arm_TST_LS
+	arm_TST_GE
+	arm_TST_LT
+	arm_TST_GT
+	arm_TST_LE
+	arm_TST
+	arm_TST_ZZ
+	arm_UADD16_EQ
+	arm_UADD16_NE
+	arm_UADD16_CS
+	arm_UADD16_CC
+	arm_UADD16_MI
+	arm_UADD16_PL
+	arm_UADD16_VS
+	arm_UADD16_VC
+	arm_UADD16_HI
+	arm_UADD16_LS
+	arm_UADD16_GE
+	arm_UADD16_LT
+	arm_UADD16_GT
+	arm_UADD16_LE
+	arm_UADD16
+	arm_UADD16_ZZ
+	arm_UADD8_EQ
+	arm_UADD8_NE
+	arm_UADD8_CS
+	arm_UADD8_CC
+	arm_UADD8_MI
+	arm_UADD8_PL
+	arm_UADD8_VS
+	arm_UADD8_VC
+	arm_UADD8_HI
+	arm_UADD8_LS
+	arm_UADD8_GE
+	arm_UADD8_LT
+	arm_UADD8_GT
+	arm_UADD8_LE
+	arm_UADD8
+	arm_UADD8_ZZ
+	arm_UASX_EQ
+	arm_UASX_NE
+	arm_UASX_CS
+	arm_UASX_CC
+	arm_UASX_MI
+	arm_UASX_PL
+	arm_UASX_VS
+	arm_UASX_VC
+	arm_UASX_HI
+	arm_UASX_LS
+	arm_UASX_GE
+	arm_UASX_LT
+	arm_UASX_GT
+	arm_UASX_LE
+	arm_UASX
+	arm_UASX_ZZ
+	arm_UBFX_EQ
+	arm_UBFX_NE
+	arm_UBFX_CS
+	arm_UBFX_CC
+	arm_UBFX_MI
+	arm_UBFX_PL
+	arm_UBFX_VS
+	arm_UBFX_VC
+	arm_UBFX_HI
+	arm_UBFX_LS
+	arm_UBFX_GE
+	arm_UBFX_LT
+	arm_UBFX_GT
+	arm_UBFX_LE
+	arm_UBFX
+	arm_UBFX_ZZ
+	arm_UHADD16_EQ
+	arm_UHADD16_NE
+	arm_UHADD16_CS
+	arm_UHADD16_CC
+	arm_UHADD16_MI
+	arm_UHADD16_PL
+	arm_UHADD16_VS
+	arm_UHADD16_VC
+	arm_UHADD16_HI
+	arm_UHADD16_LS
+	arm_UHADD16_GE
+	arm_UHADD16_LT
+	arm_UHADD16_GT
+	arm_UHADD16_LE
+	arm_UHADD16
+	arm_UHADD16_ZZ
+	arm_UHADD8_EQ
+	arm_UHADD8_NE
+	arm_UHADD8_CS
+	arm_UHADD8_CC
+	arm_UHADD8_MI
+	arm_UHADD8_PL
+	arm_UHADD8_VS
+	arm_UHADD8_VC
+	arm_UHADD8_HI
+	arm_UHADD8_LS
+	arm_UHADD8_GE
+	arm_UHADD8_LT
+	arm_UHADD8_GT
+	arm_UHADD8_LE
+	arm_UHADD8
+	arm_UHADD8_ZZ
+	arm_UHASX_EQ
+	arm_UHASX_NE
+	arm_UHASX_CS
+	arm_UHASX_CC
+	arm_UHASX_MI
+	arm_UHASX_PL
+	arm_UHASX_VS
+	arm_UHASX_VC
+	arm_UHASX_HI
+	arm_UHASX_LS
+	arm_UHASX_GE
+	arm_UHASX_LT
+	arm_UHASX_GT
+	arm_UHASX_LE
+	arm_UHASX
+	arm_UHASX_ZZ
+	arm_UHSAX_EQ
+	arm_UHSAX_NE
+	arm_UHSAX_CS
+	arm_UHSAX_CC
+	arm_UHSAX_MI
+	arm_UHSAX_PL
+	arm_UHSAX_VS
+	arm_UHSAX_VC
+	arm_UHSAX_HI
+	arm_UHSAX_LS
+	arm_UHSAX_GE
+	arm_UHSAX_LT
+	arm_UHSAX_GT
+	arm_UHSAX_LE
+	arm_UHSAX
+	arm_UHSAX_ZZ
+	arm_UHSUB16_EQ
+	arm_UHSUB16_NE
+	arm_UHSUB16_CS
+	arm_UHSUB16_CC
+	arm_UHSUB16_MI
+	arm_UHSUB16_PL
+	arm_UHSUB16_VS
+	arm_UHSUB16_VC
+	arm_UHSUB16_HI
+	arm_UHSUB16_LS
+	arm_UHSUB16_GE
+	arm_UHSUB16_LT
+	arm_UHSUB16_GT
+	arm_UHSUB16_LE
+	arm_UHSUB16
+	arm_UHSUB16_ZZ
+	arm_UHSUB8_EQ
+	arm_UHSUB8_NE
+	arm_UHSUB8_CS
+	arm_UHSUB8_CC
+	arm_UHSUB8_MI
+	arm_UHSUB8_PL
+	arm_UHSUB8_VS
+	arm_UHSUB8_VC
+	arm_UHSUB8_HI
+	arm_UHSUB8_LS
+	arm_UHSUB8_GE
+	arm_UHSUB8_LT
+	arm_UHSUB8_GT
+	arm_UHSUB8_LE
+	arm_UHSUB8
+	arm_UHSUB8_ZZ
+	arm_UMAAL_EQ
+	arm_UMAAL_NE
+	arm_UMAAL_CS
+	arm_UMAAL_CC
+	arm_UMAAL_MI
+	arm_UMAAL_PL
+	arm_UMAAL_VS
+	arm_UMAAL_VC
+	arm_UMAAL_HI
+	arm_UMAAL_LS
+	arm_UMAAL_GE
+	arm_UMAAL_LT
+	arm_UMAAL_GT
+	arm_UMAAL_LE
+	arm_UMAAL
+	arm_UMAAL_ZZ
+	arm_UMLAL_EQ
+	arm_UMLAL_NE
+	arm_UMLAL_CS
+	arm_UMLAL_CC
+	arm_UMLAL_MI
+	arm_UMLAL_PL
+	arm_UMLAL_VS
+	arm_UMLAL_VC
+	arm_UMLAL_HI
+	arm_UMLAL_LS
+	arm_UMLAL_GE
+	arm_UMLAL_LT
+	arm_UMLAL_GT
+	arm_UMLAL_LE
+	arm_UMLAL
+	arm_UMLAL_ZZ
+	arm_UMLAL_S_EQ
+	arm_UMLAL_S_NE
+	arm_UMLAL_S_CS
+	arm_UMLAL_S_CC
+	arm_UMLAL_S_MI
+	arm_UMLAL_S_PL
+	arm_UMLAL_S_VS
+	arm_UMLAL_S_VC
+	arm_UMLAL_S_HI
+	arm_UMLAL_S_LS
+	arm_UMLAL_S_GE
+	arm_UMLAL_S_LT
+	arm_UMLAL_S_GT
+	arm_UMLAL_S_LE
+	arm_UMLAL_S
+	arm_UMLAL_S_ZZ
+	arm_UMULL_EQ
+	arm_UMULL_NE
+	arm_UMULL_CS
+	arm_UMULL_CC
+	arm_UMULL_MI
+	arm_UMULL_PL
+	arm_UMULL_VS
+	arm_UMULL_VC
+	arm_UMULL_HI
+	arm_UMULL_LS
+	arm_UMULL_GE
+	arm_UMULL_LT
+	arm_UMULL_GT
+	arm_UMULL_LE
+	arm_UMULL
+	arm_UMULL_ZZ
+	arm_UMULL_S_EQ
+	arm_UMULL_S_NE
+	arm_UMULL_S_CS
+	arm_UMULL_S_CC
+	arm_UMULL_S_MI
+	arm_UMULL_S_PL
+	arm_UMULL_S_VS
+	arm_UMULL_S_VC
+	arm_UMULL_S_HI
+	arm_UMULL_S_LS
+	arm_UMULL_S_GE
+	arm_UMULL_S_LT
+	arm_UMULL_S_GT
+	arm_UMULL_S_LE
+	arm_UMULL_S
+	arm_UMULL_S_ZZ
+	arm_UNDEF
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	_
+	arm_UQADD16_EQ
+	arm_UQADD16_NE
+	arm_UQADD16_CS
+	arm_UQADD16_CC
+	arm_UQADD16_MI
+	arm_UQADD16_PL
+	arm_UQADD16_VS
+	arm_UQADD16_VC
+	arm_UQADD16_HI
+	arm_UQADD16_LS
+	arm_UQADD16_GE
+	arm_UQADD16_LT
+	arm_UQADD16_GT
+	arm_UQADD16_LE
+	arm_UQADD16
+	arm_UQADD16_ZZ
+	arm_UQADD8_EQ
+	arm_UQADD8_NE
+	arm_UQADD8_CS
+	arm_UQADD8_CC
+	arm_UQADD8_MI
+	arm_UQADD8_PL
+	arm_UQADD8_VS
+	arm_UQADD8_VC
+	arm_UQADD8_HI
+	arm_UQADD8_LS
+	arm_UQADD8_GE
+	arm_UQADD8_LT
+	arm_UQADD8_GT
+	arm_UQADD8_LE
+	arm_UQADD8
+	arm_UQADD8_ZZ
+	arm_UQASX_EQ
+	arm_UQASX_NE
+	arm_UQASX_CS
+	arm_UQASX_CC
+	arm_UQASX_MI
+	arm_UQASX_PL
+	arm_UQASX_VS
+	arm_UQASX_VC
+	arm_UQASX_HI
+	arm_UQASX_LS
+	arm_UQASX_GE
+	arm_UQASX_LT
+	arm_UQASX_GT
+	arm_UQASX_LE
+	arm_UQASX
+	arm_UQASX_ZZ
+	arm_UQSAX_EQ
+	arm_UQSAX_NE
+	arm_UQSAX_CS
+	arm_UQSAX_CC
+	arm_UQSAX_MI
+	arm_UQSAX_PL
+	arm_UQSAX_VS
+	arm_UQSAX_VC
+	arm_UQSAX_HI
+	arm_UQSAX_LS
+	arm_UQSAX_GE
+	arm_UQSAX_LT
+	arm_UQSAX_GT
+	arm_UQSAX_LE
+	arm_UQSAX
+	arm_UQSAX_ZZ
+	arm_UQSUB16_EQ
+	arm_UQSUB16_NE
+	arm_UQSUB16_CS
+	arm_UQSUB16_CC
+	arm_UQSUB16_MI
+	arm_UQSUB16_PL
+	arm_UQSUB16_VS
+	arm_UQSUB16_VC
+	arm_UQSUB16_HI
+	arm_UQSUB16_LS
+	arm_UQSUB16_GE
+	arm_UQSUB16_LT
+	arm_UQSUB16_GT
+	arm_UQSUB16_LE
+	arm_UQSUB16
+	arm_UQSUB16_ZZ
+	arm_UQSUB8_EQ
+	arm_UQSUB8_NE
+	arm_UQSUB8_CS
+	arm_UQSUB8_CC
+	arm_UQSUB8_MI
+	arm_UQSUB8_PL
+	arm_UQSUB8_VS
+	arm_UQSUB8_VC
+	arm_UQSUB8_HI
+	arm_UQSUB8_LS
+	arm_UQSUB8_GE
+	arm_UQSUB8_LT
+	arm_UQSUB8_GT
+	arm_UQSUB8_LE
+	arm_UQSUB8
+	arm_UQSUB8_ZZ
+	arm_USAD8_EQ
+	arm_USAD8_NE
+	arm_USAD8_CS
+	arm_USAD8_CC
+	arm_USAD8_MI
+	arm_USAD8_PL
+	arm_USAD8_VS
+	arm_USAD8_VC
+	arm_USAD8_HI
+	arm_USAD8_LS
+	arm_USAD8_GE
+	arm_USAD8_LT
+	arm_USAD8_GT
+	arm_USAD8_LE
+	arm_USAD8
+	arm_USAD8_ZZ
+	arm_USADA8_EQ
+	arm_USADA8_NE
+	arm_USADA8_CS
+	arm_USADA8_CC
+	arm_USADA8_MI
+	arm_USADA8_PL
+	arm_USADA8_VS
+	arm_USADA8_VC
+	arm_USADA8_HI
+	arm_USADA8_LS
+	arm_USADA8_GE
+	arm_USADA8_LT
+	arm_USADA8_GT
+	arm_USADA8_LE
+	arm_USADA8
+	arm_USADA8_ZZ
+	arm_USAT_EQ
+	arm_USAT_NE
+	arm_USAT_CS
+	arm_USAT_CC
+	arm_USAT_MI
+	arm_USAT_PL
+	arm_USAT_VS
+	arm_USAT_VC
+	arm_USAT_HI
+	arm_USAT_LS
+	arm_USAT_GE
+	arm_USAT_LT
+	arm_USAT_GT
+	arm_USAT_LE
+	arm_USAT
+	arm_USAT_ZZ
+	arm_USAT16_EQ
+	arm_USAT16_NE
+	arm_USAT16_CS
+	arm_USAT16_CC
+	arm_USAT16_MI
+	arm_USAT16_PL
+	arm_USAT16_VS
+	arm_USAT16_VC
+	arm_USAT16_HI
+	arm_USAT16_LS
+	arm_USAT16_GE
+	arm_USAT16_LT
+	arm_USAT16_GT
+	arm_USAT16_LE
+	arm_USAT16
+	arm_USAT16_ZZ
+	arm_USAX_EQ
+	arm_USAX_NE
+	arm_USAX_CS
+	arm_USAX_CC
+	arm_USAX_MI
+	arm_USAX_PL
+	arm_USAX_VS
+	arm_USAX_VC
+	arm_USAX_HI
+	arm_USAX_LS
+	arm_USAX_GE
+	arm_USAX_LT
+	arm_USAX_GT
+	arm_USAX_LE
+	arm_USAX
+	arm_USAX_ZZ
+	arm_USUB16_EQ
+	arm_USUB16_NE
+	arm_USUB16_CS
+	arm_USUB16_CC
+	arm_USUB16_MI
+	arm_USUB16_PL
+	arm_USUB16_VS
+	arm_USUB16_VC
+	arm_USUB16_HI
+	arm_USUB16_LS
+	arm_USUB16_GE
+	arm_USUB16_LT
+	arm_USUB16_GT
+	arm_USUB16_LE
+	arm_USUB16
+	arm_USUB16_ZZ
+	arm_USUB8_EQ
+	arm_USUB8_NE
+	arm_USUB8_CS
+	arm_USUB8_CC
+	arm_USUB8_MI
+	arm_USUB8_PL
+	arm_USUB8_VS
+	arm_USUB8_VC
+	arm_USUB8_HI
+	arm_USUB8_LS
+	arm_USUB8_GE
+	arm_USUB8_LT
+	arm_USUB8_GT
+	arm_USUB8_LE
+	arm_USUB8
+	arm_USUB8_ZZ
+	arm_UXTAB_EQ
+	arm_UXTAB_NE
+	arm_UXTAB_CS
+	arm_UXTAB_CC
+	arm_UXTAB_MI
+	arm_UXTAB_PL
+	arm_UXTAB_VS
+	arm_UXTAB_VC
+	arm_UXTAB_HI
+	arm_UXTAB_LS
+	arm_UXTAB_GE
+	arm_UXTAB_LT
+	arm_UXTAB_GT
+	arm_UXTAB_LE
+	arm_UXTAB
+	arm_UXTAB_ZZ
+	arm_UXTAB16_EQ
+	arm_UXTAB16_NE
+	arm_UXTAB16_CS
+	arm_UXTAB16_CC
+	arm_UXTAB16_MI
+	arm_UXTAB16_PL
+	arm_UXTAB16_VS
+	arm_UXTAB16_VC
+	arm_UXTAB16_HI
+	arm_UXTAB16_LS
+	arm_UXTAB16_GE
+	arm_UXTAB16_LT
+	arm_UXTAB16_GT
+	arm_UXTAB16_LE
+	arm_UXTAB16
+	arm_UXTAB16_ZZ
+	arm_UXTAH_EQ
+	arm_UXTAH_NE
+	arm_UXTAH_CS
+	arm_UXTAH_CC
+	arm_UXTAH_MI
+	arm_UXTAH_PL
+	arm_UXTAH_VS
+	arm_UXTAH_VC
+	arm_UXTAH_HI
+	arm_UXTAH_LS
+	arm_UXTAH_GE
+	arm_UXTAH_LT
+	arm_UXTAH_GT
+	arm_UXTAH_LE
+	arm_UXTAH
+	arm_UXTAH_ZZ
+	arm_UXTB_EQ
+	arm_UXTB_NE
+	arm_UXTB_CS
+	arm_UXTB_CC
+	arm_UXTB_MI
+	arm_UXTB_PL
+	arm_UXTB_VS
+	arm_UXTB_VC
+	arm_UXTB_HI
+	arm_UXTB_LS
+	arm_UXTB_GE
+	arm_UXTB_LT
+	arm_UXTB_GT
+	arm_UXTB_LE
+	arm_UXTB
+	arm_UXTB_ZZ
+	arm_UXTB16_EQ
+	arm_UXTB16_NE
+	arm_UXTB16_CS
+	arm_UXTB16_CC
+	arm_UXTB16_MI
+	arm_UXTB16_PL
+	arm_UXTB16_VS
+	arm_UXTB16_VC
+	arm_UXTB16_HI
+	arm_UXTB16_LS
+	arm_UXTB16_GE
+	arm_UXTB16_LT
+	arm_UXTB16_GT
+	arm_UXTB16_LE
+	arm_UXTB16
+	arm_UXTB16_ZZ
+	arm_UXTH_EQ
+	arm_UXTH_NE
+	arm_UXTH_CS
+	arm_UXTH_CC
+	arm_UXTH_MI
+	arm_UXTH_PL
+	arm_UXTH_VS
+	arm_UXTH_VC
+	arm_UXTH_HI
+	arm_UXTH_LS
+	arm_UXTH_GE
+	arm_UXTH_LT
+	arm_UXTH_GT
+	arm_UXTH_LE
+	arm_UXTH
+	arm_UXTH_ZZ
+	arm_VABS_EQ_F32
+	arm_VABS_NE_F32
+	arm_VABS_CS_F32
+	arm_VABS_CC_F32
+	arm_VABS_MI_F32
+	arm_VABS_PL_F32
+	arm_VABS_VS_F32
+	arm_VABS_VC_F32
+	arm_VABS_HI_F32
+	arm_VABS_LS_F32
+	arm_VABS_GE_F32
+	arm_VABS_LT_F32
+	arm_VABS_GT_F32
+	arm_VABS_LE_F32
+	arm_VABS_F32
+	arm_VABS_ZZ_F32
+	arm_VABS_EQ_F64
+	arm_VABS_NE_F64
+	arm_VABS_CS_F64
+	arm_VABS_CC_F64
+	arm_VABS_MI_F64
+	arm_VABS_PL_F64
+	arm_VABS_VS_F64
+	arm_VABS_VC_F64
+	arm_VABS_HI_F64
+	arm_VABS_LS_F64
+	arm_VABS_GE_F64
+	arm_VABS_LT_F64
+	arm_VABS_GT_F64
+	arm_VABS_LE_F64
+	arm_VABS_F64
+	arm_VABS_ZZ_F64
+	arm_VADD_EQ_F32
+	arm_VADD_NE_F32
+	arm_VADD_CS_F32
+	arm_VADD_CC_F32
+	arm_VADD_MI_F32
+	arm_VADD_PL_F32
+	arm_VADD_VS_F32
+	arm_VADD_VC_F32
+	arm_VADD_HI_F32
+	arm_VADD_LS_F32
+	arm_VADD_GE_F32
+	arm_VADD_LT_F32
+	arm_VADD_GT_F32
+	arm_VADD_LE_F32
+	arm_VADD_F32
+	arm_VADD_ZZ_F32
+	arm_VADD_EQ_F64
+	arm_VADD_NE_F64
+	arm_VADD_CS_F64
+	arm_VADD_CC_F64
+	arm_VADD_MI_F64
+	arm_VADD_PL_F64
+	arm_VADD_VS_F64
+	arm_VADD_VC_F64
+	arm_VADD_HI_F64
+	arm_VADD_LS_F64
+	arm_VADD_GE_F64
+	arm_VADD_LT_F64
+	arm_VADD_GT_F64
+	arm_VADD_LE_F64
+	arm_VADD_F64
+	arm_VADD_ZZ_F64
+	arm_VCMP_EQ_F32
+	arm_VCMP_NE_F32
+	arm_VCMP_CS_F32
+	arm_VCMP_CC_F32
+	arm_VCMP_MI_F32
+	arm_VCMP_PL_F32
+	arm_VCMP_VS_F32
+	arm_VCMP_VC_F32
+	arm_VCMP_HI_F32
+	arm_VCMP_LS_F32
+	arm_VCMP_GE_F32
+	arm_VCMP_LT_F32
+	arm_VCMP_GT_F32
+	arm_VCMP_LE_F32
+	arm_VCMP_F32
+	arm_VCMP_ZZ_F32
+	arm_VCMP_EQ_F64
+	arm_VCMP_NE_F64
+	arm_VCMP_CS_F64
+	arm_VCMP_CC_F64
+	arm_VCMP_MI_F64
+	arm_VCMP_PL_F64
+	arm_VCMP_VS_F64
+	arm_VCMP_VC_F64
+	arm_VCMP_HI_F64
+	arm_VCMP_LS_F64
+	arm_VCMP_GE_F64
+	arm_VCMP_LT_F64
+	arm_VCMP_GT_F64
+	arm_VCMP_LE_F64
+	arm_VCMP_F64
+	arm_VCMP_ZZ_F64
+	arm_VCMP_E_EQ_F32
+	arm_VCMP_E_NE_F32
+	arm_VCMP_E_CS_F32
+	arm_VCMP_E_CC_F32
+	arm_VCMP_E_MI_F32
+	arm_VCMP_E_PL_F32
+	arm_VCMP_E_VS_F32
+	arm_VCMP_E_VC_F32
+	arm_VCMP_E_HI_F32
+	arm_VCMP_E_LS_F32
+	arm_VCMP_E_GE_F32
+	arm_VCMP_E_LT_F32
+	arm_VCMP_E_GT_F32
+	arm_VCMP_E_LE_F32
+	arm_VCMP_E_F32
+	arm_VCMP_E_ZZ_F32
+	arm_VCMP_E_EQ_F64
+	arm_VCMP_E_NE_F64
+	arm_VCMP_E_CS_F64
+	arm_VCMP_E_CC_F64
+	arm_VCMP_E_MI_F64
+	arm_VCMP_E_PL_F64
+	arm_VCMP_E_VS_F64
+	arm_VCMP_E_VC_F64
+	arm_VCMP_E_HI_F64
+	arm_VCMP_E_LS_F64
+	arm_VCMP_E_GE_F64
+	arm_VCMP_E_LT_F64
+	arm_VCMP_E_GT_F64
+	arm_VCMP_E_LE_F64
+	arm_VCMP_E_F64
+	arm_VCMP_E_ZZ_F64
+	arm_VCVT_EQ_F32_FXS16
+	arm_VCVT_NE_F32_FXS16
+	arm_VCVT_CS_F32_FXS16
+	arm_VCVT_CC_F32_FXS16
+	arm_VCVT_MI_F32_FXS16
+	arm_VCVT_PL_F32_FXS16
+	arm_VCVT_VS_F32_FXS16
+	arm_VCVT_VC_F32_FXS16
+	arm_VCVT_HI_F32_FXS16
+	arm_VCVT_LS_F32_FXS16
+	arm_VCVT_GE_F32_FXS16
+	arm_VCVT_LT_F32_FXS16
+	arm_VCVT_GT_F32_FXS16
+	arm_VCVT_LE_F32_FXS16
+	arm_VCVT_F32_FXS16
+	arm_VCVT_ZZ_F32_FXS16
+	arm_VCVT_EQ_F32_FXS32
+	arm_VCVT_NE_F32_FXS32
+	arm_VCVT_CS_F32_FXS32
+	arm_VCVT_CC_F32_FXS32
+	arm_VCVT_MI_F32_FXS32
+	arm_VCVT_PL_F32_FXS32
+	arm_VCVT_VS_F32_FXS32
+	arm_VCVT_VC_F32_FXS32
+	arm_VCVT_HI_F32_FXS32
+	arm_VCVT_LS_F32_FXS32
+	arm_VCVT_GE_F32_FXS32
+	arm_VCVT_LT_F32_FXS32
+	arm_VCVT_GT_F32_FXS32
+	arm_VCVT_LE_F32_FXS32
+	arm_VCVT_F32_FXS32
+	arm_VCVT_ZZ_F32_FXS32
+	arm_VCVT_EQ_F32_FXU16
+	arm_VCVT_NE_F32_FXU16
+	arm_VCVT_CS_F32_FXU16
+	arm_VCVT_CC_F32_FXU16
+	arm_VCVT_MI_F32_FXU16
+	arm_VCVT_PL_F32_FXU16
+	arm_VCVT_VS_F32_FXU16
+	arm_VCVT_VC_F32_FXU16
+	arm_VCVT_HI_F32_FXU16
+	arm_VCVT_LS_F32_FXU16
+	arm_VCVT_GE_F32_FXU16
+	arm_VCVT_LT_F32_FXU16
+	arm_VCVT_GT_F32_FXU16
+	arm_VCVT_LE_F32_FXU16
+	arm_VCVT_F32_FXU16
+	arm_VCVT_ZZ_F32_FXU16
+	arm_VCVT_EQ_F32_FXU32
+	arm_VCVT_NE_F32_FXU32
+	arm_VCVT_CS_F32_FXU32
+	arm_VCVT_CC_F32_FXU32
+	arm_VCVT_MI_F32_FXU32
+	arm_VCVT_PL_F32_FXU32
+	arm_VCVT_VS_F32_FXU32
+	arm_VCVT_VC_F32_FXU32
+	arm_VCVT_HI_F32_FXU32
+	arm_VCVT_LS_F32_FXU32
+	arm_VCVT_GE_F32_FXU32
+	arm_VCVT_LT_F32_FXU32
+	arm_VCVT_GT_F32_FXU32
+	arm_VCVT_LE_F32_FXU32
+	arm_VCVT_F32_FXU32
+	arm_VCVT_ZZ_F32_FXU32
+	arm_VCVT_EQ_F64_FXS16
+	arm_VCVT_NE_F64_FXS16
+	arm_VCVT_CS_F64_FXS16
+	arm_VCVT_CC_F64_FXS16
+	arm_VCVT_MI_F64_FXS16
+	arm_VCVT_PL_F64_FXS16
+	arm_VCVT_VS_F64_FXS16
+	arm_VCVT_VC_F64_FXS16
+	arm_VCVT_HI_F64_FXS16
+	arm_VCVT_LS_F64_FXS16
+	arm_VCVT_GE_F64_FXS16
+	arm_VCVT_LT_F64_FXS16
+	arm_VCVT_GT_F64_FXS16
+	arm_VCVT_LE_F64_FXS16
+	arm_VCVT_F64_FXS16
+	arm_VCVT_ZZ_F64_FXS16
+	arm_VCVT_EQ_F64_FXS32
+	arm_VCVT_NE_F64_FXS32
+	arm_VCVT_CS_F64_FXS32
+	arm_VCVT_CC_F64_FXS32
+	arm_VCVT_MI_F64_FXS32
+	arm_VCVT_PL_F64_FXS32
+	arm_VCVT_VS_F64_FXS32
+	arm_VCVT_VC_F64_FXS32
+	arm_VCVT_HI_F64_FXS32
+	arm_VCVT_LS_F64_FXS32
+	arm_VCVT_GE_F64_FXS32
+	arm_VCVT_LT_F64_FXS32
+	arm_VCVT_GT_F64_FXS32
+	arm_VCVT_LE_F64_FXS32
+	arm_VCVT_F64_FXS32
+	arm_VCVT_ZZ_F64_FXS32
+	arm_VCVT_EQ_F64_FXU16
+	arm_VCVT_NE_F64_FXU16
+	arm_VCVT_CS_F64_FXU16
+	arm_VCVT_CC_F64_FXU16
+	arm_VCVT_MI_F64_FXU16
+	arm_VCVT_PL_F64_FXU16
+	arm_VCVT_VS_F64_FXU16
+	arm_VCVT_VC_F64_FXU16
+	arm_VCVT_HI_F64_FXU16
+	arm_VCVT_LS_F64_FXU16
+	arm_VCVT_GE_F64_FXU16
+	arm_VCVT_LT_F64_FXU16
+	arm_VCVT_GT_F64_FXU16
+	arm_VCVT_LE_F64_FXU16
+	arm_VCVT_F64_FXU16
+	arm_VCVT_ZZ_F64_FXU16
+	arm_VCVT_EQ_F64_FXU32
+	arm_VCVT_NE_F64_FXU32
+	arm_VCVT_CS_F64_FXU32
+	arm_VCVT_CC_F64_FXU32
+	arm_VCVT_MI_F64_FXU32
+	arm_VCVT_PL_F64_FXU32
+	arm_VCVT_VS_F64_FXU32
+	arm_VCVT_VC_F64_FXU32
+	arm_VCVT_HI_F64_FXU32
+	arm_VCVT_LS_F64_FXU32
+	arm_VCVT_GE_F64_FXU32
+	arm_VCVT_LT_F64_FXU32
+	arm_VCVT_GT_F64_FXU32
+	arm_VCVT_LE_F64_FXU32
+	arm_VCVT_F64_FXU32
+	arm_VCVT_ZZ_F64_FXU32
+	arm_VCVT_EQ_F32_U32
+	arm_VCVT_NE_F32_U32
+	arm_VCVT_CS_F32_U32
+	arm_VCVT_CC_F32_U32
+	arm_VCVT_MI_F32_U32
+	arm_VCVT_PL_F32_U32
+	arm_VCVT_VS_F32_U32
+	arm_VCVT_VC_F32_U32
+	arm_VCVT_HI_F32_U32
+	arm_VCVT_LS_F32_U32
+	arm_VCVT_GE_F32_U32
+	arm_VCVT_LT_F32_U32
+	arm_VCVT_GT_F32_U32
+	arm_VCVT_LE_F32_U32
+	arm_VCVT_F32_U32
+	arm_VCVT_ZZ_F32_U32
+	arm_VCVT_EQ_F32_S32
+	arm_VCVT_NE_F32_S32
+	arm_VCVT_CS_F32_S32
+	arm_VCVT_CC_F32_S32
+	arm_VCVT_MI_F32_S32
+	arm_VCVT_PL_F32_S32
+	arm_VCVT_VS_F32_S32
+	arm_VCVT_VC_F32_S32
+	arm_VCVT_HI_F32_S32
+	arm_VCVT_LS_F32_S32
+	arm_VCVT_GE_F32_S32
+	arm_VCVT_LT_F32_S32
+	arm_VCVT_GT_F32_S32
+	arm_VCVT_LE_F32_S32
+	arm_VCVT_F32_S32
+	arm_VCVT_ZZ_F32_S32
+	arm_VCVT_EQ_F64_U32
+	arm_VCVT_NE_F64_U32
+	arm_VCVT_CS_F64_U32
+	arm_VCVT_CC_F64_U32
+	arm_VCVT_MI_F64_U32
+	arm_VCVT_PL_F64_U32
+	arm_VCVT_VS_F64_U32
+	arm_VCVT_VC_F64_U32
+	arm_VCVT_HI_F64_U32
+	arm_VCVT_LS_F64_U32
+	arm_VCVT_GE_F64_U32
+	arm_VCVT_LT_F64_U32
+	arm_VCVT_GT_F64_U32
+	arm_VCVT_LE_F64_U32
+	arm_VCVT_F64_U32
+	arm_VCVT_ZZ_F64_U32
+	arm_VCVT_EQ_F64_S32
+	arm_VCVT_NE_F64_S32
+	arm_VCVT_CS_F64_S32
+	arm_VCVT_CC_F64_S32
+	arm_VCVT_MI_F64_S32
+	arm_VCVT_PL_F64_S32
+	arm_VCVT_VS_F64_S32
+	arm_VCVT_VC_F64_S32
+	arm_VCVT_HI_F64_S32
+	arm_VCVT_LS_F64_S32
+	arm_VCVT_GE_F64_S32
+	arm_VCVT_LT_F64_S32
+	arm_VCVT_GT_F64_S32
+	arm_VCVT_LE_F64_S32
+	arm_VCVT_F64_S32
+	arm_VCVT_ZZ_F64_S32
+	arm_VCVT_EQ_F64_F32
+	arm_VCVT_NE_F64_F32
+	arm_VCVT_CS_F64_F32
+	arm_VCVT_CC_F64_F32
+	arm_VCVT_MI_F64_F32
+	arm_VCVT_PL_F64_F32
+	arm_VCVT_VS_F64_F32
+	arm_VCVT_VC_F64_F32
+	arm_VCVT_HI_F64_F32
+	arm_VCVT_LS_F64_F32
+	arm_VCVT_GE_F64_F32
+	arm_VCVT_LT_F64_F32
+	arm_VCVT_GT_F64_F32
+	arm_VCVT_LE_F64_F32
+	arm_VCVT_F64_F32
+	arm_VCVT_ZZ_F64_F32
+	arm_VCVT_EQ_F32_F64
+	arm_VCVT_NE_F32_F64
+	arm_VCVT_CS_F32_F64
+	arm_VCVT_CC_F32_F64
+	arm_VCVT_MI_F32_F64
+	arm_VCVT_PL_F32_F64
+	arm_VCVT_VS_F32_F64
+	arm_VCVT_VC_F32_F64
+	arm_VCVT_HI_F32_F64
+	arm_VCVT_LS_F32_F64
+	arm_VCVT_GE_F32_F64
+	arm_VCVT_LT_F32_F64
+	arm_VCVT_GT_F32_F64
+	arm_VCVT_LE_F32_F64
+	arm_VCVT_F32_F64
+	arm_VCVT_ZZ_F32_F64
+	arm_VCVT_EQ_FXS16_F32
+	arm_VCVT_NE_FXS16_F32
+	arm_VCVT_CS_FXS16_F32
+	arm_VCVT_CC_FXS16_F32
+	arm_VCVT_MI_FXS16_F32
+	arm_VCVT_PL_FXS16_F32
+	arm_VCVT_VS_FXS16_F32
+	arm_VCVT_VC_FXS16_F32
+	arm_VCVT_HI_FXS16_F32
+	arm_VCVT_LS_FXS16_F32
+	arm_VCVT_GE_FXS16_F32
+	arm_VCVT_LT_FXS16_F32
+	arm_VCVT_GT_FXS16_F32
+	arm_VCVT_LE_FXS16_F32
+	arm_VCVT_FXS16_F32
+	arm_VCVT_ZZ_FXS16_F32
+	arm_VCVT_EQ_FXS16_F64
+	arm_VCVT_NE_FXS16_F64
+	arm_VCVT_CS_FXS16_F64
+	arm_VCVT_CC_FXS16_F64
+	arm_VCVT_MI_FXS16_F64
+	arm_VCVT_PL_FXS16_F64
+	arm_VCVT_VS_FXS16_F64
+	arm_VCVT_VC_FXS16_F64
+	arm_VCVT_HI_FXS16_F64
+	arm_VCVT_LS_FXS16_F64
+	arm_VCVT_GE_FXS16_F64
+	arm_VCVT_LT_FXS16_F64
+	arm_VCVT_GT_FXS16_F64
+	arm_VCVT_LE_FXS16_F64
+	arm_VCVT_FXS16_F64
+	arm_VCVT_ZZ_FXS16_F64
+	arm_VCVT_EQ_FXS32_F32
+	arm_VCVT_NE_FXS32_F32
+	arm_VCVT_CS_FXS32_F32
+	arm_VCVT_CC_FXS32_F32
+	arm_VCVT_MI_FXS32_F32
+	arm_VCVT_PL_FXS32_F32
+	arm_VCVT_VS_FXS32_F32
+	arm_VCVT_VC_FXS32_F32
+	arm_VCVT_HI_FXS32_F32
+	arm_VCVT_LS_FXS32_F32
+	arm_VCVT_GE_FXS32_F32
+	arm_VCVT_LT_FXS32_F32
+	arm_VCVT_GT_FXS32_F32
+	arm_VCVT_LE_FXS32_F32
+	arm_VCVT_FXS32_F32
+	arm_VCVT_ZZ_FXS32_F32
+	arm_VCVT_EQ_FXS32_F64
+	arm_VCVT_NE_FXS32_F64
+	arm_VCVT_CS_FXS32_F64
+	arm_VCVT_CC_FXS32_F64
+	arm_VCVT_MI_FXS32_F64
+	arm_VCVT_PL_FXS32_F64
+	arm_VCVT_VS_FXS32_F64
+	arm_VCVT_VC_FXS32_F64
+	arm_VCVT_HI_FXS32_F64
+	arm_VCVT_LS_FXS32_F64
+	arm_VCVT_GE_FXS32_F64
+	arm_VCVT_LT_FXS32_F64
+	arm_VCVT_GT_FXS32_F64
+	arm_VCVT_LE_FXS32_F64
+	arm_VCVT_FXS32_F64
+	arm_VCVT_ZZ_FXS32_F64
+	arm_VCVT_EQ_FXU16_F32
+	arm_VCVT_NE_FXU16_F32
+	arm_VCVT_CS_FXU16_F32
+	arm_VCVT_CC_FXU16_F32
+	arm_VCVT_MI_FXU16_F32
+	arm_VCVT_PL_FXU16_F32
+	arm_VCVT_VS_FXU16_F32
+	arm_VCVT_VC_FXU16_F32
+	arm_VCVT_HI_FXU16_F32
+	arm_VCVT_LS_FXU16_F32
+	arm_VCVT_GE_FXU16_F32
+	arm_VCVT_LT_FXU16_F32
+	arm_VCVT_GT_FXU16_F32
+	arm_VCVT_LE_FXU16_F32
+	arm_VCVT_FXU16_F32
+	arm_VCVT_ZZ_FXU16_F32
+	arm_VCVT_EQ_FXU16_F64
+	arm_VCVT_NE_FXU16_F64
+	arm_VCVT_CS_FXU16_F64
+	arm_VCVT_CC_FXU16_F64
+	arm_VCVT_MI_FXU16_F64
+	arm_VCVT_PL_FXU16_F64
+	arm_VCVT_VS_FXU16_F64
+	arm_VCVT_VC_FXU16_F64
+	arm_VCVT_HI_FXU16_F64
+	arm_VCVT_LS_FXU16_F64
+	arm_VCVT_GE_FXU16_F64
+	arm_VCVT_LT_FXU16_F64
+	arm_VCVT_GT_FXU16_F64
+	arm_VCVT_LE_FXU16_F64
+	arm_VCVT_FXU16_F64
+	arm_VCVT_ZZ_FXU16_F64
+	arm_VCVT_EQ_FXU32_F32
+	arm_VCVT_NE_FXU32_F32
+	arm_VCVT_CS_FXU32_F32
+	arm_VCVT_CC_FXU32_F32
+	arm_VCVT_MI_FXU32_F32
+	arm_VCVT_PL_FXU32_F32
+	arm_VCVT_VS_FXU32_F32
+	arm_VCVT_VC_FXU32_F32
+	arm_VCVT_HI_FXU32_F32
+	arm_VCVT_LS_FXU32_F32
+	arm_VCVT_GE_FXU32_F32
+	arm_VCVT_LT_FXU32_F32
+	arm_VCVT_GT_FXU32_F32
+	arm_VCVT_LE_FXU32_F32
+	arm_VCVT_FXU32_F32
+	arm_VCVT_ZZ_FXU32_F32
+	arm_VCVT_EQ_FXU32_F64
+	arm_VCVT_NE_FXU32_F64
+	arm_VCVT_CS_FXU32_F64
+	arm_VCVT_CC_FXU32_F64
+	arm_VCVT_MI_FXU32_F64
+	arm_VCVT_PL_FXU32_F64
+	arm_VCVT_VS_FXU32_F64
+	arm_VCVT_VC_FXU32_F64
+	arm_VCVT_HI_FXU32_F64
+	arm_VCVT_LS_FXU32_F64
+	arm_VCVT_GE_FXU32_F64
+	arm_VCVT_LT_FXU32_F64
+	arm_VCVT_GT_FXU32_F64
+	arm_VCVT_LE_FXU32_F64
+	arm_VCVT_FXU32_F64
+	arm_VCVT_ZZ_FXU32_F64
+	arm_VCVTB_EQ_F32_F16
+	arm_VCVTB_NE_F32_F16
+	arm_VCVTB_CS_F32_F16
+	arm_VCVTB_CC_F32_F16
+	arm_VCVTB_MI_F32_F16
+	arm_VCVTB_PL_F32_F16
+	arm_VCVTB_VS_F32_F16
+	arm_VCVTB_VC_F32_F16
+	arm_VCVTB_HI_F32_F16
+	arm_VCVTB_LS_F32_F16
+	arm_VCVTB_GE_F32_F16
+	arm_VCVTB_LT_F32_F16
+	arm_VCVTB_GT_F32_F16
+	arm_VCVTB_LE_F32_F16
+	arm_VCVTB_F32_F16
+	arm_VCVTB_ZZ_F32_F16
+	arm_VCVTB_EQ_F16_F32
+	arm_VCVTB_NE_F16_F32
+	arm_VCVTB_CS_F16_F32
+	arm_VCVTB_CC_F16_F32
+	arm_VCVTB_MI_F16_F32
+	arm_VCVTB_PL_F16_F32
+	arm_VCVTB_VS_F16_F32
+	arm_VCVTB_VC_F16_F32
+	arm_VCVTB_HI_F16_F32
+	arm_VCVTB_LS_F16_F32
+	arm_VCVTB_GE_F16_F32
+	arm_VCVTB_LT_F16_F32
+	arm_VCVTB_GT_F16_F32
+	arm_VCVTB_LE_F16_F32
+	arm_VCVTB_F16_F32
+	arm_VCVTB_ZZ_F16_F32
+	arm_VCVTT_EQ_F32_F16
+	arm_VCVTT_NE_F32_F16
+	arm_VCVTT_CS_F32_F16
+	arm_VCVTT_CC_F32_F16
+	arm_VCVTT_MI_F32_F16
+	arm_VCVTT_PL_F32_F16
+	arm_VCVTT_VS_F32_F16
+	arm_VCVTT_VC_F32_F16
+	arm_VCVTT_HI_F32_F16
+	arm_VCVTT_LS_F32_F16
+	arm_VCVTT_GE_F32_F16
+	arm_VCVTT_LT_F32_F16
+	arm_VCVTT_GT_F32_F16
+	arm_VCVTT_LE_F32_F16
+	arm_VCVTT_F32_F16
+	arm_VCVTT_ZZ_F32_F16
+	arm_VCVTT_EQ_F16_F32
+	arm_VCVTT_NE_F16_F32
+	arm_VCVTT_CS_F16_F32
+	arm_VCVTT_CC_F16_F32
+	arm_VCVTT_MI_F16_F32
+	arm_VCVTT_PL_F16_F32
+	arm_VCVTT_VS_F16_F32
+	arm_VCVTT_VC_F16_F32
+	arm_VCVTT_HI_F16_F32
+	arm_VCVTT_LS_F16_F32
+	arm_VCVTT_GE_F16_F32
+	arm_VCVTT_LT_F16_F32
+	arm_VCVTT_GT_F16_F32
+	arm_VCVTT_LE_F16_F32
+	arm_VCVTT_F16_F32
+	arm_VCVTT_ZZ_F16_F32
+	arm_VCVTR_EQ_U32_F32
+	arm_VCVTR_NE_U32_F32
+	arm_VCVTR_CS_U32_F32
+	arm_VCVTR_CC_U32_F32
+	arm_VCVTR_MI_U32_F32
+	arm_VCVTR_PL_U32_F32
+	arm_VCVTR_VS_U32_F32
+	arm_VCVTR_VC_U32_F32
+	arm_VCVTR_HI_U32_F32
+	arm_VCVTR_LS_U32_F32
+	arm_VCVTR_GE_U32_F32
+	arm_VCVTR_LT_U32_F32
+	arm_VCVTR_GT_U32_F32
+	arm_VCVTR_LE_U32_F32
+	arm_VCVTR_U32_F32
+	arm_VCVTR_ZZ_U32_F32
+	arm_VCVTR_EQ_U32_F64
+	arm_VCVTR_NE_U32_F64
+	arm_VCVTR_CS_U32_F64
+	arm_VCVTR_CC_U32_F64
+	arm_VCVTR_MI_U32_F64
+	arm_VCVTR_PL_U32_F64
+	arm_VCVTR_VS_U32_F64
+	arm_VCVTR_VC_U32_F64
+	arm_VCVTR_HI_U32_F64
+	arm_VCVTR_LS_U32_F64
+	arm_VCVTR_GE_U32_F64
+	arm_VCVTR_LT_U32_F64
+	arm_VCVTR_GT_U32_F64
+	arm_VCVTR_LE_U32_F64
+	arm_VCVTR_U32_F64
+	arm_VCVTR_ZZ_U32_F64
+	arm_VCVTR_EQ_S32_F32
+	arm_VCVTR_NE_S32_F32
+	arm_VCVTR_CS_S32_F32
+	arm_VCVTR_CC_S32_F32
+	arm_VCVTR_MI_S32_F32
+	arm_VCVTR_PL_S32_F32
+	arm_VCVTR_VS_S32_F32
+	arm_VCVTR_VC_S32_F32
+	arm_VCVTR_HI_S32_F32
+	arm_VCVTR_LS_S32_F32
+	arm_VCVTR_GE_S32_F32
+	arm_VCVTR_LT_S32_F32
+	arm_VCVTR_GT_S32_F32
+	arm_VCVTR_LE_S32_F32
+	arm_VCVTR_S32_F32
+	arm_VCVTR_ZZ_S32_F32
+	arm_VCVTR_EQ_S32_F64
+	arm_VCVTR_NE_S32_F64
+	arm_VCVTR_CS_S32_F64
+	arm_VCVTR_CC_S32_F64
+	arm_VCVTR_MI_S32_F64
+	arm_VCVTR_PL_S32_F64
+	arm_VCVTR_VS_S32_F64
+	arm_VCVTR_VC_S32_F64
+	arm_VCVTR_HI_S32_F64
+	arm_VCVTR_LS_S32_F64
+	arm_VCVTR_GE_S32_F64
+	arm_VCVTR_LT_S32_F64
+	arm_VCVTR_GT_S32_F64
+	arm_VCVTR_LE_S32_F64
+	arm_VCVTR_S32_F64
+	arm_VCVTR_ZZ_S32_F64
+	arm_VCVT_EQ_U32_F32
+	arm_VCVT_NE_U32_F32
+	arm_VCVT_CS_U32_F32
+	arm_VCVT_CC_U32_F32
+	arm_VCVT_MI_U32_F32
+	arm_VCVT_PL_U32_F32
+	arm_VCVT_VS_U32_F32
+	arm_VCVT_VC_U32_F32
+	arm_VCVT_HI_U32_F32
+	arm_VCVT_LS_U32_F32
+	arm_VCVT_GE_U32_F32
+	arm_VCVT_LT_U32_F32
+	arm_VCVT_GT_U32_F32
+	arm_VCVT_LE_U32_F32
+	arm_VCVT_U32_F32
+	arm_VCVT_ZZ_U32_F32
+	arm_VCVT_EQ_U32_F64
+	arm_VCVT_NE_U32_F64
+	arm_VCVT_CS_U32_F64
+	arm_VCVT_CC_U32_F64
+	arm_VCVT_MI_U32_F64
+	arm_VCVT_PL_U32_F64
+	arm_VCVT_VS_U32_F64
+	arm_VCVT_VC_U32_F64
+	arm_VCVT_HI_U32_F64
+	arm_VCVT_LS_U32_F64
+	arm_VCVT_GE_U32_F64
+	arm_VCVT_LT_U32_F64
+	arm_VCVT_GT_U32_F64
+	arm_VCVT_LE_U32_F64
+	arm_VCVT_U32_F64
+	arm_VCVT_ZZ_U32_F64
+	arm_VCVT_EQ_S32_F32
+	arm_VCVT_NE_S32_F32
+	arm_VCVT_CS_S32_F32
+	arm_VCVT_CC_S32_F32
+	arm_VCVT_MI_S32_F32
+	arm_VCVT_PL_S32_F32
+	arm_VCVT_VS_S32_F32
+	arm_VCVT_VC_S32_F32
+	arm_VCVT_HI_S32_F32
+	arm_VCVT_LS_S32_F32
+	arm_VCVT_GE_S32_F32
+	arm_VCVT_LT_S32_F32
+	arm_VCVT_GT_S32_F32
+	arm_VCVT_LE_S32_F32
+	arm_VCVT_S32_F32
+	arm_VCVT_ZZ_S32_F32
+	arm_VCVT_EQ_S32_F64
+	arm_VCVT_NE_S32_F64
+	arm_VCVT_CS_S32_F64
+	arm_VCVT_CC_S32_F64
+	arm_VCVT_MI_S32_F64
+	arm_VCVT_PL_S32_F64
+	arm_VCVT_VS_S32_F64
+	arm_VCVT_VC_S32_F64
+	arm_VCVT_HI_S32_F64
+	arm_VCVT_LS_S32_F64
+	arm_VCVT_GE_S32_F64
+	arm_VCVT_LT_S32_F64
+	arm_VCVT_GT_S32_F64
+	arm_VCVT_LE_S32_F64
+	arm_VCVT_S32_F64
+	arm_VCVT_ZZ_S32_F64
+	arm_VDIV_EQ_F32
+	arm_VDIV_NE_F32
+	arm_VDIV_CS_F32
+	arm_VDIV_CC_F32
+	arm_VDIV_MI_F32
+	arm_VDIV_PL_F32
+	arm_VDIV_VS_F32
+	arm_VDIV_VC_F32
+	arm_VDIV_HI_F32
+	arm_VDIV_LS_F32
+	arm_VDIV_GE_F32
+	arm_VDIV_LT_F32
+	arm_VDIV_GT_F32
+	arm_VDIV_LE_F32
+	arm_VDIV_F32
+	arm_VDIV_ZZ_F32
+	arm_VDIV_EQ_F64
+	arm_VDIV_NE_F64
+	arm_VDIV_CS_F64
+	arm_VDIV_CC_F64
+	arm_VDIV_MI_F64
+	arm_VDIV_PL_F64
+	arm_VDIV_VS_F64
+	arm_VDIV_VC_F64
+	arm_VDIV_HI_F64
+	arm_VDIV_LS_F64
+	arm_VDIV_GE_F64
+	arm_VDIV_LT_F64
+	arm_VDIV_GT_F64
+	arm_VDIV_LE_F64
+	arm_VDIV_F64
+	arm_VDIV_ZZ_F64
+	arm_VLDR_EQ
+	arm_VLDR_NE
+	arm_VLDR_CS
+	arm_VLDR_CC
+	arm_VLDR_MI
+	arm_VLDR_PL
+	arm_VLDR_VS
+	arm_VLDR_VC
+	arm_VLDR_HI
+	arm_VLDR_LS
+	arm_VLDR_GE
+	arm_VLDR_LT
+	arm_VLDR_GT
+	arm_VLDR_LE
+	arm_VLDR
+	arm_VLDR_ZZ
+	arm_VMLA_EQ_F32
+	arm_VMLA_NE_F32
+	arm_VMLA_CS_F32
+	arm_VMLA_CC_F32
+	arm_VMLA_MI_F32
+	arm_VMLA_PL_F32
+	arm_VMLA_VS_F32
+	arm_VMLA_VC_F32
+	arm_VMLA_HI_F32
+	arm_VMLA_LS_F32
+	arm_VMLA_GE_F32
+	arm_VMLA_LT_F32
+	arm_VMLA_GT_F32
+	arm_VMLA_LE_F32
+	arm_VMLA_F32
+	arm_VMLA_ZZ_F32
+	arm_VMLA_EQ_F64
+	arm_VMLA_NE_F64
+	arm_VMLA_CS_F64
+	arm_VMLA_CC_F64
+	arm_VMLA_MI_F64
+	arm_VMLA_PL_F64
+	arm_VMLA_VS_F64
+	arm_VMLA_VC_F64
+	arm_VMLA_HI_F64
+	arm_VMLA_LS_F64
+	arm_VMLA_GE_F64
+	arm_VMLA_LT_F64
+	arm_VMLA_GT_F64
+	arm_VMLA_LE_F64
+	arm_VMLA_F64
+	arm_VMLA_ZZ_F64
+	arm_VMLS_EQ_F32
+	arm_VMLS_NE_F32
+	arm_VMLS_CS_F32
+	arm_VMLS_CC_F32
+	arm_VMLS_MI_F32
+	arm_VMLS_PL_F32
+	arm_VMLS_VS_F32
+	arm_VMLS_VC_F32
+	arm_VMLS_HI_F32
+	arm_VMLS_LS_F32
+	arm_VMLS_GE_F32
+	arm_VMLS_LT_F32
+	arm_VMLS_GT_F32
+	arm_VMLS_LE_F32
+	arm_VMLS_F32
+	arm_VMLS_ZZ_F32
+	arm_VMLS_EQ_F64
+	arm_VMLS_NE_F64
+	arm_VMLS_CS_F64
+	arm_VMLS_CC_F64
+	arm_VMLS_MI_F64
+	arm_VMLS_PL_F64
+	arm_VMLS_VS_F64
+	arm_VMLS_VC_F64
+	arm_VMLS_HI_F64
+	arm_VMLS_LS_F64
+	arm_VMLS_GE_F64
+	arm_VMLS_LT_F64
+	arm_VMLS_GT_F64
+	arm_VMLS_LE_F64
+	arm_VMLS_F64
+	arm_VMLS_ZZ_F64
+	arm_VMOV_EQ
+	arm_VMOV_NE
+	arm_VMOV_CS
+	arm_VMOV_CC
+	arm_VMOV_MI
+	arm_VMOV_PL
+	arm_VMOV_VS
+	arm_VMOV_VC
+	arm_VMOV_HI
+	arm_VMOV_LS
+	arm_VMOV_GE
+	arm_VMOV_LT
+	arm_VMOV_GT
+	arm_VMOV_LE
+	arm_VMOV
+	arm_VMOV_ZZ
+	arm_VMOV_EQ_32
+	arm_VMOV_NE_32
+	arm_VMOV_CS_32
+	arm_VMOV_CC_32
+	arm_VMOV_MI_32
+	arm_VMOV_PL_32
+	arm_VMOV_VS_32
+	arm_VMOV_VC_32
+	arm_VMOV_HI_32
+	arm_VMOV_LS_32
+	arm_VMOV_GE_32
+	arm_VMOV_LT_32
+	arm_VMOV_GT_32
+	arm_VMOV_LE_32
+	arm_VMOV_32
+	arm_VMOV_ZZ_32
+	arm_VMOV_EQ_F32
+	arm_VMOV_NE_F32
+	arm_VMOV_CS_F32
+	arm_VMOV_CC_F32
+	arm_VMOV_MI_F32
+	arm_VMOV_PL_F32
+	arm_VMOV_VS_F32
+	arm_VMOV_VC_F32
+	arm_VMOV_HI_F32
+	arm_VMOV_LS_F32
+	arm_VMOV_GE_F32
+	arm_VMOV_LT_F32
+	arm_VMOV_GT_F32
+	arm_VMOV_LE_F32
+	arm_VMOV_F32
+	arm_VMOV_ZZ_F32
+	arm_VMOV_EQ_F64
+	arm_VMOV_NE_F64
+	arm_VMOV_CS_F64
+	arm_VMOV_CC_F64
+	arm_VMOV_MI_F64
+	arm_VMOV_PL_F64
+	arm_VMOV_VS_F64
+	arm_VMOV_VC_F64
+	arm_VMOV_HI_F64
+	arm_VMOV_LS_F64
+	arm_VMOV_GE_F64
+	arm_VMOV_LT_F64
+	arm_VMOV_GT_F64
+	arm_VMOV_LE_F64
+	arm_VMOV_F64
+	arm_VMOV_ZZ_F64
+	arm_VMRS_EQ
+	arm_VMRS_NE
+	arm_VMRS_CS
+	arm_VMRS_CC
+	arm_VMRS_MI
+	arm_VMRS_PL
+	arm_VMRS_VS
+	arm_VMRS_VC
+	arm_VMRS_HI
+	arm_VMRS_LS
+	arm_VMRS_GE
+	arm_VMRS_LT
+	arm_VMRS_GT
+	arm_VMRS_LE
+	arm_VMRS
+	arm_VMRS_ZZ
+	arm_VMSR_EQ
+	arm_VMSR_NE
+	arm_VMSR_CS
+	arm_VMSR_CC
+	arm_VMSR_MI
+	arm_VMSR_PL
+	arm_VMSR_VS
+	arm_VMSR_VC
+	arm_VMSR_HI
+	arm_VMSR_LS
+	arm_VMSR_GE
+	arm_VMSR_LT
+	arm_VMSR_GT
+	arm_VMSR_LE
+	arm_VMSR
+	arm_VMSR_ZZ
+	arm_VMUL_EQ_F32
+	arm_VMUL_NE_F32
+	arm_VMUL_CS_F32
+	arm_VMUL_CC_F32
+	arm_VMUL_MI_F32
+	arm_VMUL_PL_F32
+	arm_VMUL_VS_F32
+	arm_VMUL_VC_F32
+	arm_VMUL_HI_F32
+	arm_VMUL_LS_F32
+	arm_VMUL_GE_F32
+	arm_VMUL_LT_F32
+	arm_VMUL_GT_F32
+	arm_VMUL_LE_F32
+	arm_VMUL_F32
+	arm_VMUL_ZZ_F32
+	arm_VMUL_EQ_F64
+	arm_VMUL_NE_F64
+	arm_VMUL_CS_F64
+	arm_VMUL_CC_F64
+	arm_VMUL_MI_F64
+	arm_VMUL_PL_F64
+	arm_VMUL_VS_F64
+	arm_VMUL_VC_F64
+	arm_VMUL_HI_F64
+	arm_VMUL_LS_F64
+	arm_VMUL_GE_F64
+	arm_VMUL_LT_F64
+	arm_VMUL_GT_F64
+	arm_VMUL_LE_F64
+	arm_VMUL_F64
+	arm_VMUL_ZZ_F64
+	arm_VNEG_EQ_F32
+	arm_VNEG_NE_F32
+	arm_VNEG_CS_F32
+	arm_VNEG_CC_F32
+	arm_VNEG_MI_F32
+	arm_VNEG_PL_F32
+	arm_VNEG_VS_F32
+	arm_VNEG_VC_F32
+	arm_VNEG_HI_F32
+	arm_VNEG_LS_F32
+	arm_VNEG_GE_F32
+	arm_VNEG_LT_F32
+	arm_VNEG_GT_F32
+	arm_VNEG_LE_F32
+	arm_VNEG_F32
+	arm_VNEG_ZZ_F32
+	arm_VNEG_EQ_F64
+	arm_VNEG_NE_F64
+	arm_VNEG_CS_F64
+	arm_VNEG_CC_F64
+	arm_VNEG_MI_F64
+	arm_VNEG_PL_F64
+	arm_VNEG_VS_F64
+	arm_VNEG_VC_F64
+	arm_VNEG_HI_F64
+	arm_VNEG_LS_F64
+	arm_VNEG_GE_F64
+	arm_VNEG_LT_F64
+	arm_VNEG_GT_F64
+	arm_VNEG_LE_F64
+	arm_VNEG_F64
+	arm_VNEG_ZZ_F64
+	arm_VNMLS_EQ_F32
+	arm_VNMLS_NE_F32
+	arm_VNMLS_CS_F32
+	arm_VNMLS_CC_F32
+	arm_VNMLS_MI_F32
+	arm_VNMLS_PL_F32
+	arm_VNMLS_VS_F32
+	arm_VNMLS_VC_F32
+	arm_VNMLS_HI_F32
+	arm_VNMLS_LS_F32
+	arm_VNMLS_GE_F32
+	arm_VNMLS_LT_F32
+	arm_VNMLS_GT_F32
+	arm_VNMLS_LE_F32
+	arm_VNMLS_F32
+	arm_VNMLS_ZZ_F32
+	arm_VNMLS_EQ_F64
+	arm_VNMLS_NE_F64
+	arm_VNMLS_CS_F64
+	arm_VNMLS_CC_F64
+	arm_VNMLS_MI_F64
+	arm_VNMLS_PL_F64
+	arm_VNMLS_VS_F64
+	arm_VNMLS_VC_F64
+	arm_VNMLS_HI_F64
+	arm_VNMLS_LS_F64
+	arm_VNMLS_GE_F64
+	arm_VNMLS_LT_F64
+	arm_VNMLS_GT_F64
+	arm_VNMLS_LE_F64
+	arm_VNMLS_F64
+	arm_VNMLS_ZZ_F64
+	arm_VNMLA_EQ_F32
+	arm_VNMLA_NE_F32
+	arm_VNMLA_CS_F32
+	arm_VNMLA_CC_F32
+	arm_VNMLA_MI_F32
+	arm_VNMLA_PL_F32
+	arm_VNMLA_VS_F32
+	arm_VNMLA_VC_F32
+	arm_VNMLA_HI_F32
+	arm_VNMLA_LS_F32
+	arm_VNMLA_GE_F32
+	arm_VNMLA_LT_F32
+	arm_VNMLA_GT_F32
+	arm_VNMLA_LE_F32
+	arm_VNMLA_F32
+	arm_VNMLA_ZZ_F32
+	arm_VNMLA_EQ_F64
+	arm_VNMLA_NE_F64
+	arm_VNMLA_CS_F64
+	arm_VNMLA_CC_F64
+	arm_VNMLA_MI_F64
+	arm_VNMLA_PL_F64
+	arm_VNMLA_VS_F64
+	arm_VNMLA_VC_F64
+	arm_VNMLA_HI_F64
+	arm_VNMLA_LS_F64
+	arm_VNMLA_GE_F64
+	arm_VNMLA_LT_F64
+	arm_VNMLA_GT_F64
+	arm_VNMLA_LE_F64
+	arm_VNMLA_F64
+	arm_VNMLA_ZZ_F64
+	arm_VNMUL_EQ_F32
+	arm_VNMUL_NE_F32
+	arm_VNMUL_CS_F32
+	arm_VNMUL_CC_F32
+	arm_VNMUL_MI_F32
+	arm_VNMUL_PL_F32
+	arm_VNMUL_VS_F32
+	arm_VNMUL_VC_F32
+	arm_VNMUL_HI_F32
+	arm_VNMUL_LS_F32
+	arm_VNMUL_GE_F32
+	arm_VNMUL_LT_F32
+	arm_VNMUL_GT_F32
+	arm_VNMUL_LE_F32
+	arm_VNMUL_F32
+	arm_VNMUL_ZZ_F32
+	arm_VNMUL_EQ_F64
+	arm_VNMUL_NE_F64
+	arm_VNMUL_CS_F64
+	arm_VNMUL_CC_F64
+	arm_VNMUL_MI_F64
+	arm_VNMUL_PL_F64
+	arm_VNMUL_VS_F64
+	arm_VNMUL_VC_F64
+	arm_VNMUL_HI_F64
+	arm_VNMUL_LS_F64
+	arm_VNMUL_GE_F64
+	arm_VNMUL_LT_F64
+	arm_VNMUL_GT_F64
+	arm_VNMUL_LE_F64
+	arm_VNMUL_F64
+	arm_VNMUL_ZZ_F64
+	arm_VSQRT_EQ_F32
+	arm_VSQRT_NE_F32
+	arm_VSQRT_CS_F32
+	arm_VSQRT_CC_F32
+	arm_VSQRT_MI_F32
+	arm_VSQRT_PL_F32
+	arm_VSQRT_VS_F32
+	arm_VSQRT_VC_F32
+	arm_VSQRT_HI_F32
+	arm_VSQRT_LS_F32
+	arm_VSQRT_GE_F32
+	arm_VSQRT_LT_F32
+	arm_VSQRT_GT_F32
+	arm_VSQRT_LE_F32
+	arm_VSQRT_F32
+	arm_VSQRT_ZZ_F32
+	arm_VSQRT_EQ_F64
+	arm_VSQRT_NE_F64
+	arm_VSQRT_CS_F64
+	arm_VSQRT_CC_F64
+	arm_VSQRT_MI_F64
+	arm_VSQRT_PL_F64
+	arm_VSQRT_VS_F64
+	arm_VSQRT_VC_F64
+	arm_VSQRT_HI_F64
+	arm_VSQRT_LS_F64
+	arm_VSQRT_GE_F64
+	arm_VSQRT_LT_F64
+	arm_VSQRT_GT_F64
+	arm_VSQRT_LE_F64
+	arm_VSQRT_F64
+	arm_VSQRT_ZZ_F64
+	arm_VSTR_EQ
+	arm_VSTR_NE
+	arm_VSTR_CS
+	arm_VSTR_CC
+	arm_VSTR_MI
+	arm_VSTR_PL
+	arm_VSTR_VS
+	arm_VSTR_VC
+	arm_VSTR_HI
+	arm_VSTR_LS
+	arm_VSTR_GE
+	arm_VSTR_LT
+	arm_VSTR_GT
+	arm_VSTR_LE
+	arm_VSTR
+	arm_VSTR_ZZ
+	arm_VSUB_EQ_F32
+	arm_VSUB_NE_F32
+	arm_VSUB_CS_F32
+	arm_VSUB_CC_F32
+	arm_VSUB_MI_F32
+	arm_VSUB_PL_F32
+	arm_VSUB_VS_F32
+	arm_VSUB_VC_F32
+	arm_VSUB_HI_F32
+	arm_VSUB_LS_F32
+	arm_VSUB_GE_F32
+	arm_VSUB_LT_F32
+	arm_VSUB_GT_F32
+	arm_VSUB_LE_F32
+	arm_VSUB_F32
+	arm_VSUB_ZZ_F32
+	arm_VSUB_EQ_F64
+	arm_VSUB_NE_F64
+	arm_VSUB_CS_F64
+	arm_VSUB_CC_F64
+	arm_VSUB_MI_F64
+	arm_VSUB_PL_F64
+	arm_VSUB_VS_F64
+	arm_VSUB_VC_F64
+	arm_VSUB_HI_F64
+	arm_VSUB_LS_F64
+	arm_VSUB_GE_F64
+	arm_VSUB_LT_F64
+	arm_VSUB_GT_F64
+	arm_VSUB_LE_F64
+	arm_VSUB_F64
+	arm_VSUB_ZZ_F64
+	arm_WFE_EQ
+	arm_WFE_NE
+	arm_WFE_CS
+	arm_WFE_CC
+	arm_WFE_MI
+	arm_WFE_PL
+	arm_WFE_VS
+	arm_WFE_VC
+	arm_WFE_HI
+	arm_WFE_LS
+	arm_WFE_GE
+	arm_WFE_LT
+	arm_WFE_GT
+	arm_WFE_LE
+	arm_WFE
+	arm_WFE_ZZ
+	arm_WFI_EQ
+	arm_WFI_NE
+	arm_WFI_CS
+	arm_WFI_CC
+	arm_WFI_MI
+	arm_WFI_PL
+	arm_WFI_VS
+	arm_WFI_VC
+	arm_WFI_HI
+	arm_WFI_LS
+	arm_WFI_GE
+	arm_WFI_LT
+	arm_WFI_GT
+	arm_WFI_LE
+	arm_WFI
+	arm_WFI_ZZ
+	arm_YIELD_EQ
+	arm_YIELD_NE
+	arm_YIELD_CS
+	arm_YIELD_CC
+	arm_YIELD_MI
+	arm_YIELD_PL
+	arm_YIELD_VS
+	arm_YIELD_VC
+	arm_YIELD_HI
+	arm_YIELD_LS
+	arm_YIELD_GE
+	arm_YIELD_LT
+	arm_YIELD_GT
+	arm_YIELD_LE
+	arm_YIELD
+	arm_YIELD_ZZ
+)
+
+var arm_opstr = [...]string{
+	arm_ADC_EQ:            "ADC.EQ",
+	arm_ADC_NE:            "ADC.NE",
+	arm_ADC_CS:            "ADC.CS",
+	arm_ADC_CC:            "ADC.CC",
+	arm_ADC_MI:            "ADC.MI",
+	arm_ADC_PL:            "ADC.PL",
+	arm_ADC_VS:            "ADC.VS",
+	arm_ADC_VC:            "ADC.VC",
+	arm_ADC_HI:            "ADC.HI",
+	arm_ADC_LS:            "ADC.LS",
+	arm_ADC_GE:            "ADC.GE",
+	arm_ADC_LT:            "ADC.LT",
+	arm_ADC_GT:            "ADC.GT",
+	arm_ADC_LE:            "ADC.LE",
+	arm_ADC:               "ADC",
+	arm_ADC_ZZ:            "ADC.ZZ",
+	arm_ADC_S_EQ:          "ADC.S.EQ",
+	arm_ADC_S_NE:          "ADC.S.NE",
+	arm_ADC_S_CS:          "ADC.S.CS",
+	arm_ADC_S_CC:          "ADC.S.CC",
+	arm_ADC_S_MI:          "ADC.S.MI",
+	arm_ADC_S_PL:          "ADC.S.PL",
+	arm_ADC_S_VS:          "ADC.S.VS",
+	arm_ADC_S_VC:          "ADC.S.VC",
+	arm_ADC_S_HI:          "ADC.S.HI",
+	arm_ADC_S_LS:          "ADC.S.LS",
+	arm_ADC_S_GE:          "ADC.S.GE",
+	arm_ADC_S_LT:          "ADC.S.LT",
+	arm_ADC_S_GT:          "ADC.S.GT",
+	arm_ADC_S_LE:          "ADC.S.LE",
+	arm_ADC_S:             "ADC.S",
+	arm_ADC_S_ZZ:          "ADC.S.ZZ",
+	arm_ADD_EQ:            "ADD.EQ",
+	arm_ADD_NE:            "ADD.NE",
+	arm_ADD_CS:            "ADD.CS",
+	arm_ADD_CC:            "ADD.CC",
+	arm_ADD_MI:            "ADD.MI",
+	arm_ADD_PL:            "ADD.PL",
+	arm_ADD_VS:            "ADD.VS",
+	arm_ADD_VC:            "ADD.VC",
+	arm_ADD_HI:            "ADD.HI",
+	arm_ADD_LS:            "ADD.LS",
+	arm_ADD_GE:            "ADD.GE",
+	arm_ADD_LT:            "ADD.LT",
+	arm_ADD_GT:            "ADD.GT",
+	arm_ADD_LE:            "ADD.LE",
+	arm_ADD:               "ADD",
+	arm_ADD_ZZ:            "ADD.ZZ",
+	arm_ADD_S_EQ:          "ADD.S.EQ",
+	arm_ADD_S_NE:          "ADD.S.NE",
+	arm_ADD_S_CS:          "ADD.S.CS",
+	arm_ADD_S_CC:          "ADD.S.CC",
+	arm_ADD_S_MI:          "ADD.S.MI",
+	arm_ADD_S_PL:          "ADD.S.PL",
+	arm_ADD_S_VS:          "ADD.S.VS",
+	arm_ADD_S_VC:          "ADD.S.VC",
+	arm_ADD_S_HI:          "ADD.S.HI",
+	arm_ADD_S_LS:          "ADD.S.LS",
+	arm_ADD_S_GE:          "ADD.S.GE",
+	arm_ADD_S_LT:          "ADD.S.LT",
+	arm_ADD_S_GT:          "ADD.S.GT",
+	arm_ADD_S_LE:          "ADD.S.LE",
+	arm_ADD_S:             "ADD.S",
+	arm_ADD_S_ZZ:          "ADD.S.ZZ",
+	arm_AND_EQ:            "AND.EQ",
+	arm_AND_NE:            "AND.NE",
+	arm_AND_CS:            "AND.CS",
+	arm_AND_CC:            "AND.CC",
+	arm_AND_MI:            "AND.MI",
+	arm_AND_PL:            "AND.PL",
+	arm_AND_VS:            "AND.VS",
+	arm_AND_VC:            "AND.VC",
+	arm_AND_HI:            "AND.HI",
+	arm_AND_LS:            "AND.LS",
+	arm_AND_GE:            "AND.GE",
+	arm_AND_LT:            "AND.LT",
+	arm_AND_GT:            "AND.GT",
+	arm_AND_LE:            "AND.LE",
+	arm_AND:               "AND",
+	arm_AND_ZZ:            "AND.ZZ",
+	arm_AND_S_EQ:          "AND.S.EQ",
+	arm_AND_S_NE:          "AND.S.NE",
+	arm_AND_S_CS:          "AND.S.CS",
+	arm_AND_S_CC:          "AND.S.CC",
+	arm_AND_S_MI:          "AND.S.MI",
+	arm_AND_S_PL:          "AND.S.PL",
+	arm_AND_S_VS:          "AND.S.VS",
+	arm_AND_S_VC:          "AND.S.VC",
+	arm_AND_S_HI:          "AND.S.HI",
+	arm_AND_S_LS:          "AND.S.LS",
+	arm_AND_S_GE:          "AND.S.GE",
+	arm_AND_S_LT:          "AND.S.LT",
+	arm_AND_S_GT:          "AND.S.GT",
+	arm_AND_S_LE:          "AND.S.LE",
+	arm_AND_S:             "AND.S",
+	arm_AND_S_ZZ:          "AND.S.ZZ",
+	arm_ASR_EQ:            "ASR.EQ",
+	arm_ASR_NE:            "ASR.NE",
+	arm_ASR_CS:            "ASR.CS",
+	arm_ASR_CC:            "ASR.CC",
+	arm_ASR_MI:            "ASR.MI",
+	arm_ASR_PL:            "ASR.PL",
+	arm_ASR_VS:            "ASR.VS",
+	arm_ASR_VC:            "ASR.VC",
+	arm_ASR_HI:            "ASR.HI",
+	arm_ASR_LS:            "ASR.LS",
+	arm_ASR_GE:            "ASR.GE",
+	arm_ASR_LT:            "ASR.LT",
+	arm_ASR_GT:            "ASR.GT",
+	arm_ASR_LE:            "ASR.LE",
+	arm_ASR:               "ASR",
+	arm_ASR_ZZ:            "ASR.ZZ",
+	arm_ASR_S_EQ:          "ASR.S.EQ",
+	arm_ASR_S_NE:          "ASR.S.NE",
+	arm_ASR_S_CS:          "ASR.S.CS",
+	arm_ASR_S_CC:          "ASR.S.CC",
+	arm_ASR_S_MI:          "ASR.S.MI",
+	arm_ASR_S_PL:          "ASR.S.PL",
+	arm_ASR_S_VS:          "ASR.S.VS",
+	arm_ASR_S_VC:          "ASR.S.VC",
+	arm_ASR_S_HI:          "ASR.S.HI",
+	arm_ASR_S_LS:          "ASR.S.LS",
+	arm_ASR_S_GE:          "ASR.S.GE",
+	arm_ASR_S_LT:          "ASR.S.LT",
+	arm_ASR_S_GT:          "ASR.S.GT",
+	arm_ASR_S_LE:          "ASR.S.LE",
+	arm_ASR_S:             "ASR.S",
+	arm_ASR_S_ZZ:          "ASR.S.ZZ",
+	arm_B_EQ:              "B.EQ",
+	arm_B_NE:              "B.NE",
+	arm_B_CS:              "B.CS",
+	arm_B_CC:              "B.CC",
+	arm_B_MI:              "B.MI",
+	arm_B_PL:              "B.PL",
+	arm_B_VS:              "B.VS",
+	arm_B_VC:              "B.VC",
+	arm_B_HI:              "B.HI",
+	arm_B_LS:              "B.LS",
+	arm_B_GE:              "B.GE",
+	arm_B_LT:              "B.LT",
+	arm_B_GT:              "B.GT",
+	arm_B_LE:              "B.LE",
+	arm_B:                 "B",
+	arm_B_ZZ:              "B.ZZ",
+	arm_BFC_EQ:            "BFC.EQ",
+	arm_BFC_NE:            "BFC.NE",
+	arm_BFC_CS:            "BFC.CS",
+	arm_BFC_CC:            "BFC.CC",
+	arm_BFC_MI:            "BFC.MI",
+	arm_BFC_PL:            "BFC.PL",
+	arm_BFC_VS:            "BFC.VS",
+	arm_BFC_VC:            "BFC.VC",
+	arm_BFC_HI:            "BFC.HI",
+	arm_BFC_LS:            "BFC.LS",
+	arm_BFC_GE:            "BFC.GE",
+	arm_BFC_LT:            "BFC.LT",
+	arm_BFC_GT:            "BFC.GT",
+	arm_BFC_LE:            "BFC.LE",
+	arm_BFC:               "BFC",
+	arm_BFC_ZZ:            "BFC.ZZ",
+	arm_BFI_EQ:            "BFI.EQ",
+	arm_BFI_NE:            "BFI.NE",
+	arm_BFI_CS:            "BFI.CS",
+	arm_BFI_CC:            "BFI.CC",
+	arm_BFI_MI:            "BFI.MI",
+	arm_BFI_PL:            "BFI.PL",
+	arm_BFI_VS:            "BFI.VS",
+	arm_BFI_VC:            "BFI.VC",
+	arm_BFI_HI:            "BFI.HI",
+	arm_BFI_LS:            "BFI.LS",
+	arm_BFI_GE:            "BFI.GE",
+	arm_BFI_LT:            "BFI.LT",
+	arm_BFI_GT:            "BFI.GT",
+	arm_BFI_LE:            "BFI.LE",
+	arm_BFI:               "BFI",
+	arm_BFI_ZZ:            "BFI.ZZ",
+	arm_BIC_EQ:            "BIC.EQ",
+	arm_BIC_NE:            "BIC.NE",
+	arm_BIC_CS:            "BIC.CS",
+	arm_BIC_CC:            "BIC.CC",
+	arm_BIC_MI:            "BIC.MI",
+	arm_BIC_PL:            "BIC.PL",
+	arm_BIC_VS:            "BIC.VS",
+	arm_BIC_VC:            "BIC.VC",
+	arm_BIC_HI:            "BIC.HI",
+	arm_BIC_LS:            "BIC.LS",
+	arm_BIC_GE:            "BIC.GE",
+	arm_BIC_LT:            "BIC.LT",
+	arm_BIC_GT:            "BIC.GT",
+	arm_BIC_LE:            "BIC.LE",
+	arm_BIC:               "BIC",
+	arm_BIC_ZZ:            "BIC.ZZ",
+	arm_BIC_S_EQ:          "BIC.S.EQ",
+	arm_BIC_S_NE:          "BIC.S.NE",
+	arm_BIC_S_CS:          "BIC.S.CS",
+	arm_BIC_S_CC:          "BIC.S.CC",
+	arm_BIC_S_MI:          "BIC.S.MI",
+	arm_BIC_S_PL:          "BIC.S.PL",
+	arm_BIC_S_VS:          "BIC.S.VS",
+	arm_BIC_S_VC:          "BIC.S.VC",
+	arm_BIC_S_HI:          "BIC.S.HI",
+	arm_BIC_S_LS:          "BIC.S.LS",
+	arm_BIC_S_GE:          "BIC.S.GE",
+	arm_BIC_S_LT:          "BIC.S.LT",
+	arm_BIC_S_GT:          "BIC.S.GT",
+	arm_BIC_S_LE:          "BIC.S.LE",
+	arm_BIC_S:             "BIC.S",
+	arm_BIC_S_ZZ:          "BIC.S.ZZ",
+	arm_BKPT_EQ:           "BKPT.EQ",
+	arm_BKPT_NE:           "BKPT.NE",
+	arm_BKPT_CS:           "BKPT.CS",
+	arm_BKPT_CC:           "BKPT.CC",
+	arm_BKPT_MI:           "BKPT.MI",
+	arm_BKPT_PL:           "BKPT.PL",
+	arm_BKPT_VS:           "BKPT.VS",
+	arm_BKPT_VC:           "BKPT.VC",
+	arm_BKPT_HI:           "BKPT.HI",
+	arm_BKPT_LS:           "BKPT.LS",
+	arm_BKPT_GE:           "BKPT.GE",
+	arm_BKPT_LT:           "BKPT.LT",
+	arm_BKPT_GT:           "BKPT.GT",
+	arm_BKPT_LE:           "BKPT.LE",
+	arm_BKPT:              "BKPT",
+	arm_BKPT_ZZ:           "BKPT.ZZ",
+	arm_BL_EQ:             "BL.EQ",
+	arm_BL_NE:             "BL.NE",
+	arm_BL_CS:             "BL.CS",
+	arm_BL_CC:             "BL.CC",
+	arm_BL_MI:             "BL.MI",
+	arm_BL_PL:             "BL.PL",
+	arm_BL_VS:             "BL.VS",
+	arm_BL_VC:             "BL.VC",
+	arm_BL_HI:             "BL.HI",
+	arm_BL_LS:             "BL.LS",
+	arm_BL_GE:             "BL.GE",
+	arm_BL_LT:             "BL.LT",
+	arm_BL_GT:             "BL.GT",
+	arm_BL_LE:             "BL.LE",
+	arm_BL:                "BL",
+	arm_BL_ZZ:             "BL.ZZ",
+	arm_BLX_EQ:            "BLX.EQ",
+	arm_BLX_NE:            "BLX.NE",
+	arm_BLX_CS:            "BLX.CS",
+	arm_BLX_CC:            "BLX.CC",
+	arm_BLX_MI:            "BLX.MI",
+	arm_BLX_PL:            "BLX.PL",
+	arm_BLX_VS:            "BLX.VS",
+	arm_BLX_VC:            "BLX.VC",
+	arm_BLX_HI:            "BLX.HI",
+	arm_BLX_LS:            "BLX.LS",
+	arm_BLX_GE:            "BLX.GE",
+	arm_BLX_LT:            "BLX.LT",
+	arm_BLX_GT:            "BLX.GT",
+	arm_BLX_LE:            "BLX.LE",
+	arm_BLX:               "BLX",
+	arm_BLX_ZZ:            "BLX.ZZ",
+	arm_BX_EQ:             "BX.EQ",
+	arm_BX_NE:             "BX.NE",
+	arm_BX_CS:             "BX.CS",
+	arm_BX_CC:             "BX.CC",
+	arm_BX_MI:             "BX.MI",
+	arm_BX_PL:             "BX.PL",
+	arm_BX_VS:             "BX.VS",
+	arm_BX_VC:             "BX.VC",
+	arm_BX_HI:             "BX.HI",
+	arm_BX_LS:             "BX.LS",
+	arm_BX_GE:             "BX.GE",
+	arm_BX_LT:             "BX.LT",
+	arm_BX_GT:             "BX.GT",
+	arm_BX_LE:             "BX.LE",
+	arm_BX:                "BX",
+	arm_BX_ZZ:             "BX.ZZ",
+	arm_BXJ_EQ:            "BXJ.EQ",
+	arm_BXJ_NE:            "BXJ.NE",
+	arm_BXJ_CS:            "BXJ.CS",
+	arm_BXJ_CC:            "BXJ.CC",
+	arm_BXJ_MI:            "BXJ.MI",
+	arm_BXJ_PL:            "BXJ.PL",
+	arm_BXJ_VS:            "BXJ.VS",
+	arm_BXJ_VC:            "BXJ.VC",
+	arm_BXJ_HI:            "BXJ.HI",
+	arm_BXJ_LS:            "BXJ.LS",
+	arm_BXJ_GE:            "BXJ.GE",
+	arm_BXJ_LT:            "BXJ.LT",
+	arm_BXJ_GT:            "BXJ.GT",
+	arm_BXJ_LE:            "BXJ.LE",
+	arm_BXJ:               "BXJ",
+	arm_BXJ_ZZ:            "BXJ.ZZ",
+	arm_CLREX:             "CLREX",
+	arm_CLZ_EQ:            "CLZ.EQ",
+	arm_CLZ_NE:            "CLZ.NE",
+	arm_CLZ_CS:            "CLZ.CS",
+	arm_CLZ_CC:            "CLZ.CC",
+	arm_CLZ_MI:            "CLZ.MI",
+	arm_CLZ_PL:            "CLZ.PL",
+	arm_CLZ_VS:            "CLZ.VS",
+	arm_CLZ_VC:            "CLZ.VC",
+	arm_CLZ_HI:            "CLZ.HI",
+	arm_CLZ_LS:            "CLZ.LS",
+	arm_CLZ_GE:            "CLZ.GE",
+	arm_CLZ_LT:            "CLZ.LT",
+	arm_CLZ_GT:            "CLZ.GT",
+	arm_CLZ_LE:            "CLZ.LE",
+	arm_CLZ:               "CLZ",
+	arm_CLZ_ZZ:            "CLZ.ZZ",
+	arm_CMN_EQ:            "CMN.EQ",
+	arm_CMN_NE:            "CMN.NE",
+	arm_CMN_CS:            "CMN.CS",
+	arm_CMN_CC:            "CMN.CC",
+	arm_CMN_MI:            "CMN.MI",
+	arm_CMN_PL:            "CMN.PL",
+	arm_CMN_VS:            "CMN.VS",
+	arm_CMN_VC:            "CMN.VC",
+	arm_CMN_HI:            "CMN.HI",
+	arm_CMN_LS:            "CMN.LS",
+	arm_CMN_GE:            "CMN.GE",
+	arm_CMN_LT:            "CMN.LT",
+	arm_CMN_GT:            "CMN.GT",
+	arm_CMN_LE:            "CMN.LE",
+	arm_CMN:               "CMN",
+	arm_CMN_ZZ:            "CMN.ZZ",
+	arm_CMP_EQ:            "CMP.EQ",
+	arm_CMP_NE:            "CMP.NE",
+	arm_CMP_CS:            "CMP.CS",
+	arm_CMP_CC:            "CMP.CC",
+	arm_CMP_MI:            "CMP.MI",
+	arm_CMP_PL:            "CMP.PL",
+	arm_CMP_VS:            "CMP.VS",
+	arm_CMP_VC:            "CMP.VC",
+	arm_CMP_HI:            "CMP.HI",
+	arm_CMP_LS:            "CMP.LS",
+	arm_CMP_GE:            "CMP.GE",
+	arm_CMP_LT:            "CMP.LT",
+	arm_CMP_GT:            "CMP.GT",
+	arm_CMP_LE:            "CMP.LE",
+	arm_CMP:               "CMP",
+	arm_CMP_ZZ:            "CMP.ZZ",
+	arm_DBG_EQ:            "DBG.EQ",
+	arm_DBG_NE:            "DBG.NE",
+	arm_DBG_CS:            "DBG.CS",
+	arm_DBG_CC:            "DBG.CC",
+	arm_DBG_MI:            "DBG.MI",
+	arm_DBG_PL:            "DBG.PL",
+	arm_DBG_VS:            "DBG.VS",
+	arm_DBG_VC:            "DBG.VC",
+	arm_DBG_HI:            "DBG.HI",
+	arm_DBG_LS:            "DBG.LS",
+	arm_DBG_GE:            "DBG.GE",
+	arm_DBG_LT:            "DBG.LT",
+	arm_DBG_GT:            "DBG.GT",
+	arm_DBG_LE:            "DBG.LE",
+	arm_DBG:               "DBG",
+	arm_DBG_ZZ:            "DBG.ZZ",
+	arm_DMB:               "DMB",
+	arm_DSB:               "DSB",
+	arm_EOR_EQ:            "EOR.EQ",
+	arm_EOR_NE:            "EOR.NE",
+	arm_EOR_CS:            "EOR.CS",
+	arm_EOR_CC:            "EOR.CC",
+	arm_EOR_MI:            "EOR.MI",
+	arm_EOR_PL:            "EOR.PL",
+	arm_EOR_VS:            "EOR.VS",
+	arm_EOR_VC:            "EOR.VC",
+	arm_EOR_HI:            "EOR.HI",
+	arm_EOR_LS:            "EOR.LS",
+	arm_EOR_GE:            "EOR.GE",
+	arm_EOR_LT:            "EOR.LT",
+	arm_EOR_GT:            "EOR.GT",
+	arm_EOR_LE:            "EOR.LE",
+	arm_EOR:               "EOR",
+	arm_EOR_ZZ:            "EOR.ZZ",
+	arm_EOR_S_EQ:          "EOR.S.EQ",
+	arm_EOR_S_NE:          "EOR.S.NE",
+	arm_EOR_S_CS:          "EOR.S.CS",
+	arm_EOR_S_CC:          "EOR.S.CC",
+	arm_EOR_S_MI:          "EOR.S.MI",
+	arm_EOR_S_PL:          "EOR.S.PL",
+	arm_EOR_S_VS:          "EOR.S.VS",
+	arm_EOR_S_VC:          "EOR.S.VC",
+	arm_EOR_S_HI:          "EOR.S.HI",
+	arm_EOR_S_LS:          "EOR.S.LS",
+	arm_EOR_S_GE:          "EOR.S.GE",
+	arm_EOR_S_LT:          "EOR.S.LT",
+	arm_EOR_S_GT:          "EOR.S.GT",
+	arm_EOR_S_LE:          "EOR.S.LE",
+	arm_EOR_S:             "EOR.S",
+	arm_EOR_S_ZZ:          "EOR.S.ZZ",
+	arm_ISB:               "ISB",
+	arm_LDM_EQ:            "LDM.EQ",
+	arm_LDM_NE:            "LDM.NE",
+	arm_LDM_CS:            "LDM.CS",
+	arm_LDM_CC:            "LDM.CC",
+	arm_LDM_MI:            "LDM.MI",
+	arm_LDM_PL:            "LDM.PL",
+	arm_LDM_VS:            "LDM.VS",
+	arm_LDM_VC:            "LDM.VC",
+	arm_LDM_HI:            "LDM.HI",
+	arm_LDM_LS:            "LDM.LS",
+	arm_LDM_GE:            "LDM.GE",
+	arm_LDM_LT:            "LDM.LT",
+	arm_LDM_GT:            "LDM.GT",
+	arm_LDM_LE:            "LDM.LE",
+	arm_LDM:               "LDM",
+	arm_LDM_ZZ:            "LDM.ZZ",
+	arm_LDMDA_EQ:          "LDMDA.EQ",
+	arm_LDMDA_NE:          "LDMDA.NE",
+	arm_LDMDA_CS:          "LDMDA.CS",
+	arm_LDMDA_CC:          "LDMDA.CC",
+	arm_LDMDA_MI:          "LDMDA.MI",
+	arm_LDMDA_PL:          "LDMDA.PL",
+	arm_LDMDA_VS:          "LDMDA.VS",
+	arm_LDMDA_VC:          "LDMDA.VC",
+	arm_LDMDA_HI:          "LDMDA.HI",
+	arm_LDMDA_LS:          "LDMDA.LS",
+	arm_LDMDA_GE:          "LDMDA.GE",
+	arm_LDMDA_LT:          "LDMDA.LT",
+	arm_LDMDA_GT:          "LDMDA.GT",
+	arm_LDMDA_LE:          "LDMDA.LE",
+	arm_LDMDA:             "LDMDA",
+	arm_LDMDA_ZZ:          "LDMDA.ZZ",
+	arm_LDMDB_EQ:          "LDMDB.EQ",
+	arm_LDMDB_NE:          "LDMDB.NE",
+	arm_LDMDB_CS:          "LDMDB.CS",
+	arm_LDMDB_CC:          "LDMDB.CC",
+	arm_LDMDB_MI:          "LDMDB.MI",
+	arm_LDMDB_PL:          "LDMDB.PL",
+	arm_LDMDB_VS:          "LDMDB.VS",
+	arm_LDMDB_VC:          "LDMDB.VC",
+	arm_LDMDB_HI:          "LDMDB.HI",
+	arm_LDMDB_LS:          "LDMDB.LS",
+	arm_LDMDB_GE:          "LDMDB.GE",
+	arm_LDMDB_LT:          "LDMDB.LT",
+	arm_LDMDB_GT:          "LDMDB.GT",
+	arm_LDMDB_LE:          "LDMDB.LE",
+	arm_LDMDB:             "LDMDB",
+	arm_LDMDB_ZZ:          "LDMDB.ZZ",
+	arm_LDMIB_EQ:          "LDMIB.EQ",
+	arm_LDMIB_NE:          "LDMIB.NE",
+	arm_LDMIB_CS:          "LDMIB.CS",
+	arm_LDMIB_CC:          "LDMIB.CC",
+	arm_LDMIB_MI:          "LDMIB.MI",
+	arm_LDMIB_PL:          "LDMIB.PL",
+	arm_LDMIB_VS:          "LDMIB.VS",
+	arm_LDMIB_VC:          "LDMIB.VC",
+	arm_LDMIB_HI:          "LDMIB.HI",
+	arm_LDMIB_LS:          "LDMIB.LS",
+	arm_LDMIB_GE:          "LDMIB.GE",
+	arm_LDMIB_LT:          "LDMIB.LT",
+	arm_LDMIB_GT:          "LDMIB.GT",
+	arm_LDMIB_LE:          "LDMIB.LE",
+	arm_LDMIB:             "LDMIB",
+	arm_LDMIB_ZZ:          "LDMIB.ZZ",
+	arm_LDR_EQ:            "LDR.EQ",
+	arm_LDR_NE:            "LDR.NE",
+	arm_LDR_CS:            "LDR.CS",
+	arm_LDR_CC:            "LDR.CC",
+	arm_LDR_MI:            "LDR.MI",
+	arm_LDR_PL:            "LDR.PL",
+	arm_LDR_VS:            "LDR.VS",
+	arm_LDR_VC:            "LDR.VC",
+	arm_LDR_HI:            "LDR.HI",
+	arm_LDR_LS:            "LDR.LS",
+	arm_LDR_GE:            "LDR.GE",
+	arm_LDR_LT:            "LDR.LT",
+	arm_LDR_GT:            "LDR.GT",
+	arm_LDR_LE:            "LDR.LE",
+	arm_LDR:               "LDR",
+	arm_LDR_ZZ:            "LDR.ZZ",
+	arm_LDRB_EQ:           "LDRB.EQ",
+	arm_LDRB_NE:           "LDRB.NE",
+	arm_LDRB_CS:           "LDRB.CS",
+	arm_LDRB_CC:           "LDRB.CC",
+	arm_LDRB_MI:           "LDRB.MI",
+	arm_LDRB_PL:           "LDRB.PL",
+	arm_LDRB_VS:           "LDRB.VS",
+	arm_LDRB_VC:           "LDRB.VC",
+	arm_LDRB_HI:           "LDRB.HI",
+	arm_LDRB_LS:           "LDRB.LS",
+	arm_LDRB_GE:           "LDRB.GE",
+	arm_LDRB_LT:           "LDRB.LT",
+	arm_LDRB_GT:           "LDRB.GT",
+	arm_LDRB_LE:           "LDRB.LE",
+	arm_LDRB:              "LDRB",
+	arm_LDRB_ZZ:           "LDRB.ZZ",
+	arm_LDRBT_EQ:          "LDRBT.EQ",
+	arm_LDRBT_NE:          "LDRBT.NE",
+	arm_LDRBT_CS:          "LDRBT.CS",
+	arm_LDRBT_CC:          "LDRBT.CC",
+	arm_LDRBT_MI:          "LDRBT.MI",
+	arm_LDRBT_PL:          "LDRBT.PL",
+	arm_LDRBT_VS:          "LDRBT.VS",
+	arm_LDRBT_VC:          "LDRBT.VC",
+	arm_LDRBT_HI:          "LDRBT.HI",
+	arm_LDRBT_LS:          "LDRBT.LS",
+	arm_LDRBT_GE:          "LDRBT.GE",
+	arm_LDRBT_LT:          "LDRBT.LT",
+	arm_LDRBT_GT:          "LDRBT.GT",
+	arm_LDRBT_LE:          "LDRBT.LE",
+	arm_LDRBT:             "LDRBT",
+	arm_LDRBT_ZZ:          "LDRBT.ZZ",
+	arm_LDRD_EQ:           "LDRD.EQ",
+	arm_LDRD_NE:           "LDRD.NE",
+	arm_LDRD_CS:           "LDRD.CS",
+	arm_LDRD_CC:           "LDRD.CC",
+	arm_LDRD_MI:           "LDRD.MI",
+	arm_LDRD_PL:           "LDRD.PL",
+	arm_LDRD_VS:           "LDRD.VS",
+	arm_LDRD_VC:           "LDRD.VC",
+	arm_LDRD_HI:           "LDRD.HI",
+	arm_LDRD_LS:           "LDRD.LS",
+	arm_LDRD_GE:           "LDRD.GE",
+	arm_LDRD_LT:           "LDRD.LT",
+	arm_LDRD_GT:           "LDRD.GT",
+	arm_LDRD_LE:           "LDRD.LE",
+	arm_LDRD:              "LDRD",
+	arm_LDRD_ZZ:           "LDRD.ZZ",
+	arm_LDREX_EQ:          "LDREX.EQ",
+	arm_LDREX_NE:          "LDREX.NE",
+	arm_LDREX_CS:          "LDREX.CS",
+	arm_LDREX_CC:          "LDREX.CC",
+	arm_LDREX_MI:          "LDREX.MI",
+	arm_LDREX_PL:          "LDREX.PL",
+	arm_LDREX_VS:          "LDREX.VS",
+	arm_LDREX_VC:          "LDREX.VC",
+	arm_LDREX_HI:          "LDREX.HI",
+	arm_LDREX_LS:          "LDREX.LS",
+	arm_LDREX_GE:          "LDREX.GE",
+	arm_LDREX_LT:          "LDREX.LT",
+	arm_LDREX_GT:          "LDREX.GT",
+	arm_LDREX_LE:          "LDREX.LE",
+	arm_LDREX:             "LDREX",
+	arm_LDREX_ZZ:          "LDREX.ZZ",
+	arm_LDREXB_EQ:         "LDREXB.EQ",
+	arm_LDREXB_NE:         "LDREXB.NE",
+	arm_LDREXB_CS:         "LDREXB.CS",
+	arm_LDREXB_CC:         "LDREXB.CC",
+	arm_LDREXB_MI:         "LDREXB.MI",
+	arm_LDREXB_PL:         "LDREXB.PL",
+	arm_LDREXB_VS:         "LDREXB.VS",
+	arm_LDREXB_VC:         "LDREXB.VC",
+	arm_LDREXB_HI:         "LDREXB.HI",
+	arm_LDREXB_LS:         "LDREXB.LS",
+	arm_LDREXB_GE:         "LDREXB.GE",
+	arm_LDREXB_LT:         "LDREXB.LT",
+	arm_LDREXB_GT:         "LDREXB.GT",
+	arm_LDREXB_LE:         "LDREXB.LE",
+	arm_LDREXB:            "LDREXB",
+	arm_LDREXB_ZZ:         "LDREXB.ZZ",
+	arm_LDREXD_EQ:         "LDREXD.EQ",
+	arm_LDREXD_NE:         "LDREXD.NE",
+	arm_LDREXD_CS:         "LDREXD.CS",
+	arm_LDREXD_CC:         "LDREXD.CC",
+	arm_LDREXD_MI:         "LDREXD.MI",
+	arm_LDREXD_PL:         "LDREXD.PL",
+	arm_LDREXD_VS:         "LDREXD.VS",
+	arm_LDREXD_VC:         "LDREXD.VC",
+	arm_LDREXD_HI:         "LDREXD.HI",
+	arm_LDREXD_LS:         "LDREXD.LS",
+	arm_LDREXD_GE:         "LDREXD.GE",
+	arm_LDREXD_LT:         "LDREXD.LT",
+	arm_LDREXD_GT:         "LDREXD.GT",
+	arm_LDREXD_LE:         "LDREXD.LE",
+	arm_LDREXD:            "LDREXD",
+	arm_LDREXD_ZZ:         "LDREXD.ZZ",
+	arm_LDREXH_EQ:         "LDREXH.EQ",
+	arm_LDREXH_NE:         "LDREXH.NE",
+	arm_LDREXH_CS:         "LDREXH.CS",
+	arm_LDREXH_CC:         "LDREXH.CC",
+	arm_LDREXH_MI:         "LDREXH.MI",
+	arm_LDREXH_PL:         "LDREXH.PL",
+	arm_LDREXH_VS:         "LDREXH.VS",
+	arm_LDREXH_VC:         "LDREXH.VC",
+	arm_LDREXH_HI:         "LDREXH.HI",
+	arm_LDREXH_LS:         "LDREXH.LS",
+	arm_LDREXH_GE:         "LDREXH.GE",
+	arm_LDREXH_LT:         "LDREXH.LT",
+	arm_LDREXH_GT:         "LDREXH.GT",
+	arm_LDREXH_LE:         "LDREXH.LE",
+	arm_LDREXH:            "LDREXH",
+	arm_LDREXH_ZZ:         "LDREXH.ZZ",
+	arm_LDRH_EQ:           "LDRH.EQ",
+	arm_LDRH_NE:           "LDRH.NE",
+	arm_LDRH_CS:           "LDRH.CS",
+	arm_LDRH_CC:           "LDRH.CC",
+	arm_LDRH_MI:           "LDRH.MI",
+	arm_LDRH_PL:           "LDRH.PL",
+	arm_LDRH_VS:           "LDRH.VS",
+	arm_LDRH_VC:           "LDRH.VC",
+	arm_LDRH_HI:           "LDRH.HI",
+	arm_LDRH_LS:           "LDRH.LS",
+	arm_LDRH_GE:           "LDRH.GE",
+	arm_LDRH_LT:           "LDRH.LT",
+	arm_LDRH_GT:           "LDRH.GT",
+	arm_LDRH_LE:           "LDRH.LE",
+	arm_LDRH:              "LDRH",
+	arm_LDRH_ZZ:           "LDRH.ZZ",
+	arm_LDRHT_EQ:          "LDRHT.EQ",
+	arm_LDRHT_NE:          "LDRHT.NE",
+	arm_LDRHT_CS:          "LDRHT.CS",
+	arm_LDRHT_CC:          "LDRHT.CC",
+	arm_LDRHT_MI:          "LDRHT.MI",
+	arm_LDRHT_PL:          "LDRHT.PL",
+	arm_LDRHT_VS:          "LDRHT.VS",
+	arm_LDRHT_VC:          "LDRHT.VC",
+	arm_LDRHT_HI:          "LDRHT.HI",
+	arm_LDRHT_LS:          "LDRHT.LS",
+	arm_LDRHT_GE:          "LDRHT.GE",
+	arm_LDRHT_LT:          "LDRHT.LT",
+	arm_LDRHT_GT:          "LDRHT.GT",
+	arm_LDRHT_LE:          "LDRHT.LE",
+	arm_LDRHT:             "LDRHT",
+	arm_LDRHT_ZZ:          "LDRHT.ZZ",
+	arm_LDRSB_EQ:          "LDRSB.EQ",
+	arm_LDRSB_NE:          "LDRSB.NE",
+	arm_LDRSB_CS:          "LDRSB.CS",
+	arm_LDRSB_CC:          "LDRSB.CC",
+	arm_LDRSB_MI:          "LDRSB.MI",
+	arm_LDRSB_PL:          "LDRSB.PL",
+	arm_LDRSB_VS:          "LDRSB.VS",
+	arm_LDRSB_VC:          "LDRSB.VC",
+	arm_LDRSB_HI:          "LDRSB.HI",
+	arm_LDRSB_LS:          "LDRSB.LS",
+	arm_LDRSB_GE:          "LDRSB.GE",
+	arm_LDRSB_LT:          "LDRSB.LT",
+	arm_LDRSB_GT:          "LDRSB.GT",
+	arm_LDRSB_LE:          "LDRSB.LE",
+	arm_LDRSB:             "LDRSB",
+	arm_LDRSB_ZZ:          "LDRSB.ZZ",
+	arm_LDRSBT_EQ:         "LDRSBT.EQ",
+	arm_LDRSBT_NE:         "LDRSBT.NE",
+	arm_LDRSBT_CS:         "LDRSBT.CS",
+	arm_LDRSBT_CC:         "LDRSBT.CC",
+	arm_LDRSBT_MI:         "LDRSBT.MI",
+	arm_LDRSBT_PL:         "LDRSBT.PL",
+	arm_LDRSBT_VS:         "LDRSBT.VS",
+	arm_LDRSBT_VC:         "LDRSBT.VC",
+	arm_LDRSBT_HI:         "LDRSBT.HI",
+	arm_LDRSBT_LS:         "LDRSBT.LS",
+	arm_LDRSBT_GE:         "LDRSBT.GE",
+	arm_LDRSBT_LT:         "LDRSBT.LT",
+	arm_LDRSBT_GT:         "LDRSBT.GT",
+	arm_LDRSBT_LE:         "LDRSBT.LE",
+	arm_LDRSBT:            "LDRSBT",
+	arm_LDRSBT_ZZ:         "LDRSBT.ZZ",
+	arm_LDRSH_EQ:          "LDRSH.EQ",
+	arm_LDRSH_NE:          "LDRSH.NE",
+	arm_LDRSH_CS:          "LDRSH.CS",
+	arm_LDRSH_CC:          "LDRSH.CC",
+	arm_LDRSH_MI:          "LDRSH.MI",
+	arm_LDRSH_PL:          "LDRSH.PL",
+	arm_LDRSH_VS:          "LDRSH.VS",
+	arm_LDRSH_VC:          "LDRSH.VC",
+	arm_LDRSH_HI:          "LDRSH.HI",
+	arm_LDRSH_LS:          "LDRSH.LS",
+	arm_LDRSH_GE:          "LDRSH.GE",
+	arm_LDRSH_LT:          "LDRSH.LT",
+	arm_LDRSH_GT:          "LDRSH.GT",
+	arm_LDRSH_LE:          "LDRSH.LE",
+	arm_LDRSH:             "LDRSH",
+	arm_LDRSH_ZZ:          "LDRSH.ZZ",
+	arm_LDRSHT_EQ:         "LDRSHT.EQ",
+	arm_LDRSHT_NE:         "LDRSHT.NE",
+	arm_LDRSHT_CS:         "LDRSHT.CS",
+	arm_LDRSHT_CC:         "LDRSHT.CC",
+	arm_LDRSHT_MI:         "LDRSHT.MI",
+	arm_LDRSHT_PL:         "LDRSHT.PL",
+	arm_LDRSHT_VS:         "LDRSHT.VS",
+	arm_LDRSHT_VC:         "LDRSHT.VC",
+	arm_LDRSHT_HI:         "LDRSHT.HI",
+	arm_LDRSHT_LS:         "LDRSHT.LS",
+	arm_LDRSHT_GE:         "LDRSHT.GE",
+	arm_LDRSHT_LT:         "LDRSHT.LT",
+	arm_LDRSHT_GT:         "LDRSHT.GT",
+	arm_LDRSHT_LE:         "LDRSHT.LE",
+	arm_LDRSHT:            "LDRSHT",
+	arm_LDRSHT_ZZ:         "LDRSHT.ZZ",
+	arm_LDRT_EQ:           "LDRT.EQ",
+	arm_LDRT_NE:           "LDRT.NE",
+	arm_LDRT_CS:           "LDRT.CS",
+	arm_LDRT_CC:           "LDRT.CC",
+	arm_LDRT_MI:           "LDRT.MI",
+	arm_LDRT_PL:           "LDRT.PL",
+	arm_LDRT_VS:           "LDRT.VS",
+	arm_LDRT_VC:           "LDRT.VC",
+	arm_LDRT_HI:           "LDRT.HI",
+	arm_LDRT_LS:           "LDRT.LS",
+	arm_LDRT_GE:           "LDRT.GE",
+	arm_LDRT_LT:           "LDRT.LT",
+	arm_LDRT_GT:           "LDRT.GT",
+	arm_LDRT_LE:           "LDRT.LE",
+	arm_LDRT:              "LDRT",
+	arm_LDRT_ZZ:           "LDRT.ZZ",
+	arm_LSL_EQ:            "LSL.EQ",
+	arm_LSL_NE:            "LSL.NE",
+	arm_LSL_CS:            "LSL.CS",
+	arm_LSL_CC:            "LSL.CC",
+	arm_LSL_MI:            "LSL.MI",
+	arm_LSL_PL:            "LSL.PL",
+	arm_LSL_VS:            "LSL.VS",
+	arm_LSL_VC:            "LSL.VC",
+	arm_LSL_HI:            "LSL.HI",
+	arm_LSL_LS:            "LSL.LS",
+	arm_LSL_GE:            "LSL.GE",
+	arm_LSL_LT:            "LSL.LT",
+	arm_LSL_GT:            "LSL.GT",
+	arm_LSL_LE:            "LSL.LE",
+	arm_LSL:               "LSL",
+	arm_LSL_ZZ:            "LSL.ZZ",
+	arm_LSL_S_EQ:          "LSL.S.EQ",
+	arm_LSL_S_NE:          "LSL.S.NE",
+	arm_LSL_S_CS:          "LSL.S.CS",
+	arm_LSL_S_CC:          "LSL.S.CC",
+	arm_LSL_S_MI:          "LSL.S.MI",
+	arm_LSL_S_PL:          "LSL.S.PL",
+	arm_LSL_S_VS:          "LSL.S.VS",
+	arm_LSL_S_VC:          "LSL.S.VC",
+	arm_LSL_S_HI:          "LSL.S.HI",
+	arm_LSL_S_LS:          "LSL.S.LS",
+	arm_LSL_S_GE:          "LSL.S.GE",
+	arm_LSL_S_LT:          "LSL.S.LT",
+	arm_LSL_S_GT:          "LSL.S.GT",
+	arm_LSL_S_LE:          "LSL.S.LE",
+	arm_LSL_S:             "LSL.S",
+	arm_LSL_S_ZZ:          "LSL.S.ZZ",
+	arm_LSR_EQ:            "LSR.EQ",
+	arm_LSR_NE:            "LSR.NE",
+	arm_LSR_CS:            "LSR.CS",
+	arm_LSR_CC:            "LSR.CC",
+	arm_LSR_MI:            "LSR.MI",
+	arm_LSR_PL:            "LSR.PL",
+	arm_LSR_VS:            "LSR.VS",
+	arm_LSR_VC:            "LSR.VC",
+	arm_LSR_HI:            "LSR.HI",
+	arm_LSR_LS:            "LSR.LS",
+	arm_LSR_GE:            "LSR.GE",
+	arm_LSR_LT:            "LSR.LT",
+	arm_LSR_GT:            "LSR.GT",
+	arm_LSR_LE:            "LSR.LE",
+	arm_LSR:               "LSR",
+	arm_LSR_ZZ:            "LSR.ZZ",
+	arm_LSR_S_EQ:          "LSR.S.EQ",
+	arm_LSR_S_NE:          "LSR.S.NE",
+	arm_LSR_S_CS:          "LSR.S.CS",
+	arm_LSR_S_CC:          "LSR.S.CC",
+	arm_LSR_S_MI:          "LSR.S.MI",
+	arm_LSR_S_PL:          "LSR.S.PL",
+	arm_LSR_S_VS:          "LSR.S.VS",
+	arm_LSR_S_VC:          "LSR.S.VC",
+	arm_LSR_S_HI:          "LSR.S.HI",
+	arm_LSR_S_LS:          "LSR.S.LS",
+	arm_LSR_S_GE:          "LSR.S.GE",
+	arm_LSR_S_LT:          "LSR.S.LT",
+	arm_LSR_S_GT:          "LSR.S.GT",
+	arm_LSR_S_LE:          "LSR.S.LE",
+	arm_LSR_S:             "LSR.S",
+	arm_LSR_S_ZZ:          "LSR.S.ZZ",
+	arm_MLA_EQ:            "MLA.EQ",
+	arm_MLA_NE:            "MLA.NE",
+	arm_MLA_CS:            "MLA.CS",
+	arm_MLA_CC:            "MLA.CC",
+	arm_MLA_MI:            "MLA.MI",
+	arm_MLA_PL:            "MLA.PL",
+	arm_MLA_VS:            "MLA.VS",
+	arm_MLA_VC:            "MLA.VC",
+	arm_MLA_HI:            "MLA.HI",
+	arm_MLA_LS:            "MLA.LS",
+	arm_MLA_GE:            "MLA.GE",
+	arm_MLA_LT:            "MLA.LT",
+	arm_MLA_GT:            "MLA.GT",
+	arm_MLA_LE:            "MLA.LE",
+	arm_MLA:               "MLA",
+	arm_MLA_ZZ:            "MLA.ZZ",
+	arm_MLA_S_EQ:          "MLA.S.EQ",
+	arm_MLA_S_NE:          "MLA.S.NE",
+	arm_MLA_S_CS:          "MLA.S.CS",
+	arm_MLA_S_CC:          "MLA.S.CC",
+	arm_MLA_S_MI:          "MLA.S.MI",
+	arm_MLA_S_PL:          "MLA.S.PL",
+	arm_MLA_S_VS:          "MLA.S.VS",
+	arm_MLA_S_VC:          "MLA.S.VC",
+	arm_MLA_S_HI:          "MLA.S.HI",
+	arm_MLA_S_LS:          "MLA.S.LS",
+	arm_MLA_S_GE:          "MLA.S.GE",
+	arm_MLA_S_LT:          "MLA.S.LT",
+	arm_MLA_S_GT:          "MLA.S.GT",
+	arm_MLA_S_LE:          "MLA.S.LE",
+	arm_MLA_S:             "MLA.S",
+	arm_MLA_S_ZZ:          "MLA.S.ZZ",
+	arm_MLS_EQ:            "MLS.EQ",
+	arm_MLS_NE:            "MLS.NE",
+	arm_MLS_CS:            "MLS.CS",
+	arm_MLS_CC:            "MLS.CC",
+	arm_MLS_MI:            "MLS.MI",
+	arm_MLS_PL:            "MLS.PL",
+	arm_MLS_VS:            "MLS.VS",
+	arm_MLS_VC:            "MLS.VC",
+	arm_MLS_HI:            "MLS.HI",
+	arm_MLS_LS:            "MLS.LS",
+	arm_MLS_GE:            "MLS.GE",
+	arm_MLS_LT:            "MLS.LT",
+	arm_MLS_GT:            "MLS.GT",
+	arm_MLS_LE:            "MLS.LE",
+	arm_MLS:               "MLS",
+	arm_MLS_ZZ:            "MLS.ZZ",
+	arm_MOV_EQ:            "MOV.EQ",
+	arm_MOV_NE:            "MOV.NE",
+	arm_MOV_CS:            "MOV.CS",
+	arm_MOV_CC:            "MOV.CC",
+	arm_MOV_MI:            "MOV.MI",
+	arm_MOV_PL:            "MOV.PL",
+	arm_MOV_VS:            "MOV.VS",
+	arm_MOV_VC:            "MOV.VC",
+	arm_MOV_HI:            "MOV.HI",
+	arm_MOV_LS:            "MOV.LS",
+	arm_MOV_GE:            "MOV.GE",
+	arm_MOV_LT:            "MOV.LT",
+	arm_MOV_GT:            "MOV.GT",
+	arm_MOV_LE:            "MOV.LE",
+	arm_MOV:               "MOV",
+	arm_MOV_ZZ:            "MOV.ZZ",
+	arm_MOV_S_EQ:          "MOV.S.EQ",
+	arm_MOV_S_NE:          "MOV.S.NE",
+	arm_MOV_S_CS:          "MOV.S.CS",
+	arm_MOV_S_CC:          "MOV.S.CC",
+	arm_MOV_S_MI:          "MOV.S.MI",
+	arm_MOV_S_PL:          "MOV.S.PL",
+	arm_MOV_S_VS:          "MOV.S.VS",
+	arm_MOV_S_VC:          "MOV.S.VC",
+	arm_MOV_S_HI:          "MOV.S.HI",
+	arm_MOV_S_LS:          "MOV.S.LS",
+	arm_MOV_S_GE:          "MOV.S.GE",
+	arm_MOV_S_LT:          "MOV.S.LT",
+	arm_MOV_S_GT:          "MOV.S.GT",
+	arm_MOV_S_LE:          "MOV.S.LE",
+	arm_MOV_S:             "MOV.S",
+	arm_MOV_S_ZZ:          "MOV.S.ZZ",
+	arm_MOVT_EQ:           "MOVT.EQ",
+	arm_MOVT_NE:           "MOVT.NE",
+	arm_MOVT_CS:           "MOVT.CS",
+	arm_MOVT_CC:           "MOVT.CC",
+	arm_MOVT_MI:           "MOVT.MI",
+	arm_MOVT_PL:           "MOVT.PL",
+	arm_MOVT_VS:           "MOVT.VS",
+	arm_MOVT_VC:           "MOVT.VC",
+	arm_MOVT_HI:           "MOVT.HI",
+	arm_MOVT_LS:           "MOVT.LS",
+	arm_MOVT_GE:           "MOVT.GE",
+	arm_MOVT_LT:           "MOVT.LT",
+	arm_MOVT_GT:           "MOVT.GT",
+	arm_MOVT_LE:           "MOVT.LE",
+	arm_MOVT:              "MOVT",
+	arm_MOVT_ZZ:           "MOVT.ZZ",
+	arm_MOVW_EQ:           "MOVW.EQ",
+	arm_MOVW_NE:           "MOVW.NE",
+	arm_MOVW_CS:           "MOVW.CS",
+	arm_MOVW_CC:           "MOVW.CC",
+	arm_MOVW_MI:           "MOVW.MI",
+	arm_MOVW_PL:           "MOVW.PL",
+	arm_MOVW_VS:           "MOVW.VS",
+	arm_MOVW_VC:           "MOVW.VC",
+	arm_MOVW_HI:           "MOVW.HI",
+	arm_MOVW_LS:           "MOVW.LS",
+	arm_MOVW_GE:           "MOVW.GE",
+	arm_MOVW_LT:           "MOVW.LT",
+	arm_MOVW_GT:           "MOVW.GT",
+	arm_MOVW_LE:           "MOVW.LE",
+	arm_MOVW:              "MOVW",
+	arm_MOVW_ZZ:           "MOVW.ZZ",
+	arm_MRS_EQ:            "MRS.EQ",
+	arm_MRS_NE:            "MRS.NE",
+	arm_MRS_CS:            "MRS.CS",
+	arm_MRS_CC:            "MRS.CC",
+	arm_MRS_MI:            "MRS.MI",
+	arm_MRS_PL:            "MRS.PL",
+	arm_MRS_VS:            "MRS.VS",
+	arm_MRS_VC:            "MRS.VC",
+	arm_MRS_HI:            "MRS.HI",
+	arm_MRS_LS:            "MRS.LS",
+	arm_MRS_GE:            "MRS.GE",
+	arm_MRS_LT:            "MRS.LT",
+	arm_MRS_GT:            "MRS.GT",
+	arm_MRS_LE:            "MRS.LE",
+	arm_MRS:               "MRS",
+	arm_MRS_ZZ:            "MRS.ZZ",
+	arm_MUL_EQ:            "MUL.EQ",
+	arm_MUL_NE:            "MUL.NE",
+	arm_MUL_CS:            "MUL.CS",
+	arm_MUL_CC:            "MUL.CC",
+	arm_MUL_MI:            "MUL.MI",
+	arm_MUL_PL:            "MUL.PL",
+	arm_MUL_VS:            "MUL.VS",
+	arm_MUL_VC:            "MUL.VC",
+	arm_MUL_HI:            "MUL.HI",
+	arm_MUL_LS:            "MUL.LS",
+	arm_MUL_GE:            "MUL.GE",
+	arm_MUL_LT:            "MUL.LT",
+	arm_MUL_GT:            "MUL.GT",
+	arm_MUL_LE:            "MUL.LE",
+	arm_MUL:               "MUL",
+	arm_MUL_ZZ:            "MUL.ZZ",
+	arm_MUL_S_EQ:          "MUL.S.EQ",
+	arm_MUL_S_NE:          "MUL.S.NE",
+	arm_MUL_S_CS:          "MUL.S.CS",
+	arm_MUL_S_CC:          "MUL.S.CC",
+	arm_MUL_S_MI:          "MUL.S.MI",
+	arm_MUL_S_PL:          "MUL.S.PL",
+	arm_MUL_S_VS:          "MUL.S.VS",
+	arm_MUL_S_VC:          "MUL.S.VC",
+	arm_MUL_S_HI:          "MUL.S.HI",
+	arm_MUL_S_LS:          "MUL.S.LS",
+	arm_MUL_S_GE:          "MUL.S.GE",
+	arm_MUL_S_LT:          "MUL.S.LT",
+	arm_MUL_S_GT:          "MUL.S.GT",
+	arm_MUL_S_LE:          "MUL.S.LE",
+	arm_MUL_S:             "MUL.S",
+	arm_MUL_S_ZZ:          "MUL.S.ZZ",
+	arm_MVN_EQ:            "MVN.EQ",
+	arm_MVN_NE:            "MVN.NE",
+	arm_MVN_CS:            "MVN.CS",
+	arm_MVN_CC:            "MVN.CC",
+	arm_MVN_MI:            "MVN.MI",
+	arm_MVN_PL:            "MVN.PL",
+	arm_MVN_VS:            "MVN.VS",
+	arm_MVN_VC:            "MVN.VC",
+	arm_MVN_HI:            "MVN.HI",
+	arm_MVN_LS:            "MVN.LS",
+	arm_MVN_GE:            "MVN.GE",
+	arm_MVN_LT:            "MVN.LT",
+	arm_MVN_GT:            "MVN.GT",
+	arm_MVN_LE:            "MVN.LE",
+	arm_MVN:               "MVN",
+	arm_MVN_ZZ:            "MVN.ZZ",
+	arm_MVN_S_EQ:          "MVN.S.EQ",
+	arm_MVN_S_NE:          "MVN.S.NE",
+	arm_MVN_S_CS:          "MVN.S.CS",
+	arm_MVN_S_CC:          "MVN.S.CC",
+	arm_MVN_S_MI:          "MVN.S.MI",
+	arm_MVN_S_PL:          "MVN.S.PL",
+	arm_MVN_S_VS:          "MVN.S.VS",
+	arm_MVN_S_VC:          "MVN.S.VC",
+	arm_MVN_S_HI:          "MVN.S.HI",
+	arm_MVN_S_LS:          "MVN.S.LS",
+	arm_MVN_S_GE:          "MVN.S.GE",
+	arm_MVN_S_LT:          "MVN.S.LT",
+	arm_MVN_S_GT:          "MVN.S.GT",
+	arm_MVN_S_LE:          "MVN.S.LE",
+	arm_MVN_S:             "MVN.S",
+	arm_MVN_S_ZZ:          "MVN.S.ZZ",
+	arm_NOP_EQ:            "NOP.EQ",
+	arm_NOP_NE:            "NOP.NE",
+	arm_NOP_CS:            "NOP.CS",
+	arm_NOP_CC:            "NOP.CC",
+	arm_NOP_MI:            "NOP.MI",
+	arm_NOP_PL:            "NOP.PL",
+	arm_NOP_VS:            "NOP.VS",
+	arm_NOP_VC:            "NOP.VC",
+	arm_NOP_HI:            "NOP.HI",
+	arm_NOP_LS:            "NOP.LS",
+	arm_NOP_GE:            "NOP.GE",
+	arm_NOP_LT:            "NOP.LT",
+	arm_NOP_GT:            "NOP.GT",
+	arm_NOP_LE:            "NOP.LE",
+	arm_NOP:               "NOP",
+	arm_NOP_ZZ:            "NOP.ZZ",
+	arm_ORR_EQ:            "ORR.EQ",
+	arm_ORR_NE:            "ORR.NE",
+	arm_ORR_CS:            "ORR.CS",
+	arm_ORR_CC:            "ORR.CC",
+	arm_ORR_MI:            "ORR.MI",
+	arm_ORR_PL:            "ORR.PL",
+	arm_ORR_VS:            "ORR.VS",
+	arm_ORR_VC:            "ORR.VC",
+	arm_ORR_HI:            "ORR.HI",
+	arm_ORR_LS:            "ORR.LS",
+	arm_ORR_GE:            "ORR.GE",
+	arm_ORR_LT:            "ORR.LT",
+	arm_ORR_GT:            "ORR.GT",
+	arm_ORR_LE:            "ORR.LE",
+	arm_ORR:               "ORR",
+	arm_ORR_ZZ:            "ORR.ZZ",
+	arm_ORR_S_EQ:          "ORR.S.EQ",
+	arm_ORR_S_NE:          "ORR.S.NE",
+	arm_ORR_S_CS:          "ORR.S.CS",
+	arm_ORR_S_CC:          "ORR.S.CC",
+	arm_ORR_S_MI:          "ORR.S.MI",
+	arm_ORR_S_PL:          "ORR.S.PL",
+	arm_ORR_S_VS:          "ORR.S.VS",
+	arm_ORR_S_VC:          "ORR.S.VC",
+	arm_ORR_S_HI:          "ORR.S.HI",
+	arm_ORR_S_LS:          "ORR.S.LS",
+	arm_ORR_S_GE:          "ORR.S.GE",
+	arm_ORR_S_LT:          "ORR.S.LT",
+	arm_ORR_S_GT:          "ORR.S.GT",
+	arm_ORR_S_LE:          "ORR.S.LE",
+	arm_ORR_S:             "ORR.S",
+	arm_ORR_S_ZZ:          "ORR.S.ZZ",
+	arm_PKHBT_EQ:          "PKHBT.EQ",
+	arm_PKHBT_NE:          "PKHBT.NE",
+	arm_PKHBT_CS:          "PKHBT.CS",
+	arm_PKHBT_CC:          "PKHBT.CC",
+	arm_PKHBT_MI:          "PKHBT.MI",
+	arm_PKHBT_PL:          "PKHBT.PL",
+	arm_PKHBT_VS:          "PKHBT.VS",
+	arm_PKHBT_VC:          "PKHBT.VC",
+	arm_PKHBT_HI:          "PKHBT.HI",
+	arm_PKHBT_LS:          "PKHBT.LS",
+	arm_PKHBT_GE:          "PKHBT.GE",
+	arm_PKHBT_LT:          "PKHBT.LT",
+	arm_PKHBT_GT:          "PKHBT.GT",
+	arm_PKHBT_LE:          "PKHBT.LE",
+	arm_PKHBT:             "PKHBT",
+	arm_PKHBT_ZZ:          "PKHBT.ZZ",
+	arm_PKHTB_EQ:          "PKHTB.EQ",
+	arm_PKHTB_NE:          "PKHTB.NE",
+	arm_PKHTB_CS:          "PKHTB.CS",
+	arm_PKHTB_CC:          "PKHTB.CC",
+	arm_PKHTB_MI:          "PKHTB.MI",
+	arm_PKHTB_PL:          "PKHTB.PL",
+	arm_PKHTB_VS:          "PKHTB.VS",
+	arm_PKHTB_VC:          "PKHTB.VC",
+	arm_PKHTB_HI:          "PKHTB.HI",
+	arm_PKHTB_LS:          "PKHTB.LS",
+	arm_PKHTB_GE:          "PKHTB.GE",
+	arm_PKHTB_LT:          "PKHTB.LT",
+	arm_PKHTB_GT:          "PKHTB.GT",
+	arm_PKHTB_LE:          "PKHTB.LE",
+	arm_PKHTB:             "PKHTB",
+	arm_PKHTB_ZZ:          "PKHTB.ZZ",
+	arm_PLD_W:             "PLD.W",
+	arm_PLD:               "PLD",
+	arm_PLI:               "PLI",
+	arm_POP_EQ:            "POP.EQ",
+	arm_POP_NE:            "POP.NE",
+	arm_POP_CS:            "POP.CS",
+	arm_POP_CC:            "POP.CC",
+	arm_POP_MI:            "POP.MI",
+	arm_POP_PL:            "POP.PL",
+	arm_POP_VS:            "POP.VS",
+	arm_POP_VC:            "POP.VC",
+	arm_POP_HI:            "POP.HI",
+	arm_POP_LS:            "POP.LS",
+	arm_POP_GE:            "POP.GE",
+	arm_POP_LT:            "POP.LT",
+	arm_POP_GT:            "POP.GT",
+	arm_POP_LE:            "POP.LE",
+	arm_POP:               "POP",
+	arm_POP_ZZ:            "POP.ZZ",
+	arm_PUSH_EQ:           "PUSH.EQ",
+	arm_PUSH_NE:           "PUSH.NE",
+	arm_PUSH_CS:           "PUSH.CS",
+	arm_PUSH_CC:           "PUSH.CC",
+	arm_PUSH_MI:           "PUSH.MI",
+	arm_PUSH_PL:           "PUSH.PL",
+	arm_PUSH_VS:           "PUSH.VS",
+	arm_PUSH_VC:           "PUSH.VC",
+	arm_PUSH_HI:           "PUSH.HI",
+	arm_PUSH_LS:           "PUSH.LS",
+	arm_PUSH_GE:           "PUSH.GE",
+	arm_PUSH_LT:           "PUSH.LT",
+	arm_PUSH_GT:           "PUSH.GT",
+	arm_PUSH_LE:           "PUSH.LE",
+	arm_PUSH:              "PUSH",
+	arm_PUSH_ZZ:           "PUSH.ZZ",
+	arm_QADD_EQ:           "QADD.EQ",
+	arm_QADD_NE:           "QADD.NE",
+	arm_QADD_CS:           "QADD.CS",
+	arm_QADD_CC:           "QADD.CC",
+	arm_QADD_MI:           "QADD.MI",
+	arm_QADD_PL:           "QADD.PL",
+	arm_QADD_VS:           "QADD.VS",
+	arm_QADD_VC:           "QADD.VC",
+	arm_QADD_HI:           "QADD.HI",
+	arm_QADD_LS:           "QADD.LS",
+	arm_QADD_GE:           "QADD.GE",
+	arm_QADD_LT:           "QADD.LT",
+	arm_QADD_GT:           "QADD.GT",
+	arm_QADD_LE:           "QADD.LE",
+	arm_QADD:              "QADD",
+	arm_QADD_ZZ:           "QADD.ZZ",
+	arm_QADD16_EQ:         "QADD16.EQ",
+	arm_QADD16_NE:         "QADD16.NE",
+	arm_QADD16_CS:         "QADD16.CS",
+	arm_QADD16_CC:         "QADD16.CC",
+	arm_QADD16_MI:         "QADD16.MI",
+	arm_QADD16_PL:         "QADD16.PL",
+	arm_QADD16_VS:         "QADD16.VS",
+	arm_QADD16_VC:         "QADD16.VC",
+	arm_QADD16_HI:         "QADD16.HI",
+	arm_QADD16_LS:         "QADD16.LS",
+	arm_QADD16_GE:         "QADD16.GE",
+	arm_QADD16_LT:         "QADD16.LT",
+	arm_QADD16_GT:         "QADD16.GT",
+	arm_QADD16_LE:         "QADD16.LE",
+	arm_QADD16:            "QADD16",
+	arm_QADD16_ZZ:         "QADD16.ZZ",
+	arm_QADD8_EQ:          "QADD8.EQ",
+	arm_QADD8_NE:          "QADD8.NE",
+	arm_QADD8_CS:          "QADD8.CS",
+	arm_QADD8_CC:          "QADD8.CC",
+	arm_QADD8_MI:          "QADD8.MI",
+	arm_QADD8_PL:          "QADD8.PL",
+	arm_QADD8_VS:          "QADD8.VS",
+	arm_QADD8_VC:          "QADD8.VC",
+	arm_QADD8_HI:          "QADD8.HI",
+	arm_QADD8_LS:          "QADD8.LS",
+	arm_QADD8_GE:          "QADD8.GE",
+	arm_QADD8_LT:          "QADD8.LT",
+	arm_QADD8_GT:          "QADD8.GT",
+	arm_QADD8_LE:          "QADD8.LE",
+	arm_QADD8:             "QADD8",
+	arm_QADD8_ZZ:          "QADD8.ZZ",
+	arm_QASX_EQ:           "QASX.EQ",
+	arm_QASX_NE:           "QASX.NE",
+	arm_QASX_CS:           "QASX.CS",
+	arm_QASX_CC:           "QASX.CC",
+	arm_QASX_MI:           "QASX.MI",
+	arm_QASX_PL:           "QASX.PL",
+	arm_QASX_VS:           "QASX.VS",
+	arm_QASX_VC:           "QASX.VC",
+	arm_QASX_HI:           "QASX.HI",
+	arm_QASX_LS:           "QASX.LS",
+	arm_QASX_GE:           "QASX.GE",
+	arm_QASX_LT:           "QASX.LT",
+	arm_QASX_GT:           "QASX.GT",
+	arm_QASX_LE:           "QASX.LE",
+	arm_QASX:              "QASX",
+	arm_QASX_ZZ:           "QASX.ZZ",
+	arm_QDADD_EQ:          "QDADD.EQ",
+	arm_QDADD_NE:          "QDADD.NE",
+	arm_QDADD_CS:          "QDADD.CS",
+	arm_QDADD_CC:          "QDADD.CC",
+	arm_QDADD_MI:          "QDADD.MI",
+	arm_QDADD_PL:          "QDADD.PL",
+	arm_QDADD_VS:          "QDADD.VS",
+	arm_QDADD_VC:          "QDADD.VC",
+	arm_QDADD_HI:          "QDADD.HI",
+	arm_QDADD_LS:          "QDADD.LS",
+	arm_QDADD_GE:          "QDADD.GE",
+	arm_QDADD_LT:          "QDADD.LT",
+	arm_QDADD_GT:          "QDADD.GT",
+	arm_QDADD_LE:          "QDADD.LE",
+	arm_QDADD:             "QDADD",
+	arm_QDADD_ZZ:          "QDADD.ZZ",
+	arm_QDSUB_EQ:          "QDSUB.EQ",
+	arm_QDSUB_NE:          "QDSUB.NE",
+	arm_QDSUB_CS:          "QDSUB.CS",
+	arm_QDSUB_CC:          "QDSUB.CC",
+	arm_QDSUB_MI:          "QDSUB.MI",
+	arm_QDSUB_PL:          "QDSUB.PL",
+	arm_QDSUB_VS:          "QDSUB.VS",
+	arm_QDSUB_VC:          "QDSUB.VC",
+	arm_QDSUB_HI:          "QDSUB.HI",
+	arm_QDSUB_LS:          "QDSUB.LS",
+	arm_QDSUB_GE:          "QDSUB.GE",
+	arm_QDSUB_LT:          "QDSUB.LT",
+	arm_QDSUB_GT:          "QDSUB.GT",
+	arm_QDSUB_LE:          "QDSUB.LE",
+	arm_QDSUB:             "QDSUB",
+	arm_QDSUB_ZZ:          "QDSUB.ZZ",
+	arm_QSAX_EQ:           "QSAX.EQ",
+	arm_QSAX_NE:           "QSAX.NE",
+	arm_QSAX_CS:           "QSAX.CS",
+	arm_QSAX_CC:           "QSAX.CC",
+	arm_QSAX_MI:           "QSAX.MI",
+	arm_QSAX_PL:           "QSAX.PL",
+	arm_QSAX_VS:           "QSAX.VS",
+	arm_QSAX_VC:           "QSAX.VC",
+	arm_QSAX_HI:           "QSAX.HI",
+	arm_QSAX_LS:           "QSAX.LS",
+	arm_QSAX_GE:           "QSAX.GE",
+	arm_QSAX_LT:           "QSAX.LT",
+	arm_QSAX_GT:           "QSAX.GT",
+	arm_QSAX_LE:           "QSAX.LE",
+	arm_QSAX:              "QSAX",
+	arm_QSAX_ZZ:           "QSAX.ZZ",
+	arm_QSUB_EQ:           "QSUB.EQ",
+	arm_QSUB_NE:           "QSUB.NE",
+	arm_QSUB_CS:           "QSUB.CS",
+	arm_QSUB_CC:           "QSUB.CC",
+	arm_QSUB_MI:           "QSUB.MI",
+	arm_QSUB_PL:           "QSUB.PL",
+	arm_QSUB_VS:           "QSUB.VS",
+	arm_QSUB_VC:           "QSUB.VC",
+	arm_QSUB_HI:           "QSUB.HI",
+	arm_QSUB_LS:           "QSUB.LS",
+	arm_QSUB_GE:           "QSUB.GE",
+	arm_QSUB_LT:           "QSUB.LT",
+	arm_QSUB_GT:           "QSUB.GT",
+	arm_QSUB_LE:           "QSUB.LE",
+	arm_QSUB:              "QSUB",
+	arm_QSUB_ZZ:           "QSUB.ZZ",
+	arm_QSUB16_EQ:         "QSUB16.EQ",
+	arm_QSUB16_NE:         "QSUB16.NE",
+	arm_QSUB16_CS:         "QSUB16.CS",
+	arm_QSUB16_CC:         "QSUB16.CC",
+	arm_QSUB16_MI:         "QSUB16.MI",
+	arm_QSUB16_PL:         "QSUB16.PL",
+	arm_QSUB16_VS:         "QSUB16.VS",
+	arm_QSUB16_VC:         "QSUB16.VC",
+	arm_QSUB16_HI:         "QSUB16.HI",
+	arm_QSUB16_LS:         "QSUB16.LS",
+	arm_QSUB16_GE:         "QSUB16.GE",
+	arm_QSUB16_LT:         "QSUB16.LT",
+	arm_QSUB16_GT:         "QSUB16.GT",
+	arm_QSUB16_LE:         "QSUB16.LE",
+	arm_QSUB16:            "QSUB16",
+	arm_QSUB16_ZZ:         "QSUB16.ZZ",
+	arm_QSUB8_EQ:          "QSUB8.EQ",
+	arm_QSUB8_NE:          "QSUB8.NE",
+	arm_QSUB8_CS:          "QSUB8.CS",
+	arm_QSUB8_CC:          "QSUB8.CC",
+	arm_QSUB8_MI:          "QSUB8.MI",
+	arm_QSUB8_PL:          "QSUB8.PL",
+	arm_QSUB8_VS:          "QSUB8.VS",
+	arm_QSUB8_VC:          "QSUB8.VC",
+	arm_QSUB8_HI:          "QSUB8.HI",
+	arm_QSUB8_LS:          "QSUB8.LS",
+	arm_QSUB8_GE:          "QSUB8.GE",
+	arm_QSUB8_LT:          "QSUB8.LT",
+	arm_QSUB8_GT:          "QSUB8.GT",
+	arm_QSUB8_LE:          "QSUB8.LE",
+	arm_QSUB8:             "QSUB8",
+	arm_QSUB8_ZZ:          "QSUB8.ZZ",
+	arm_RBIT_EQ:           "RBIT.EQ",
+	arm_RBIT_NE:           "RBIT.NE",
+	arm_RBIT_CS:           "RBIT.CS",
+	arm_RBIT_CC:           "RBIT.CC",
+	arm_RBIT_MI:           "RBIT.MI",
+	arm_RBIT_PL:           "RBIT.PL",
+	arm_RBIT_VS:           "RBIT.VS",
+	arm_RBIT_VC:           "RBIT.VC",
+	arm_RBIT_HI:           "RBIT.HI",
+	arm_RBIT_LS:           "RBIT.LS",
+	arm_RBIT_GE:           "RBIT.GE",
+	arm_RBIT_LT:           "RBIT.LT",
+	arm_RBIT_GT:           "RBIT.GT",
+	arm_RBIT_LE:           "RBIT.LE",
+	arm_RBIT:              "RBIT",
+	arm_RBIT_ZZ:           "RBIT.ZZ",
+	arm_REV_EQ:            "REV.EQ",
+	arm_REV_NE:            "REV.NE",
+	arm_REV_CS:            "REV.CS",
+	arm_REV_CC:            "REV.CC",
+	arm_REV_MI:            "REV.MI",
+	arm_REV_PL:            "REV.PL",
+	arm_REV_VS:            "REV.VS",
+	arm_REV_VC:            "REV.VC",
+	arm_REV_HI:            "REV.HI",
+	arm_REV_LS:            "REV.LS",
+	arm_REV_GE:            "REV.GE",
+	arm_REV_LT:            "REV.LT",
+	arm_REV_GT:            "REV.GT",
+	arm_REV_LE:            "REV.LE",
+	arm_REV:               "REV",
+	arm_REV_ZZ:            "REV.ZZ",
+	arm_REV16_EQ:          "REV16.EQ",
+	arm_REV16_NE:          "REV16.NE",
+	arm_REV16_CS:          "REV16.CS",
+	arm_REV16_CC:          "REV16.CC",
+	arm_REV16_MI:          "REV16.MI",
+	arm_REV16_PL:          "REV16.PL",
+	arm_REV16_VS:          "REV16.VS",
+	arm_REV16_VC:          "REV16.VC",
+	arm_REV16_HI:          "REV16.HI",
+	arm_REV16_LS:          "REV16.LS",
+	arm_REV16_GE:          "REV16.GE",
+	arm_REV16_LT:          "REV16.LT",
+	arm_REV16_GT:          "REV16.GT",
+	arm_REV16_LE:          "REV16.LE",
+	arm_REV16:             "REV16",
+	arm_REV16_ZZ:          "REV16.ZZ",
+	arm_REVSH_EQ:          "REVSH.EQ",
+	arm_REVSH_NE:          "REVSH.NE",
+	arm_REVSH_CS:          "REVSH.CS",
+	arm_REVSH_CC:          "REVSH.CC",
+	arm_REVSH_MI:          "REVSH.MI",
+	arm_REVSH_PL:          "REVSH.PL",
+	arm_REVSH_VS:          "REVSH.VS",
+	arm_REVSH_VC:          "REVSH.VC",
+	arm_REVSH_HI:          "REVSH.HI",
+	arm_REVSH_LS:          "REVSH.LS",
+	arm_REVSH_GE:          "REVSH.GE",
+	arm_REVSH_LT:          "REVSH.LT",
+	arm_REVSH_GT:          "REVSH.GT",
+	arm_REVSH_LE:          "REVSH.LE",
+	arm_REVSH:             "REVSH",
+	arm_REVSH_ZZ:          "REVSH.ZZ",
+	arm_ROR_EQ:            "ROR.EQ",
+	arm_ROR_NE:            "ROR.NE",
+	arm_ROR_CS:            "ROR.CS",
+	arm_ROR_CC:            "ROR.CC",
+	arm_ROR_MI:            "ROR.MI",
+	arm_ROR_PL:            "ROR.PL",
+	arm_ROR_VS:            "ROR.VS",
+	arm_ROR_VC:            "ROR.VC",
+	arm_ROR_HI:            "ROR.HI",
+	arm_ROR_LS:            "ROR.LS",
+	arm_ROR_GE:            "ROR.GE",
+	arm_ROR_LT:            "ROR.LT",
+	arm_ROR_GT:            "ROR.GT",
+	arm_ROR_LE:            "ROR.LE",
+	arm_ROR:               "ROR",
+	arm_ROR_ZZ:            "ROR.ZZ",
+	arm_ROR_S_EQ:          "ROR.S.EQ",
+	arm_ROR_S_NE:          "ROR.S.NE",
+	arm_ROR_S_CS:          "ROR.S.CS",
+	arm_ROR_S_CC:          "ROR.S.CC",
+	arm_ROR_S_MI:          "ROR.S.MI",
+	arm_ROR_S_PL:          "ROR.S.PL",
+	arm_ROR_S_VS:          "ROR.S.VS",
+	arm_ROR_S_VC:          "ROR.S.VC",
+	arm_ROR_S_HI:          "ROR.S.HI",
+	arm_ROR_S_LS:          "ROR.S.LS",
+	arm_ROR_S_GE:          "ROR.S.GE",
+	arm_ROR_S_LT:          "ROR.S.LT",
+	arm_ROR_S_GT:          "ROR.S.GT",
+	arm_ROR_S_LE:          "ROR.S.LE",
+	arm_ROR_S:             "ROR.S",
+	arm_ROR_S_ZZ:          "ROR.S.ZZ",
+	arm_RRX_EQ:            "RRX.EQ",
+	arm_RRX_NE:            "RRX.NE",
+	arm_RRX_CS:            "RRX.CS",
+	arm_RRX_CC:            "RRX.CC",
+	arm_RRX_MI:            "RRX.MI",
+	arm_RRX_PL:            "RRX.PL",
+	arm_RRX_VS:            "RRX.VS",
+	arm_RRX_VC:            "RRX.VC",
+	arm_RRX_HI:            "RRX.HI",
+	arm_RRX_LS:            "RRX.LS",
+	arm_RRX_GE:            "RRX.GE",
+	arm_RRX_LT:            "RRX.LT",
+	arm_RRX_GT:            "RRX.GT",
+	arm_RRX_LE:            "RRX.LE",
+	arm_RRX:               "RRX",
+	arm_RRX_ZZ:            "RRX.ZZ",
+	arm_RRX_S_EQ:          "RRX.S.EQ",
+	arm_RRX_S_NE:          "RRX.S.NE",
+	arm_RRX_S_CS:          "RRX.S.CS",
+	arm_RRX_S_CC:          "RRX.S.CC",
+	arm_RRX_S_MI:          "RRX.S.MI",
+	arm_RRX_S_PL:          "RRX.S.PL",
+	arm_RRX_S_VS:          "RRX.S.VS",
+	arm_RRX_S_VC:          "RRX.S.VC",
+	arm_RRX_S_HI:          "RRX.S.HI",
+	arm_RRX_S_LS:          "RRX.S.LS",
+	arm_RRX_S_GE:          "RRX.S.GE",
+	arm_RRX_S_LT:          "RRX.S.LT",
+	arm_RRX_S_GT:          "RRX.S.GT",
+	arm_RRX_S_LE:          "RRX.S.LE",
+	arm_RRX_S:             "RRX.S",
+	arm_RRX_S_ZZ:          "RRX.S.ZZ",
+	arm_RSB_EQ:            "RSB.EQ",
+	arm_RSB_NE:            "RSB.NE",
+	arm_RSB_CS:            "RSB.CS",
+	arm_RSB_CC:            "RSB.CC",
+	arm_RSB_MI:            "RSB.MI",
+	arm_RSB_PL:            "RSB.PL",
+	arm_RSB_VS:            "RSB.VS",
+	arm_RSB_VC:            "RSB.VC",
+	arm_RSB_HI:            "RSB.HI",
+	arm_RSB_LS:            "RSB.LS",
+	arm_RSB_GE:            "RSB.GE",
+	arm_RSB_LT:            "RSB.LT",
+	arm_RSB_GT:            "RSB.GT",
+	arm_RSB_LE:            "RSB.LE",
+	arm_RSB:               "RSB",
+	arm_RSB_ZZ:            "RSB.ZZ",
+	arm_RSB_S_EQ:          "RSB.S.EQ",
+	arm_RSB_S_NE:          "RSB.S.NE",
+	arm_RSB_S_CS:          "RSB.S.CS",
+	arm_RSB_S_CC:          "RSB.S.CC",
+	arm_RSB_S_MI:          "RSB.S.MI",
+	arm_RSB_S_PL:          "RSB.S.PL",
+	arm_RSB_S_VS:          "RSB.S.VS",
+	arm_RSB_S_VC:          "RSB.S.VC",
+	arm_RSB_S_HI:          "RSB.S.HI",
+	arm_RSB_S_LS:          "RSB.S.LS",
+	arm_RSB_S_GE:          "RSB.S.GE",
+	arm_RSB_S_LT:          "RSB.S.LT",
+	arm_RSB_S_GT:          "RSB.S.GT",
+	arm_RSB_S_LE:          "RSB.S.LE",
+	arm_RSB_S:             "RSB.S",
+	arm_RSB_S_ZZ:          "RSB.S.ZZ",
+	arm_RSC_EQ:            "RSC.EQ",
+	arm_RSC_NE:            "RSC.NE",
+	arm_RSC_CS:            "RSC.CS",
+	arm_RSC_CC:            "RSC.CC",
+	arm_RSC_MI:            "RSC.MI",
+	arm_RSC_PL:            "RSC.PL",
+	arm_RSC_VS:            "RSC.VS",
+	arm_RSC_VC:            "RSC.VC",
+	arm_RSC_HI:            "RSC.HI",
+	arm_RSC_LS:            "RSC.LS",
+	arm_RSC_GE:            "RSC.GE",
+	arm_RSC_LT:            "RSC.LT",
+	arm_RSC_GT:            "RSC.GT",
+	arm_RSC_LE:            "RSC.LE",
+	arm_RSC:               "RSC",
+	arm_RSC_ZZ:            "RSC.ZZ",
+	arm_RSC_S_EQ:          "RSC.S.EQ",
+	arm_RSC_S_NE:          "RSC.S.NE",
+	arm_RSC_S_CS:          "RSC.S.CS",
+	arm_RSC_S_CC:          "RSC.S.CC",
+	arm_RSC_S_MI:          "RSC.S.MI",
+	arm_RSC_S_PL:          "RSC.S.PL",
+	arm_RSC_S_VS:          "RSC.S.VS",
+	arm_RSC_S_VC:          "RSC.S.VC",
+	arm_RSC_S_HI:          "RSC.S.HI",
+	arm_RSC_S_LS:          "RSC.S.LS",
+	arm_RSC_S_GE:          "RSC.S.GE",
+	arm_RSC_S_LT:          "RSC.S.LT",
+	arm_RSC_S_GT:          "RSC.S.GT",
+	arm_RSC_S_LE:          "RSC.S.LE",
+	arm_RSC_S:             "RSC.S",
+	arm_RSC_S_ZZ:          "RSC.S.ZZ",
+	arm_SADD16_EQ:         "SADD16.EQ",
+	arm_SADD16_NE:         "SADD16.NE",
+	arm_SADD16_CS:         "SADD16.CS",
+	arm_SADD16_CC:         "SADD16.CC",
+	arm_SADD16_MI:         "SADD16.MI",
+	arm_SADD16_PL:         "SADD16.PL",
+	arm_SADD16_VS:         "SADD16.VS",
+	arm_SADD16_VC:         "SADD16.VC",
+	arm_SADD16_HI:         "SADD16.HI",
+	arm_SADD16_LS:         "SADD16.LS",
+	arm_SADD16_GE:         "SADD16.GE",
+	arm_SADD16_LT:         "SADD16.LT",
+	arm_SADD16_GT:         "SADD16.GT",
+	arm_SADD16_LE:         "SADD16.LE",
+	arm_SADD16:            "SADD16",
+	arm_SADD16_ZZ:         "SADD16.ZZ",
+	arm_SADD8_EQ:          "SADD8.EQ",
+	arm_SADD8_NE:          "SADD8.NE",
+	arm_SADD8_CS:          "SADD8.CS",
+	arm_SADD8_CC:          "SADD8.CC",
+	arm_SADD8_MI:          "SADD8.MI",
+	arm_SADD8_PL:          "SADD8.PL",
+	arm_SADD8_VS:          "SADD8.VS",
+	arm_SADD8_VC:          "SADD8.VC",
+	arm_SADD8_HI:          "SADD8.HI",
+	arm_SADD8_LS:          "SADD8.LS",
+	arm_SADD8_GE:          "SADD8.GE",
+	arm_SADD8_LT:          "SADD8.LT",
+	arm_SADD8_GT:          "SADD8.GT",
+	arm_SADD8_LE:          "SADD8.LE",
+	arm_SADD8:             "SADD8",
+	arm_SADD8_ZZ:          "SADD8.ZZ",
+	arm_SASX_EQ:           "SASX.EQ",
+	arm_SASX_NE:           "SASX.NE",
+	arm_SASX_CS:           "SASX.CS",
+	arm_SASX_CC:           "SASX.CC",
+	arm_SASX_MI:           "SASX.MI",
+	arm_SASX_PL:           "SASX.PL",
+	arm_SASX_VS:           "SASX.VS",
+	arm_SASX_VC:           "SASX.VC",
+	arm_SASX_HI:           "SASX.HI",
+	arm_SASX_LS:           "SASX.LS",
+	arm_SASX_GE:           "SASX.GE",
+	arm_SASX_LT:           "SASX.LT",
+	arm_SASX_GT:           "SASX.GT",
+	arm_SASX_LE:           "SASX.LE",
+	arm_SASX:              "SASX",
+	arm_SASX_ZZ:           "SASX.ZZ",
+	arm_SBC_EQ:            "SBC.EQ",
+	arm_SBC_NE:            "SBC.NE",
+	arm_SBC_CS:            "SBC.CS",
+	arm_SBC_CC:            "SBC.CC",
+	arm_SBC_MI:            "SBC.MI",
+	arm_SBC_PL:            "SBC.PL",
+	arm_SBC_VS:            "SBC.VS",
+	arm_SBC_VC:            "SBC.VC",
+	arm_SBC_HI:            "SBC.HI",
+	arm_SBC_LS:            "SBC.LS",
+	arm_SBC_GE:            "SBC.GE",
+	arm_SBC_LT:            "SBC.LT",
+	arm_SBC_GT:            "SBC.GT",
+	arm_SBC_LE:            "SBC.LE",
+	arm_SBC:               "SBC",
+	arm_SBC_ZZ:            "SBC.ZZ",
+	arm_SBC_S_EQ:          "SBC.S.EQ",
+	arm_SBC_S_NE:          "SBC.S.NE",
+	arm_SBC_S_CS:          "SBC.S.CS",
+	arm_SBC_S_CC:          "SBC.S.CC",
+	arm_SBC_S_MI:          "SBC.S.MI",
+	arm_SBC_S_PL:          "SBC.S.PL",
+	arm_SBC_S_VS:          "SBC.S.VS",
+	arm_SBC_S_VC:          "SBC.S.VC",
+	arm_SBC_S_HI:          "SBC.S.HI",
+	arm_SBC_S_LS:          "SBC.S.LS",
+	arm_SBC_S_GE:          "SBC.S.GE",
+	arm_SBC_S_LT:          "SBC.S.LT",
+	arm_SBC_S_GT:          "SBC.S.GT",
+	arm_SBC_S_LE:          "SBC.S.LE",
+	arm_SBC_S:             "SBC.S",
+	arm_SBC_S_ZZ:          "SBC.S.ZZ",
+	arm_SBFX_EQ:           "SBFX.EQ",
+	arm_SBFX_NE:           "SBFX.NE",
+	arm_SBFX_CS:           "SBFX.CS",
+	arm_SBFX_CC:           "SBFX.CC",
+	arm_SBFX_MI:           "SBFX.MI",
+	arm_SBFX_PL:           "SBFX.PL",
+	arm_SBFX_VS:           "SBFX.VS",
+	arm_SBFX_VC:           "SBFX.VC",
+	arm_SBFX_HI:           "SBFX.HI",
+	arm_SBFX_LS:           "SBFX.LS",
+	arm_SBFX_GE:           "SBFX.GE",
+	arm_SBFX_LT:           "SBFX.LT",
+	arm_SBFX_GT:           "SBFX.GT",
+	arm_SBFX_LE:           "SBFX.LE",
+	arm_SBFX:              "SBFX",
+	arm_SBFX_ZZ:           "SBFX.ZZ",
+	arm_SEL_EQ:            "SEL.EQ",
+	arm_SEL_NE:            "SEL.NE",
+	arm_SEL_CS:            "SEL.CS",
+	arm_SEL_CC:            "SEL.CC",
+	arm_SEL_MI:            "SEL.MI",
+	arm_SEL_PL:            "SEL.PL",
+	arm_SEL_VS:            "SEL.VS",
+	arm_SEL_VC:            "SEL.VC",
+	arm_SEL_HI:            "SEL.HI",
+	arm_SEL_LS:            "SEL.LS",
+	arm_SEL_GE:            "SEL.GE",
+	arm_SEL_LT:            "SEL.LT",
+	arm_SEL_GT:            "SEL.GT",
+	arm_SEL_LE:            "SEL.LE",
+	arm_SEL:               "SEL",
+	arm_SEL_ZZ:            "SEL.ZZ",
+	arm_SETEND:            "SETEND",
+	arm_SEV_EQ:            "SEV.EQ",
+	arm_SEV_NE:            "SEV.NE",
+	arm_SEV_CS:            "SEV.CS",
+	arm_SEV_CC:            "SEV.CC",
+	arm_SEV_MI:            "SEV.MI",
+	arm_SEV_PL:            "SEV.PL",
+	arm_SEV_VS:            "SEV.VS",
+	arm_SEV_VC:            "SEV.VC",
+	arm_SEV_HI:            "SEV.HI",
+	arm_SEV_LS:            "SEV.LS",
+	arm_SEV_GE:            "SEV.GE",
+	arm_SEV_LT:            "SEV.LT",
+	arm_SEV_GT:            "SEV.GT",
+	arm_SEV_LE:            "SEV.LE",
+	arm_SEV:               "SEV",
+	arm_SEV_ZZ:            "SEV.ZZ",
+	arm_SHADD16_EQ:        "SHADD16.EQ",
+	arm_SHADD16_NE:        "SHADD16.NE",
+	arm_SHADD16_CS:        "SHADD16.CS",
+	arm_SHADD16_CC:        "SHADD16.CC",
+	arm_SHADD16_MI:        "SHADD16.MI",
+	arm_SHADD16_PL:        "SHADD16.PL",
+	arm_SHADD16_VS:        "SHADD16.VS",
+	arm_SHADD16_VC:        "SHADD16.VC",
+	arm_SHADD16_HI:        "SHADD16.HI",
+	arm_SHADD16_LS:        "SHADD16.LS",
+	arm_SHADD16_GE:        "SHADD16.GE",
+	arm_SHADD16_LT:        "SHADD16.LT",
+	arm_SHADD16_GT:        "SHADD16.GT",
+	arm_SHADD16_LE:        "SHADD16.LE",
+	arm_SHADD16:           "SHADD16",
+	arm_SHADD16_ZZ:        "SHADD16.ZZ",
+	arm_SHADD8_EQ:         "SHADD8.EQ",
+	arm_SHADD8_NE:         "SHADD8.NE",
+	arm_SHADD8_CS:         "SHADD8.CS",
+	arm_SHADD8_CC:         "SHADD8.CC",
+	arm_SHADD8_MI:         "SHADD8.MI",
+	arm_SHADD8_PL:         "SHADD8.PL",
+	arm_SHADD8_VS:         "SHADD8.VS",
+	arm_SHADD8_VC:         "SHADD8.VC",
+	arm_SHADD8_HI:         "SHADD8.HI",
+	arm_SHADD8_LS:         "SHADD8.LS",
+	arm_SHADD8_GE:         "SHADD8.GE",
+	arm_SHADD8_LT:         "SHADD8.LT",
+	arm_SHADD8_GT:         "SHADD8.GT",
+	arm_SHADD8_LE:         "SHADD8.LE",
+	arm_SHADD8:            "SHADD8",
+	arm_SHADD8_ZZ:         "SHADD8.ZZ",
+	arm_SHASX_EQ:          "SHASX.EQ",
+	arm_SHASX_NE:          "SHASX.NE",
+	arm_SHASX_CS:          "SHASX.CS",
+	arm_SHASX_CC:          "SHASX.CC",
+	arm_SHASX_MI:          "SHASX.MI",
+	arm_SHASX_PL:          "SHASX.PL",
+	arm_SHASX_VS:          "SHASX.VS",
+	arm_SHASX_VC:          "SHASX.VC",
+	arm_SHASX_HI:          "SHASX.HI",
+	arm_SHASX_LS:          "SHASX.LS",
+	arm_SHASX_GE:          "SHASX.GE",
+	arm_SHASX_LT:          "SHASX.LT",
+	arm_SHASX_GT:          "SHASX.GT",
+	arm_SHASX_LE:          "SHASX.LE",
+	arm_SHASX:             "SHASX",
+	arm_SHASX_ZZ:          "SHASX.ZZ",
+	arm_SHSAX_EQ:          "SHSAX.EQ",
+	arm_SHSAX_NE:          "SHSAX.NE",
+	arm_SHSAX_CS:          "SHSAX.CS",
+	arm_SHSAX_CC:          "SHSAX.CC",
+	arm_SHSAX_MI:          "SHSAX.MI",
+	arm_SHSAX_PL:          "SHSAX.PL",
+	arm_SHSAX_VS:          "SHSAX.VS",
+	arm_SHSAX_VC:          "SHSAX.VC",
+	arm_SHSAX_HI:          "SHSAX.HI",
+	arm_SHSAX_LS:          "SHSAX.LS",
+	arm_SHSAX_GE:          "SHSAX.GE",
+	arm_SHSAX_LT:          "SHSAX.LT",
+	arm_SHSAX_GT:          "SHSAX.GT",
+	arm_SHSAX_LE:          "SHSAX.LE",
+	arm_SHSAX:             "SHSAX",
+	arm_SHSAX_ZZ:          "SHSAX.ZZ",
+	arm_SHSUB16_EQ:        "SHSUB16.EQ",
+	arm_SHSUB16_NE:        "SHSUB16.NE",
+	arm_SHSUB16_CS:        "SHSUB16.CS",
+	arm_SHSUB16_CC:        "SHSUB16.CC",
+	arm_SHSUB16_MI:        "SHSUB16.MI",
+	arm_SHSUB16_PL:        "SHSUB16.PL",
+	arm_SHSUB16_VS:        "SHSUB16.VS",
+	arm_SHSUB16_VC:        "SHSUB16.VC",
+	arm_SHSUB16_HI:        "SHSUB16.HI",
+	arm_SHSUB16_LS:        "SHSUB16.LS",
+	arm_SHSUB16_GE:        "SHSUB16.GE",
+	arm_SHSUB16_LT:        "SHSUB16.LT",
+	arm_SHSUB16_GT:        "SHSUB16.GT",
+	arm_SHSUB16_LE:        "SHSUB16.LE",
+	arm_SHSUB16:           "SHSUB16",
+	arm_SHSUB16_ZZ:        "SHSUB16.ZZ",
+	arm_SHSUB8_EQ:         "SHSUB8.EQ",
+	arm_SHSUB8_NE:         "SHSUB8.NE",
+	arm_SHSUB8_CS:         "SHSUB8.CS",
+	arm_SHSUB8_CC:         "SHSUB8.CC",
+	arm_SHSUB8_MI:         "SHSUB8.MI",
+	arm_SHSUB8_PL:         "SHSUB8.PL",
+	arm_SHSUB8_VS:         "SHSUB8.VS",
+	arm_SHSUB8_VC:         "SHSUB8.VC",
+	arm_SHSUB8_HI:         "SHSUB8.HI",
+	arm_SHSUB8_LS:         "SHSUB8.LS",
+	arm_SHSUB8_GE:         "SHSUB8.GE",
+	arm_SHSUB8_LT:         "SHSUB8.LT",
+	arm_SHSUB8_GT:         "SHSUB8.GT",
+	arm_SHSUB8_LE:         "SHSUB8.LE",
+	arm_SHSUB8:            "SHSUB8",
+	arm_SHSUB8_ZZ:         "SHSUB8.ZZ",
+	arm_SMLABB_EQ:         "SMLABB.EQ",
+	arm_SMLABB_NE:         "SMLABB.NE",
+	arm_SMLABB_CS:         "SMLABB.CS",
+	arm_SMLABB_CC:         "SMLABB.CC",
+	arm_SMLABB_MI:         "SMLABB.MI",
+	arm_SMLABB_PL:         "SMLABB.PL",
+	arm_SMLABB_VS:         "SMLABB.VS",
+	arm_SMLABB_VC:         "SMLABB.VC",
+	arm_SMLABB_HI:         "SMLABB.HI",
+	arm_SMLABB_LS:         "SMLABB.LS",
+	arm_SMLABB_GE:         "SMLABB.GE",
+	arm_SMLABB_LT:         "SMLABB.LT",
+	arm_SMLABB_GT:         "SMLABB.GT",
+	arm_SMLABB_LE:         "SMLABB.LE",
+	arm_SMLABB:            "SMLABB",
+	arm_SMLABB_ZZ:         "SMLABB.ZZ",
+	arm_SMLABT_EQ:         "SMLABT.EQ",
+	arm_SMLABT_NE:         "SMLABT.NE",
+	arm_SMLABT_CS:         "SMLABT.CS",
+	arm_SMLABT_CC:         "SMLABT.CC",
+	arm_SMLABT_MI:         "SMLABT.MI",
+	arm_SMLABT_PL:         "SMLABT.PL",
+	arm_SMLABT_VS:         "SMLABT.VS",
+	arm_SMLABT_VC:         "SMLABT.VC",
+	arm_SMLABT_HI:         "SMLABT.HI",
+	arm_SMLABT_LS:         "SMLABT.LS",
+	arm_SMLABT_GE:         "SMLABT.GE",
+	arm_SMLABT_LT:         "SMLABT.LT",
+	arm_SMLABT_GT:         "SMLABT.GT",
+	arm_SMLABT_LE:         "SMLABT.LE",
+	arm_SMLABT:            "SMLABT",
+	arm_SMLABT_ZZ:         "SMLABT.ZZ",
+	arm_SMLATB_EQ:         "SMLATB.EQ",
+	arm_SMLATB_NE:         "SMLATB.NE",
+	arm_SMLATB_CS:         "SMLATB.CS",
+	arm_SMLATB_CC:         "SMLATB.CC",
+	arm_SMLATB_MI:         "SMLATB.MI",
+	arm_SMLATB_PL:         "SMLATB.PL",
+	arm_SMLATB_VS:         "SMLATB.VS",
+	arm_SMLATB_VC:         "SMLATB.VC",
+	arm_SMLATB_HI:         "SMLATB.HI",
+	arm_SMLATB_LS:         "SMLATB.LS",
+	arm_SMLATB_GE:         "SMLATB.GE",
+	arm_SMLATB_LT:         "SMLATB.LT",
+	arm_SMLATB_GT:         "SMLATB.GT",
+	arm_SMLATB_LE:         "SMLATB.LE",
+	arm_SMLATB:            "SMLATB",
+	arm_SMLATB_ZZ:         "SMLATB.ZZ",
+	arm_SMLATT_EQ:         "SMLATT.EQ",
+	arm_SMLATT_NE:         "SMLATT.NE",
+	arm_SMLATT_CS:         "SMLATT.CS",
+	arm_SMLATT_CC:         "SMLATT.CC",
+	arm_SMLATT_MI:         "SMLATT.MI",
+	arm_SMLATT_PL:         "SMLATT.PL",
+	arm_SMLATT_VS:         "SMLATT.VS",
+	arm_SMLATT_VC:         "SMLATT.VC",
+	arm_SMLATT_HI:         "SMLATT.HI",
+	arm_SMLATT_LS:         "SMLATT.LS",
+	arm_SMLATT_GE:         "SMLATT.GE",
+	arm_SMLATT_LT:         "SMLATT.LT",
+	arm_SMLATT_GT:         "SMLATT.GT",
+	arm_SMLATT_LE:         "SMLATT.LE",
+	arm_SMLATT:            "SMLATT",
+	arm_SMLATT_ZZ:         "SMLATT.ZZ",
+	arm_SMLAD_EQ:          "SMLAD.EQ",
+	arm_SMLAD_NE:          "SMLAD.NE",
+	arm_SMLAD_CS:          "SMLAD.CS",
+	arm_SMLAD_CC:          "SMLAD.CC",
+	arm_SMLAD_MI:          "SMLAD.MI",
+	arm_SMLAD_PL:          "SMLAD.PL",
+	arm_SMLAD_VS:          "SMLAD.VS",
+	arm_SMLAD_VC:          "SMLAD.VC",
+	arm_SMLAD_HI:          "SMLAD.HI",
+	arm_SMLAD_LS:          "SMLAD.LS",
+	arm_SMLAD_GE:          "SMLAD.GE",
+	arm_SMLAD_LT:          "SMLAD.LT",
+	arm_SMLAD_GT:          "SMLAD.GT",
+	arm_SMLAD_LE:          "SMLAD.LE",
+	arm_SMLAD:             "SMLAD",
+	arm_SMLAD_ZZ:          "SMLAD.ZZ",
+	arm_SMLAD_X_EQ:        "SMLAD.X.EQ",
+	arm_SMLAD_X_NE:        "SMLAD.X.NE",
+	arm_SMLAD_X_CS:        "SMLAD.X.CS",
+	arm_SMLAD_X_CC:        "SMLAD.X.CC",
+	arm_SMLAD_X_MI:        "SMLAD.X.MI",
+	arm_SMLAD_X_PL:        "SMLAD.X.PL",
+	arm_SMLAD_X_VS:        "SMLAD.X.VS",
+	arm_SMLAD_X_VC:        "SMLAD.X.VC",
+	arm_SMLAD_X_HI:        "SMLAD.X.HI",
+	arm_SMLAD_X_LS:        "SMLAD.X.LS",
+	arm_SMLAD_X_GE:        "SMLAD.X.GE",
+	arm_SMLAD_X_LT:        "SMLAD.X.LT",
+	arm_SMLAD_X_GT:        "SMLAD.X.GT",
+	arm_SMLAD_X_LE:        "SMLAD.X.LE",
+	arm_SMLAD_X:           "SMLAD.X",
+	arm_SMLAD_X_ZZ:        "SMLAD.X.ZZ",
+	arm_SMLAL_EQ:          "SMLAL.EQ",
+	arm_SMLAL_NE:          "SMLAL.NE",
+	arm_SMLAL_CS:          "SMLAL.CS",
+	arm_SMLAL_CC:          "SMLAL.CC",
+	arm_SMLAL_MI:          "SMLAL.MI",
+	arm_SMLAL_PL:          "SMLAL.PL",
+	arm_SMLAL_VS:          "SMLAL.VS",
+	arm_SMLAL_VC:          "SMLAL.VC",
+	arm_SMLAL_HI:          "SMLAL.HI",
+	arm_SMLAL_LS:          "SMLAL.LS",
+	arm_SMLAL_GE:          "SMLAL.GE",
+	arm_SMLAL_LT:          "SMLAL.LT",
+	arm_SMLAL_GT:          "SMLAL.GT",
+	arm_SMLAL_LE:          "SMLAL.LE",
+	arm_SMLAL:             "SMLAL",
+	arm_SMLAL_ZZ:          "SMLAL.ZZ",
+	arm_SMLAL_S_EQ:        "SMLAL.S.EQ",
+	arm_SMLAL_S_NE:        "SMLAL.S.NE",
+	arm_SMLAL_S_CS:        "SMLAL.S.CS",
+	arm_SMLAL_S_CC:        "SMLAL.S.CC",
+	arm_SMLAL_S_MI:        "SMLAL.S.MI",
+	arm_SMLAL_S_PL:        "SMLAL.S.PL",
+	arm_SMLAL_S_VS:        "SMLAL.S.VS",
+	arm_SMLAL_S_VC:        "SMLAL.S.VC",
+	arm_SMLAL_S_HI:        "SMLAL.S.HI",
+	arm_SMLAL_S_LS:        "SMLAL.S.LS",
+	arm_SMLAL_S_GE:        "SMLAL.S.GE",
+	arm_SMLAL_S_LT:        "SMLAL.S.LT",
+	arm_SMLAL_S_GT:        "SMLAL.S.GT",
+	arm_SMLAL_S_LE:        "SMLAL.S.LE",
+	arm_SMLAL_S:           "SMLAL.S",
+	arm_SMLAL_S_ZZ:        "SMLAL.S.ZZ",
+	arm_SMLALBB_EQ:        "SMLALBB.EQ",
+	arm_SMLALBB_NE:        "SMLALBB.NE",
+	arm_SMLALBB_CS:        "SMLALBB.CS",
+	arm_SMLALBB_CC:        "SMLALBB.CC",
+	arm_SMLALBB_MI:        "SMLALBB.MI",
+	arm_SMLALBB_PL:        "SMLALBB.PL",
+	arm_SMLALBB_VS:        "SMLALBB.VS",
+	arm_SMLALBB_VC:        "SMLALBB.VC",
+	arm_SMLALBB_HI:        "SMLALBB.HI",
+	arm_SMLALBB_LS:        "SMLALBB.LS",
+	arm_SMLALBB_GE:        "SMLALBB.GE",
+	arm_SMLALBB_LT:        "SMLALBB.LT",
+	arm_SMLALBB_GT:        "SMLALBB.GT",
+	arm_SMLALBB_LE:        "SMLALBB.LE",
+	arm_SMLALBB:           "SMLALBB",
+	arm_SMLALBB_ZZ:        "SMLALBB.ZZ",
+	arm_SMLALBT_EQ:        "SMLALBT.EQ",
+	arm_SMLALBT_NE:        "SMLALBT.NE",
+	arm_SMLALBT_CS:        "SMLALBT.CS",
+	arm_SMLALBT_CC:        "SMLALBT.CC",
+	arm_SMLALBT_MI:        "SMLALBT.MI",
+	arm_SMLALBT_PL:        "SMLALBT.PL",
+	arm_SMLALBT_VS:        "SMLALBT.VS",
+	arm_SMLALBT_VC:        "SMLALBT.VC",
+	arm_SMLALBT_HI:        "SMLALBT.HI",
+	arm_SMLALBT_LS:        "SMLALBT.LS",
+	arm_SMLALBT_GE:        "SMLALBT.GE",
+	arm_SMLALBT_LT:        "SMLALBT.LT",
+	arm_SMLALBT_GT:        "SMLALBT.GT",
+	arm_SMLALBT_LE:        "SMLALBT.LE",
+	arm_SMLALBT:           "SMLALBT",
+	arm_SMLALBT_ZZ:        "SMLALBT.ZZ",
+	arm_SMLALTB_EQ:        "SMLALTB.EQ",
+	arm_SMLALTB_NE:        "SMLALTB.NE",
+	arm_SMLALTB_CS:        "SMLALTB.CS",
+	arm_SMLALTB_CC:        "SMLALTB.CC",
+	arm_SMLALTB_MI:        "SMLALTB.MI",
+	arm_SMLALTB_PL:        "SMLALTB.PL",
+	arm_SMLALTB_VS:        "SMLALTB.VS",
+	arm_SMLALTB_VC:        "SMLALTB.VC",
+	arm_SMLALTB_HI:        "SMLALTB.HI",
+	arm_SMLALTB_LS:        "SMLALTB.LS",
+	arm_SMLALTB_GE:        "SMLALTB.GE",
+	arm_SMLALTB_LT:        "SMLALTB.LT",
+	arm_SMLALTB_GT:        "SMLALTB.GT",
+	arm_SMLALTB_LE:        "SMLALTB.LE",
+	arm_SMLALTB:           "SMLALTB",
+	arm_SMLALTB_ZZ:        "SMLALTB.ZZ",
+	arm_SMLALTT_EQ:        "SMLALTT.EQ",
+	arm_SMLALTT_NE:        "SMLALTT.NE",
+	arm_SMLALTT_CS:        "SMLALTT.CS",
+	arm_SMLALTT_CC:        "SMLALTT.CC",
+	arm_SMLALTT_MI:        "SMLALTT.MI",
+	arm_SMLALTT_PL:        "SMLALTT.PL",
+	arm_SMLALTT_VS:        "SMLALTT.VS",
+	arm_SMLALTT_VC:        "SMLALTT.VC",
+	arm_SMLALTT_HI:        "SMLALTT.HI",
+	arm_SMLALTT_LS:        "SMLALTT.LS",
+	arm_SMLALTT_GE:        "SMLALTT.GE",
+	arm_SMLALTT_LT:        "SMLALTT.LT",
+	arm_SMLALTT_GT:        "SMLALTT.GT",
+	arm_SMLALTT_LE:        "SMLALTT.LE",
+	arm_SMLALTT:           "SMLALTT",
+	arm_SMLALTT_ZZ:        "SMLALTT.ZZ",
+	arm_SMLALD_EQ:         "SMLALD.EQ",
+	arm_SMLALD_NE:         "SMLALD.NE",
+	arm_SMLALD_CS:         "SMLALD.CS",
+	arm_SMLALD_CC:         "SMLALD.CC",
+	arm_SMLALD_MI:         "SMLALD.MI",
+	arm_SMLALD_PL:         "SMLALD.PL",
+	arm_SMLALD_VS:         "SMLALD.VS",
+	arm_SMLALD_VC:         "SMLALD.VC",
+	arm_SMLALD_HI:         "SMLALD.HI",
+	arm_SMLALD_LS:         "SMLALD.LS",
+	arm_SMLALD_GE:         "SMLALD.GE",
+	arm_SMLALD_LT:         "SMLALD.LT",
+	arm_SMLALD_GT:         "SMLALD.GT",
+	arm_SMLALD_LE:         "SMLALD.LE",
+	arm_SMLALD:            "SMLALD",
+	arm_SMLALD_ZZ:         "SMLALD.ZZ",
+	arm_SMLALD_X_EQ:       "SMLALD.X.EQ",
+	arm_SMLALD_X_NE:       "SMLALD.X.NE",
+	arm_SMLALD_X_CS:       "SMLALD.X.CS",
+	arm_SMLALD_X_CC:       "SMLALD.X.CC",
+	arm_SMLALD_X_MI:       "SMLALD.X.MI",
+	arm_SMLALD_X_PL:       "SMLALD.X.PL",
+	arm_SMLALD_X_VS:       "SMLALD.X.VS",
+	arm_SMLALD_X_VC:       "SMLALD.X.VC",
+	arm_SMLALD_X_HI:       "SMLALD.X.HI",
+	arm_SMLALD_X_LS:       "SMLALD.X.LS",
+	arm_SMLALD_X_GE:       "SMLALD.X.GE",
+	arm_SMLALD_X_LT:       "SMLALD.X.LT",
+	arm_SMLALD_X_GT:       "SMLALD.X.GT",
+	arm_SMLALD_X_LE:       "SMLALD.X.LE",
+	arm_SMLALD_X:          "SMLALD.X",
+	arm_SMLALD_X_ZZ:       "SMLALD.X.ZZ",
+	arm_SMLAWB_EQ:         "SMLAWB.EQ",
+	arm_SMLAWB_NE:         "SMLAWB.NE",
+	arm_SMLAWB_CS:         "SMLAWB.CS",
+	arm_SMLAWB_CC:         "SMLAWB.CC",
+	arm_SMLAWB_MI:         "SMLAWB.MI",
+	arm_SMLAWB_PL:         "SMLAWB.PL",
+	arm_SMLAWB_VS:         "SMLAWB.VS",
+	arm_SMLAWB_VC:         "SMLAWB.VC",
+	arm_SMLAWB_HI:         "SMLAWB.HI",
+	arm_SMLAWB_LS:         "SMLAWB.LS",
+	arm_SMLAWB_GE:         "SMLAWB.GE",
+	arm_SMLAWB_LT:         "SMLAWB.LT",
+	arm_SMLAWB_GT:         "SMLAWB.GT",
+	arm_SMLAWB_LE:         "SMLAWB.LE",
+	arm_SMLAWB:            "SMLAWB",
+	arm_SMLAWB_ZZ:         "SMLAWB.ZZ",
+	arm_SMLAWT_EQ:         "SMLAWT.EQ",
+	arm_SMLAWT_NE:         "SMLAWT.NE",
+	arm_SMLAWT_CS:         "SMLAWT.CS",
+	arm_SMLAWT_CC:         "SMLAWT.CC",
+	arm_SMLAWT_MI:         "SMLAWT.MI",
+	arm_SMLAWT_PL:         "SMLAWT.PL",
+	arm_SMLAWT_VS:         "SMLAWT.VS",
+	arm_SMLAWT_VC:         "SMLAWT.VC",
+	arm_SMLAWT_HI:         "SMLAWT.HI",
+	arm_SMLAWT_LS:         "SMLAWT.LS",
+	arm_SMLAWT_GE:         "SMLAWT.GE",
+	arm_SMLAWT_LT:         "SMLAWT.LT",
+	arm_SMLAWT_GT:         "SMLAWT.GT",
+	arm_SMLAWT_LE:         "SMLAWT.LE",
+	arm_SMLAWT:            "SMLAWT",
+	arm_SMLAWT_ZZ:         "SMLAWT.ZZ",
+	arm_SMLSD_EQ:          "SMLSD.EQ",
+	arm_SMLSD_NE:          "SMLSD.NE",
+	arm_SMLSD_CS:          "SMLSD.CS",
+	arm_SMLSD_CC:          "SMLSD.CC",
+	arm_SMLSD_MI:          "SMLSD.MI",
+	arm_SMLSD_PL:          "SMLSD.PL",
+	arm_SMLSD_VS:          "SMLSD.VS",
+	arm_SMLSD_VC:          "SMLSD.VC",
+	arm_SMLSD_HI:          "SMLSD.HI",
+	arm_SMLSD_LS:          "SMLSD.LS",
+	arm_SMLSD_GE:          "SMLSD.GE",
+	arm_SMLSD_LT:          "SMLSD.LT",
+	arm_SMLSD_GT:          "SMLSD.GT",
+	arm_SMLSD_LE:          "SMLSD.LE",
+	arm_SMLSD:             "SMLSD",
+	arm_SMLSD_ZZ:          "SMLSD.ZZ",
+	arm_SMLSD_X_EQ:        "SMLSD.X.EQ",
+	arm_SMLSD_X_NE:        "SMLSD.X.NE",
+	arm_SMLSD_X_CS:        "SMLSD.X.CS",
+	arm_SMLSD_X_CC:        "SMLSD.X.CC",
+	arm_SMLSD_X_MI:        "SMLSD.X.MI",
+	arm_SMLSD_X_PL:        "SMLSD.X.PL",
+	arm_SMLSD_X_VS:        "SMLSD.X.VS",
+	arm_SMLSD_X_VC:        "SMLSD.X.VC",
+	arm_SMLSD_X_HI:        "SMLSD.X.HI",
+	arm_SMLSD_X_LS:        "SMLSD.X.LS",
+	arm_SMLSD_X_GE:        "SMLSD.X.GE",
+	arm_SMLSD_X_LT:        "SMLSD.X.LT",
+	arm_SMLSD_X_GT:        "SMLSD.X.GT",
+	arm_SMLSD_X_LE:        "SMLSD.X.LE",
+	arm_SMLSD_X:           "SMLSD.X",
+	arm_SMLSD_X_ZZ:        "SMLSD.X.ZZ",
+	arm_SMLSLD_EQ:         "SMLSLD.EQ",
+	arm_SMLSLD_NE:         "SMLSLD.NE",
+	arm_SMLSLD_CS:         "SMLSLD.CS",
+	arm_SMLSLD_CC:         "SMLSLD.CC",
+	arm_SMLSLD_MI:         "SMLSLD.MI",
+	arm_SMLSLD_PL:         "SMLSLD.PL",
+	arm_SMLSLD_VS:         "SMLSLD.VS",
+	arm_SMLSLD_VC:         "SMLSLD.VC",
+	arm_SMLSLD_HI:         "SMLSLD.HI",
+	arm_SMLSLD_LS:         "SMLSLD.LS",
+	arm_SMLSLD_GE:         "SMLSLD.GE",
+	arm_SMLSLD_LT:         "SMLSLD.LT",
+	arm_SMLSLD_GT:         "SMLSLD.GT",
+	arm_SMLSLD_LE:         "SMLSLD.LE",
+	arm_SMLSLD:            "SMLSLD",
+	arm_SMLSLD_ZZ:         "SMLSLD.ZZ",
+	arm_SMLSLD_X_EQ:       "SMLSLD.X.EQ",
+	arm_SMLSLD_X_NE:       "SMLSLD.X.NE",
+	arm_SMLSLD_X_CS:       "SMLSLD.X.CS",
+	arm_SMLSLD_X_CC:       "SMLSLD.X.CC",
+	arm_SMLSLD_X_MI:       "SMLSLD.X.MI",
+	arm_SMLSLD_X_PL:       "SMLSLD.X.PL",
+	arm_SMLSLD_X_VS:       "SMLSLD.X.VS",
+	arm_SMLSLD_X_VC:       "SMLSLD.X.VC",
+	arm_SMLSLD_X_HI:       "SMLSLD.X.HI",
+	arm_SMLSLD_X_LS:       "SMLSLD.X.LS",
+	arm_SMLSLD_X_GE:       "SMLSLD.X.GE",
+	arm_SMLSLD_X_LT:       "SMLSLD.X.LT",
+	arm_SMLSLD_X_GT:       "SMLSLD.X.GT",
+	arm_SMLSLD_X_LE:       "SMLSLD.X.LE",
+	arm_SMLSLD_X:          "SMLSLD.X",
+	arm_SMLSLD_X_ZZ:       "SMLSLD.X.ZZ",
+	arm_SMMLA_EQ:          "SMMLA.EQ",
+	arm_SMMLA_NE:          "SMMLA.NE",
+	arm_SMMLA_CS:          "SMMLA.CS",
+	arm_SMMLA_CC:          "SMMLA.CC",
+	arm_SMMLA_MI:          "SMMLA.MI",
+	arm_SMMLA_PL:          "SMMLA.PL",
+	arm_SMMLA_VS:          "SMMLA.VS",
+	arm_SMMLA_VC:          "SMMLA.VC",
+	arm_SMMLA_HI:          "SMMLA.HI",
+	arm_SMMLA_LS:          "SMMLA.LS",
+	arm_SMMLA_GE:          "SMMLA.GE",
+	arm_SMMLA_LT:          "SMMLA.LT",
+	arm_SMMLA_GT:          "SMMLA.GT",
+	arm_SMMLA_LE:          "SMMLA.LE",
+	arm_SMMLA:             "SMMLA",
+	arm_SMMLA_ZZ:          "SMMLA.ZZ",
+	arm_SMMLA_R_EQ:        "SMMLA.R.EQ",
+	arm_SMMLA_R_NE:        "SMMLA.R.NE",
+	arm_SMMLA_R_CS:        "SMMLA.R.CS",
+	arm_SMMLA_R_CC:        "SMMLA.R.CC",
+	arm_SMMLA_R_MI:        "SMMLA.R.MI",
+	arm_SMMLA_R_PL:        "SMMLA.R.PL",
+	arm_SMMLA_R_VS:        "SMMLA.R.VS",
+	arm_SMMLA_R_VC:        "SMMLA.R.VC",
+	arm_SMMLA_R_HI:        "SMMLA.R.HI",
+	arm_SMMLA_R_LS:        "SMMLA.R.LS",
+	arm_SMMLA_R_GE:        "SMMLA.R.GE",
+	arm_SMMLA_R_LT:        "SMMLA.R.LT",
+	arm_SMMLA_R_GT:        "SMMLA.R.GT",
+	arm_SMMLA_R_LE:        "SMMLA.R.LE",
+	arm_SMMLA_R:           "SMMLA.R",
+	arm_SMMLA_R_ZZ:        "SMMLA.R.ZZ",
+	arm_SMMLS_EQ:          "SMMLS.EQ",
+	arm_SMMLS_NE:          "SMMLS.NE",
+	arm_SMMLS_CS:          "SMMLS.CS",
+	arm_SMMLS_CC:          "SMMLS.CC",
+	arm_SMMLS_MI:          "SMMLS.MI",
+	arm_SMMLS_PL:          "SMMLS.PL",
+	arm_SMMLS_VS:          "SMMLS.VS",
+	arm_SMMLS_VC:          "SMMLS.VC",
+	arm_SMMLS_HI:          "SMMLS.HI",
+	arm_SMMLS_LS:          "SMMLS.LS",
+	arm_SMMLS_GE:          "SMMLS.GE",
+	arm_SMMLS_LT:          "SMMLS.LT",
+	arm_SMMLS_GT:          "SMMLS.GT",
+	arm_SMMLS_LE:          "SMMLS.LE",
+	arm_SMMLS:             "SMMLS",
+	arm_SMMLS_ZZ:          "SMMLS.ZZ",
+	arm_SMMLS_R_EQ:        "SMMLS.R.EQ",
+	arm_SMMLS_R_NE:        "SMMLS.R.NE",
+	arm_SMMLS_R_CS:        "SMMLS.R.CS",
+	arm_SMMLS_R_CC:        "SMMLS.R.CC",
+	arm_SMMLS_R_MI:        "SMMLS.R.MI",
+	arm_SMMLS_R_PL:        "SMMLS.R.PL",
+	arm_SMMLS_R_VS:        "SMMLS.R.VS",
+	arm_SMMLS_R_VC:        "SMMLS.R.VC",
+	arm_SMMLS_R_HI:        "SMMLS.R.HI",
+	arm_SMMLS_R_LS:        "SMMLS.R.LS",
+	arm_SMMLS_R_GE:        "SMMLS.R.GE",
+	arm_SMMLS_R_LT:        "SMMLS.R.LT",
+	arm_SMMLS_R_GT:        "SMMLS.R.GT",
+	arm_SMMLS_R_LE:        "SMMLS.R.LE",
+	arm_SMMLS_R:           "SMMLS.R",
+	arm_SMMLS_R_ZZ:        "SMMLS.R.ZZ",
+	arm_SMMUL_EQ:          "SMMUL.EQ",
+	arm_SMMUL_NE:          "SMMUL.NE",
+	arm_SMMUL_CS:          "SMMUL.CS",
+	arm_SMMUL_CC:          "SMMUL.CC",
+	arm_SMMUL_MI:          "SMMUL.MI",
+	arm_SMMUL_PL:          "SMMUL.PL",
+	arm_SMMUL_VS:          "SMMUL.VS",
+	arm_SMMUL_VC:          "SMMUL.VC",
+	arm_SMMUL_HI:          "SMMUL.HI",
+	arm_SMMUL_LS:          "SMMUL.LS",
+	arm_SMMUL_GE:          "SMMUL.GE",
+	arm_SMMUL_LT:          "SMMUL.LT",
+	arm_SMMUL_GT:          "SMMUL.GT",
+	arm_SMMUL_LE:          "SMMUL.LE",
+	arm_SMMUL:             "SMMUL",
+	arm_SMMUL_ZZ:          "SMMUL.ZZ",
+	arm_SMMUL_R_EQ:        "SMMUL.R.EQ",
+	arm_SMMUL_R_NE:        "SMMUL.R.NE",
+	arm_SMMUL_R_CS:        "SMMUL.R.CS",
+	arm_SMMUL_R_CC:        "SMMUL.R.CC",
+	arm_SMMUL_R_MI:        "SMMUL.R.MI",
+	arm_SMMUL_R_PL:        "SMMUL.R.PL",
+	arm_SMMUL_R_VS:        "SMMUL.R.VS",
+	arm_SMMUL_R_VC:        "SMMUL.R.VC",
+	arm_SMMUL_R_HI:        "SMMUL.R.HI",
+	arm_SMMUL_R_LS:        "SMMUL.R.LS",
+	arm_SMMUL_R_GE:        "SMMUL.R.GE",
+	arm_SMMUL_R_LT:        "SMMUL.R.LT",
+	arm_SMMUL_R_GT:        "SMMUL.R.GT",
+	arm_SMMUL_R_LE:        "SMMUL.R.LE",
+	arm_SMMUL_R:           "SMMUL.R",
+	arm_SMMUL_R_ZZ:        "SMMUL.R.ZZ",
+	arm_SMUAD_EQ:          "SMUAD.EQ",
+	arm_SMUAD_NE:          "SMUAD.NE",
+	arm_SMUAD_CS:          "SMUAD.CS",
+	arm_SMUAD_CC:          "SMUAD.CC",
+	arm_SMUAD_MI:          "SMUAD.MI",
+	arm_SMUAD_PL:          "SMUAD.PL",
+	arm_SMUAD_VS:          "SMUAD.VS",
+	arm_SMUAD_VC:          "SMUAD.VC",
+	arm_SMUAD_HI:          "SMUAD.HI",
+	arm_SMUAD_LS:          "SMUAD.LS",
+	arm_SMUAD_GE:          "SMUAD.GE",
+	arm_SMUAD_LT:          "SMUAD.LT",
+	arm_SMUAD_GT:          "SMUAD.GT",
+	arm_SMUAD_LE:          "SMUAD.LE",
+	arm_SMUAD:             "SMUAD",
+	arm_SMUAD_ZZ:          "SMUAD.ZZ",
+	arm_SMUAD_X_EQ:        "SMUAD.X.EQ",
+	arm_SMUAD_X_NE:        "SMUAD.X.NE",
+	arm_SMUAD_X_CS:        "SMUAD.X.CS",
+	arm_SMUAD_X_CC:        "SMUAD.X.CC",
+	arm_SMUAD_X_MI:        "SMUAD.X.MI",
+	arm_SMUAD_X_PL:        "SMUAD.X.PL",
+	arm_SMUAD_X_VS:        "SMUAD.X.VS",
+	arm_SMUAD_X_VC:        "SMUAD.X.VC",
+	arm_SMUAD_X_HI:        "SMUAD.X.HI",
+	arm_SMUAD_X_LS:        "SMUAD.X.LS",
+	arm_SMUAD_X_GE:        "SMUAD.X.GE",
+	arm_SMUAD_X_LT:        "SMUAD.X.LT",
+	arm_SMUAD_X_GT:        "SMUAD.X.GT",
+	arm_SMUAD_X_LE:        "SMUAD.X.LE",
+	arm_SMUAD_X:           "SMUAD.X",
+	arm_SMUAD_X_ZZ:        "SMUAD.X.ZZ",
+	arm_SMULBB_EQ:         "SMULBB.EQ",
+	arm_SMULBB_NE:         "SMULBB.NE",
+	arm_SMULBB_CS:         "SMULBB.CS",
+	arm_SMULBB_CC:         "SMULBB.CC",
+	arm_SMULBB_MI:         "SMULBB.MI",
+	arm_SMULBB_PL:         "SMULBB.PL",
+	arm_SMULBB_VS:         "SMULBB.VS",
+	arm_SMULBB_VC:         "SMULBB.VC",
+	arm_SMULBB_HI:         "SMULBB.HI",
+	arm_SMULBB_LS:         "SMULBB.LS",
+	arm_SMULBB_GE:         "SMULBB.GE",
+	arm_SMULBB_LT:         "SMULBB.LT",
+	arm_SMULBB_GT:         "SMULBB.GT",
+	arm_SMULBB_LE:         "SMULBB.LE",
+	arm_SMULBB:            "SMULBB",
+	arm_SMULBB_ZZ:         "SMULBB.ZZ",
+	arm_SMULBT_EQ:         "SMULBT.EQ",
+	arm_SMULBT_NE:         "SMULBT.NE",
+	arm_SMULBT_CS:         "SMULBT.CS",
+	arm_SMULBT_CC:         "SMULBT.CC",
+	arm_SMULBT_MI:         "SMULBT.MI",
+	arm_SMULBT_PL:         "SMULBT.PL",
+	arm_SMULBT_VS:         "SMULBT.VS",
+	arm_SMULBT_VC:         "SMULBT.VC",
+	arm_SMULBT_HI:         "SMULBT.HI",
+	arm_SMULBT_LS:         "SMULBT.LS",
+	arm_SMULBT_GE:         "SMULBT.GE",
+	arm_SMULBT_LT:         "SMULBT.LT",
+	arm_SMULBT_GT:         "SMULBT.GT",
+	arm_SMULBT_LE:         "SMULBT.LE",
+	arm_SMULBT:            "SMULBT",
+	arm_SMULBT_ZZ:         "SMULBT.ZZ",
+	arm_SMULTB_EQ:         "SMULTB.EQ",
+	arm_SMULTB_NE:         "SMULTB.NE",
+	arm_SMULTB_CS:         "SMULTB.CS",
+	arm_SMULTB_CC:         "SMULTB.CC",
+	arm_SMULTB_MI:         "SMULTB.MI",
+	arm_SMULTB_PL:         "SMULTB.PL",
+	arm_SMULTB_VS:         "SMULTB.VS",
+	arm_SMULTB_VC:         "SMULTB.VC",
+	arm_SMULTB_HI:         "SMULTB.HI",
+	arm_SMULTB_LS:         "SMULTB.LS",
+	arm_SMULTB_GE:         "SMULTB.GE",
+	arm_SMULTB_LT:         "SMULTB.LT",
+	arm_SMULTB_GT:         "SMULTB.GT",
+	arm_SMULTB_LE:         "SMULTB.LE",
+	arm_SMULTB:            "SMULTB",
+	arm_SMULTB_ZZ:         "SMULTB.ZZ",
+	arm_SMULTT_EQ:         "SMULTT.EQ",
+	arm_SMULTT_NE:         "SMULTT.NE",
+	arm_SMULTT_CS:         "SMULTT.CS",
+	arm_SMULTT_CC:         "SMULTT.CC",
+	arm_SMULTT_MI:         "SMULTT.MI",
+	arm_SMULTT_PL:         "SMULTT.PL",
+	arm_SMULTT_VS:         "SMULTT.VS",
+	arm_SMULTT_VC:         "SMULTT.VC",
+	arm_SMULTT_HI:         "SMULTT.HI",
+	arm_SMULTT_LS:         "SMULTT.LS",
+	arm_SMULTT_GE:         "SMULTT.GE",
+	arm_SMULTT_LT:         "SMULTT.LT",
+	arm_SMULTT_GT:         "SMULTT.GT",
+	arm_SMULTT_LE:         "SMULTT.LE",
+	arm_SMULTT:            "SMULTT",
+	arm_SMULTT_ZZ:         "SMULTT.ZZ",
+	arm_SMULL_EQ:          "SMULL.EQ",
+	arm_SMULL_NE:          "SMULL.NE",
+	arm_SMULL_CS:          "SMULL.CS",
+	arm_SMULL_CC:          "SMULL.CC",
+	arm_SMULL_MI:          "SMULL.MI",
+	arm_SMULL_PL:          "SMULL.PL",
+	arm_SMULL_VS:          "SMULL.VS",
+	arm_SMULL_VC:          "SMULL.VC",
+	arm_SMULL_HI:          "SMULL.HI",
+	arm_SMULL_LS:          "SMULL.LS",
+	arm_SMULL_GE:          "SMULL.GE",
+	arm_SMULL_LT:          "SMULL.LT",
+	arm_SMULL_GT:          "SMULL.GT",
+	arm_SMULL_LE:          "SMULL.LE",
+	arm_SMULL:             "SMULL",
+	arm_SMULL_ZZ:          "SMULL.ZZ",
+	arm_SMULL_S_EQ:        "SMULL.S.EQ",
+	arm_SMULL_S_NE:        "SMULL.S.NE",
+	arm_SMULL_S_CS:        "SMULL.S.CS",
+	arm_SMULL_S_CC:        "SMULL.S.CC",
+	arm_SMULL_S_MI:        "SMULL.S.MI",
+	arm_SMULL_S_PL:        "SMULL.S.PL",
+	arm_SMULL_S_VS:        "SMULL.S.VS",
+	arm_SMULL_S_VC:        "SMULL.S.VC",
+	arm_SMULL_S_HI:        "SMULL.S.HI",
+	arm_SMULL_S_LS:        "SMULL.S.LS",
+	arm_SMULL_S_GE:        "SMULL.S.GE",
+	arm_SMULL_S_LT:        "SMULL.S.LT",
+	arm_SMULL_S_GT:        "SMULL.S.GT",
+	arm_SMULL_S_LE:        "SMULL.S.LE",
+	arm_SMULL_S:           "SMULL.S",
+	arm_SMULL_S_ZZ:        "SMULL.S.ZZ",
+	arm_SMULWB_EQ:         "SMULWB.EQ",
+	arm_SMULWB_NE:         "SMULWB.NE",
+	arm_SMULWB_CS:         "SMULWB.CS",
+	arm_SMULWB_CC:         "SMULWB.CC",
+	arm_SMULWB_MI:         "SMULWB.MI",
+	arm_SMULWB_PL:         "SMULWB.PL",
+	arm_SMULWB_VS:         "SMULWB.VS",
+	arm_SMULWB_VC:         "SMULWB.VC",
+	arm_SMULWB_HI:         "SMULWB.HI",
+	arm_SMULWB_LS:         "SMULWB.LS",
+	arm_SMULWB_GE:         "SMULWB.GE",
+	arm_SMULWB_LT:         "SMULWB.LT",
+	arm_SMULWB_GT:         "SMULWB.GT",
+	arm_SMULWB_LE:         "SMULWB.LE",
+	arm_SMULWB:            "SMULWB",
+	arm_SMULWB_ZZ:         "SMULWB.ZZ",
+	arm_SMULWT_EQ:         "SMULWT.EQ",
+	arm_SMULWT_NE:         "SMULWT.NE",
+	arm_SMULWT_CS:         "SMULWT.CS",
+	arm_SMULWT_CC:         "SMULWT.CC",
+	arm_SMULWT_MI:         "SMULWT.MI",
+	arm_SMULWT_PL:         "SMULWT.PL",
+	arm_SMULWT_VS:         "SMULWT.VS",
+	arm_SMULWT_VC:         "SMULWT.VC",
+	arm_SMULWT_HI:         "SMULWT.HI",
+	arm_SMULWT_LS:         "SMULWT.LS",
+	arm_SMULWT_GE:         "SMULWT.GE",
+	arm_SMULWT_LT:         "SMULWT.LT",
+	arm_SMULWT_GT:         "SMULWT.GT",
+	arm_SMULWT_LE:         "SMULWT.LE",
+	arm_SMULWT:            "SMULWT",
+	arm_SMULWT_ZZ:         "SMULWT.ZZ",
+	arm_SMUSD_EQ:          "SMUSD.EQ",
+	arm_SMUSD_NE:          "SMUSD.NE",
+	arm_SMUSD_CS:          "SMUSD.CS",
+	arm_SMUSD_CC:          "SMUSD.CC",
+	arm_SMUSD_MI:          "SMUSD.MI",
+	arm_SMUSD_PL:          "SMUSD.PL",
+	arm_SMUSD_VS:          "SMUSD.VS",
+	arm_SMUSD_VC:          "SMUSD.VC",
+	arm_SMUSD_HI:          "SMUSD.HI",
+	arm_SMUSD_LS:          "SMUSD.LS",
+	arm_SMUSD_GE:          "SMUSD.GE",
+	arm_SMUSD_LT:          "SMUSD.LT",
+	arm_SMUSD_GT:          "SMUSD.GT",
+	arm_SMUSD_LE:          "SMUSD.LE",
+	arm_SMUSD:             "SMUSD",
+	arm_SMUSD_ZZ:          "SMUSD.ZZ",
+	arm_SMUSD_X_EQ:        "SMUSD.X.EQ",
+	arm_SMUSD_X_NE:        "SMUSD.X.NE",
+	arm_SMUSD_X_CS:        "SMUSD.X.CS",
+	arm_SMUSD_X_CC:        "SMUSD.X.CC",
+	arm_SMUSD_X_MI:        "SMUSD.X.MI",
+	arm_SMUSD_X_PL:        "SMUSD.X.PL",
+	arm_SMUSD_X_VS:        "SMUSD.X.VS",
+	arm_SMUSD_X_VC:        "SMUSD.X.VC",
+	arm_SMUSD_X_HI:        "SMUSD.X.HI",
+	arm_SMUSD_X_LS:        "SMUSD.X.LS",
+	arm_SMUSD_X_GE:        "SMUSD.X.GE",
+	arm_SMUSD_X_LT:        "SMUSD.X.LT",
+	arm_SMUSD_X_GT:        "SMUSD.X.GT",
+	arm_SMUSD_X_LE:        "SMUSD.X.LE",
+	arm_SMUSD_X:           "SMUSD.X",
+	arm_SMUSD_X_ZZ:        "SMUSD.X.ZZ",
+	arm_SSAT_EQ:           "SSAT.EQ",
+	arm_SSAT_NE:           "SSAT.NE",
+	arm_SSAT_CS:           "SSAT.CS",
+	arm_SSAT_CC:           "SSAT.CC",
+	arm_SSAT_MI:           "SSAT.MI",
+	arm_SSAT_PL:           "SSAT.PL",
+	arm_SSAT_VS:           "SSAT.VS",
+	arm_SSAT_VC:           "SSAT.VC",
+	arm_SSAT_HI:           "SSAT.HI",
+	arm_SSAT_LS:           "SSAT.LS",
+	arm_SSAT_GE:           "SSAT.GE",
+	arm_SSAT_LT:           "SSAT.LT",
+	arm_SSAT_GT:           "SSAT.GT",
+	arm_SSAT_LE:           "SSAT.LE",
+	arm_SSAT:              "SSAT",
+	arm_SSAT_ZZ:           "SSAT.ZZ",
+	arm_SSAT16_EQ:         "SSAT16.EQ",
+	arm_SSAT16_NE:         "SSAT16.NE",
+	arm_SSAT16_CS:         "SSAT16.CS",
+	arm_SSAT16_CC:         "SSAT16.CC",
+	arm_SSAT16_MI:         "SSAT16.MI",
+	arm_SSAT16_PL:         "SSAT16.PL",
+	arm_SSAT16_VS:         "SSAT16.VS",
+	arm_SSAT16_VC:         "SSAT16.VC",
+	arm_SSAT16_HI:         "SSAT16.HI",
+	arm_SSAT16_LS:         "SSAT16.LS",
+	arm_SSAT16_GE:         "SSAT16.GE",
+	arm_SSAT16_LT:         "SSAT16.LT",
+	arm_SSAT16_GT:         "SSAT16.GT",
+	arm_SSAT16_LE:         "SSAT16.LE",
+	arm_SSAT16:            "SSAT16",
+	arm_SSAT16_ZZ:         "SSAT16.ZZ",
+	arm_SSAX_EQ:           "SSAX.EQ",
+	arm_SSAX_NE:           "SSAX.NE",
+	arm_SSAX_CS:           "SSAX.CS",
+	arm_SSAX_CC:           "SSAX.CC",
+	arm_SSAX_MI:           "SSAX.MI",
+	arm_SSAX_PL:           "SSAX.PL",
+	arm_SSAX_VS:           "SSAX.VS",
+	arm_SSAX_VC:           "SSAX.VC",
+	arm_SSAX_HI:           "SSAX.HI",
+	arm_SSAX_LS:           "SSAX.LS",
+	arm_SSAX_GE:           "SSAX.GE",
+	arm_SSAX_LT:           "SSAX.LT",
+	arm_SSAX_GT:           "SSAX.GT",
+	arm_SSAX_LE:           "SSAX.LE",
+	arm_SSAX:              "SSAX",
+	arm_SSAX_ZZ:           "SSAX.ZZ",
+	arm_SSUB16_EQ:         "SSUB16.EQ",
+	arm_SSUB16_NE:         "SSUB16.NE",
+	arm_SSUB16_CS:         "SSUB16.CS",
+	arm_SSUB16_CC:         "SSUB16.CC",
+	arm_SSUB16_MI:         "SSUB16.MI",
+	arm_SSUB16_PL:         "SSUB16.PL",
+	arm_SSUB16_VS:         "SSUB16.VS",
+	arm_SSUB16_VC:         "SSUB16.VC",
+	arm_SSUB16_HI:         "SSUB16.HI",
+	arm_SSUB16_LS:         "SSUB16.LS",
+	arm_SSUB16_GE:         "SSUB16.GE",
+	arm_SSUB16_LT:         "SSUB16.LT",
+	arm_SSUB16_GT:         "SSUB16.GT",
+	arm_SSUB16_LE:         "SSUB16.LE",
+	arm_SSUB16:            "SSUB16",
+	arm_SSUB16_ZZ:         "SSUB16.ZZ",
+	arm_SSUB8_EQ:          "SSUB8.EQ",
+	arm_SSUB8_NE:          "SSUB8.NE",
+	arm_SSUB8_CS:          "SSUB8.CS",
+	arm_SSUB8_CC:          "SSUB8.CC",
+	arm_SSUB8_MI:          "SSUB8.MI",
+	arm_SSUB8_PL:          "SSUB8.PL",
+	arm_SSUB8_VS:          "SSUB8.VS",
+	arm_SSUB8_VC:          "SSUB8.VC",
+	arm_SSUB8_HI:          "SSUB8.HI",
+	arm_SSUB8_LS:          "SSUB8.LS",
+	arm_SSUB8_GE:          "SSUB8.GE",
+	arm_SSUB8_LT:          "SSUB8.LT",
+	arm_SSUB8_GT:          "SSUB8.GT",
+	arm_SSUB8_LE:          "SSUB8.LE",
+	arm_SSUB8:             "SSUB8",
+	arm_SSUB8_ZZ:          "SSUB8.ZZ",
+	arm_STM_EQ:            "STM.EQ",
+	arm_STM_NE:            "STM.NE",
+	arm_STM_CS:            "STM.CS",
+	arm_STM_CC:            "STM.CC",
+	arm_STM_MI:            "STM.MI",
+	arm_STM_PL:            "STM.PL",
+	arm_STM_VS:            "STM.VS",
+	arm_STM_VC:            "STM.VC",
+	arm_STM_HI:            "STM.HI",
+	arm_STM_LS:            "STM.LS",
+	arm_STM_GE:            "STM.GE",
+	arm_STM_LT:            "STM.LT",
+	arm_STM_GT:            "STM.GT",
+	arm_STM_LE:            "STM.LE",
+	arm_STM:               "STM",
+	arm_STM_ZZ:            "STM.ZZ",
+	arm_STMDA_EQ:          "STMDA.EQ",
+	arm_STMDA_NE:          "STMDA.NE",
+	arm_STMDA_CS:          "STMDA.CS",
+	arm_STMDA_CC:          "STMDA.CC",
+	arm_STMDA_MI:          "STMDA.MI",
+	arm_STMDA_PL:          "STMDA.PL",
+	arm_STMDA_VS:          "STMDA.VS",
+	arm_STMDA_VC:          "STMDA.VC",
+	arm_STMDA_HI:          "STMDA.HI",
+	arm_STMDA_LS:          "STMDA.LS",
+	arm_STMDA_GE:          "STMDA.GE",
+	arm_STMDA_LT:          "STMDA.LT",
+	arm_STMDA_GT:          "STMDA.GT",
+	arm_STMDA_LE:          "STMDA.LE",
+	arm_STMDA:             "STMDA",
+	arm_STMDA_ZZ:          "STMDA.ZZ",
+	arm_STMDB_EQ:          "STMDB.EQ",
+	arm_STMDB_NE:          "STMDB.NE",
+	arm_STMDB_CS:          "STMDB.CS",
+	arm_STMDB_CC:          "STMDB.CC",
+	arm_STMDB_MI:          "STMDB.MI",
+	arm_STMDB_PL:          "STMDB.PL",
+	arm_STMDB_VS:          "STMDB.VS",
+	arm_STMDB_VC:          "STMDB.VC",
+	arm_STMDB_HI:          "STMDB.HI",
+	arm_STMDB_LS:          "STMDB.LS",
+	arm_STMDB_GE:          "STMDB.GE",
+	arm_STMDB_LT:          "STMDB.LT",
+	arm_STMDB_GT:          "STMDB.GT",
+	arm_STMDB_LE:          "STMDB.LE",
+	arm_STMDB:             "STMDB",
+	arm_STMDB_ZZ:          "STMDB.ZZ",
+	arm_STMIB_EQ:          "STMIB.EQ",
+	arm_STMIB_NE:          "STMIB.NE",
+	arm_STMIB_CS:          "STMIB.CS",
+	arm_STMIB_CC:          "STMIB.CC",
+	arm_STMIB_MI:          "STMIB.MI",
+	arm_STMIB_PL:          "STMIB.PL",
+	arm_STMIB_VS:          "STMIB.VS",
+	arm_STMIB_VC:          "STMIB.VC",
+	arm_STMIB_HI:          "STMIB.HI",
+	arm_STMIB_LS:          "STMIB.LS",
+	arm_STMIB_GE:          "STMIB.GE",
+	arm_STMIB_LT:          "STMIB.LT",
+	arm_STMIB_GT:          "STMIB.GT",
+	arm_STMIB_LE:          "STMIB.LE",
+	arm_STMIB:             "STMIB",
+	arm_STMIB_ZZ:          "STMIB.ZZ",
+	arm_STR_EQ:            "STR.EQ",
+	arm_STR_NE:            "STR.NE",
+	arm_STR_CS:            "STR.CS",
+	arm_STR_CC:            "STR.CC",
+	arm_STR_MI:            "STR.MI",
+	arm_STR_PL:            "STR.PL",
+	arm_STR_VS:            "STR.VS",
+	arm_STR_VC:            "STR.VC",
+	arm_STR_HI:            "STR.HI",
+	arm_STR_LS:            "STR.LS",
+	arm_STR_GE:            "STR.GE",
+	arm_STR_LT:            "STR.LT",
+	arm_STR_GT:            "STR.GT",
+	arm_STR_LE:            "STR.LE",
+	arm_STR:               "STR",
+	arm_STR_ZZ:            "STR.ZZ",
+	arm_STRB_EQ:           "STRB.EQ",
+	arm_STRB_NE:           "STRB.NE",
+	arm_STRB_CS:           "STRB.CS",
+	arm_STRB_CC:           "STRB.CC",
+	arm_STRB_MI:           "STRB.MI",
+	arm_STRB_PL:           "STRB.PL",
+	arm_STRB_VS:           "STRB.VS",
+	arm_STRB_VC:           "STRB.VC",
+	arm_STRB_HI:           "STRB.HI",
+	arm_STRB_LS:           "STRB.LS",
+	arm_STRB_GE:           "STRB.GE",
+	arm_STRB_LT:           "STRB.LT",
+	arm_STRB_GT:           "STRB.GT",
+	arm_STRB_LE:           "STRB.LE",
+	arm_STRB:              "STRB",
+	arm_STRB_ZZ:           "STRB.ZZ",
+	arm_STRBT_EQ:          "STRBT.EQ",
+	arm_STRBT_NE:          "STRBT.NE",
+	arm_STRBT_CS:          "STRBT.CS",
+	arm_STRBT_CC:          "STRBT.CC",
+	arm_STRBT_MI:          "STRBT.MI",
+	arm_STRBT_PL:          "STRBT.PL",
+	arm_STRBT_VS:          "STRBT.VS",
+	arm_STRBT_VC:          "STRBT.VC",
+	arm_STRBT_HI:          "STRBT.HI",
+	arm_STRBT_LS:          "STRBT.LS",
+	arm_STRBT_GE:          "STRBT.GE",
+	arm_STRBT_LT:          "STRBT.LT",
+	arm_STRBT_GT:          "STRBT.GT",
+	arm_STRBT_LE:          "STRBT.LE",
+	arm_STRBT:             "STRBT",
+	arm_STRBT_ZZ:          "STRBT.ZZ",
+	arm_STRD_EQ:           "STRD.EQ",
+	arm_STRD_NE:           "STRD.NE",
+	arm_STRD_CS:           "STRD.CS",
+	arm_STRD_CC:           "STRD.CC",
+	arm_STRD_MI:           "STRD.MI",
+	arm_STRD_PL:           "STRD.PL",
+	arm_STRD_VS:           "STRD.VS",
+	arm_STRD_VC:           "STRD.VC",
+	arm_STRD_HI:           "STRD.HI",
+	arm_STRD_LS:           "STRD.LS",
+	arm_STRD_GE:           "STRD.GE",
+	arm_STRD_LT:           "STRD.LT",
+	arm_STRD_GT:           "STRD.GT",
+	arm_STRD_LE:           "STRD.LE",
+	arm_STRD:              "STRD",
+	arm_STRD_ZZ:           "STRD.ZZ",
+	arm_STREX_EQ:          "STREX.EQ",
+	arm_STREX_NE:          "STREX.NE",
+	arm_STREX_CS:          "STREX.CS",
+	arm_STREX_CC:          "STREX.CC",
+	arm_STREX_MI:          "STREX.MI",
+	arm_STREX_PL:          "STREX.PL",
+	arm_STREX_VS:          "STREX.VS",
+	arm_STREX_VC:          "STREX.VC",
+	arm_STREX_HI:          "STREX.HI",
+	arm_STREX_LS:          "STREX.LS",
+	arm_STREX_GE:          "STREX.GE",
+	arm_STREX_LT:          "STREX.LT",
+	arm_STREX_GT:          "STREX.GT",
+	arm_STREX_LE:          "STREX.LE",
+	arm_STREX:             "STREX",
+	arm_STREX_ZZ:          "STREX.ZZ",
+	arm_STREXB_EQ:         "STREXB.EQ",
+	arm_STREXB_NE:         "STREXB.NE",
+	arm_STREXB_CS:         "STREXB.CS",
+	arm_STREXB_CC:         "STREXB.CC",
+	arm_STREXB_MI:         "STREXB.MI",
+	arm_STREXB_PL:         "STREXB.PL",
+	arm_STREXB_VS:         "STREXB.VS",
+	arm_STREXB_VC:         "STREXB.VC",
+	arm_STREXB_HI:         "STREXB.HI",
+	arm_STREXB_LS:         "STREXB.LS",
+	arm_STREXB_GE:         "STREXB.GE",
+	arm_STREXB_LT:         "STREXB.LT",
+	arm_STREXB_GT:         "STREXB.GT",
+	arm_STREXB_LE:         "STREXB.LE",
+	arm_STREXB:            "STREXB",
+	arm_STREXB_ZZ:         "STREXB.ZZ",
+	arm_STREXD_EQ:         "STREXD.EQ",
+	arm_STREXD_NE:         "STREXD.NE",
+	arm_STREXD_CS:         "STREXD.CS",
+	arm_STREXD_CC:         "STREXD.CC",
+	arm_STREXD_MI:         "STREXD.MI",
+	arm_STREXD_PL:         "STREXD.PL",
+	arm_STREXD_VS:         "STREXD.VS",
+	arm_STREXD_VC:         "STREXD.VC",
+	arm_STREXD_HI:         "STREXD.HI",
+	arm_STREXD_LS:         "STREXD.LS",
+	arm_STREXD_GE:         "STREXD.GE",
+	arm_STREXD_LT:         "STREXD.LT",
+	arm_STREXD_GT:         "STREXD.GT",
+	arm_STREXD_LE:         "STREXD.LE",
+	arm_STREXD:            "STREXD",
+	arm_STREXD_ZZ:         "STREXD.ZZ",
+	arm_STREXH_EQ:         "STREXH.EQ",
+	arm_STREXH_NE:         "STREXH.NE",
+	arm_STREXH_CS:         "STREXH.CS",
+	arm_STREXH_CC:         "STREXH.CC",
+	arm_STREXH_MI:         "STREXH.MI",
+	arm_STREXH_PL:         "STREXH.PL",
+	arm_STREXH_VS:         "STREXH.VS",
+	arm_STREXH_VC:         "STREXH.VC",
+	arm_STREXH_HI:         "STREXH.HI",
+	arm_STREXH_LS:         "STREXH.LS",
+	arm_STREXH_GE:         "STREXH.GE",
+	arm_STREXH_LT:         "STREXH.LT",
+	arm_STREXH_GT:         "STREXH.GT",
+	arm_STREXH_LE:         "STREXH.LE",
+	arm_STREXH:            "STREXH",
+	arm_STREXH_ZZ:         "STREXH.ZZ",
+	arm_STRH_EQ:           "STRH.EQ",
+	arm_STRH_NE:           "STRH.NE",
+	arm_STRH_CS:           "STRH.CS",
+	arm_STRH_CC:           "STRH.CC",
+	arm_STRH_MI:           "STRH.MI",
+	arm_STRH_PL:           "STRH.PL",
+	arm_STRH_VS:           "STRH.VS",
+	arm_STRH_VC:           "STRH.VC",
+	arm_STRH_HI:           "STRH.HI",
+	arm_STRH_LS:           "STRH.LS",
+	arm_STRH_GE:           "STRH.GE",
+	arm_STRH_LT:           "STRH.LT",
+	arm_STRH_GT:           "STRH.GT",
+	arm_STRH_LE:           "STRH.LE",
+	arm_STRH:              "STRH",
+	arm_STRH_ZZ:           "STRH.ZZ",
+	arm_STRHT_EQ:          "STRHT.EQ",
+	arm_STRHT_NE:          "STRHT.NE",
+	arm_STRHT_CS:          "STRHT.CS",
+	arm_STRHT_CC:          "STRHT.CC",
+	arm_STRHT_MI:          "STRHT.MI",
+	arm_STRHT_PL:          "STRHT.PL",
+	arm_STRHT_VS:          "STRHT.VS",
+	arm_STRHT_VC:          "STRHT.VC",
+	arm_STRHT_HI:          "STRHT.HI",
+	arm_STRHT_LS:          "STRHT.LS",
+	arm_STRHT_GE:          "STRHT.GE",
+	arm_STRHT_LT:          "STRHT.LT",
+	arm_STRHT_GT:          "STRHT.GT",
+	arm_STRHT_LE:          "STRHT.LE",
+	arm_STRHT:             "STRHT",
+	arm_STRHT_ZZ:          "STRHT.ZZ",
+	arm_STRT_EQ:           "STRT.EQ",
+	arm_STRT_NE:           "STRT.NE",
+	arm_STRT_CS:           "STRT.CS",
+	arm_STRT_CC:           "STRT.CC",
+	arm_STRT_MI:           "STRT.MI",
+	arm_STRT_PL:           "STRT.PL",
+	arm_STRT_VS:           "STRT.VS",
+	arm_STRT_VC:           "STRT.VC",
+	arm_STRT_HI:           "STRT.HI",
+	arm_STRT_LS:           "STRT.LS",
+	arm_STRT_GE:           "STRT.GE",
+	arm_STRT_LT:           "STRT.LT",
+	arm_STRT_GT:           "STRT.GT",
+	arm_STRT_LE:           "STRT.LE",
+	arm_STRT:              "STRT",
+	arm_STRT_ZZ:           "STRT.ZZ",
+	arm_SUB_EQ:            "SUB.EQ",
+	arm_SUB_NE:            "SUB.NE",
+	arm_SUB_CS:            "SUB.CS",
+	arm_SUB_CC:            "SUB.CC",
+	arm_SUB_MI:            "SUB.MI",
+	arm_SUB_PL:            "SUB.PL",
+	arm_SUB_VS:            "SUB.VS",
+	arm_SUB_VC:            "SUB.VC",
+	arm_SUB_HI:            "SUB.HI",
+	arm_SUB_LS:            "SUB.LS",
+	arm_SUB_GE:            "SUB.GE",
+	arm_SUB_LT:            "SUB.LT",
+	arm_SUB_GT:            "SUB.GT",
+	arm_SUB_LE:            "SUB.LE",
+	arm_SUB:               "SUB",
+	arm_SUB_ZZ:            "SUB.ZZ",
+	arm_SUB_S_EQ:          "SUB.S.EQ",
+	arm_SUB_S_NE:          "SUB.S.NE",
+	arm_SUB_S_CS:          "SUB.S.CS",
+	arm_SUB_S_CC:          "SUB.S.CC",
+	arm_SUB_S_MI:          "SUB.S.MI",
+	arm_SUB_S_PL:          "SUB.S.PL",
+	arm_SUB_S_VS:          "SUB.S.VS",
+	arm_SUB_S_VC:          "SUB.S.VC",
+	arm_SUB_S_HI:          "SUB.S.HI",
+	arm_SUB_S_LS:          "SUB.S.LS",
+	arm_SUB_S_GE:          "SUB.S.GE",
+	arm_SUB_S_LT:          "SUB.S.LT",
+	arm_SUB_S_GT:          "SUB.S.GT",
+	arm_SUB_S_LE:          "SUB.S.LE",
+	arm_SUB_S:             "SUB.S",
+	arm_SUB_S_ZZ:          "SUB.S.ZZ",
+	arm_SVC_EQ:            "SVC.EQ",
+	arm_SVC_NE:            "SVC.NE",
+	arm_SVC_CS:            "SVC.CS",
+	arm_SVC_CC:            "SVC.CC",
+	arm_SVC_MI:            "SVC.MI",
+	arm_SVC_PL:            "SVC.PL",
+	arm_SVC_VS:            "SVC.VS",
+	arm_SVC_VC:            "SVC.VC",
+	arm_SVC_HI:            "SVC.HI",
+	arm_SVC_LS:            "SVC.LS",
+	arm_SVC_GE:            "SVC.GE",
+	arm_SVC_LT:            "SVC.LT",
+	arm_SVC_GT:            "SVC.GT",
+	arm_SVC_LE:            "SVC.LE",
+	arm_SVC:               "SVC",
+	arm_SVC_ZZ:            "SVC.ZZ",
+	arm_SWP_EQ:            "SWP.EQ",
+	arm_SWP_NE:            "SWP.NE",
+	arm_SWP_CS:            "SWP.CS",
+	arm_SWP_CC:            "SWP.CC",
+	arm_SWP_MI:            "SWP.MI",
+	arm_SWP_PL:            "SWP.PL",
+	arm_SWP_VS:            "SWP.VS",
+	arm_SWP_VC:            "SWP.VC",
+	arm_SWP_HI:            "SWP.HI",
+	arm_SWP_LS:            "SWP.LS",
+	arm_SWP_GE:            "SWP.GE",
+	arm_SWP_LT:            "SWP.LT",
+	arm_SWP_GT:            "SWP.GT",
+	arm_SWP_LE:            "SWP.LE",
+	arm_SWP:               "SWP",
+	arm_SWP_ZZ:            "SWP.ZZ",
+	arm_SWP_B_EQ:          "SWP.B.EQ",
+	arm_SWP_B_NE:          "SWP.B.NE",
+	arm_SWP_B_CS:          "SWP.B.CS",
+	arm_SWP_B_CC:          "SWP.B.CC",
+	arm_SWP_B_MI:          "SWP.B.MI",
+	arm_SWP_B_PL:          "SWP.B.PL",
+	arm_SWP_B_VS:          "SWP.B.VS",
+	arm_SWP_B_VC:          "SWP.B.VC",
+	arm_SWP_B_HI:          "SWP.B.HI",
+	arm_SWP_B_LS:          "SWP.B.LS",
+	arm_SWP_B_GE:          "SWP.B.GE",
+	arm_SWP_B_LT:          "SWP.B.LT",
+	arm_SWP_B_GT:          "SWP.B.GT",
+	arm_SWP_B_LE:          "SWP.B.LE",
+	arm_SWP_B:             "SWP.B",
+	arm_SWP_B_ZZ:          "SWP.B.ZZ",
+	arm_SXTAB_EQ:          "SXTAB.EQ",
+	arm_SXTAB_NE:          "SXTAB.NE",
+	arm_SXTAB_CS:          "SXTAB.CS",
+	arm_SXTAB_CC:          "SXTAB.CC",
+	arm_SXTAB_MI:          "SXTAB.MI",
+	arm_SXTAB_PL:          "SXTAB.PL",
+	arm_SXTAB_VS:          "SXTAB.VS",
+	arm_SXTAB_VC:          "SXTAB.VC",
+	arm_SXTAB_HI:          "SXTAB.HI",
+	arm_SXTAB_LS:          "SXTAB.LS",
+	arm_SXTAB_GE:          "SXTAB.GE",
+	arm_SXTAB_LT:          "SXTAB.LT",
+	arm_SXTAB_GT:          "SXTAB.GT",
+	arm_SXTAB_LE:          "SXTAB.LE",
+	arm_SXTAB:             "SXTAB",
+	arm_SXTAB_ZZ:          "SXTAB.ZZ",
+	arm_SXTAB16_EQ:        "SXTAB16.EQ",
+	arm_SXTAB16_NE:        "SXTAB16.NE",
+	arm_SXTAB16_CS:        "SXTAB16.CS",
+	arm_SXTAB16_CC:        "SXTAB16.CC",
+	arm_SXTAB16_MI:        "SXTAB16.MI",
+	arm_SXTAB16_PL:        "SXTAB16.PL",
+	arm_SXTAB16_VS:        "SXTAB16.VS",
+	arm_SXTAB16_VC:        "SXTAB16.VC",
+	arm_SXTAB16_HI:        "SXTAB16.HI",
+	arm_SXTAB16_LS:        "SXTAB16.LS",
+	arm_SXTAB16_GE:        "SXTAB16.GE",
+	arm_SXTAB16_LT:        "SXTAB16.LT",
+	arm_SXTAB16_GT:        "SXTAB16.GT",
+	arm_SXTAB16_LE:        "SXTAB16.LE",
+	arm_SXTAB16:           "SXTAB16",
+	arm_SXTAB16_ZZ:        "SXTAB16.ZZ",
+	arm_SXTAH_EQ:          "SXTAH.EQ",
+	arm_SXTAH_NE:          "SXTAH.NE",
+	arm_SXTAH_CS:          "SXTAH.CS",
+	arm_SXTAH_CC:          "SXTAH.CC",
+	arm_SXTAH_MI:          "SXTAH.MI",
+	arm_SXTAH_PL:          "SXTAH.PL",
+	arm_SXTAH_VS:          "SXTAH.VS",
+	arm_SXTAH_VC:          "SXTAH.VC",
+	arm_SXTAH_HI:          "SXTAH.HI",
+	arm_SXTAH_LS:          "SXTAH.LS",
+	arm_SXTAH_GE:          "SXTAH.GE",
+	arm_SXTAH_LT:          "SXTAH.LT",
+	arm_SXTAH_GT:          "SXTAH.GT",
+	arm_SXTAH_LE:          "SXTAH.LE",
+	arm_SXTAH:             "SXTAH",
+	arm_SXTAH_ZZ:          "SXTAH.ZZ",
+	arm_SXTB_EQ:           "SXTB.EQ",
+	arm_SXTB_NE:           "SXTB.NE",
+	arm_SXTB_CS:           "SXTB.CS",
+	arm_SXTB_CC:           "SXTB.CC",
+	arm_SXTB_MI:           "SXTB.MI",
+	arm_SXTB_PL:           "SXTB.PL",
+	arm_SXTB_VS:           "SXTB.VS",
+	arm_SXTB_VC:           "SXTB.VC",
+	arm_SXTB_HI:           "SXTB.HI",
+	arm_SXTB_LS:           "SXTB.LS",
+	arm_SXTB_GE:           "SXTB.GE",
+	arm_SXTB_LT:           "SXTB.LT",
+	arm_SXTB_GT:           "SXTB.GT",
+	arm_SXTB_LE:           "SXTB.LE",
+	arm_SXTB:              "SXTB",
+	arm_SXTB_ZZ:           "SXTB.ZZ",
+	arm_SXTB16_EQ:         "SXTB16.EQ",
+	arm_SXTB16_NE:         "SXTB16.NE",
+	arm_SXTB16_CS:         "SXTB16.CS",
+	arm_SXTB16_CC:         "SXTB16.CC",
+	arm_SXTB16_MI:         "SXTB16.MI",
+	arm_SXTB16_PL:         "SXTB16.PL",
+	arm_SXTB16_VS:         "SXTB16.VS",
+	arm_SXTB16_VC:         "SXTB16.VC",
+	arm_SXTB16_HI:         "SXTB16.HI",
+	arm_SXTB16_LS:         "SXTB16.LS",
+	arm_SXTB16_GE:         "SXTB16.GE",
+	arm_SXTB16_LT:         "SXTB16.LT",
+	arm_SXTB16_GT:         "SXTB16.GT",
+	arm_SXTB16_LE:         "SXTB16.LE",
+	arm_SXTB16:            "SXTB16",
+	arm_SXTB16_ZZ:         "SXTB16.ZZ",
+	arm_SXTH_EQ:           "SXTH.EQ",
+	arm_SXTH_NE:           "SXTH.NE",
+	arm_SXTH_CS:           "SXTH.CS",
+	arm_SXTH_CC:           "SXTH.CC",
+	arm_SXTH_MI:           "SXTH.MI",
+	arm_SXTH_PL:           "SXTH.PL",
+	arm_SXTH_VS:           "SXTH.VS",
+	arm_SXTH_VC:           "SXTH.VC",
+	arm_SXTH_HI:           "SXTH.HI",
+	arm_SXTH_LS:           "SXTH.LS",
+	arm_SXTH_GE:           "SXTH.GE",
+	arm_SXTH_LT:           "SXTH.LT",
+	arm_SXTH_GT:           "SXTH.GT",
+	arm_SXTH_LE:           "SXTH.LE",
+	arm_SXTH:              "SXTH",
+	arm_SXTH_ZZ:           "SXTH.ZZ",
+	arm_TEQ_EQ:            "TEQ.EQ",
+	arm_TEQ_NE:            "TEQ.NE",
+	arm_TEQ_CS:            "TEQ.CS",
+	arm_TEQ_CC:            "TEQ.CC",
+	arm_TEQ_MI:            "TEQ.MI",
+	arm_TEQ_PL:            "TEQ.PL",
+	arm_TEQ_VS:            "TEQ.VS",
+	arm_TEQ_VC:            "TEQ.VC",
+	arm_TEQ_HI:            "TEQ.HI",
+	arm_TEQ_LS:            "TEQ.LS",
+	arm_TEQ_GE:            "TEQ.GE",
+	arm_TEQ_LT:            "TEQ.LT",
+	arm_TEQ_GT:            "TEQ.GT",
+	arm_TEQ_LE:            "TEQ.LE",
+	arm_TEQ:               "TEQ",
+	arm_TEQ_ZZ:            "TEQ.ZZ",
+	arm_TST_EQ:            "TST.EQ",
+	arm_TST_NE:            "TST.NE",
+	arm_TST_CS:            "TST.CS",
+	arm_TST_CC:            "TST.CC",
+	arm_TST_MI:            "TST.MI",
+	arm_TST_PL:            "TST.PL",
+	arm_TST_VS:            "TST.VS",
+	arm_TST_VC:            "TST.VC",
+	arm_TST_HI:            "TST.HI",
+	arm_TST_LS:            "TST.LS",
+	arm_TST_GE:            "TST.GE",
+	arm_TST_LT:            "TST.LT",
+	arm_TST_GT:            "TST.GT",
+	arm_TST_LE:            "TST.LE",
+	arm_TST:               "TST",
+	arm_TST_ZZ:            "TST.ZZ",
+	arm_UADD16_EQ:         "UADD16.EQ",
+	arm_UADD16_NE:         "UADD16.NE",
+	arm_UADD16_CS:         "UADD16.CS",
+	arm_UADD16_CC:         "UADD16.CC",
+	arm_UADD16_MI:         "UADD16.MI",
+	arm_UADD16_PL:         "UADD16.PL",
+	arm_UADD16_VS:         "UADD16.VS",
+	arm_UADD16_VC:         "UADD16.VC",
+	arm_UADD16_HI:         "UADD16.HI",
+	arm_UADD16_LS:         "UADD16.LS",
+	arm_UADD16_GE:         "UADD16.GE",
+	arm_UADD16_LT:         "UADD16.LT",
+	arm_UADD16_GT:         "UADD16.GT",
+	arm_UADD16_LE:         "UADD16.LE",
+	arm_UADD16:            "UADD16",
+	arm_UADD16_ZZ:         "UADD16.ZZ",
+	arm_UADD8_EQ:          "UADD8.EQ",
+	arm_UADD8_NE:          "UADD8.NE",
+	arm_UADD8_CS:          "UADD8.CS",
+	arm_UADD8_CC:          "UADD8.CC",
+	arm_UADD8_MI:          "UADD8.MI",
+	arm_UADD8_PL:          "UADD8.PL",
+	arm_UADD8_VS:          "UADD8.VS",
+	arm_UADD8_VC:          "UADD8.VC",
+	arm_UADD8_HI:          "UADD8.HI",
+	arm_UADD8_LS:          "UADD8.LS",
+	arm_UADD8_GE:          "UADD8.GE",
+	arm_UADD8_LT:          "UADD8.LT",
+	arm_UADD8_GT:          "UADD8.GT",
+	arm_UADD8_LE:          "UADD8.LE",
+	arm_UADD8:             "UADD8",
+	arm_UADD8_ZZ:          "UADD8.ZZ",
+	arm_UASX_EQ:           "UASX.EQ",
+	arm_UASX_NE:           "UASX.NE",
+	arm_UASX_CS:           "UASX.CS",
+	arm_UASX_CC:           "UASX.CC",
+	arm_UASX_MI:           "UASX.MI",
+	arm_UASX_PL:           "UASX.PL",
+	arm_UASX_VS:           "UASX.VS",
+	arm_UASX_VC:           "UASX.VC",
+	arm_UASX_HI:           "UASX.HI",
+	arm_UASX_LS:           "UASX.LS",
+	arm_UASX_GE:           "UASX.GE",
+	arm_UASX_LT:           "UASX.LT",
+	arm_UASX_GT:           "UASX.GT",
+	arm_UASX_LE:           "UASX.LE",
+	arm_UASX:              "UASX",
+	arm_UASX_ZZ:           "UASX.ZZ",
+	arm_UBFX_EQ:           "UBFX.EQ",
+	arm_UBFX_NE:           "UBFX.NE",
+	arm_UBFX_CS:           "UBFX.CS",
+	arm_UBFX_CC:           "UBFX.CC",
+	arm_UBFX_MI:           "UBFX.MI",
+	arm_UBFX_PL:           "UBFX.PL",
+	arm_UBFX_VS:           "UBFX.VS",
+	arm_UBFX_VC:           "UBFX.VC",
+	arm_UBFX_HI:           "UBFX.HI",
+	arm_UBFX_LS:           "UBFX.LS",
+	arm_UBFX_GE:           "UBFX.GE",
+	arm_UBFX_LT:           "UBFX.LT",
+	arm_UBFX_GT:           "UBFX.GT",
+	arm_UBFX_LE:           "UBFX.LE",
+	arm_UBFX:              "UBFX",
+	arm_UBFX_ZZ:           "UBFX.ZZ",
+	arm_UHADD16_EQ:        "UHADD16.EQ",
+	arm_UHADD16_NE:        "UHADD16.NE",
+	arm_UHADD16_CS:        "UHADD16.CS",
+	arm_UHADD16_CC:        "UHADD16.CC",
+	arm_UHADD16_MI:        "UHADD16.MI",
+	arm_UHADD16_PL:        "UHADD16.PL",
+	arm_UHADD16_VS:        "UHADD16.VS",
+	arm_UHADD16_VC:        "UHADD16.VC",
+	arm_UHADD16_HI:        "UHADD16.HI",
+	arm_UHADD16_LS:        "UHADD16.LS",
+	arm_UHADD16_GE:        "UHADD16.GE",
+	arm_UHADD16_LT:        "UHADD16.LT",
+	arm_UHADD16_GT:        "UHADD16.GT",
+	arm_UHADD16_LE:        "UHADD16.LE",
+	arm_UHADD16:           "UHADD16",
+	arm_UHADD16_ZZ:        "UHADD16.ZZ",
+	arm_UHADD8_EQ:         "UHADD8.EQ",
+	arm_UHADD8_NE:         "UHADD8.NE",
+	arm_UHADD8_CS:         "UHADD8.CS",
+	arm_UHADD8_CC:         "UHADD8.CC",
+	arm_UHADD8_MI:         "UHADD8.MI",
+	arm_UHADD8_PL:         "UHADD8.PL",
+	arm_UHADD8_VS:         "UHADD8.VS",
+	arm_UHADD8_VC:         "UHADD8.VC",
+	arm_UHADD8_HI:         "UHADD8.HI",
+	arm_UHADD8_LS:         "UHADD8.LS",
+	arm_UHADD8_GE:         "UHADD8.GE",
+	arm_UHADD8_LT:         "UHADD8.LT",
+	arm_UHADD8_GT:         "UHADD8.GT",
+	arm_UHADD8_LE:         "UHADD8.LE",
+	arm_UHADD8:            "UHADD8",
+	arm_UHADD8_ZZ:         "UHADD8.ZZ",
+	arm_UHASX_EQ:          "UHASX.EQ",
+	arm_UHASX_NE:          "UHASX.NE",
+	arm_UHASX_CS:          "UHASX.CS",
+	arm_UHASX_CC:          "UHASX.CC",
+	arm_UHASX_MI:          "UHASX.MI",
+	arm_UHASX_PL:          "UHASX.PL",
+	arm_UHASX_VS:          "UHASX.VS",
+	arm_UHASX_VC:          "UHASX.VC",
+	arm_UHASX_HI:          "UHASX.HI",
+	arm_UHASX_LS:          "UHASX.LS",
+	arm_UHASX_GE:          "UHASX.GE",
+	arm_UHASX_LT:          "UHASX.LT",
+	arm_UHASX_GT:          "UHASX.GT",
+	arm_UHASX_LE:          "UHASX.LE",
+	arm_UHASX:             "UHASX",
+	arm_UHASX_ZZ:          "UHASX.ZZ",
+	arm_UHSAX_EQ:          "UHSAX.EQ",
+	arm_UHSAX_NE:          "UHSAX.NE",
+	arm_UHSAX_CS:          "UHSAX.CS",
+	arm_UHSAX_CC:          "UHSAX.CC",
+	arm_UHSAX_MI:          "UHSAX.MI",
+	arm_UHSAX_PL:          "UHSAX.PL",
+	arm_UHSAX_VS:          "UHSAX.VS",
+	arm_UHSAX_VC:          "UHSAX.VC",
+	arm_UHSAX_HI:          "UHSAX.HI",
+	arm_UHSAX_LS:          "UHSAX.LS",
+	arm_UHSAX_GE:          "UHSAX.GE",
+	arm_UHSAX_LT:          "UHSAX.LT",
+	arm_UHSAX_GT:          "UHSAX.GT",
+	arm_UHSAX_LE:          "UHSAX.LE",
+	arm_UHSAX:             "UHSAX",
+	arm_UHSAX_ZZ:          "UHSAX.ZZ",
+	arm_UHSUB16_EQ:        "UHSUB16.EQ",
+	arm_UHSUB16_NE:        "UHSUB16.NE",
+	arm_UHSUB16_CS:        "UHSUB16.CS",
+	arm_UHSUB16_CC:        "UHSUB16.CC",
+	arm_UHSUB16_MI:        "UHSUB16.MI",
+	arm_UHSUB16_PL:        "UHSUB16.PL",
+	arm_UHSUB16_VS:        "UHSUB16.VS",
+	arm_UHSUB16_VC:        "UHSUB16.VC",
+	arm_UHSUB16_HI:        "UHSUB16.HI",
+	arm_UHSUB16_LS:        "UHSUB16.LS",
+	arm_UHSUB16_GE:        "UHSUB16.GE",
+	arm_UHSUB16_LT:        "UHSUB16.LT",
+	arm_UHSUB16_GT:        "UHSUB16.GT",
+	arm_UHSUB16_LE:        "UHSUB16.LE",
+	arm_UHSUB16:           "UHSUB16",
+	arm_UHSUB16_ZZ:        "UHSUB16.ZZ",
+	arm_UHSUB8_EQ:         "UHSUB8.EQ",
+	arm_UHSUB8_NE:         "UHSUB8.NE",
+	arm_UHSUB8_CS:         "UHSUB8.CS",
+	arm_UHSUB8_CC:         "UHSUB8.CC",
+	arm_UHSUB8_MI:         "UHSUB8.MI",
+	arm_UHSUB8_PL:         "UHSUB8.PL",
+	arm_UHSUB8_VS:         "UHSUB8.VS",
+	arm_UHSUB8_VC:         "UHSUB8.VC",
+	arm_UHSUB8_HI:         "UHSUB8.HI",
+	arm_UHSUB8_LS:         "UHSUB8.LS",
+	arm_UHSUB8_GE:         "UHSUB8.GE",
+	arm_UHSUB8_LT:         "UHSUB8.LT",
+	arm_UHSUB8_GT:         "UHSUB8.GT",
+	arm_UHSUB8_LE:         "UHSUB8.LE",
+	arm_UHSUB8:            "UHSUB8",
+	arm_UHSUB8_ZZ:         "UHSUB8.ZZ",
+	arm_UMAAL_EQ:          "UMAAL.EQ",
+	arm_UMAAL_NE:          "UMAAL.NE",
+	arm_UMAAL_CS:          "UMAAL.CS",
+	arm_UMAAL_CC:          "UMAAL.CC",
+	arm_UMAAL_MI:          "UMAAL.MI",
+	arm_UMAAL_PL:          "UMAAL.PL",
+	arm_UMAAL_VS:          "UMAAL.VS",
+	arm_UMAAL_VC:          "UMAAL.VC",
+	arm_UMAAL_HI:          "UMAAL.HI",
+	arm_UMAAL_LS:          "UMAAL.LS",
+	arm_UMAAL_GE:          "UMAAL.GE",
+	arm_UMAAL_LT:          "UMAAL.LT",
+	arm_UMAAL_GT:          "UMAAL.GT",
+	arm_UMAAL_LE:          "UMAAL.LE",
+	arm_UMAAL:             "UMAAL",
+	arm_UMAAL_ZZ:          "UMAAL.ZZ",
+	arm_UMLAL_EQ:          "UMLAL.EQ",
+	arm_UMLAL_NE:          "UMLAL.NE",
+	arm_UMLAL_CS:          "UMLAL.CS",
+	arm_UMLAL_CC:          "UMLAL.CC",
+	arm_UMLAL_MI:          "UMLAL.MI",
+	arm_UMLAL_PL:          "UMLAL.PL",
+	arm_UMLAL_VS:          "UMLAL.VS",
+	arm_UMLAL_VC:          "UMLAL.VC",
+	arm_UMLAL_HI:          "UMLAL.HI",
+	arm_UMLAL_LS:          "UMLAL.LS",
+	arm_UMLAL_GE:          "UMLAL.GE",
+	arm_UMLAL_LT:          "UMLAL.LT",
+	arm_UMLAL_GT:          "UMLAL.GT",
+	arm_UMLAL_LE:          "UMLAL.LE",
+	arm_UMLAL:             "UMLAL",
+	arm_UMLAL_ZZ:          "UMLAL.ZZ",
+	arm_UMLAL_S_EQ:        "UMLAL.S.EQ",
+	arm_UMLAL_S_NE:        "UMLAL.S.NE",
+	arm_UMLAL_S_CS:        "UMLAL.S.CS",
+	arm_UMLAL_S_CC:        "UMLAL.S.CC",
+	arm_UMLAL_S_MI:        "UMLAL.S.MI",
+	arm_UMLAL_S_PL:        "UMLAL.S.PL",
+	arm_UMLAL_S_VS:        "UMLAL.S.VS",
+	arm_UMLAL_S_VC:        "UMLAL.S.VC",
+	arm_UMLAL_S_HI:        "UMLAL.S.HI",
+	arm_UMLAL_S_LS:        "UMLAL.S.LS",
+	arm_UMLAL_S_GE:        "UMLAL.S.GE",
+	arm_UMLAL_S_LT:        "UMLAL.S.LT",
+	arm_UMLAL_S_GT:        "UMLAL.S.GT",
+	arm_UMLAL_S_LE:        "UMLAL.S.LE",
+	arm_UMLAL_S:           "UMLAL.S",
+	arm_UMLAL_S_ZZ:        "UMLAL.S.ZZ",
+	arm_UMULL_EQ:          "UMULL.EQ",
+	arm_UMULL_NE:          "UMULL.NE",
+	arm_UMULL_CS:          "UMULL.CS",
+	arm_UMULL_CC:          "UMULL.CC",
+	arm_UMULL_MI:          "UMULL.MI",
+	arm_UMULL_PL:          "UMULL.PL",
+	arm_UMULL_VS:          "UMULL.VS",
+	arm_UMULL_VC:          "UMULL.VC",
+	arm_UMULL_HI:          "UMULL.HI",
+	arm_UMULL_LS:          "UMULL.LS",
+	arm_UMULL_GE:          "UMULL.GE",
+	arm_UMULL_LT:          "UMULL.LT",
+	arm_UMULL_GT:          "UMULL.GT",
+	arm_UMULL_LE:          "UMULL.LE",
+	arm_UMULL:             "UMULL",
+	arm_UMULL_ZZ:          "UMULL.ZZ",
+	arm_UMULL_S_EQ:        "UMULL.S.EQ",
+	arm_UMULL_S_NE:        "UMULL.S.NE",
+	arm_UMULL_S_CS:        "UMULL.S.CS",
+	arm_UMULL_S_CC:        "UMULL.S.CC",
+	arm_UMULL_S_MI:        "UMULL.S.MI",
+	arm_UMULL_S_PL:        "UMULL.S.PL",
+	arm_UMULL_S_VS:        "UMULL.S.VS",
+	arm_UMULL_S_VC:        "UMULL.S.VC",
+	arm_UMULL_S_HI:        "UMULL.S.HI",
+	arm_UMULL_S_LS:        "UMULL.S.LS",
+	arm_UMULL_S_GE:        "UMULL.S.GE",
+	arm_UMULL_S_LT:        "UMULL.S.LT",
+	arm_UMULL_S_GT:        "UMULL.S.GT",
+	arm_UMULL_S_LE:        "UMULL.S.LE",
+	arm_UMULL_S:           "UMULL.S",
+	arm_UMULL_S_ZZ:        "UMULL.S.ZZ",
+	arm_UNDEF:             "UNDEF",
+	arm_UQADD16_EQ:        "UQADD16.EQ",
+	arm_UQADD16_NE:        "UQADD16.NE",
+	arm_UQADD16_CS:        "UQADD16.CS",
+	arm_UQADD16_CC:        "UQADD16.CC",
+	arm_UQADD16_MI:        "UQADD16.MI",
+	arm_UQADD16_PL:        "UQADD16.PL",
+	arm_UQADD16_VS:        "UQADD16.VS",
+	arm_UQADD16_VC:        "UQADD16.VC",
+	arm_UQADD16_HI:        "UQADD16.HI",
+	arm_UQADD16_LS:        "UQADD16.LS",
+	arm_UQADD16_GE:        "UQADD16.GE",
+	arm_UQADD16_LT:        "UQADD16.LT",
+	arm_UQADD16_GT:        "UQADD16.GT",
+	arm_UQADD16_LE:        "UQADD16.LE",
+	arm_UQADD16:           "UQADD16",
+	arm_UQADD16_ZZ:        "UQADD16.ZZ",
+	arm_UQADD8_EQ:         "UQADD8.EQ",
+	arm_UQADD8_NE:         "UQADD8.NE",
+	arm_UQADD8_CS:         "UQADD8.CS",
+	arm_UQADD8_CC:         "UQADD8.CC",
+	arm_UQADD8_MI:         "UQADD8.MI",
+	arm_UQADD8_PL:         "UQADD8.PL",
+	arm_UQADD8_VS:         "UQADD8.VS",
+	arm_UQADD8_VC:         "UQADD8.VC",
+	arm_UQADD8_HI:         "UQADD8.HI",
+	arm_UQADD8_LS:         "UQADD8.LS",
+	arm_UQADD8_GE:         "UQADD8.GE",
+	arm_UQADD8_LT:         "UQADD8.LT",
+	arm_UQADD8_GT:         "UQADD8.GT",
+	arm_UQADD8_LE:         "UQADD8.LE",
+	arm_UQADD8:            "UQADD8",
+	arm_UQADD8_ZZ:         "UQADD8.ZZ",
+	arm_UQASX_EQ:          "UQASX.EQ",
+	arm_UQASX_NE:          "UQASX.NE",
+	arm_UQASX_CS:          "UQASX.CS",
+	arm_UQASX_CC:          "UQASX.CC",
+	arm_UQASX_MI:          "UQASX.MI",
+	arm_UQASX_PL:          "UQASX.PL",
+	arm_UQASX_VS:          "UQASX.VS",
+	arm_UQASX_VC:          "UQASX.VC",
+	arm_UQASX_HI:          "UQASX.HI",
+	arm_UQASX_LS:          "UQASX.LS",
+	arm_UQASX_GE:          "UQASX.GE",
+	arm_UQASX_LT:          "UQASX.LT",
+	arm_UQASX_GT:          "UQASX.GT",
+	arm_UQASX_LE:          "UQASX.LE",
+	arm_UQASX:             "UQASX",
+	arm_UQASX_ZZ:          "UQASX.ZZ",
+	arm_UQSAX_EQ:          "UQSAX.EQ",
+	arm_UQSAX_NE:          "UQSAX.NE",
+	arm_UQSAX_CS:          "UQSAX.CS",
+	arm_UQSAX_CC:          "UQSAX.CC",
+	arm_UQSAX_MI:          "UQSAX.MI",
+	arm_UQSAX_PL:          "UQSAX.PL",
+	arm_UQSAX_VS:          "UQSAX.VS",
+	arm_UQSAX_VC:          "UQSAX.VC",
+	arm_UQSAX_HI:          "UQSAX.HI",
+	arm_UQSAX_LS:          "UQSAX.LS",
+	arm_UQSAX_GE:          "UQSAX.GE",
+	arm_UQSAX_LT:          "UQSAX.LT",
+	arm_UQSAX_GT:          "UQSAX.GT",
+	arm_UQSAX_LE:          "UQSAX.LE",
+	arm_UQSAX:             "UQSAX",
+	arm_UQSAX_ZZ:          "UQSAX.ZZ",
+	arm_UQSUB16_EQ:        "UQSUB16.EQ",
+	arm_UQSUB16_NE:        "UQSUB16.NE",
+	arm_UQSUB16_CS:        "UQSUB16.CS",
+	arm_UQSUB16_CC:        "UQSUB16.CC",
+	arm_UQSUB16_MI:        "UQSUB16.MI",
+	arm_UQSUB16_PL:        "UQSUB16.PL",
+	arm_UQSUB16_VS:        "UQSUB16.VS",
+	arm_UQSUB16_VC:        "UQSUB16.VC",
+	arm_UQSUB16_HI:        "UQSUB16.HI",
+	arm_UQSUB16_LS:        "UQSUB16.LS",
+	arm_UQSUB16_GE:        "UQSUB16.GE",
+	arm_UQSUB16_LT:        "UQSUB16.LT",
+	arm_UQSUB16_GT:        "UQSUB16.GT",
+	arm_UQSUB16_LE:        "UQSUB16.LE",
+	arm_UQSUB16:           "UQSUB16",
+	arm_UQSUB16_ZZ:        "UQSUB16.ZZ",
+	arm_UQSUB8_EQ:         "UQSUB8.EQ",
+	arm_UQSUB8_NE:         "UQSUB8.NE",
+	arm_UQSUB8_CS:         "UQSUB8.CS",
+	arm_UQSUB8_CC:         "UQSUB8.CC",
+	arm_UQSUB8_MI:         "UQSUB8.MI",
+	arm_UQSUB8_PL:         "UQSUB8.PL",
+	arm_UQSUB8_VS:         "UQSUB8.VS",
+	arm_UQSUB8_VC:         "UQSUB8.VC",
+	arm_UQSUB8_HI:         "UQSUB8.HI",
+	arm_UQSUB8_LS:         "UQSUB8.LS",
+	arm_UQSUB8_GE:         "UQSUB8.GE",
+	arm_UQSUB8_LT:         "UQSUB8.LT",
+	arm_UQSUB8_GT:         "UQSUB8.GT",
+	arm_UQSUB8_LE:         "UQSUB8.LE",
+	arm_UQSUB8:            "UQSUB8",
+	arm_UQSUB8_ZZ:         "UQSUB8.ZZ",
+	arm_USAD8_EQ:          "USAD8.EQ",
+	arm_USAD8_NE:          "USAD8.NE",
+	arm_USAD8_CS:          "USAD8.CS",
+	arm_USAD8_CC:          "USAD8.CC",
+	arm_USAD8_MI:          "USAD8.MI",
+	arm_USAD8_PL:          "USAD8.PL",
+	arm_USAD8_VS:          "USAD8.VS",
+	arm_USAD8_VC:          "USAD8.VC",
+	arm_USAD8_HI:          "USAD8.HI",
+	arm_USAD8_LS:          "USAD8.LS",
+	arm_USAD8_GE:          "USAD8.GE",
+	arm_USAD8_LT:          "USAD8.LT",
+	arm_USAD8_GT:          "USAD8.GT",
+	arm_USAD8_LE:          "USAD8.LE",
+	arm_USAD8:             "USAD8",
+	arm_USAD8_ZZ:          "USAD8.ZZ",
+	arm_USADA8_EQ:         "USADA8.EQ",
+	arm_USADA8_NE:         "USADA8.NE",
+	arm_USADA8_CS:         "USADA8.CS",
+	arm_USADA8_CC:         "USADA8.CC",
+	arm_USADA8_MI:         "USADA8.MI",
+	arm_USADA8_PL:         "USADA8.PL",
+	arm_USADA8_VS:         "USADA8.VS",
+	arm_USADA8_VC:         "USADA8.VC",
+	arm_USADA8_HI:         "USADA8.HI",
+	arm_USADA8_LS:         "USADA8.LS",
+	arm_USADA8_GE:         "USADA8.GE",
+	arm_USADA8_LT:         "USADA8.LT",
+	arm_USADA8_GT:         "USADA8.GT",
+	arm_USADA8_LE:         "USADA8.LE",
+	arm_USADA8:            "USADA8",
+	arm_USADA8_ZZ:         "USADA8.ZZ",
+	arm_USAT_EQ:           "USAT.EQ",
+	arm_USAT_NE:           "USAT.NE",
+	arm_USAT_CS:           "USAT.CS",
+	arm_USAT_CC:           "USAT.CC",
+	arm_USAT_MI:           "USAT.MI",
+	arm_USAT_PL:           "USAT.PL",
+	arm_USAT_VS:           "USAT.VS",
+	arm_USAT_VC:           "USAT.VC",
+	arm_USAT_HI:           "USAT.HI",
+	arm_USAT_LS:           "USAT.LS",
+	arm_USAT_GE:           "USAT.GE",
+	arm_USAT_LT:           "USAT.LT",
+	arm_USAT_GT:           "USAT.GT",
+	arm_USAT_LE:           "USAT.LE",
+	arm_USAT:              "USAT",
+	arm_USAT_ZZ:           "USAT.ZZ",
+	arm_USAT16_EQ:         "USAT16.EQ",
+	arm_USAT16_NE:         "USAT16.NE",
+	arm_USAT16_CS:         "USAT16.CS",
+	arm_USAT16_CC:         "USAT16.CC",
+	arm_USAT16_MI:         "USAT16.MI",
+	arm_USAT16_PL:         "USAT16.PL",
+	arm_USAT16_VS:         "USAT16.VS",
+	arm_USAT16_VC:         "USAT16.VC",
+	arm_USAT16_HI:         "USAT16.HI",
+	arm_USAT16_LS:         "USAT16.LS",
+	arm_USAT16_GE:         "USAT16.GE",
+	arm_USAT16_LT:         "USAT16.LT",
+	arm_USAT16_GT:         "USAT16.GT",
+	arm_USAT16_LE:         "USAT16.LE",
+	arm_USAT16:            "USAT16",
+	arm_USAT16_ZZ:         "USAT16.ZZ",
+	arm_USAX_EQ:           "USAX.EQ",
+	arm_USAX_NE:           "USAX.NE",
+	arm_USAX_CS:           "USAX.CS",
+	arm_USAX_CC:           "USAX.CC",
+	arm_USAX_MI:           "USAX.MI",
+	arm_USAX_PL:           "USAX.PL",
+	arm_USAX_VS:           "USAX.VS",
+	arm_USAX_VC:           "USAX.VC",
+	arm_USAX_HI:           "USAX.HI",
+	arm_USAX_LS:           "USAX.LS",
+	arm_USAX_GE:           "USAX.GE",
+	arm_USAX_LT:           "USAX.LT",
+	arm_USAX_GT:           "USAX.GT",
+	arm_USAX_LE:           "USAX.LE",
+	arm_USAX:              "USAX",
+	arm_USAX_ZZ:           "USAX.ZZ",
+	arm_USUB16_EQ:         "USUB16.EQ",
+	arm_USUB16_NE:         "USUB16.NE",
+	arm_USUB16_CS:         "USUB16.CS",
+	arm_USUB16_CC:         "USUB16.CC",
+	arm_USUB16_MI:         "USUB16.MI",
+	arm_USUB16_PL:         "USUB16.PL",
+	arm_USUB16_VS:         "USUB16.VS",
+	arm_USUB16_VC:         "USUB16.VC",
+	arm_USUB16_HI:         "USUB16.HI",
+	arm_USUB16_LS:         "USUB16.LS",
+	arm_USUB16_GE:         "USUB16.GE",
+	arm_USUB16_LT:         "USUB16.LT",
+	arm_USUB16_GT:         "USUB16.GT",
+	arm_USUB16_LE:         "USUB16.LE",
+	arm_USUB16:            "USUB16",
+	arm_USUB16_ZZ:         "USUB16.ZZ",
+	arm_USUB8_EQ:          "USUB8.EQ",
+	arm_USUB8_NE:          "USUB8.NE",
+	arm_USUB8_CS:          "USUB8.CS",
+	arm_USUB8_CC:          "USUB8.CC",
+	arm_USUB8_MI:          "USUB8.MI",
+	arm_USUB8_PL:          "USUB8.PL",
+	arm_USUB8_VS:          "USUB8.VS",
+	arm_USUB8_VC:          "USUB8.VC",
+	arm_USUB8_HI:          "USUB8.HI",
+	arm_USUB8_LS:          "USUB8.LS",
+	arm_USUB8_GE:          "USUB8.GE",
+	arm_USUB8_LT:          "USUB8.LT",
+	arm_USUB8_GT:          "USUB8.GT",
+	arm_USUB8_LE:          "USUB8.LE",
+	arm_USUB8:             "USUB8",
+	arm_USUB8_ZZ:          "USUB8.ZZ",
+	arm_UXTAB_EQ:          "UXTAB.EQ",
+	arm_UXTAB_NE:          "UXTAB.NE",
+	arm_UXTAB_CS:          "UXTAB.CS",
+	arm_UXTAB_CC:          "UXTAB.CC",
+	arm_UXTAB_MI:          "UXTAB.MI",
+	arm_UXTAB_PL:          "UXTAB.PL",
+	arm_UXTAB_VS:          "UXTAB.VS",
+	arm_UXTAB_VC:          "UXTAB.VC",
+	arm_UXTAB_HI:          "UXTAB.HI",
+	arm_UXTAB_LS:          "UXTAB.LS",
+	arm_UXTAB_GE:          "UXTAB.GE",
+	arm_UXTAB_LT:          "UXTAB.LT",
+	arm_UXTAB_GT:          "UXTAB.GT",
+	arm_UXTAB_LE:          "UXTAB.LE",
+	arm_UXTAB:             "UXTAB",
+	arm_UXTAB_ZZ:          "UXTAB.ZZ",
+	arm_UXTAB16_EQ:        "UXTAB16.EQ",
+	arm_UXTAB16_NE:        "UXTAB16.NE",
+	arm_UXTAB16_CS:        "UXTAB16.CS",
+	arm_UXTAB16_CC:        "UXTAB16.CC",
+	arm_UXTAB16_MI:        "UXTAB16.MI",
+	arm_UXTAB16_PL:        "UXTAB16.PL",
+	arm_UXTAB16_VS:        "UXTAB16.VS",
+	arm_UXTAB16_VC:        "UXTAB16.VC",
+	arm_UXTAB16_HI:        "UXTAB16.HI",
+	arm_UXTAB16_LS:        "UXTAB16.LS",
+	arm_UXTAB16_GE:        "UXTAB16.GE",
+	arm_UXTAB16_LT:        "UXTAB16.LT",
+	arm_UXTAB16_GT:        "UXTAB16.GT",
+	arm_UXTAB16_LE:        "UXTAB16.LE",
+	arm_UXTAB16:           "UXTAB16",
+	arm_UXTAB16_ZZ:        "UXTAB16.ZZ",
+	arm_UXTAH_EQ:          "UXTAH.EQ",
+	arm_UXTAH_NE:          "UXTAH.NE",
+	arm_UXTAH_CS:          "UXTAH.CS",
+	arm_UXTAH_CC:          "UXTAH.CC",
+	arm_UXTAH_MI:          "UXTAH.MI",
+	arm_UXTAH_PL:          "UXTAH.PL",
+	arm_UXTAH_VS:          "UXTAH.VS",
+	arm_UXTAH_VC:          "UXTAH.VC",
+	arm_UXTAH_HI:          "UXTAH.HI",
+	arm_UXTAH_LS:          "UXTAH.LS",
+	arm_UXTAH_GE:          "UXTAH.GE",
+	arm_UXTAH_LT:          "UXTAH.LT",
+	arm_UXTAH_GT:          "UXTAH.GT",
+	arm_UXTAH_LE:          "UXTAH.LE",
+	arm_UXTAH:             "UXTAH",
+	arm_UXTAH_ZZ:          "UXTAH.ZZ",
+	arm_UXTB_EQ:           "UXTB.EQ",
+	arm_UXTB_NE:           "UXTB.NE",
+	arm_UXTB_CS:           "UXTB.CS",
+	arm_UXTB_CC:           "UXTB.CC",
+	arm_UXTB_MI:           "UXTB.MI",
+	arm_UXTB_PL:           "UXTB.PL",
+	arm_UXTB_VS:           "UXTB.VS",
+	arm_UXTB_VC:           "UXTB.VC",
+	arm_UXTB_HI:           "UXTB.HI",
+	arm_UXTB_LS:           "UXTB.LS",
+	arm_UXTB_GE:           "UXTB.GE",
+	arm_UXTB_LT:           "UXTB.LT",
+	arm_UXTB_GT:           "UXTB.GT",
+	arm_UXTB_LE:           "UXTB.LE",
+	arm_UXTB:              "UXTB",
+	arm_UXTB_ZZ:           "UXTB.ZZ",
+	arm_UXTB16_EQ:         "UXTB16.EQ",
+	arm_UXTB16_NE:         "UXTB16.NE",
+	arm_UXTB16_CS:         "UXTB16.CS",
+	arm_UXTB16_CC:         "UXTB16.CC",
+	arm_UXTB16_MI:         "UXTB16.MI",
+	arm_UXTB16_PL:         "UXTB16.PL",
+	arm_UXTB16_VS:         "UXTB16.VS",
+	arm_UXTB16_VC:         "UXTB16.VC",
+	arm_UXTB16_HI:         "UXTB16.HI",
+	arm_UXTB16_LS:         "UXTB16.LS",
+	arm_UXTB16_GE:         "UXTB16.GE",
+	arm_UXTB16_LT:         "UXTB16.LT",
+	arm_UXTB16_GT:         "UXTB16.GT",
+	arm_UXTB16_LE:         "UXTB16.LE",
+	arm_UXTB16:            "UXTB16",
+	arm_UXTB16_ZZ:         "UXTB16.ZZ",
+	arm_UXTH_EQ:           "UXTH.EQ",
+	arm_UXTH_NE:           "UXTH.NE",
+	arm_UXTH_CS:           "UXTH.CS",
+	arm_UXTH_CC:           "UXTH.CC",
+	arm_UXTH_MI:           "UXTH.MI",
+	arm_UXTH_PL:           "UXTH.PL",
+	arm_UXTH_VS:           "UXTH.VS",
+	arm_UXTH_VC:           "UXTH.VC",
+	arm_UXTH_HI:           "UXTH.HI",
+	arm_UXTH_LS:           "UXTH.LS",
+	arm_UXTH_GE:           "UXTH.GE",
+	arm_UXTH_LT:           "UXTH.LT",
+	arm_UXTH_GT:           "UXTH.GT",
+	arm_UXTH_LE:           "UXTH.LE",
+	arm_UXTH:              "UXTH",
+	arm_UXTH_ZZ:           "UXTH.ZZ",
+	arm_VABS_EQ_F32:       "VABS.EQ.F32",
+	arm_VABS_NE_F32:       "VABS.NE.F32",
+	arm_VABS_CS_F32:       "VABS.CS.F32",
+	arm_VABS_CC_F32:       "VABS.CC.F32",
+	arm_VABS_MI_F32:       "VABS.MI.F32",
+	arm_VABS_PL_F32:       "VABS.PL.F32",
+	arm_VABS_VS_F32:       "VABS.VS.F32",
+	arm_VABS_VC_F32:       "VABS.VC.F32",
+	arm_VABS_HI_F32:       "VABS.HI.F32",
+	arm_VABS_LS_F32:       "VABS.LS.F32",
+	arm_VABS_GE_F32:       "VABS.GE.F32",
+	arm_VABS_LT_F32:       "VABS.LT.F32",
+	arm_VABS_GT_F32:       "VABS.GT.F32",
+	arm_VABS_LE_F32:       "VABS.LE.F32",
+	arm_VABS_F32:          "VABS.F32",
+	arm_VABS_ZZ_F32:       "VABS.ZZ.F32",
+	arm_VABS_EQ_F64:       "VABS.EQ.F64",
+	arm_VABS_NE_F64:       "VABS.NE.F64",
+	arm_VABS_CS_F64:       "VABS.CS.F64",
+	arm_VABS_CC_F64:       "VABS.CC.F64",
+	arm_VABS_MI_F64:       "VABS.MI.F64",
+	arm_VABS_PL_F64:       "VABS.PL.F64",
+	arm_VABS_VS_F64:       "VABS.VS.F64",
+	arm_VABS_VC_F64:       "VABS.VC.F64",
+	arm_VABS_HI_F64:       "VABS.HI.F64",
+	arm_VABS_LS_F64:       "VABS.LS.F64",
+	arm_VABS_GE_F64:       "VABS.GE.F64",
+	arm_VABS_LT_F64:       "VABS.LT.F64",
+	arm_VABS_GT_F64:       "VABS.GT.F64",
+	arm_VABS_LE_F64:       "VABS.LE.F64",
+	arm_VABS_F64:          "VABS.F64",
+	arm_VABS_ZZ_F64:       "VABS.ZZ.F64",
+	arm_VADD_EQ_F32:       "VADD.EQ.F32",
+	arm_VADD_NE_F32:       "VADD.NE.F32",
+	arm_VADD_CS_F32:       "VADD.CS.F32",
+	arm_VADD_CC_F32:       "VADD.CC.F32",
+	arm_VADD_MI_F32:       "VADD.MI.F32",
+	arm_VADD_PL_F32:       "VADD.PL.F32",
+	arm_VADD_VS_F32:       "VADD.VS.F32",
+	arm_VADD_VC_F32:       "VADD.VC.F32",
+	arm_VADD_HI_F32:       "VADD.HI.F32",
+	arm_VADD_LS_F32:       "VADD.LS.F32",
+	arm_VADD_GE_F32:       "VADD.GE.F32",
+	arm_VADD_LT_F32:       "VADD.LT.F32",
+	arm_VADD_GT_F32:       "VADD.GT.F32",
+	arm_VADD_LE_F32:       "VADD.LE.F32",
+	arm_VADD_F32:          "VADD.F32",
+	arm_VADD_ZZ_F32:       "VADD.ZZ.F32",
+	arm_VADD_EQ_F64:       "VADD.EQ.F64",
+	arm_VADD_NE_F64:       "VADD.NE.F64",
+	arm_VADD_CS_F64:       "VADD.CS.F64",
+	arm_VADD_CC_F64:       "VADD.CC.F64",
+	arm_VADD_MI_F64:       "VADD.MI.F64",
+	arm_VADD_PL_F64:       "VADD.PL.F64",
+	arm_VADD_VS_F64:       "VADD.VS.F64",
+	arm_VADD_VC_F64:       "VADD.VC.F64",
+	arm_VADD_HI_F64:       "VADD.HI.F64",
+	arm_VADD_LS_F64:       "VADD.LS.F64",
+	arm_VADD_GE_F64:       "VADD.GE.F64",
+	arm_VADD_LT_F64:       "VADD.LT.F64",
+	arm_VADD_GT_F64:       "VADD.GT.F64",
+	arm_VADD_LE_F64:       "VADD.LE.F64",
+	arm_VADD_F64:          "VADD.F64",
+	arm_VADD_ZZ_F64:       "VADD.ZZ.F64",
+	arm_VCMP_EQ_F32:       "VCMP.EQ.F32",
+	arm_VCMP_NE_F32:       "VCMP.NE.F32",
+	arm_VCMP_CS_F32:       "VCMP.CS.F32",
+	arm_VCMP_CC_F32:       "VCMP.CC.F32",
+	arm_VCMP_MI_F32:       "VCMP.MI.F32",
+	arm_VCMP_PL_F32:       "VCMP.PL.F32",
+	arm_VCMP_VS_F32:       "VCMP.VS.F32",
+	arm_VCMP_VC_F32:       "VCMP.VC.F32",
+	arm_VCMP_HI_F32:       "VCMP.HI.F32",
+	arm_VCMP_LS_F32:       "VCMP.LS.F32",
+	arm_VCMP_GE_F32:       "VCMP.GE.F32",
+	arm_VCMP_LT_F32:       "VCMP.LT.F32",
+	arm_VCMP_GT_F32:       "VCMP.GT.F32",
+	arm_VCMP_LE_F32:       "VCMP.LE.F32",
+	arm_VCMP_F32:          "VCMP.F32",
+	arm_VCMP_ZZ_F32:       "VCMP.ZZ.F32",
+	arm_VCMP_EQ_F64:       "VCMP.EQ.F64",
+	arm_VCMP_NE_F64:       "VCMP.NE.F64",
+	arm_VCMP_CS_F64:       "VCMP.CS.F64",
+	arm_VCMP_CC_F64:       "VCMP.CC.F64",
+	arm_VCMP_MI_F64:       "VCMP.MI.F64",
+	arm_VCMP_PL_F64:       "VCMP.PL.F64",
+	arm_VCMP_VS_F64:       "VCMP.VS.F64",
+	arm_VCMP_VC_F64:       "VCMP.VC.F64",
+	arm_VCMP_HI_F64:       "VCMP.HI.F64",
+	arm_VCMP_LS_F64:       "VCMP.LS.F64",
+	arm_VCMP_GE_F64:       "VCMP.GE.F64",
+	arm_VCMP_LT_F64:       "VCMP.LT.F64",
+	arm_VCMP_GT_F64:       "VCMP.GT.F64",
+	arm_VCMP_LE_F64:       "VCMP.LE.F64",
+	arm_VCMP_F64:          "VCMP.F64",
+	arm_VCMP_ZZ_F64:       "VCMP.ZZ.F64",
+	arm_VCMP_E_EQ_F32:     "VCMP.E.EQ.F32",
+	arm_VCMP_E_NE_F32:     "VCMP.E.NE.F32",
+	arm_VCMP_E_CS_F32:     "VCMP.E.CS.F32",
+	arm_VCMP_E_CC_F32:     "VCMP.E.CC.F32",
+	arm_VCMP_E_MI_F32:     "VCMP.E.MI.F32",
+	arm_VCMP_E_PL_F32:     "VCMP.E.PL.F32",
+	arm_VCMP_E_VS_F32:     "VCMP.E.VS.F32",
+	arm_VCMP_E_VC_F32:     "VCMP.E.VC.F32",
+	arm_VCMP_E_HI_F32:     "VCMP.E.HI.F32",
+	arm_VCMP_E_LS_F32:     "VCMP.E.LS.F32",
+	arm_VCMP_E_GE_F32:     "VCMP.E.GE.F32",
+	arm_VCMP_E_LT_F32:     "VCMP.E.LT.F32",
+	arm_VCMP_E_GT_F32:     "VCMP.E.GT.F32",
+	arm_VCMP_E_LE_F32:     "VCMP.E.LE.F32",
+	arm_VCMP_E_F32:        "VCMP.E.F32",
+	arm_VCMP_E_ZZ_F32:     "VCMP.E.ZZ.F32",
+	arm_VCMP_E_EQ_F64:     "VCMP.E.EQ.F64",
+	arm_VCMP_E_NE_F64:     "VCMP.E.NE.F64",
+	arm_VCMP_E_CS_F64:     "VCMP.E.CS.F64",
+	arm_VCMP_E_CC_F64:     "VCMP.E.CC.F64",
+	arm_VCMP_E_MI_F64:     "VCMP.E.MI.F64",
+	arm_VCMP_E_PL_F64:     "VCMP.E.PL.F64",
+	arm_VCMP_E_VS_F64:     "VCMP.E.VS.F64",
+	arm_VCMP_E_VC_F64:     "VCMP.E.VC.F64",
+	arm_VCMP_E_HI_F64:     "VCMP.E.HI.F64",
+	arm_VCMP_E_LS_F64:     "VCMP.E.LS.F64",
+	arm_VCMP_E_GE_F64:     "VCMP.E.GE.F64",
+	arm_VCMP_E_LT_F64:     "VCMP.E.LT.F64",
+	arm_VCMP_E_GT_F64:     "VCMP.E.GT.F64",
+	arm_VCMP_E_LE_F64:     "VCMP.E.LE.F64",
+	arm_VCMP_E_F64:        "VCMP.E.F64",
+	arm_VCMP_E_ZZ_F64:     "VCMP.E.ZZ.F64",
+	arm_VCVT_EQ_F32_FXS16: "VCVT.EQ.F32.FXS16",
+	arm_VCVT_NE_F32_FXS16: "VCVT.NE.F32.FXS16",
+	arm_VCVT_CS_F32_FXS16: "VCVT.CS.F32.FXS16",
+	arm_VCVT_CC_F32_FXS16: "VCVT.CC.F32.FXS16",
+	arm_VCVT_MI_F32_FXS16: "VCVT.MI.F32.FXS16",
+	arm_VCVT_PL_F32_FXS16: "VCVT.PL.F32.FXS16",
+	arm_VCVT_VS_F32_FXS16: "VCVT.VS.F32.FXS16",
+	arm_VCVT_VC_F32_FXS16: "VCVT.VC.F32.FXS16",
+	arm_VCVT_HI_F32_FXS16: "VCVT.HI.F32.FXS16",
+	arm_VCVT_LS_F32_FXS16: "VCVT.LS.F32.FXS16",
+	arm_VCVT_GE_F32_FXS16: "VCVT.GE.F32.FXS16",
+	arm_VCVT_LT_F32_FXS16: "VCVT.LT.F32.FXS16",
+	arm_VCVT_GT_F32_FXS16: "VCVT.GT.F32.FXS16",
+	arm_VCVT_LE_F32_FXS16: "VCVT.LE.F32.FXS16",
+	arm_VCVT_F32_FXS16:    "VCVT.F32.FXS16",
+	arm_VCVT_ZZ_F32_FXS16: "VCVT.ZZ.F32.FXS16",
+	arm_VCVT_EQ_F32_FXS32: "VCVT.EQ.F32.FXS32",
+	arm_VCVT_NE_F32_FXS32: "VCVT.NE.F32.FXS32",
+	arm_VCVT_CS_F32_FXS32: "VCVT.CS.F32.FXS32",
+	arm_VCVT_CC_F32_FXS32: "VCVT.CC.F32.FXS32",
+	arm_VCVT_MI_F32_FXS32: "VCVT.MI.F32.FXS32",
+	arm_VCVT_PL_F32_FXS32: "VCVT.PL.F32.FXS32",
+	arm_VCVT_VS_F32_FXS32: "VCVT.VS.F32.FXS32",
+	arm_VCVT_VC_F32_FXS32: "VCVT.VC.F32.FXS32",
+	arm_VCVT_HI_F32_FXS32: "VCVT.HI.F32.FXS32",
+	arm_VCVT_LS_F32_FXS32: "VCVT.LS.F32.FXS32",
+	arm_VCVT_GE_F32_FXS32: "VCVT.GE.F32.FXS32",
+	arm_VCVT_LT_F32_FXS32: "VCVT.LT.F32.FXS32",
+	arm_VCVT_GT_F32_FXS32: "VCVT.GT.F32.FXS32",
+	arm_VCVT_LE_F32_FXS32: "VCVT.LE.F32.FXS32",
+	arm_VCVT_F32_FXS32:    "VCVT.F32.FXS32",
+	arm_VCVT_ZZ_F32_FXS32: "VCVT.ZZ.F32.FXS32",
+	arm_VCVT_EQ_F32_FXU16: "VCVT.EQ.F32.FXU16",
+	arm_VCVT_NE_F32_FXU16: "VCVT.NE.F32.FXU16",
+	arm_VCVT_CS_F32_FXU16: "VCVT.CS.F32.FXU16",
+	arm_VCVT_CC_F32_FXU16: "VCVT.CC.F32.FXU16",
+	arm_VCVT_MI_F32_FXU16: "VCVT.MI.F32.FXU16",
+	arm_VCVT_PL_F32_FXU16: "VCVT.PL.F32.FXU16",
+	arm_VCVT_VS_F32_FXU16: "VCVT.VS.F32.FXU16",
+	arm_VCVT_VC_F32_FXU16: "VCVT.VC.F32.FXU16",
+	arm_VCVT_HI_F32_FXU16: "VCVT.HI.F32.FXU16",
+	arm_VCVT_LS_F32_FXU16: "VCVT.LS.F32.FXU16",
+	arm_VCVT_GE_F32_FXU16: "VCVT.GE.F32.FXU16",
+	arm_VCVT_LT_F32_FXU16: "VCVT.LT.F32.FXU16",
+	arm_VCVT_GT_F32_FXU16: "VCVT.GT.F32.FXU16",
+	arm_VCVT_LE_F32_FXU16: "VCVT.LE.F32.FXU16",
+	arm_VCVT_F32_FXU16:    "VCVT.F32.FXU16",
+	arm_VCVT_ZZ_F32_FXU16: "VCVT.ZZ.F32.FXU16",
+	arm_VCVT_EQ_F32_FXU32: "VCVT.EQ.F32.FXU32",
+	arm_VCVT_NE_F32_FXU32: "VCVT.NE.F32.FXU32",
+	arm_VCVT_CS_F32_FXU32: "VCVT.CS.F32.FXU32",
+	arm_VCVT_CC_F32_FXU32: "VCVT.CC.F32.FXU32",
+	arm_VCVT_MI_F32_FXU32: "VCVT.MI.F32.FXU32",
+	arm_VCVT_PL_F32_FXU32: "VCVT.PL.F32.FXU32",
+	arm_VCVT_VS_F32_FXU32: "VCVT.VS.F32.FXU32",
+	arm_VCVT_VC_F32_FXU32: "VCVT.VC.F32.FXU32",
+	arm_VCVT_HI_F32_FXU32: "VCVT.HI.F32.FXU32",
+	arm_VCVT_LS_F32_FXU32: "VCVT.LS.F32.FXU32",
+	arm_VCVT_GE_F32_FXU32: "VCVT.GE.F32.FXU32",
+	arm_VCVT_LT_F32_FXU32: "VCVT.LT.F32.FXU32",
+	arm_VCVT_GT_F32_FXU32: "VCVT.GT.F32.FXU32",
+	arm_VCVT_LE_F32_FXU32: "VCVT.LE.F32.FXU32",
+	arm_VCVT_F32_FXU32:    "VCVT.F32.FXU32",
+	arm_VCVT_ZZ_F32_FXU32: "VCVT.ZZ.F32.FXU32",
+	arm_VCVT_EQ_F64_FXS16: "VCVT.EQ.F64.FXS16",
+	arm_VCVT_NE_F64_FXS16: "VCVT.NE.F64.FXS16",
+	arm_VCVT_CS_F64_FXS16: "VCVT.CS.F64.FXS16",
+	arm_VCVT_CC_F64_FXS16: "VCVT.CC.F64.FXS16",
+	arm_VCVT_MI_F64_FXS16: "VCVT.MI.F64.FXS16",
+	arm_VCVT_PL_F64_FXS16: "VCVT.PL.F64.FXS16",
+	arm_VCVT_VS_F64_FXS16: "VCVT.VS.F64.FXS16",
+	arm_VCVT_VC_F64_FXS16: "VCVT.VC.F64.FXS16",
+	arm_VCVT_HI_F64_FXS16: "VCVT.HI.F64.FXS16",
+	arm_VCVT_LS_F64_FXS16: "VCVT.LS.F64.FXS16",
+	arm_VCVT_GE_F64_FXS16: "VCVT.GE.F64.FXS16",
+	arm_VCVT_LT_F64_FXS16: "VCVT.LT.F64.FXS16",
+	arm_VCVT_GT_F64_FXS16: "VCVT.GT.F64.FXS16",
+	arm_VCVT_LE_F64_FXS16: "VCVT.LE.F64.FXS16",
+	arm_VCVT_F64_FXS16:    "VCVT.F64.FXS16",
+	arm_VCVT_ZZ_F64_FXS16: "VCVT.ZZ.F64.FXS16",
+	arm_VCVT_EQ_F64_FXS32: "VCVT.EQ.F64.FXS32",
+	arm_VCVT_NE_F64_FXS32: "VCVT.NE.F64.FXS32",
+	arm_VCVT_CS_F64_FXS32: "VCVT.CS.F64.FXS32",
+	arm_VCVT_CC_F64_FXS32: "VCVT.CC.F64.FXS32",
+	arm_VCVT_MI_F64_FXS32: "VCVT.MI.F64.FXS32",
+	arm_VCVT_PL_F64_FXS32: "VCVT.PL.F64.FXS32",
+	arm_VCVT_VS_F64_FXS32: "VCVT.VS.F64.FXS32",
+	arm_VCVT_VC_F64_FXS32: "VCVT.VC.F64.FXS32",
+	arm_VCVT_HI_F64_FXS32: "VCVT.HI.F64.FXS32",
+	arm_VCVT_LS_F64_FXS32: "VCVT.LS.F64.FXS32",
+	arm_VCVT_GE_F64_FXS32: "VCVT.GE.F64.FXS32",
+	arm_VCVT_LT_F64_FXS32: "VCVT.LT.F64.FXS32",
+	arm_VCVT_GT_F64_FXS32: "VCVT.GT.F64.FXS32",
+	arm_VCVT_LE_F64_FXS32: "VCVT.LE.F64.FXS32",
+	arm_VCVT_F64_FXS32:    "VCVT.F64.FXS32",
+	arm_VCVT_ZZ_F64_FXS32: "VCVT.ZZ.F64.FXS32",
+	arm_VCVT_EQ_F64_FXU16: "VCVT.EQ.F64.FXU16",
+	arm_VCVT_NE_F64_FXU16: "VCVT.NE.F64.FXU16",
+	arm_VCVT_CS_F64_FXU16: "VCVT.CS.F64.FXU16",
+	arm_VCVT_CC_F64_FXU16: "VCVT.CC.F64.FXU16",
+	arm_VCVT_MI_F64_FXU16: "VCVT.MI.F64.FXU16",
+	arm_VCVT_PL_F64_FXU16: "VCVT.PL.F64.FXU16",
+	arm_VCVT_VS_F64_FXU16: "VCVT.VS.F64.FXU16",
+	arm_VCVT_VC_F64_FXU16: "VCVT.VC.F64.FXU16",
+	arm_VCVT_HI_F64_FXU16: "VCVT.HI.F64.FXU16",
+	arm_VCVT_LS_F64_FXU16: "VCVT.LS.F64.FXU16",
+	arm_VCVT_GE_F64_FXU16: "VCVT.GE.F64.FXU16",
+	arm_VCVT_LT_F64_FXU16: "VCVT.LT.F64.FXU16",
+	arm_VCVT_GT_F64_FXU16: "VCVT.GT.F64.FXU16",
+	arm_VCVT_LE_F64_FXU16: "VCVT.LE.F64.FXU16",
+	arm_VCVT_F64_FXU16:    "VCVT.F64.FXU16",
+	arm_VCVT_ZZ_F64_FXU16: "VCVT.ZZ.F64.FXU16",
+	arm_VCVT_EQ_F64_FXU32: "VCVT.EQ.F64.FXU32",
+	arm_VCVT_NE_F64_FXU32: "VCVT.NE.F64.FXU32",
+	arm_VCVT_CS_F64_FXU32: "VCVT.CS.F64.FXU32",
+	arm_VCVT_CC_F64_FXU32: "VCVT.CC.F64.FXU32",
+	arm_VCVT_MI_F64_FXU32: "VCVT.MI.F64.FXU32",
+	arm_VCVT_PL_F64_FXU32: "VCVT.PL.F64.FXU32",
+	arm_VCVT_VS_F64_FXU32: "VCVT.VS.F64.FXU32",
+	arm_VCVT_VC_F64_FXU32: "VCVT.VC.F64.FXU32",
+	arm_VCVT_HI_F64_FXU32: "VCVT.HI.F64.FXU32",
+	arm_VCVT_LS_F64_FXU32: "VCVT.LS.F64.FXU32",
+	arm_VCVT_GE_F64_FXU32: "VCVT.GE.F64.FXU32",
+	arm_VCVT_LT_F64_FXU32: "VCVT.LT.F64.FXU32",
+	arm_VCVT_GT_F64_FXU32: "VCVT.GT.F64.FXU32",
+	arm_VCVT_LE_F64_FXU32: "VCVT.LE.F64.FXU32",
+	arm_VCVT_F64_FXU32:    "VCVT.F64.FXU32",
+	arm_VCVT_ZZ_F64_FXU32: "VCVT.ZZ.F64.FXU32",
+	arm_VCVT_EQ_F32_U32:   "VCVT.EQ.F32.U32",
+	arm_VCVT_NE_F32_U32:   "VCVT.NE.F32.U32",
+	arm_VCVT_CS_F32_U32:   "VCVT.CS.F32.U32",
+	arm_VCVT_CC_F32_U32:   "VCVT.CC.F32.U32",
+	arm_VCVT_MI_F32_U32:   "VCVT.MI.F32.U32",
+	arm_VCVT_PL_F32_U32:   "VCVT.PL.F32.U32",
+	arm_VCVT_VS_F32_U32:   "VCVT.VS.F32.U32",
+	arm_VCVT_VC_F32_U32:   "VCVT.VC.F32.U32",
+	arm_VCVT_HI_F32_U32:   "VCVT.HI.F32.U32",
+	arm_VCVT_LS_F32_U32:   "VCVT.LS.F32.U32",
+	arm_VCVT_GE_F32_U32:   "VCVT.GE.F32.U32",
+	arm_VCVT_LT_F32_U32:   "VCVT.LT.F32.U32",
+	arm_VCVT_GT_F32_U32:   "VCVT.GT.F32.U32",
+	arm_VCVT_LE_F32_U32:   "VCVT.LE.F32.U32",
+	arm_VCVT_F32_U32:      "VCVT.F32.U32",
+	arm_VCVT_ZZ_F32_U32:   "VCVT.ZZ.F32.U32",
+	arm_VCVT_EQ_F32_S32:   "VCVT.EQ.F32.S32",
+	arm_VCVT_NE_F32_S32:   "VCVT.NE.F32.S32",
+	arm_VCVT_CS_F32_S32:   "VCVT.CS.F32.S32",
+	arm_VCVT_CC_F32_S32:   "VCVT.CC.F32.S32",
+	arm_VCVT_MI_F32_S32:   "VCVT.MI.F32.S32",
+	arm_VCVT_PL_F32_S32:   "VCVT.PL.F32.S32",
+	arm_VCVT_VS_F32_S32:   "VCVT.VS.F32.S32",
+	arm_VCVT_VC_F32_S32:   "VCVT.VC.F32.S32",
+	arm_VCVT_HI_F32_S32:   "VCVT.HI.F32.S32",
+	arm_VCVT_LS_F32_S32:   "VCVT.LS.F32.S32",
+	arm_VCVT_GE_F32_S32:   "VCVT.GE.F32.S32",
+	arm_VCVT_LT_F32_S32:   "VCVT.LT.F32.S32",
+	arm_VCVT_GT_F32_S32:   "VCVT.GT.F32.S32",
+	arm_VCVT_LE_F32_S32:   "VCVT.LE.F32.S32",
+	arm_VCVT_F32_S32:      "VCVT.F32.S32",
+	arm_VCVT_ZZ_F32_S32:   "VCVT.ZZ.F32.S32",
+	arm_VCVT_EQ_F64_U32:   "VCVT.EQ.F64.U32",
+	arm_VCVT_NE_F64_U32:   "VCVT.NE.F64.U32",
+	arm_VCVT_CS_F64_U32:   "VCVT.CS.F64.U32",
+	arm_VCVT_CC_F64_U32:   "VCVT.CC.F64.U32",
+	arm_VCVT_MI_F64_U32:   "VCVT.MI.F64.U32",
+	arm_VCVT_PL_F64_U32:   "VCVT.PL.F64.U32",
+	arm_VCVT_VS_F64_U32:   "VCVT.VS.F64.U32",
+	arm_VCVT_VC_F64_U32:   "VCVT.VC.F64.U32",
+	arm_VCVT_HI_F64_U32:   "VCVT.HI.F64.U32",
+	arm_VCVT_LS_F64_U32:   "VCVT.LS.F64.U32",
+	arm_VCVT_GE_F64_U32:   "VCVT.GE.F64.U32",
+	arm_VCVT_LT_F64_U32:   "VCVT.LT.F64.U32",
+	arm_VCVT_GT_F64_U32:   "VCVT.GT.F64.U32",
+	arm_VCVT_LE_F64_U32:   "VCVT.LE.F64.U32",
+	arm_VCVT_F64_U32:      "VCVT.F64.U32",
+	arm_VCVT_ZZ_F64_U32:   "VCVT.ZZ.F64.U32",
+	arm_VCVT_EQ_F64_S32:   "VCVT.EQ.F64.S32",
+	arm_VCVT_NE_F64_S32:   "VCVT.NE.F64.S32",
+	arm_VCVT_CS_F64_S32:   "VCVT.CS.F64.S32",
+	arm_VCVT_CC_F64_S32:   "VCVT.CC.F64.S32",
+	arm_VCVT_MI_F64_S32:   "VCVT.MI.F64.S32",
+	arm_VCVT_PL_F64_S32:   "VCVT.PL.F64.S32",
+	arm_VCVT_VS_F64_S32:   "VCVT.VS.F64.S32",
+	arm_VCVT_VC_F64_S32:   "VCVT.VC.F64.S32",
+	arm_VCVT_HI_F64_S32:   "VCVT.HI.F64.S32",
+	arm_VCVT_LS_F64_S32:   "VCVT.LS.F64.S32",
+	arm_VCVT_GE_F64_S32:   "VCVT.GE.F64.S32",
+	arm_VCVT_LT_F64_S32:   "VCVT.LT.F64.S32",
+	arm_VCVT_GT_F64_S32:   "VCVT.GT.F64.S32",
+	arm_VCVT_LE_F64_S32:   "VCVT.LE.F64.S32",
+	arm_VCVT_F64_S32:      "VCVT.F64.S32",
+	arm_VCVT_ZZ_F64_S32:   "VCVT.ZZ.F64.S32",
+	arm_VCVT_EQ_F64_F32:   "VCVT.EQ.F64.F32",
+	arm_VCVT_NE_F64_F32:   "VCVT.NE.F64.F32",
+	arm_VCVT_CS_F64_F32:   "VCVT.CS.F64.F32",
+	arm_VCVT_CC_F64_F32:   "VCVT.CC.F64.F32",
+	arm_VCVT_MI_F64_F32:   "VCVT.MI.F64.F32",
+	arm_VCVT_PL_F64_F32:   "VCVT.PL.F64.F32",
+	arm_VCVT_VS_F64_F32:   "VCVT.VS.F64.F32",
+	arm_VCVT_VC_F64_F32:   "VCVT.VC.F64.F32",
+	arm_VCVT_HI_F64_F32:   "VCVT.HI.F64.F32",
+	arm_VCVT_LS_F64_F32:   "VCVT.LS.F64.F32",
+	arm_VCVT_GE_F64_F32:   "VCVT.GE.F64.F32",
+	arm_VCVT_LT_F64_F32:   "VCVT.LT.F64.F32",
+	arm_VCVT_GT_F64_F32:   "VCVT.GT.F64.F32",
+	arm_VCVT_LE_F64_F32:   "VCVT.LE.F64.F32",
+	arm_VCVT_F64_F32:      "VCVT.F64.F32",
+	arm_VCVT_ZZ_F64_F32:   "VCVT.ZZ.F64.F32",
+	arm_VCVT_EQ_F32_F64:   "VCVT.EQ.F32.F64",
+	arm_VCVT_NE_F32_F64:   "VCVT.NE.F32.F64",
+	arm_VCVT_CS_F32_F64:   "VCVT.CS.F32.F64",
+	arm_VCVT_CC_F32_F64:   "VCVT.CC.F32.F64",
+	arm_VCVT_MI_F32_F64:   "VCVT.MI.F32.F64",
+	arm_VCVT_PL_F32_F64:   "VCVT.PL.F32.F64",
+	arm_VCVT_VS_F32_F64:   "VCVT.VS.F32.F64",
+	arm_VCVT_VC_F32_F64:   "VCVT.VC.F32.F64",
+	arm_VCVT_HI_F32_F64:   "VCVT.HI.F32.F64",
+	arm_VCVT_LS_F32_F64:   "VCVT.LS.F32.F64",
+	arm_VCVT_GE_F32_F64:   "VCVT.GE.F32.F64",
+	arm_VCVT_LT_F32_F64:   "VCVT.LT.F32.F64",
+	arm_VCVT_GT_F32_F64:   "VCVT.GT.F32.F64",
+	arm_VCVT_LE_F32_F64:   "VCVT.LE.F32.F64",
+	arm_VCVT_F32_F64:      "VCVT.F32.F64",
+	arm_VCVT_ZZ_F32_F64:   "VCVT.ZZ.F32.F64",
+	arm_VCVT_EQ_FXS16_F32: "VCVT.EQ.FXS16.F32",
+	arm_VCVT_NE_FXS16_F32: "VCVT.NE.FXS16.F32",
+	arm_VCVT_CS_FXS16_F32: "VCVT.CS.FXS16.F32",
+	arm_VCVT_CC_FXS16_F32: "VCVT.CC.FXS16.F32",
+	arm_VCVT_MI_FXS16_F32: "VCVT.MI.FXS16.F32",
+	arm_VCVT_PL_FXS16_F32: "VCVT.PL.FXS16.F32",
+	arm_VCVT_VS_FXS16_F32: "VCVT.VS.FXS16.F32",
+	arm_VCVT_VC_FXS16_F32: "VCVT.VC.FXS16.F32",
+	arm_VCVT_HI_FXS16_F32: "VCVT.HI.FXS16.F32",
+	arm_VCVT_LS_FXS16_F32: "VCVT.LS.FXS16.F32",
+	arm_VCVT_GE_FXS16_F32: "VCVT.GE.FXS16.F32",
+	arm_VCVT_LT_FXS16_F32: "VCVT.LT.FXS16.F32",
+	arm_VCVT_GT_FXS16_F32: "VCVT.GT.FXS16.F32",
+	arm_VCVT_LE_FXS16_F32: "VCVT.LE.FXS16.F32",
+	arm_VCVT_FXS16_F32:    "VCVT.FXS16.F32",
+	arm_VCVT_ZZ_FXS16_F32: "VCVT.ZZ.FXS16.F32",
+	arm_VCVT_EQ_FXS16_F64: "VCVT.EQ.FXS16.F64",
+	arm_VCVT_NE_FXS16_F64: "VCVT.NE.FXS16.F64",
+	arm_VCVT_CS_FXS16_F64: "VCVT.CS.FXS16.F64",
+	arm_VCVT_CC_FXS16_F64: "VCVT.CC.FXS16.F64",
+	arm_VCVT_MI_FXS16_F64: "VCVT.MI.FXS16.F64",
+	arm_VCVT_PL_FXS16_F64: "VCVT.PL.FXS16.F64",
+	arm_VCVT_VS_FXS16_F64: "VCVT.VS.FXS16.F64",
+	arm_VCVT_VC_FXS16_F64: "VCVT.VC.FXS16.F64",
+	arm_VCVT_HI_FXS16_F64: "VCVT.HI.FXS16.F64",
+	arm_VCVT_LS_FXS16_F64: "VCVT.LS.FXS16.F64",
+	arm_VCVT_GE_FXS16_F64: "VCVT.GE.FXS16.F64",
+	arm_VCVT_LT_FXS16_F64: "VCVT.LT.FXS16.F64",
+	arm_VCVT_GT_FXS16_F64: "VCVT.GT.FXS16.F64",
+	arm_VCVT_LE_FXS16_F64: "VCVT.LE.FXS16.F64",
+	arm_VCVT_FXS16_F64:    "VCVT.FXS16.F64",
+	arm_VCVT_ZZ_FXS16_F64: "VCVT.ZZ.FXS16.F64",
+	arm_VCVT_EQ_FXS32_F32: "VCVT.EQ.FXS32.F32",
+	arm_VCVT_NE_FXS32_F32: "VCVT.NE.FXS32.F32",
+	arm_VCVT_CS_FXS32_F32: "VCVT.CS.FXS32.F32",
+	arm_VCVT_CC_FXS32_F32: "VCVT.CC.FXS32.F32",
+	arm_VCVT_MI_FXS32_F32: "VCVT.MI.FXS32.F32",
+	arm_VCVT_PL_FXS32_F32: "VCVT.PL.FXS32.F32",
+	arm_VCVT_VS_FXS32_F32: "VCVT.VS.FXS32.F32",
+	arm_VCVT_VC_FXS32_F32: "VCVT.VC.FXS32.F32",
+	arm_VCVT_HI_FXS32_F32: "VCVT.HI.FXS32.F32",
+	arm_VCVT_LS_FXS32_F32: "VCVT.LS.FXS32.F32",
+	arm_VCVT_GE_FXS32_F32: "VCVT.GE.FXS32.F32",
+	arm_VCVT_LT_FXS32_F32: "VCVT.LT.FXS32.F32",
+	arm_VCVT_GT_FXS32_F32: "VCVT.GT.FXS32.F32",
+	arm_VCVT_LE_FXS32_F32: "VCVT.LE.FXS32.F32",
+	arm_VCVT_FXS32_F32:    "VCVT.FXS32.F32",
+	arm_VCVT_ZZ_FXS32_F32: "VCVT.ZZ.FXS32.F32",
+	arm_VCVT_EQ_FXS32_F64: "VCVT.EQ.FXS32.F64",
+	arm_VCVT_NE_FXS32_F64: "VCVT.NE.FXS32.F64",
+	arm_VCVT_CS_FXS32_F64: "VCVT.CS.FXS32.F64",
+	arm_VCVT_CC_FXS32_F64: "VCVT.CC.FXS32.F64",
+	arm_VCVT_MI_FXS32_F64: "VCVT.MI.FXS32.F64",
+	arm_VCVT_PL_FXS32_F64: "VCVT.PL.FXS32.F64",
+	arm_VCVT_VS_FXS32_F64: "VCVT.VS.FXS32.F64",
+	arm_VCVT_VC_FXS32_F64: "VCVT.VC.FXS32.F64",
+	arm_VCVT_HI_FXS32_F64: "VCVT.HI.FXS32.F64",
+	arm_VCVT_LS_FXS32_F64: "VCVT.LS.FXS32.F64",
+	arm_VCVT_GE_FXS32_F64: "VCVT.GE.FXS32.F64",
+	arm_VCVT_LT_FXS32_F64: "VCVT.LT.FXS32.F64",
+	arm_VCVT_GT_FXS32_F64: "VCVT.GT.FXS32.F64",
+	arm_VCVT_LE_FXS32_F64: "VCVT.LE.FXS32.F64",
+	arm_VCVT_FXS32_F64:    "VCVT.FXS32.F64",
+	arm_VCVT_ZZ_FXS32_F64: "VCVT.ZZ.FXS32.F64",
+	arm_VCVT_EQ_FXU16_F32: "VCVT.EQ.FXU16.F32",
+	arm_VCVT_NE_FXU16_F32: "VCVT.NE.FXU16.F32",
+	arm_VCVT_CS_FXU16_F32: "VCVT.CS.FXU16.F32",
+	arm_VCVT_CC_FXU16_F32: "VCVT.CC.FXU16.F32",
+	arm_VCVT_MI_FXU16_F32: "VCVT.MI.FXU16.F32",
+	arm_VCVT_PL_FXU16_F32: "VCVT.PL.FXU16.F32",
+	arm_VCVT_VS_FXU16_F32: "VCVT.VS.FXU16.F32",
+	arm_VCVT_VC_FXU16_F32: "VCVT.VC.FXU16.F32",
+	arm_VCVT_HI_FXU16_F32: "VCVT.HI.FXU16.F32",
+	arm_VCVT_LS_FXU16_F32: "VCVT.LS.FXU16.F32",
+	arm_VCVT_GE_FXU16_F32: "VCVT.GE.FXU16.F32",
+	arm_VCVT_LT_FXU16_F32: "VCVT.LT.FXU16.F32",
+	arm_VCVT_GT_FXU16_F32: "VCVT.GT.FXU16.F32",
+	arm_VCVT_LE_FXU16_F32: "VCVT.LE.FXU16.F32",
+	arm_VCVT_FXU16_F32:    "VCVT.FXU16.F32",
+	arm_VCVT_ZZ_FXU16_F32: "VCVT.ZZ.FXU16.F32",
+	arm_VCVT_EQ_FXU16_F64: "VCVT.EQ.FXU16.F64",
+	arm_VCVT_NE_FXU16_F64: "VCVT.NE.FXU16.F64",
+	arm_VCVT_CS_FXU16_F64: "VCVT.CS.FXU16.F64",
+	arm_VCVT_CC_FXU16_F64: "VCVT.CC.FXU16.F64",
+	arm_VCVT_MI_FXU16_F64: "VCVT.MI.FXU16.F64",
+	arm_VCVT_PL_FXU16_F64: "VCVT.PL.FXU16.F64",
+	arm_VCVT_VS_FXU16_F64: "VCVT.VS.FXU16.F64",
+	arm_VCVT_VC_FXU16_F64: "VCVT.VC.FXU16.F64",
+	arm_VCVT_HI_FXU16_F64: "VCVT.HI.FXU16.F64",
+	arm_VCVT_LS_FXU16_F64: "VCVT.LS.FXU16.F64",
+	arm_VCVT_GE_FXU16_F64: "VCVT.GE.FXU16.F64",
+	arm_VCVT_LT_FXU16_F64: "VCVT.LT.FXU16.F64",
+	arm_VCVT_GT_FXU16_F64: "VCVT.GT.FXU16.F64",
+	arm_VCVT_LE_FXU16_F64: "VCVT.LE.FXU16.F64",
+	arm_VCVT_FXU16_F64:    "VCVT.FXU16.F64",
+	arm_VCVT_ZZ_FXU16_F64: "VCVT.ZZ.FXU16.F64",
+	arm_VCVT_EQ_FXU32_F32: "VCVT.EQ.FXU32.F32",
+	arm_VCVT_NE_FXU32_F32: "VCVT.NE.FXU32.F32",
+	arm_VCVT_CS_FXU32_F32: "VCVT.CS.FXU32.F32",
+	arm_VCVT_CC_FXU32_F32: "VCVT.CC.FXU32.F32",
+	arm_VCVT_MI_FXU32_F32: "VCVT.MI.FXU32.F32",
+	arm_VCVT_PL_FXU32_F32: "VCVT.PL.FXU32.F32",
+	arm_VCVT_VS_FXU32_F32: "VCVT.VS.FXU32.F32",
+	arm_VCVT_VC_FXU32_F32: "VCVT.VC.FXU32.F32",
+	arm_VCVT_HI_FXU32_F32: "VCVT.HI.FXU32.F32",
+	arm_VCVT_LS_FXU32_F32: "VCVT.LS.FXU32.F32",
+	arm_VCVT_GE_FXU32_F32: "VCVT.GE.FXU32.F32",
+	arm_VCVT_LT_FXU32_F32: "VCVT.LT.FXU32.F32",
+	arm_VCVT_GT_FXU32_F32: "VCVT.GT.FXU32.F32",
+	arm_VCVT_LE_FXU32_F32: "VCVT.LE.FXU32.F32",
+	arm_VCVT_FXU32_F32:    "VCVT.FXU32.F32",
+	arm_VCVT_ZZ_FXU32_F32: "VCVT.ZZ.FXU32.F32",
+	arm_VCVT_EQ_FXU32_F64: "VCVT.EQ.FXU32.F64",
+	arm_VCVT_NE_FXU32_F64: "VCVT.NE.FXU32.F64",
+	arm_VCVT_CS_FXU32_F64: "VCVT.CS.FXU32.F64",
+	arm_VCVT_CC_FXU32_F64: "VCVT.CC.FXU32.F64",
+	arm_VCVT_MI_FXU32_F64: "VCVT.MI.FXU32.F64",
+	arm_VCVT_PL_FXU32_F64: "VCVT.PL.FXU32.F64",
+	arm_VCVT_VS_FXU32_F64: "VCVT.VS.FXU32.F64",
+	arm_VCVT_VC_FXU32_F64: "VCVT.VC.FXU32.F64",
+	arm_VCVT_HI_FXU32_F64: "VCVT.HI.FXU32.F64",
+	arm_VCVT_LS_FXU32_F64: "VCVT.LS.FXU32.F64",
+	arm_VCVT_GE_FXU32_F64: "VCVT.GE.FXU32.F64",
+	arm_VCVT_LT_FXU32_F64: "VCVT.LT.FXU32.F64",
+	arm_VCVT_GT_FXU32_F64: "VCVT.GT.FXU32.F64",
+	arm_VCVT_LE_FXU32_F64: "VCVT.LE.FXU32.F64",
+	arm_VCVT_FXU32_F64:    "VCVT.FXU32.F64",
+	arm_VCVT_ZZ_FXU32_F64: "VCVT.ZZ.FXU32.F64",
+	arm_VCVTB_EQ_F32_F16:  "VCVTB.EQ.F32.F16",
+	arm_VCVTB_NE_F32_F16:  "VCVTB.NE.F32.F16",
+	arm_VCVTB_CS_F32_F16:  "VCVTB.CS.F32.F16",
+	arm_VCVTB_CC_F32_F16:  "VCVTB.CC.F32.F16",
+	arm_VCVTB_MI_F32_F16:  "VCVTB.MI.F32.F16",
+	arm_VCVTB_PL_F32_F16:  "VCVTB.PL.F32.F16",
+	arm_VCVTB_VS_F32_F16:  "VCVTB.VS.F32.F16",
+	arm_VCVTB_VC_F32_F16:  "VCVTB.VC.F32.F16",
+	arm_VCVTB_HI_F32_F16:  "VCVTB.HI.F32.F16",
+	arm_VCVTB_LS_F32_F16:  "VCVTB.LS.F32.F16",
+	arm_VCVTB_GE_F32_F16:  "VCVTB.GE.F32.F16",
+	arm_VCVTB_LT_F32_F16:  "VCVTB.LT.F32.F16",
+	arm_VCVTB_GT_F32_F16:  "VCVTB.GT.F32.F16",
+	arm_VCVTB_LE_F32_F16:  "VCVTB.LE.F32.F16",
+	arm_VCVTB_F32_F16:     "VCVTB.F32.F16",
+	arm_VCVTB_ZZ_F32_F16:  "VCVTB.ZZ.F32.F16",
+	arm_VCVTB_EQ_F16_F32:  "VCVTB.EQ.F16.F32",
+	arm_VCVTB_NE_F16_F32:  "VCVTB.NE.F16.F32",
+	arm_VCVTB_CS_F16_F32:  "VCVTB.CS.F16.F32",
+	arm_VCVTB_CC_F16_F32:  "VCVTB.CC.F16.F32",
+	arm_VCVTB_MI_F16_F32:  "VCVTB.MI.F16.F32",
+	arm_VCVTB_PL_F16_F32:  "VCVTB.PL.F16.F32",
+	arm_VCVTB_VS_F16_F32:  "VCVTB.VS.F16.F32",
+	arm_VCVTB_VC_F16_F32:  "VCVTB.VC.F16.F32",
+	arm_VCVTB_HI_F16_F32:  "VCVTB.HI.F16.F32",
+	arm_VCVTB_LS_F16_F32:  "VCVTB.LS.F16.F32",
+	arm_VCVTB_GE_F16_F32:  "VCVTB.GE.F16.F32",
+	arm_VCVTB_LT_F16_F32:  "VCVTB.LT.F16.F32",
+	arm_VCVTB_GT_F16_F32:  "VCVTB.GT.F16.F32",
+	arm_VCVTB_LE_F16_F32:  "VCVTB.LE.F16.F32",
+	arm_VCVTB_F16_F32:     "VCVTB.F16.F32",
+	arm_VCVTB_ZZ_F16_F32:  "VCVTB.ZZ.F16.F32",
+	arm_VCVTT_EQ_F32_F16:  "VCVTT.EQ.F32.F16",
+	arm_VCVTT_NE_F32_F16:  "VCVTT.NE.F32.F16",
+	arm_VCVTT_CS_F32_F16:  "VCVTT.CS.F32.F16",
+	arm_VCVTT_CC_F32_F16:  "VCVTT.CC.F32.F16",
+	arm_VCVTT_MI_F32_F16:  "VCVTT.MI.F32.F16",
+	arm_VCVTT_PL_F32_F16:  "VCVTT.PL.F32.F16",
+	arm_VCVTT_VS_F32_F16:  "VCVTT.VS.F32.F16",
+	arm_VCVTT_VC_F32_F16:  "VCVTT.VC.F32.F16",
+	arm_VCVTT_HI_F32_F16:  "VCVTT.HI.F32.F16",
+	arm_VCVTT_LS_F32_F16:  "VCVTT.LS.F32.F16",
+	arm_VCVTT_GE_F32_F16:  "VCVTT.GE.F32.F16",
+	arm_VCVTT_LT_F32_F16:  "VCVTT.LT.F32.F16",
+	arm_VCVTT_GT_F32_F16:  "VCVTT.GT.F32.F16",
+	arm_VCVTT_LE_F32_F16:  "VCVTT.LE.F32.F16",
+	arm_VCVTT_F32_F16:     "VCVTT.F32.F16",
+	arm_VCVTT_ZZ_F32_F16:  "VCVTT.ZZ.F32.F16",
+	arm_VCVTT_EQ_F16_F32:  "VCVTT.EQ.F16.F32",
+	arm_VCVTT_NE_F16_F32:  "VCVTT.NE.F16.F32",
+	arm_VCVTT_CS_F16_F32:  "VCVTT.CS.F16.F32",
+	arm_VCVTT_CC_F16_F32:  "VCVTT.CC.F16.F32",
+	arm_VCVTT_MI_F16_F32:  "VCVTT.MI.F16.F32",
+	arm_VCVTT_PL_F16_F32:  "VCVTT.PL.F16.F32",
+	arm_VCVTT_VS_F16_F32:  "VCVTT.VS.F16.F32",
+	arm_VCVTT_VC_F16_F32:  "VCVTT.VC.F16.F32",
+	arm_VCVTT_HI_F16_F32:  "VCVTT.HI.F16.F32",
+	arm_VCVTT_LS_F16_F32:  "VCVTT.LS.F16.F32",
+	arm_VCVTT_GE_F16_F32:  "VCVTT.GE.F16.F32",
+	arm_VCVTT_LT_F16_F32:  "VCVTT.LT.F16.F32",
+	arm_VCVTT_GT_F16_F32:  "VCVTT.GT.F16.F32",
+	arm_VCVTT_LE_F16_F32:  "VCVTT.LE.F16.F32",
+	arm_VCVTT_F16_F32:     "VCVTT.F16.F32",
+	arm_VCVTT_ZZ_F16_F32:  "VCVTT.ZZ.F16.F32",
+	arm_VCVTR_EQ_U32_F32:  "VCVTR.EQ.U32.F32",
+	arm_VCVTR_NE_U32_F32:  "VCVTR.NE.U32.F32",
+	arm_VCVTR_CS_U32_F32:  "VCVTR.CS.U32.F32",
+	arm_VCVTR_CC_U32_F32:  "VCVTR.CC.U32.F32",
+	arm_VCVTR_MI_U32_F32:  "VCVTR.MI.U32.F32",
+	arm_VCVTR_PL_U32_F32:  "VCVTR.PL.U32.F32",
+	arm_VCVTR_VS_U32_F32:  "VCVTR.VS.U32.F32",
+	arm_VCVTR_VC_U32_F32:  "VCVTR.VC.U32.F32",
+	arm_VCVTR_HI_U32_F32:  "VCVTR.HI.U32.F32",
+	arm_VCVTR_LS_U32_F32:  "VCVTR.LS.U32.F32",
+	arm_VCVTR_GE_U32_F32:  "VCVTR.GE.U32.F32",
+	arm_VCVTR_LT_U32_F32:  "VCVTR.LT.U32.F32",
+	arm_VCVTR_GT_U32_F32:  "VCVTR.GT.U32.F32",
+	arm_VCVTR_LE_U32_F32:  "VCVTR.LE.U32.F32",
+	arm_VCVTR_U32_F32:     "VCVTR.U32.F32",
+	arm_VCVTR_ZZ_U32_F32:  "VCVTR.ZZ.U32.F32",
+	arm_VCVTR_EQ_U32_F64:  "VCVTR.EQ.U32.F64",
+	arm_VCVTR_NE_U32_F64:  "VCVTR.NE.U32.F64",
+	arm_VCVTR_CS_U32_F64:  "VCVTR.CS.U32.F64",
+	arm_VCVTR_CC_U32_F64:  "VCVTR.CC.U32.F64",
+	arm_VCVTR_MI_U32_F64:  "VCVTR.MI.U32.F64",
+	arm_VCVTR_PL_U32_F64:  "VCVTR.PL.U32.F64",
+	arm_VCVTR_VS_U32_F64:  "VCVTR.VS.U32.F64",
+	arm_VCVTR_VC_U32_F64:  "VCVTR.VC.U32.F64",
+	arm_VCVTR_HI_U32_F64:  "VCVTR.HI.U32.F64",
+	arm_VCVTR_LS_U32_F64:  "VCVTR.LS.U32.F64",
+	arm_VCVTR_GE_U32_F64:  "VCVTR.GE.U32.F64",
+	arm_VCVTR_LT_U32_F64:  "VCVTR.LT.U32.F64",
+	arm_VCVTR_GT_U32_F64:  "VCVTR.GT.U32.F64",
+	arm_VCVTR_LE_U32_F64:  "VCVTR.LE.U32.F64",
+	arm_VCVTR_U32_F64:     "VCVTR.U32.F64",
+	arm_VCVTR_ZZ_U32_F64:  "VCVTR.ZZ.U32.F64",
+	arm_VCVTR_EQ_S32_F32:  "VCVTR.EQ.S32.F32",
+	arm_VCVTR_NE_S32_F32:  "VCVTR.NE.S32.F32",
+	arm_VCVTR_CS_S32_F32:  "VCVTR.CS.S32.F32",
+	arm_VCVTR_CC_S32_F32:  "VCVTR.CC.S32.F32",
+	arm_VCVTR_MI_S32_F32:  "VCVTR.MI.S32.F32",
+	arm_VCVTR_PL_S32_F32:  "VCVTR.PL.S32.F32",
+	arm_VCVTR_VS_S32_F32:  "VCVTR.VS.S32.F32",
+	arm_VCVTR_VC_S32_F32:  "VCVTR.VC.S32.F32",
+	arm_VCVTR_HI_S32_F32:  "VCVTR.HI.S32.F32",
+	arm_VCVTR_LS_S32_F32:  "VCVTR.LS.S32.F32",
+	arm_VCVTR_GE_S32_F32:  "VCVTR.GE.S32.F32",
+	arm_VCVTR_LT_S32_F32:  "VCVTR.LT.S32.F32",
+	arm_VCVTR_GT_S32_F32:  "VCVTR.GT.S32.F32",
+	arm_VCVTR_LE_S32_F32:  "VCVTR.LE.S32.F32",
+	arm_VCVTR_S32_F32:     "VCVTR.S32.F32",
+	arm_VCVTR_ZZ_S32_F32:  "VCVTR.ZZ.S32.F32",
+	arm_VCVTR_EQ_S32_F64:  "VCVTR.EQ.S32.F64",
+	arm_VCVTR_NE_S32_F64:  "VCVTR.NE.S32.F64",
+	arm_VCVTR_CS_S32_F64:  "VCVTR.CS.S32.F64",
+	arm_VCVTR_CC_S32_F64:  "VCVTR.CC.S32.F64",
+	arm_VCVTR_MI_S32_F64:  "VCVTR.MI.S32.F64",
+	arm_VCVTR_PL_S32_F64:  "VCVTR.PL.S32.F64",
+	arm_VCVTR_VS_S32_F64:  "VCVTR.VS.S32.F64",
+	arm_VCVTR_VC_S32_F64:  "VCVTR.VC.S32.F64",
+	arm_VCVTR_HI_S32_F64:  "VCVTR.HI.S32.F64",
+	arm_VCVTR_LS_S32_F64:  "VCVTR.LS.S32.F64",
+	arm_VCVTR_GE_S32_F64:  "VCVTR.GE.S32.F64",
+	arm_VCVTR_LT_S32_F64:  "VCVTR.LT.S32.F64",
+	arm_VCVTR_GT_S32_F64:  "VCVTR.GT.S32.F64",
+	arm_VCVTR_LE_S32_F64:  "VCVTR.LE.S32.F64",
+	arm_VCVTR_S32_F64:     "VCVTR.S32.F64",
+	arm_VCVTR_ZZ_S32_F64:  "VCVTR.ZZ.S32.F64",
+	arm_VCVT_EQ_U32_F32:   "VCVT.EQ.U32.F32",
+	arm_VCVT_NE_U32_F32:   "VCVT.NE.U32.F32",
+	arm_VCVT_CS_U32_F32:   "VCVT.CS.U32.F32",
+	arm_VCVT_CC_U32_F32:   "VCVT.CC.U32.F32",
+	arm_VCVT_MI_U32_F32:   "VCVT.MI.U32.F32",
+	arm_VCVT_PL_U32_F32:   "VCVT.PL.U32.F32",
+	arm_VCVT_VS_U32_F32:   "VCVT.VS.U32.F32",
+	arm_VCVT_VC_U32_F32:   "VCVT.VC.U32.F32",
+	arm_VCVT_HI_U32_F32:   "VCVT.HI.U32.F32",
+	arm_VCVT_LS_U32_F32:   "VCVT.LS.U32.F32",
+	arm_VCVT_GE_U32_F32:   "VCVT.GE.U32.F32",
+	arm_VCVT_LT_U32_F32:   "VCVT.LT.U32.F32",
+	arm_VCVT_GT_U32_F32:   "VCVT.GT.U32.F32",
+	arm_VCVT_LE_U32_F32:   "VCVT.LE.U32.F32",
+	arm_VCVT_U32_F32:      "VCVT.U32.F32",
+	arm_VCVT_ZZ_U32_F32:   "VCVT.ZZ.U32.F32",
+	arm_VCVT_EQ_U32_F64:   "VCVT.EQ.U32.F64",
+	arm_VCVT_NE_U32_F64:   "VCVT.NE.U32.F64",
+	arm_VCVT_CS_U32_F64:   "VCVT.CS.U32.F64",
+	arm_VCVT_CC_U32_F64:   "VCVT.CC.U32.F64",
+	arm_VCVT_MI_U32_F64:   "VCVT.MI.U32.F64",
+	arm_VCVT_PL_U32_F64:   "VCVT.PL.U32.F64",
+	arm_VCVT_VS_U32_F64:   "VCVT.VS.U32.F64",
+	arm_VCVT_VC_U32_F64:   "VCVT.VC.U32.F64",
+	arm_VCVT_HI_U32_F64:   "VCVT.HI.U32.F64",
+	arm_VCVT_LS_U32_F64:   "VCVT.LS.U32.F64",
+	arm_VCVT_GE_U32_F64:   "VCVT.GE.U32.F64",
+	arm_VCVT_LT_U32_F64:   "VCVT.LT.U32.F64",
+	arm_VCVT_GT_U32_F64:   "VCVT.GT.U32.F64",
+	arm_VCVT_LE_U32_F64:   "VCVT.LE.U32.F64",
+	arm_VCVT_U32_F64:      "VCVT.U32.F64",
+	arm_VCVT_ZZ_U32_F64:   "VCVT.ZZ.U32.F64",
+	arm_VCVT_EQ_S32_F32:   "VCVT.EQ.S32.F32",
+	arm_VCVT_NE_S32_F32:   "VCVT.NE.S32.F32",
+	arm_VCVT_CS_S32_F32:   "VCVT.CS.S32.F32",
+	arm_VCVT_CC_S32_F32:   "VCVT.CC.S32.F32",
+	arm_VCVT_MI_S32_F32:   "VCVT.MI.S32.F32",
+	arm_VCVT_PL_S32_F32:   "VCVT.PL.S32.F32",
+	arm_VCVT_VS_S32_F32:   "VCVT.VS.S32.F32",
+	arm_VCVT_VC_S32_F32:   "VCVT.VC.S32.F32",
+	arm_VCVT_HI_S32_F32:   "VCVT.HI.S32.F32",
+	arm_VCVT_LS_S32_F32:   "VCVT.LS.S32.F32",
+	arm_VCVT_GE_S32_F32:   "VCVT.GE.S32.F32",
+	arm_VCVT_LT_S32_F32:   "VCVT.LT.S32.F32",
+	arm_VCVT_GT_S32_F32:   "VCVT.GT.S32.F32",
+	arm_VCVT_LE_S32_F32:   "VCVT.LE.S32.F32",
+	arm_VCVT_S32_F32:      "VCVT.S32.F32",
+	arm_VCVT_ZZ_S32_F32:   "VCVT.ZZ.S32.F32",
+	arm_VCVT_EQ_S32_F64:   "VCVT.EQ.S32.F64",
+	arm_VCVT_NE_S32_F64:   "VCVT.NE.S32.F64",
+	arm_VCVT_CS_S32_F64:   "VCVT.CS.S32.F64",
+	arm_VCVT_CC_S32_F64:   "VCVT.CC.S32.F64",
+	arm_VCVT_MI_S32_F64:   "VCVT.MI.S32.F64",
+	arm_VCVT_PL_S32_F64:   "VCVT.PL.S32.F64",
+	arm_VCVT_VS_S32_F64:   "VCVT.VS.S32.F64",
+	arm_VCVT_VC_S32_F64:   "VCVT.VC.S32.F64",
+	arm_VCVT_HI_S32_F64:   "VCVT.HI.S32.F64",
+	arm_VCVT_LS_S32_F64:   "VCVT.LS.S32.F64",
+	arm_VCVT_GE_S32_F64:   "VCVT.GE.S32.F64",
+	arm_VCVT_LT_S32_F64:   "VCVT.LT.S32.F64",
+	arm_VCVT_GT_S32_F64:   "VCVT.GT.S32.F64",
+	arm_VCVT_LE_S32_F64:   "VCVT.LE.S32.F64",
+	arm_VCVT_S32_F64:      "VCVT.S32.F64",
+	arm_VCVT_ZZ_S32_F64:   "VCVT.ZZ.S32.F64",
+	arm_VDIV_EQ_F32:       "VDIV.EQ.F32",
+	arm_VDIV_NE_F32:       "VDIV.NE.F32",
+	arm_VDIV_CS_F32:       "VDIV.CS.F32",
+	arm_VDIV_CC_F32:       "VDIV.CC.F32",
+	arm_VDIV_MI_F32:       "VDIV.MI.F32",
+	arm_VDIV_PL_F32:       "VDIV.PL.F32",
+	arm_VDIV_VS_F32:       "VDIV.VS.F32",
+	arm_VDIV_VC_F32:       "VDIV.VC.F32",
+	arm_VDIV_HI_F32:       "VDIV.HI.F32",
+	arm_VDIV_LS_F32:       "VDIV.LS.F32",
+	arm_VDIV_GE_F32:       "VDIV.GE.F32",
+	arm_VDIV_LT_F32:       "VDIV.LT.F32",
+	arm_VDIV_GT_F32:       "VDIV.GT.F32",
+	arm_VDIV_LE_F32:       "VDIV.LE.F32",
+	arm_VDIV_F32:          "VDIV.F32",
+	arm_VDIV_ZZ_F32:       "VDIV.ZZ.F32",
+	arm_VDIV_EQ_F64:       "VDIV.EQ.F64",
+	arm_VDIV_NE_F64:       "VDIV.NE.F64",
+	arm_VDIV_CS_F64:       "VDIV.CS.F64",
+	arm_VDIV_CC_F64:       "VDIV.CC.F64",
+	arm_VDIV_MI_F64:       "VDIV.MI.F64",
+	arm_VDIV_PL_F64:       "VDIV.PL.F64",
+	arm_VDIV_VS_F64:       "VDIV.VS.F64",
+	arm_VDIV_VC_F64:       "VDIV.VC.F64",
+	arm_VDIV_HI_F64:       "VDIV.HI.F64",
+	arm_VDIV_LS_F64:       "VDIV.LS.F64",
+	arm_VDIV_GE_F64:       "VDIV.GE.F64",
+	arm_VDIV_LT_F64:       "VDIV.LT.F64",
+	arm_VDIV_GT_F64:       "VDIV.GT.F64",
+	arm_VDIV_LE_F64:       "VDIV.LE.F64",
+	arm_VDIV_F64:          "VDIV.F64",
+	arm_VDIV_ZZ_F64:       "VDIV.ZZ.F64",
+	arm_VLDR_EQ:           "VLDR.EQ",
+	arm_VLDR_NE:           "VLDR.NE",
+	arm_VLDR_CS:           "VLDR.CS",
+	arm_VLDR_CC:           "VLDR.CC",
+	arm_VLDR_MI:           "VLDR.MI",
+	arm_VLDR_PL:           "VLDR.PL",
+	arm_VLDR_VS:           "VLDR.VS",
+	arm_VLDR_VC:           "VLDR.VC",
+	arm_VLDR_HI:           "VLDR.HI",
+	arm_VLDR_LS:           "VLDR.LS",
+	arm_VLDR_GE:           "VLDR.GE",
+	arm_VLDR_LT:           "VLDR.LT",
+	arm_VLDR_GT:           "VLDR.GT",
+	arm_VLDR_LE:           "VLDR.LE",
+	arm_VLDR:              "VLDR",
+	arm_VLDR_ZZ:           "VLDR.ZZ",
+	arm_VMLA_EQ_F32:       "VMLA.EQ.F32",
+	arm_VMLA_NE_F32:       "VMLA.NE.F32",
+	arm_VMLA_CS_F32:       "VMLA.CS.F32",
+	arm_VMLA_CC_F32:       "VMLA.CC.F32",
+	arm_VMLA_MI_F32:       "VMLA.MI.F32",
+	arm_VMLA_PL_F32:       "VMLA.PL.F32",
+	arm_VMLA_VS_F32:       "VMLA.VS.F32",
+	arm_VMLA_VC_F32:       "VMLA.VC.F32",
+	arm_VMLA_HI_F32:       "VMLA.HI.F32",
+	arm_VMLA_LS_F32:       "VMLA.LS.F32",
+	arm_VMLA_GE_F32:       "VMLA.GE.F32",
+	arm_VMLA_LT_F32:       "VMLA.LT.F32",
+	arm_VMLA_GT_F32:       "VMLA.GT.F32",
+	arm_VMLA_LE_F32:       "VMLA.LE.F32",
+	arm_VMLA_F32:          "VMLA.F32",
+	arm_VMLA_ZZ_F32:       "VMLA.ZZ.F32",
+	arm_VMLA_EQ_F64:       "VMLA.EQ.F64",
+	arm_VMLA_NE_F64:       "VMLA.NE.F64",
+	arm_VMLA_CS_F64:       "VMLA.CS.F64",
+	arm_VMLA_CC_F64:       "VMLA.CC.F64",
+	arm_VMLA_MI_F64:       "VMLA.MI.F64",
+	arm_VMLA_PL_F64:       "VMLA.PL.F64",
+	arm_VMLA_VS_F64:       "VMLA.VS.F64",
+	arm_VMLA_VC_F64:       "VMLA.VC.F64",
+	arm_VMLA_HI_F64:       "VMLA.HI.F64",
+	arm_VMLA_LS_F64:       "VMLA.LS.F64",
+	arm_VMLA_GE_F64:       "VMLA.GE.F64",
+	arm_VMLA_LT_F64:       "VMLA.LT.F64",
+	arm_VMLA_GT_F64:       "VMLA.GT.F64",
+	arm_VMLA_LE_F64:       "VMLA.LE.F64",
+	arm_VMLA_F64:          "VMLA.F64",
+	arm_VMLA_ZZ_F64:       "VMLA.ZZ.F64",
+	arm_VMLS_EQ_F32:       "VMLS.EQ.F32",
+	arm_VMLS_NE_F32:       "VMLS.NE.F32",
+	arm_VMLS_CS_F32:       "VMLS.CS.F32",
+	arm_VMLS_CC_F32:       "VMLS.CC.F32",
+	arm_VMLS_MI_F32:       "VMLS.MI.F32",
+	arm_VMLS_PL_F32:       "VMLS.PL.F32",
+	arm_VMLS_VS_F32:       "VMLS.VS.F32",
+	arm_VMLS_VC_F32:       "VMLS.VC.F32",
+	arm_VMLS_HI_F32:       "VMLS.HI.F32",
+	arm_VMLS_LS_F32:       "VMLS.LS.F32",
+	arm_VMLS_GE_F32:       "VMLS.GE.F32",
+	arm_VMLS_LT_F32:       "VMLS.LT.F32",
+	arm_VMLS_GT_F32:       "VMLS.GT.F32",
+	arm_VMLS_LE_F32:       "VMLS.LE.F32",
+	arm_VMLS_F32:          "VMLS.F32",
+	arm_VMLS_ZZ_F32:       "VMLS.ZZ.F32",
+	arm_VMLS_EQ_F64:       "VMLS.EQ.F64",
+	arm_VMLS_NE_F64:       "VMLS.NE.F64",
+	arm_VMLS_CS_F64:       "VMLS.CS.F64",
+	arm_VMLS_CC_F64:       "VMLS.CC.F64",
+	arm_VMLS_MI_F64:       "VMLS.MI.F64",
+	arm_VMLS_PL_F64:       "VMLS.PL.F64",
+	arm_VMLS_VS_F64:       "VMLS.VS.F64",
+	arm_VMLS_VC_F64:       "VMLS.VC.F64",
+	arm_VMLS_HI_F64:       "VMLS.HI.F64",
+	arm_VMLS_LS_F64:       "VMLS.LS.F64",
+	arm_VMLS_GE_F64:       "VMLS.GE.F64",
+	arm_VMLS_LT_F64:       "VMLS.LT.F64",
+	arm_VMLS_GT_F64:       "VMLS.GT.F64",
+	arm_VMLS_LE_F64:       "VMLS.LE.F64",
+	arm_VMLS_F64:          "VMLS.F64",
+	arm_VMLS_ZZ_F64:       "VMLS.ZZ.F64",
+	arm_VMOV_EQ:           "VMOV.EQ",
+	arm_VMOV_NE:           "VMOV.NE",
+	arm_VMOV_CS:           "VMOV.CS",
+	arm_VMOV_CC:           "VMOV.CC",
+	arm_VMOV_MI:           "VMOV.MI",
+	arm_VMOV_PL:           "VMOV.PL",
+	arm_VMOV_VS:           "VMOV.VS",
+	arm_VMOV_VC:           "VMOV.VC",
+	arm_VMOV_HI:           "VMOV.HI",
+	arm_VMOV_LS:           "VMOV.LS",
+	arm_VMOV_GE:           "VMOV.GE",
+	arm_VMOV_LT:           "VMOV.LT",
+	arm_VMOV_GT:           "VMOV.GT",
+	arm_VMOV_LE:           "VMOV.LE",
+	arm_VMOV:              "VMOV",
+	arm_VMOV_ZZ:           "VMOV.ZZ",
+	arm_VMOV_EQ_32:        "VMOV.EQ.32",
+	arm_VMOV_NE_32:        "VMOV.NE.32",
+	arm_VMOV_CS_32:        "VMOV.CS.32",
+	arm_VMOV_CC_32:        "VMOV.CC.32",
+	arm_VMOV_MI_32:        "VMOV.MI.32",
+	arm_VMOV_PL_32:        "VMOV.PL.32",
+	arm_VMOV_VS_32:        "VMOV.VS.32",
+	arm_VMOV_VC_32:        "VMOV.VC.32",
+	arm_VMOV_HI_32:        "VMOV.HI.32",
+	arm_VMOV_LS_32:        "VMOV.LS.32",
+	arm_VMOV_GE_32:        "VMOV.GE.32",
+	arm_VMOV_LT_32:        "VMOV.LT.32",
+	arm_VMOV_GT_32:        "VMOV.GT.32",
+	arm_VMOV_LE_32:        "VMOV.LE.32",
+	arm_VMOV_32:           "VMOV.32",
+	arm_VMOV_ZZ_32:        "VMOV.ZZ.32",
+	arm_VMOV_EQ_F32:       "VMOV.EQ.F32",
+	arm_VMOV_NE_F32:       "VMOV.NE.F32",
+	arm_VMOV_CS_F32:       "VMOV.CS.F32",
+	arm_VMOV_CC_F32:       "VMOV.CC.F32",
+	arm_VMOV_MI_F32:       "VMOV.MI.F32",
+	arm_VMOV_PL_F32:       "VMOV.PL.F32",
+	arm_VMOV_VS_F32:       "VMOV.VS.F32",
+	arm_VMOV_VC_F32:       "VMOV.VC.F32",
+	arm_VMOV_HI_F32:       "VMOV.HI.F32",
+	arm_VMOV_LS_F32:       "VMOV.LS.F32",
+	arm_VMOV_GE_F32:       "VMOV.GE.F32",
+	arm_VMOV_LT_F32:       "VMOV.LT.F32",
+	arm_VMOV_GT_F32:       "VMOV.GT.F32",
+	arm_VMOV_LE_F32:       "VMOV.LE.F32",
+	arm_VMOV_F32:          "VMOV.F32",
+	arm_VMOV_ZZ_F32:       "VMOV.ZZ.F32",
+	arm_VMOV_EQ_F64:       "VMOV.EQ.F64",
+	arm_VMOV_NE_F64:       "VMOV.NE.F64",
+	arm_VMOV_CS_F64:       "VMOV.CS.F64",
+	arm_VMOV_CC_F64:       "VMOV.CC.F64",
+	arm_VMOV_MI_F64:       "VMOV.MI.F64",
+	arm_VMOV_PL_F64:       "VMOV.PL.F64",
+	arm_VMOV_VS_F64:       "VMOV.VS.F64",
+	arm_VMOV_VC_F64:       "VMOV.VC.F64",
+	arm_VMOV_HI_F64:       "VMOV.HI.F64",
+	arm_VMOV_LS_F64:       "VMOV.LS.F64",
+	arm_VMOV_GE_F64:       "VMOV.GE.F64",
+	arm_VMOV_LT_F64:       "VMOV.LT.F64",
+	arm_VMOV_GT_F64:       "VMOV.GT.F64",
+	arm_VMOV_LE_F64:       "VMOV.LE.F64",
+	arm_VMOV_F64:          "VMOV.F64",
+	arm_VMOV_ZZ_F64:       "VMOV.ZZ.F64",
+	arm_VMRS_EQ:           "VMRS.EQ",
+	arm_VMRS_NE:           "VMRS.NE",
+	arm_VMRS_CS:           "VMRS.CS",
+	arm_VMRS_CC:           "VMRS.CC",
+	arm_VMRS_MI:           "VMRS.MI",
+	arm_VMRS_PL:           "VMRS.PL",
+	arm_VMRS_VS:           "VMRS.VS",
+	arm_VMRS_VC:           "VMRS.VC",
+	arm_VMRS_HI:           "VMRS.HI",
+	arm_VMRS_LS:           "VMRS.LS",
+	arm_VMRS_GE:           "VMRS.GE",
+	arm_VMRS_LT:           "VMRS.LT",
+	arm_VMRS_GT:           "VMRS.GT",
+	arm_VMRS_LE:           "VMRS.LE",
+	arm_VMRS:              "VMRS",
+	arm_VMRS_ZZ:           "VMRS.ZZ",
+	arm_VMSR_EQ:           "VMSR.EQ",
+	arm_VMSR_NE:           "VMSR.NE",
+	arm_VMSR_CS:           "VMSR.CS",
+	arm_VMSR_CC:           "VMSR.CC",
+	arm_VMSR_MI:           "VMSR.MI",
+	arm_VMSR_PL:           "VMSR.PL",
+	arm_VMSR_VS:           "VMSR.VS",
+	arm_VMSR_VC:           "VMSR.VC",
+	arm_VMSR_HI:           "VMSR.HI",
+	arm_VMSR_LS:           "VMSR.LS",
+	arm_VMSR_GE:           "VMSR.GE",
+	arm_VMSR_LT:           "VMSR.LT",
+	arm_VMSR_GT:           "VMSR.GT",
+	arm_VMSR_LE:           "VMSR.LE",
+	arm_VMSR:              "VMSR",
+	arm_VMSR_ZZ:           "VMSR.ZZ",
+	arm_VMUL_EQ_F32:       "VMUL.EQ.F32",
+	arm_VMUL_NE_F32:       "VMUL.NE.F32",
+	arm_VMUL_CS_F32:       "VMUL.CS.F32",
+	arm_VMUL_CC_F32:       "VMUL.CC.F32",
+	arm_VMUL_MI_F32:       "VMUL.MI.F32",
+	arm_VMUL_PL_F32:       "VMUL.PL.F32",
+	arm_VMUL_VS_F32:       "VMUL.VS.F32",
+	arm_VMUL_VC_F32:       "VMUL.VC.F32",
+	arm_VMUL_HI_F32:       "VMUL.HI.F32",
+	arm_VMUL_LS_F32:       "VMUL.LS.F32",
+	arm_VMUL_GE_F32:       "VMUL.GE.F32",
+	arm_VMUL_LT_F32:       "VMUL.LT.F32",
+	arm_VMUL_GT_F32:       "VMUL.GT.F32",
+	arm_VMUL_LE_F32:       "VMUL.LE.F32",
+	arm_VMUL_F32:          "VMUL.F32",
+	arm_VMUL_ZZ_F32:       "VMUL.ZZ.F32",
+	arm_VMUL_EQ_F64:       "VMUL.EQ.F64",
+	arm_VMUL_NE_F64:       "VMUL.NE.F64",
+	arm_VMUL_CS_F64:       "VMUL.CS.F64",
+	arm_VMUL_CC_F64:       "VMUL.CC.F64",
+	arm_VMUL_MI_F64:       "VMUL.MI.F64",
+	arm_VMUL_PL_F64:       "VMUL.PL.F64",
+	arm_VMUL_VS_F64:       "VMUL.VS.F64",
+	arm_VMUL_VC_F64:       "VMUL.VC.F64",
+	arm_VMUL_HI_F64:       "VMUL.HI.F64",
+	arm_VMUL_LS_F64:       "VMUL.LS.F64",
+	arm_VMUL_GE_F64:       "VMUL.GE.F64",
+	arm_VMUL_LT_F64:       "VMUL.LT.F64",
+	arm_VMUL_GT_F64:       "VMUL.GT.F64",
+	arm_VMUL_LE_F64:       "VMUL.LE.F64",
+	arm_VMUL_F64:          "VMUL.F64",
+	arm_VMUL_ZZ_F64:       "VMUL.ZZ.F64",
+	arm_VNEG_EQ_F32:       "VNEG.EQ.F32",
+	arm_VNEG_NE_F32:       "VNEG.NE.F32",
+	arm_VNEG_CS_F32:       "VNEG.CS.F32",
+	arm_VNEG_CC_F32:       "VNEG.CC.F32",
+	arm_VNEG_MI_F32:       "VNEG.MI.F32",
+	arm_VNEG_PL_F32:       "VNEG.PL.F32",
+	arm_VNEG_VS_F32:       "VNEG.VS.F32",
+	arm_VNEG_VC_F32:       "VNEG.VC.F32",
+	arm_VNEG_HI_F32:       "VNEG.HI.F32",
+	arm_VNEG_LS_F32:       "VNEG.LS.F32",
+	arm_VNEG_GE_F32:       "VNEG.GE.F32",
+	arm_VNEG_LT_F32:       "VNEG.LT.F32",
+	arm_VNEG_GT_F32:       "VNEG.GT.F32",
+	arm_VNEG_LE_F32:       "VNEG.LE.F32",
+	arm_VNEG_F32:          "VNEG.F32",
+	arm_VNEG_ZZ_F32:       "VNEG.ZZ.F32",
+	arm_VNEG_EQ_F64:       "VNEG.EQ.F64",
+	arm_VNEG_NE_F64:       "VNEG.NE.F64",
+	arm_VNEG_CS_F64:       "VNEG.CS.F64",
+	arm_VNEG_CC_F64:       "VNEG.CC.F64",
+	arm_VNEG_MI_F64:       "VNEG.MI.F64",
+	arm_VNEG_PL_F64:       "VNEG.PL.F64",
+	arm_VNEG_VS_F64:       "VNEG.VS.F64",
+	arm_VNEG_VC_F64:       "VNEG.VC.F64",
+	arm_VNEG_HI_F64:       "VNEG.HI.F64",
+	arm_VNEG_LS_F64:       "VNEG.LS.F64",
+	arm_VNEG_GE_F64:       "VNEG.GE.F64",
+	arm_VNEG_LT_F64:       "VNEG.LT.F64",
+	arm_VNEG_GT_F64:       "VNEG.GT.F64",
+	arm_VNEG_LE_F64:       "VNEG.LE.F64",
+	arm_VNEG_F64:          "VNEG.F64",
+	arm_VNEG_ZZ_F64:       "VNEG.ZZ.F64",
+	arm_VNMLS_EQ_F32:      "VNMLS.EQ.F32",
+	arm_VNMLS_NE_F32:      "VNMLS.NE.F32",
+	arm_VNMLS_CS_F32:      "VNMLS.CS.F32",
+	arm_VNMLS_CC_F32:      "VNMLS.CC.F32",
+	arm_VNMLS_MI_F32:      "VNMLS.MI.F32",
+	arm_VNMLS_PL_F32:      "VNMLS.PL.F32",
+	arm_VNMLS_VS_F32:      "VNMLS.VS.F32",
+	arm_VNMLS_VC_F32:      "VNMLS.VC.F32",
+	arm_VNMLS_HI_F32:      "VNMLS.HI.F32",
+	arm_VNMLS_LS_F32:      "VNMLS.LS.F32",
+	arm_VNMLS_GE_F32:      "VNMLS.GE.F32",
+	arm_VNMLS_LT_F32:      "VNMLS.LT.F32",
+	arm_VNMLS_GT_F32:      "VNMLS.GT.F32",
+	arm_VNMLS_LE_F32:      "VNMLS.LE.F32",
+	arm_VNMLS_F32:         "VNMLS.F32",
+	arm_VNMLS_ZZ_F32:      "VNMLS.ZZ.F32",
+	arm_VNMLS_EQ_F64:      "VNMLS.EQ.F64",
+	arm_VNMLS_NE_F64:      "VNMLS.NE.F64",
+	arm_VNMLS_CS_F64:      "VNMLS.CS.F64",
+	arm_VNMLS_CC_F64:      "VNMLS.CC.F64",
+	arm_VNMLS_MI_F64:      "VNMLS.MI.F64",
+	arm_VNMLS_PL_F64:      "VNMLS.PL.F64",
+	arm_VNMLS_VS_F64:      "VNMLS.VS.F64",
+	arm_VNMLS_VC_F64:      "VNMLS.VC.F64",
+	arm_VNMLS_HI_F64:      "VNMLS.HI.F64",
+	arm_VNMLS_LS_F64:      "VNMLS.LS.F64",
+	arm_VNMLS_GE_F64:      "VNMLS.GE.F64",
+	arm_VNMLS_LT_F64:      "VNMLS.LT.F64",
+	arm_VNMLS_GT_F64:      "VNMLS.GT.F64",
+	arm_VNMLS_LE_F64:      "VNMLS.LE.F64",
+	arm_VNMLS_F64:         "VNMLS.F64",
+	arm_VNMLS_ZZ_F64:      "VNMLS.ZZ.F64",
+	arm_VNMLA_EQ_F32:      "VNMLA.EQ.F32",
+	arm_VNMLA_NE_F32:      "VNMLA.NE.F32",
+	arm_VNMLA_CS_F32:      "VNMLA.CS.F32",
+	arm_VNMLA_CC_F32:      "VNMLA.CC.F32",
+	arm_VNMLA_MI_F32:      "VNMLA.MI.F32",
+	arm_VNMLA_PL_F32:      "VNMLA.PL.F32",
+	arm_VNMLA_VS_F32:      "VNMLA.VS.F32",
+	arm_VNMLA_VC_F32:      "VNMLA.VC.F32",
+	arm_VNMLA_HI_F32:      "VNMLA.HI.F32",
+	arm_VNMLA_LS_F32:      "VNMLA.LS.F32",
+	arm_VNMLA_GE_F32:      "VNMLA.GE.F32",
+	arm_VNMLA_LT_F32:      "VNMLA.LT.F32",
+	arm_VNMLA_GT_F32:      "VNMLA.GT.F32",
+	arm_VNMLA_LE_F32:      "VNMLA.LE.F32",
+	arm_VNMLA_F32:         "VNMLA.F32",
+	arm_VNMLA_ZZ_F32:      "VNMLA.ZZ.F32",
+	arm_VNMLA_EQ_F64:      "VNMLA.EQ.F64",
+	arm_VNMLA_NE_F64:      "VNMLA.NE.F64",
+	arm_VNMLA_CS_F64:      "VNMLA.CS.F64",
+	arm_VNMLA_CC_F64:      "VNMLA.CC.F64",
+	arm_VNMLA_MI_F64:      "VNMLA.MI.F64",
+	arm_VNMLA_PL_F64:      "VNMLA.PL.F64",
+	arm_VNMLA_VS_F64:      "VNMLA.VS.F64",
+	arm_VNMLA_VC_F64:      "VNMLA.VC.F64",
+	arm_VNMLA_HI_F64:      "VNMLA.HI.F64",
+	arm_VNMLA_LS_F64:      "VNMLA.LS.F64",
+	arm_VNMLA_GE_F64:      "VNMLA.GE.F64",
+	arm_VNMLA_LT_F64:      "VNMLA.LT.F64",
+	arm_VNMLA_GT_F64:      "VNMLA.GT.F64",
+	arm_VNMLA_LE_F64:      "VNMLA.LE.F64",
+	arm_VNMLA_F64:         "VNMLA.F64",
+	arm_VNMLA_ZZ_F64:      "VNMLA.ZZ.F64",
+	arm_VNMUL_EQ_F32:      "VNMUL.EQ.F32",
+	arm_VNMUL_NE_F32:      "VNMUL.NE.F32",
+	arm_VNMUL_CS_F32:      "VNMUL.CS.F32",
+	arm_VNMUL_CC_F32:      "VNMUL.CC.F32",
+	arm_VNMUL_MI_F32:      "VNMUL.MI.F32",
+	arm_VNMUL_PL_F32:      "VNMUL.PL.F32",
+	arm_VNMUL_VS_F32:      "VNMUL.VS.F32",
+	arm_VNMUL_VC_F32:      "VNMUL.VC.F32",
+	arm_VNMUL_HI_F32:      "VNMUL.HI.F32",
+	arm_VNMUL_LS_F32:      "VNMUL.LS.F32",
+	arm_VNMUL_GE_F32:      "VNMUL.GE.F32",
+	arm_VNMUL_LT_F32:      "VNMUL.LT.F32",
+	arm_VNMUL_GT_F32:      "VNMUL.GT.F32",
+	arm_VNMUL_LE_F32:      "VNMUL.LE.F32",
+	arm_VNMUL_F32:         "VNMUL.F32",
+	arm_VNMUL_ZZ_F32:      "VNMUL.ZZ.F32",
+	arm_VNMUL_EQ_F64:      "VNMUL.EQ.F64",
+	arm_VNMUL_NE_F64:      "VNMUL.NE.F64",
+	arm_VNMUL_CS_F64:      "VNMUL.CS.F64",
+	arm_VNMUL_CC_F64:      "VNMUL.CC.F64",
+	arm_VNMUL_MI_F64:      "VNMUL.MI.F64",
+	arm_VNMUL_PL_F64:      "VNMUL.PL.F64",
+	arm_VNMUL_VS_F64:      "VNMUL.VS.F64",
+	arm_VNMUL_VC_F64:      "VNMUL.VC.F64",
+	arm_VNMUL_HI_F64:      "VNMUL.HI.F64",
+	arm_VNMUL_LS_F64:      "VNMUL.LS.F64",
+	arm_VNMUL_GE_F64:      "VNMUL.GE.F64",
+	arm_VNMUL_LT_F64:      "VNMUL.LT.F64",
+	arm_VNMUL_GT_F64:      "VNMUL.GT.F64",
+	arm_VNMUL_LE_F64:      "VNMUL.LE.F64",
+	arm_VNMUL_F64:         "VNMUL.F64",
+	arm_VNMUL_ZZ_F64:      "VNMUL.ZZ.F64",
+	arm_VSQRT_EQ_F32:      "VSQRT.EQ.F32",
+	arm_VSQRT_NE_F32:      "VSQRT.NE.F32",
+	arm_VSQRT_CS_F32:      "VSQRT.CS.F32",
+	arm_VSQRT_CC_F32:      "VSQRT.CC.F32",
+	arm_VSQRT_MI_F32:      "VSQRT.MI.F32",
+	arm_VSQRT_PL_F32:      "VSQRT.PL.F32",
+	arm_VSQRT_VS_F32:      "VSQRT.VS.F32",
+	arm_VSQRT_VC_F32:      "VSQRT.VC.F32",
+	arm_VSQRT_HI_F32:      "VSQRT.HI.F32",
+	arm_VSQRT_LS_F32:      "VSQRT.LS.F32",
+	arm_VSQRT_GE_F32:      "VSQRT.GE.F32",
+	arm_VSQRT_LT_F32:      "VSQRT.LT.F32",
+	arm_VSQRT_GT_F32:      "VSQRT.GT.F32",
+	arm_VSQRT_LE_F32:      "VSQRT.LE.F32",
+	arm_VSQRT_F32:         "VSQRT.F32",
+	arm_VSQRT_ZZ_F32:      "VSQRT.ZZ.F32",
+	arm_VSQRT_EQ_F64:      "VSQRT.EQ.F64",
+	arm_VSQRT_NE_F64:      "VSQRT.NE.F64",
+	arm_VSQRT_CS_F64:      "VSQRT.CS.F64",
+	arm_VSQRT_CC_F64:      "VSQRT.CC.F64",
+	arm_VSQRT_MI_F64:      "VSQRT.MI.F64",
+	arm_VSQRT_PL_F64:      "VSQRT.PL.F64",
+	arm_VSQRT_VS_F64:      "VSQRT.VS.F64",
+	arm_VSQRT_VC_F64:      "VSQRT.VC.F64",
+	arm_VSQRT_HI_F64:      "VSQRT.HI.F64",
+	arm_VSQRT_LS_F64:      "VSQRT.LS.F64",
+	arm_VSQRT_GE_F64:      "VSQRT.GE.F64",
+	arm_VSQRT_LT_F64:      "VSQRT.LT.F64",
+	arm_VSQRT_GT_F64:      "VSQRT.GT.F64",
+	arm_VSQRT_LE_F64:      "VSQRT.LE.F64",
+	arm_VSQRT_F64:         "VSQRT.F64",
+	arm_VSQRT_ZZ_F64:      "VSQRT.ZZ.F64",
+	arm_VSTR_EQ:           "VSTR.EQ",
+	arm_VSTR_NE:           "VSTR.NE",
+	arm_VSTR_CS:           "VSTR.CS",
+	arm_VSTR_CC:           "VSTR.CC",
+	arm_VSTR_MI:           "VSTR.MI",
+	arm_VSTR_PL:           "VSTR.PL",
+	arm_VSTR_VS:           "VSTR.VS",
+	arm_VSTR_VC:           "VSTR.VC",
+	arm_VSTR_HI:           "VSTR.HI",
+	arm_VSTR_LS:           "VSTR.LS",
+	arm_VSTR_GE:           "VSTR.GE",
+	arm_VSTR_LT:           "VSTR.LT",
+	arm_VSTR_GT:           "VSTR.GT",
+	arm_VSTR_LE:           "VSTR.LE",
+	arm_VSTR:              "VSTR",
+	arm_VSTR_ZZ:           "VSTR.ZZ",
+	arm_VSUB_EQ_F32:       "VSUB.EQ.F32",
+	arm_VSUB_NE_F32:       "VSUB.NE.F32",
+	arm_VSUB_CS_F32:       "VSUB.CS.F32",
+	arm_VSUB_CC_F32:       "VSUB.CC.F32",
+	arm_VSUB_MI_F32:       "VSUB.MI.F32",
+	arm_VSUB_PL_F32:       "VSUB.PL.F32",
+	arm_VSUB_VS_F32:       "VSUB.VS.F32",
+	arm_VSUB_VC_F32:       "VSUB.VC.F32",
+	arm_VSUB_HI_F32:       "VSUB.HI.F32",
+	arm_VSUB_LS_F32:       "VSUB.LS.F32",
+	arm_VSUB_GE_F32:       "VSUB.GE.F32",
+	arm_VSUB_LT_F32:       "VSUB.LT.F32",
+	arm_VSUB_GT_F32:       "VSUB.GT.F32",
+	arm_VSUB_LE_F32:       "VSUB.LE.F32",
+	arm_VSUB_F32:          "VSUB.F32",
+	arm_VSUB_ZZ_F32:       "VSUB.ZZ.F32",
+	arm_VSUB_EQ_F64:       "VSUB.EQ.F64",
+	arm_VSUB_NE_F64:       "VSUB.NE.F64",
+	arm_VSUB_CS_F64:       "VSUB.CS.F64",
+	arm_VSUB_CC_F64:       "VSUB.CC.F64",
+	arm_VSUB_MI_F64:       "VSUB.MI.F64",
+	arm_VSUB_PL_F64:       "VSUB.PL.F64",
+	arm_VSUB_VS_F64:       "VSUB.VS.F64",
+	arm_VSUB_VC_F64:       "VSUB.VC.F64",
+	arm_VSUB_HI_F64:       "VSUB.HI.F64",
+	arm_VSUB_LS_F64:       "VSUB.LS.F64",
+	arm_VSUB_GE_F64:       "VSUB.GE.F64",
+	arm_VSUB_LT_F64:       "VSUB.LT.F64",
+	arm_VSUB_GT_F64:       "VSUB.GT.F64",
+	arm_VSUB_LE_F64:       "VSUB.LE.F64",
+	arm_VSUB_F64:          "VSUB.F64",
+	arm_VSUB_ZZ_F64:       "VSUB.ZZ.F64",
+	arm_WFE_EQ:            "WFE.EQ",
+	arm_WFE_NE:            "WFE.NE",
+	arm_WFE_CS:            "WFE.CS",
+	arm_WFE_CC:            "WFE.CC",
+	arm_WFE_MI:            "WFE.MI",
+	arm_WFE_PL:            "WFE.PL",
+	arm_WFE_VS:            "WFE.VS",
+	arm_WFE_VC:            "WFE.VC",
+	arm_WFE_HI:            "WFE.HI",
+	arm_WFE_LS:            "WFE.LS",
+	arm_WFE_GE:            "WFE.GE",
+	arm_WFE_LT:            "WFE.LT",
+	arm_WFE_GT:            "WFE.GT",
+	arm_WFE_LE:            "WFE.LE",
+	arm_WFE:               "WFE",
+	arm_WFE_ZZ:            "WFE.ZZ",
+	arm_WFI_EQ:            "WFI.EQ",
+	arm_WFI_NE:            "WFI.NE",
+	arm_WFI_CS:            "WFI.CS",
+	arm_WFI_CC:            "WFI.CC",
+	arm_WFI_MI:            "WFI.MI",
+	arm_WFI_PL:            "WFI.PL",
+	arm_WFI_VS:            "WFI.VS",
+	arm_WFI_VC:            "WFI.VC",
+	arm_WFI_HI:            "WFI.HI",
+	arm_WFI_LS:            "WFI.LS",
+	arm_WFI_GE:            "WFI.GE",
+	arm_WFI_LT:            "WFI.LT",
+	arm_WFI_GT:            "WFI.GT",
+	arm_WFI_LE:            "WFI.LE",
+	arm_WFI:               "WFI",
+	arm_WFI_ZZ:            "WFI.ZZ",
+	arm_YIELD_EQ:          "YIELD.EQ",
+	arm_YIELD_NE:          "YIELD.NE",
+	arm_YIELD_CS:          "YIELD.CS",
+	arm_YIELD_CC:          "YIELD.CC",
+	arm_YIELD_MI:          "YIELD.MI",
+	arm_YIELD_PL:          "YIELD.PL",
+	arm_YIELD_VS:          "YIELD.VS",
+	arm_YIELD_VC:          "YIELD.VC",
+	arm_YIELD_HI:          "YIELD.HI",
+	arm_YIELD_LS:          "YIELD.LS",
+	arm_YIELD_GE:          "YIELD.GE",
+	arm_YIELD_LT:          "YIELD.LT",
+	arm_YIELD_GT:          "YIELD.GT",
+	arm_YIELD_LE:          "YIELD.LE",
+	arm_YIELD:             "YIELD",
+	arm_YIELD_ZZ:          "YIELD.ZZ",
+}
+
+var arm_instFormats = [...]arm_instFormat{
+	{0x0fe00000, 0x02a00000, 2, arm_ADC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_const}},                      // ADC{S}<c> <Rd>,<Rn>,#<const> 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}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> 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}<c> <Rd>,<Rn>,<Rm>{,<shift>} 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}<c> <Rd>,<Rn>,#<const> 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}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> 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}<c> <Rd>,<Rn>,<Rm>{,<shift>} 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}<c> <Rd>,SP,#<const> 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}<c> <Rd>,SP,<Rm>{,<shift>} 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}<c> <Rd>,<Rn>,#<const> 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}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> 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}<c> <Rd>,<Rn>,<Rm>{,<shift>} 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}<c> <Rd>,<Rm>,#<imm5_32> 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}<c> <Rd>,<Rn>,<Rm> 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<c> <label24> 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<c> <Rd>,#<lsb>,#<width> 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<c> <Rd>,<Rn>,#<lsb>,#<width> 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}<c> <Rd>,<Rn>,#<const> 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}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> 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}<c> <Rd>,<Rn>,<Rm>{,<shift>} 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<c> #<imm12+4> 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<c> <label24> cond:4|1|0|1|1|imm24:24
+	{0xfe000000, 0xfa000000, 4, arm_BLX, 0x0, arm_instArgs{arm_arg_label24H}},                                                         // BLX <label24H> 1|1|1|1|1|0|1|H|imm24:24
+	{0x0ffffff0, 0x012fff30, 4, arm_BLX_EQ, 0x1c04, arm_instArgs{arm_arg_R_0}},                                                        // BLX<c> <Rm> 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<c> <Rm> 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<c> <Rm> 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<c> <Rm> 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<c> <Rm> 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<c> <Rm> 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<c> <Rd>,<Rm> 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<c> <Rd>,<Rm> 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<c> <Rn>,#<const> 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<c> <Rn>,#<const> 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<c> <Rn>,<Rm>,<type> <Rs> 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<c> <Rn>,<Rm>,<type> <Rs> 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<c> <Rn>,<Rm>{,<shift>} 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<c> <Rn>,<Rm>{,<shift>} 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<c> <Rn>,#<const> 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<c> <Rn>,#<const> 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<c> <Rn>,<Rm>,<type> <Rs> 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<c> <Rn>,<Rm>,<type> <Rs> 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<c> <Rn>,<Rm>{,<shift>} 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<c> <Rn>,<Rm>{,<shift>} 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<c> #<option> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|1|1|1|1|option:4
+	{0x0fff00f0, 0x0320f0f0, 3, arm_DBG_EQ, 0x1c04, arm_instArgs{arm_arg_option}},                                                     // DBG<c> #<option> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|1|1|1|1|option:4
+	{0xfffffff0, 0xf57ff050, 4, arm_DMB, 0x0, arm_instArgs{arm_arg_option}},                                                           // DMB #<option> 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|1|0|1|option:4
+	{0xfff000f0, 0xf57ff050, 3, arm_DMB, 0x0, arm_instArgs{arm_arg_option}},                                                           // DMB #<option> 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|1|0|1|option:4
+	{0xfffffff0, 0xf57ff040, 4, arm_DSB, 0x0, arm_instArgs{arm_arg_option}},                                                           // DSB #<option> 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|1|0|0|option:4
+	{0xfff000f0, 0xf57ff040, 3, arm_DSB, 0x0, arm_instArgs{arm_arg_option}},                                                           // DSB #<option> 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|1|0|0|option:4
+	{0x0fe00000, 0x02200000, 2, arm_EOR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_const}},                      // EOR{S}<c> <Rd>,<Rn>,#<const> cond:4|0|0|1|0|0|0|1|S|Rn:4|Rd:4|imm12:12
+	{0x0fe00090, 0x00200010, 4, arm_EOR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_R}},                  // EOR{S}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|0|0|0|1|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4
+	{0x0fe00010, 0x00200000, 2, arm_EOR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}},                // EOR{S}<c> <Rd>,<Rn>,<Rm>{,<shift>} cond:4|0|0|0|0|0|0|1|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4
+	{0xfffffff0, 0xf57ff060, 4, arm_ISB, 0x0, arm_instArgs{arm_arg_option}},                                                           // ISB #<option> 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|1|1|0|option:4
+	{0xfff000f0, 0xf57ff060, 3, arm_ISB, 0x0, arm_instArgs{arm_arg_option}},                                                           // ISB #<option> 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|1|1|0|option:4
+	{0x0fd00000, 0x08900000, 2, arm_LDM_EQ, 0x1c04, arm_instArgs{arm_arg_R_16_WB, arm_arg_registers}},                                 // LDM<c> <Rn>{!},<registers> cond:4|1|0|0|0|1|0|W|1|Rn:4|register_list:16
+	{0x0fd00000, 0x08100000, 4, arm_LDMDA_EQ, 0x1c04, arm_instArgs{arm_arg_R_16_WB, arm_arg_registers}},                               // LDMDA<c> <Rn>{!},<registers> cond:4|1|0|0|0|0|0|W|1|Rn:4|register_list:16
+	{0x0fd00000, 0x09100000, 4, arm_LDMDB_EQ, 0x1c04, arm_instArgs{arm_arg_R_16_WB, arm_arg_registers}},                               // LDMDB<c> <Rn>{!},<registers> cond:4|1|0|0|1|0|0|W|1|Rn:4|register_list:16
+	{0x0fd00000, 0x09900000, 4, arm_LDMIB_EQ, 0x1c04, arm_instArgs{arm_arg_R_16_WB, arm_arg_registers}},                               // LDMIB<c> <Rn>{!},<registers> cond:4|1|0|0|1|1|0|W|1|Rn:4|register_list:16
+	{0x0f7f0000, 0x051f0000, 4, arm_LDR_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_label_pm_12}},                                  // LDR<c> <Rt>,<label+/-12> cond:4|0|1|0|(1)|U|0|(0)|1|1|1|1|1|Rt:4|imm12:12
+	{0x0e5f0000, 0x051f0000, 3, arm_LDR_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_label_pm_12}},                                  // LDR<c> <Rt>,<label+/-12> cond:4|0|1|0|(1)|U|0|(0)|1|1|1|1|1|Rt:4|imm12:12
+	{0x0e500010, 0x06100000, 2, arm_LDR_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_shift_imm_W}},                       // LDR<c> <Rt>,[<Rn>,+/-<Rm>{, <shift>}]{!} cond:4|0|1|1|P|U|0|W|1|Rn:4|Rt:4|imm5:5|type:2|0|Rm:4
+	{0x0e500000, 0x04100000, 2, arm_LDR_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm12_W}},                             // LDR<c> <Rt>,[<Rn>{,#+/-<imm12>}]{!} cond:4|0|1|0|P|U|0|W|1|Rn:4|Rt:4|imm12:12
+	{0x0f7f0000, 0x055f0000, 4, arm_LDRB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_label_pm_12}},                                 // LDRB<c> <Rt>,<label+/-12> cond:4|0|1|0|(1)|U|1|(0)|1|1|1|1|1|Rt:4|imm12:12
+	{0x0e5f0000, 0x055f0000, 3, arm_LDRB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_label_pm_12}},                                 // LDRB<c> <Rt>,<label+/-12> cond:4|0|1|0|(1)|U|1|(0)|1|1|1|1|1|Rt:4|imm12:12
+	{0x0e500010, 0x06500000, 2, arm_LDRB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_shift_imm_W}},                      // LDRB<c> <Rt>,[<Rn>,+/-<Rm>{, <shift>}]{!} cond:4|0|1|1|P|U|1|W|1|Rn:4|Rt:4|imm5:5|type:2|0|Rm:4
+	{0x0e500000, 0x04500000, 2, arm_LDRB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm12_W}},                            // LDRB<c> <Rt>,[<Rn>{,#+/-<imm12>}]{!} cond:4|0|1|0|P|U|1|W|1|Rn:4|Rt:4|imm12:12
+	{0x0f700000, 0x04700000, 4, arm_LDRBT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm12_postindex}},                   // LDRBT<c> <Rt>,[<Rn>],#+/-<imm12> cond:4|0|1|0|0|U|1|1|1|Rn:4|Rt:4|imm12:12
+	{0x0f700010, 0x06700000, 4, arm_LDRBT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_shift_imm_postindex}},             // LDRBT<c> <Rt>,[<Rn>],+/-<Rm>{, <shift>} cond:4|0|1|1|0|U|1|1|1|Rn:4|Rt:4|imm5:5|type:2|0|Rm:4
+	{0x0e500ff0, 0x000000d0, 4, arm_LDRD_EQ, 0x1c04, arm_instArgs{arm_arg_R1_12, arm_arg_R2_12, arm_arg_mem_R_pm_R_W}},                // LDRD<c> <Rt1>,<Rt2>,[<Rn>,+/-<Rm>]{!} cond:4|0|0|0|P|U|0|W|0|Rn:4|Rt:4|(0)|(0)|(0)|(0)|1|1|0|1|Rm:4
+	{0x0e5000f0, 0x000000d0, 3, arm_LDRD_EQ, 0x1c04, arm_instArgs{arm_arg_R1_12, arm_arg_R2_12, arm_arg_mem_R_pm_R_W}},                // LDRD<c> <Rt1>,<Rt2>,[<Rn>,+/-<Rm>]{!} cond:4|0|0|0|P|U|0|W|0|Rn:4|Rt:4|(0)|(0)|(0)|(0)|1|1|0|1|Rm:4
+	{0x0e5000f0, 0x004000d0, 2, arm_LDRD_EQ, 0x1c04, arm_instArgs{arm_arg_R1_12, arm_arg_R2_12, arm_arg_mem_R_pm_imm8_W}},             // LDRD<c> <Rt1>,<Rt2>,[<Rn>{,#+/-<imm8>}]{!} cond:4|0|0|0|P|U|1|W|0|Rn:4|Rt:4|imm4H:4|1|1|0|1|imm4L:4
+	{0x0ff00fff, 0x01900f9f, 4, arm_LDREX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R}},                                      // LDREX<c> <Rt>,[<Rn>] cond:4|0|0|0|1|1|0|0|1|Rn:4|Rt:4|(1)|(1)|(1)|(1)|1|0|0|1|(1)|(1)|(1)|(1)
+	{0x0ff000f0, 0x01900f9f, 3, arm_LDREX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R}},                                      // LDREX<c> <Rt>,[<Rn>] cond:4|0|0|0|1|1|0|0|1|Rn:4|Rt:4|(1)|(1)|(1)|(1)|1|0|0|1|(1)|(1)|(1)|(1)
+	{0x0ff00fff, 0x01d00f9f, 4, arm_LDREXB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R}},                                     // LDREXB<c> <Rt>, [<Rn>] cond:4|0|0|0|1|1|1|0|1|Rn:4|Rt:4|(1)|(1)|(1)|(1)|1|0|0|1|(1)|(1)|(1)|(1)
+	{0x0ff000f0, 0x01d00f9f, 3, arm_LDREXB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R}},                                     // LDREXB<c> <Rt>, [<Rn>] cond:4|0|0|0|1|1|1|0|1|Rn:4|Rt:4|(1)|(1)|(1)|(1)|1|0|0|1|(1)|(1)|(1)|(1)
+	{0x0ff00fff, 0x01b00f9f, 4, arm_LDREXD_EQ, 0x1c04, arm_instArgs{arm_arg_R1_12, arm_arg_R2_12, arm_arg_mem_R}},                     // LDREXD<c> <Rt1>,<Rt2>,[<Rn>] cond:4|0|0|0|1|1|0|1|1|Rn:4|Rt:4|(1)|(1)|(1)|(1)|1|0|0|1|(1)|(1)|(1)|(1)
+	{0x0ff000f0, 0x01b00f9f, 3, arm_LDREXD_EQ, 0x1c04, arm_instArgs{arm_arg_R1_12, arm_arg_R2_12, arm_arg_mem_R}},                     // LDREXD<c> <Rt1>,<Rt2>,[<Rn>] cond:4|0|0|0|1|1|0|1|1|Rn:4|Rt:4|(1)|(1)|(1)|(1)|1|0|0|1|(1)|(1)|(1)|(1)
+	{0x0ff00fff, 0x01f00f9f, 4, arm_LDREXH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R}},                                     // LDREXH<c> <Rt>, [<Rn>] cond:4|0|0|0|1|1|1|1|1|Rn:4|Rt:4|(1)|(1)|(1)|(1)|1|0|0|1|(1)|(1)|(1)|(1)
+	{0x0ff000f0, 0x01f00f9f, 3, arm_LDREXH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R}},                                     // LDREXH<c> <Rt>, [<Rn>] cond:4|0|0|0|1|1|1|1|1|Rn:4|Rt:4|(1)|(1)|(1)|(1)|1|0|0|1|(1)|(1)|(1)|(1)
+	{0x0e500ff0, 0x001000b0, 2, arm_LDRH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_W}},                                // LDRH<c> <Rt>,[<Rn>,+/-<Rm>]{!} cond:4|0|0|0|P|U|0|W|1|Rn:4|Rt:4|0|0|0|0|1|0|1|1|Rm:4
+	{0x0e5000f0, 0x005000b0, 2, arm_LDRH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm8_W}},                             // LDRH<c> <Rt>,[<Rn>{,#+/-<imm8>}]{!} cond:4|0|0|0|P|U|1|W|1|Rn:4|Rt:4|imm4H:4|1|0|1|1|imm4L:4
+	{0x0f7000f0, 0x007000b0, 4, arm_LDRHT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm8_postindex}},                    // LDRHT<c> <Rt>, [<Rn>] {,#+/-<imm8>} cond:4|0|0|0|0|U|1|1|1|Rn:4|Rt:4|imm4H:4|1|0|1|1|imm4L:4
+	{0x0f700ff0, 0x003000b0, 4, arm_LDRHT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_postindex}},                       // LDRHT<c> <Rt>, [<Rn>], +/-<Rm> cond:4|0|0|0|0|U|0|1|1|Rn:4|Rt:4|0|0|0|0|1|0|1|1|Rm:4
+	{0x0e500ff0, 0x001000d0, 2, arm_LDRSB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_W}},                               // LDRSB<c> <Rt>,[<Rn>,+/-<Rm>]{!} cond:4|0|0|0|P|U|0|W|1|Rn:4|Rt:4|0|0|0|0|1|1|0|1|Rm:4
+	{0x0e5000f0, 0x005000d0, 2, arm_LDRSB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm8_W}},                            // LDRSB<c> <Rt>,[<Rn>{,#+/-<imm8>}]{!} cond:4|0|0|0|P|U|1|W|1|Rn:4|Rt:4|imm4H:4|1|1|0|1|imm4L:4
+	{0x0f7000f0, 0x007000d0, 4, arm_LDRSBT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm8_postindex}},                   // LDRSBT<c> <Rt>, [<Rn>] {,#+/-<imm8>} cond:4|0|0|0|0|U|1|1|1|Rn:4|Rt:4|imm4H:4|1|1|0|1|imm4L:4
+	{0x0f700ff0, 0x003000d0, 4, arm_LDRSBT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_postindex}},                      // LDRSBT<c> <Rt>, [<Rn>], +/-<Rm> cond:4|0|0|0|0|U|0|1|1|Rn:4|Rt:4|0|0|0|0|1|1|0|1|Rm:4
+	{0x0e500ff0, 0x001000f0, 2, arm_LDRSH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_W}},                               // LDRSH<c> <Rt>,[<Rn>,+/-<Rm>]{!} cond:4|0|0|0|P|U|0|W|1|Rn:4|Rt:4|0|0|0|0|1|1|1|1|Rm:4
+	{0x0e5000f0, 0x005000f0, 2, arm_LDRSH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm8_W}},                            // LDRSH<c> <Rt>,[<Rn>{,#+/-<imm8>}]{!} cond:4|0|0|0|P|U|1|W|1|Rn:4|Rt:4|imm4H:4|1|1|1|1|imm4L:4
+	{0x0f7000f0, 0x007000f0, 4, arm_LDRSHT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm8_postindex}},                   // LDRSHT<c> <Rt>, [<Rn>] {,#+/-<imm8>} cond:4|0|0|0|0|U|1|1|1|Rn:4|Rt:4|imm4H:4|1|1|1|1|imm4L:4
+	{0x0f700ff0, 0x003000f0, 4, arm_LDRSHT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_postindex}},                      // LDRSHT<c> <Rt>, [<Rn>], +/-<Rm> cond:4|0|0|0|0|U|0|1|1|Rn:4|Rt:4|0|0|0|0|1|1|1|1|Rm:4
+	{0x0f700000, 0x04300000, 4, arm_LDRT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm12_postindex}},                    // LDRT<c> <Rt>, [<Rn>] {,#+/-<imm12>} cond:4|0|1|0|0|U|0|1|1|Rn:4|Rt:4|imm12:12
+	{0x0f700010, 0x06300000, 4, arm_LDRT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_shift_imm_postindex}},              // LDRT<c> <Rt>,[<Rn>],+/-<Rm>{, <shift>} cond:4|0|1|1|0|U|0|1|1|Rn:4|Rt:4|imm5:5|type:2|0|Rm:4
+	{0x0fef0070, 0x01a00000, 2, arm_LSL_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_imm5_nz}},                     // LSL{S}<c> <Rd>,<Rm>,#<imm5_nz> cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|imm5:5|0|0|0|Rm:4
+	{0x0fef00f0, 0x01a00010, 4, arm_LSL_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_R_8}},                         // LSL{S}<c> <Rd>,<Rn>,<Rm> cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|Rm:4|0|0|0|1|Rn:4
+	{0x0fef0070, 0x01a00020, 4, arm_LSR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_imm5_32}},                     // LSR{S}<c> <Rd>,<Rm>,#<imm5_32> cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|imm5:5|0|1|0|Rm:4
+	{0x0fef00f0, 0x01a00030, 4, arm_LSR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_R_8}},                         // LSR{S}<c> <Rd>,<Rn>,<Rm> cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|Rm:4|0|0|1|1|Rn:4
+	{0x0fe000f0, 0x00200090, 4, arm_MLA_EQ, 0x14011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8, arm_arg_R_12}},           // MLA{S}<c> <Rd>,<Rn>,<Rm>,<Ra> cond:4|0|0|0|0|0|0|1|S|Rd:4|Ra:4|Rm:4|1|0|0|1|Rn:4
+	{0x0ff000f0, 0x00600090, 4, arm_MLS_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8, arm_arg_R_12}},               // MLS<c> <Rd>,<Rn>,<Rm>,<Ra> cond:4|0|0|0|0|0|1|1|0|Rd:4|Ra:4|Rm:4|1|0|0|1|Rn:4
+	{0x0ff00000, 0x03400000, 4, arm_MOVT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_imm_4at16_12at0}},                             // MOVT<c> <Rd>,#<imm12+4> cond:4|0|0|1|1|0|1|0|0|imm4:4|Rd:4|imm12:12
+	{0x0ff00000, 0x03000000, 4, arm_MOVW_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_imm_4at16_12at0}},                             // MOVW<c> <Rd>,#<imm12+4> cond:4|0|0|1|1|0|0|0|0|imm4:4|Rd:4|imm12:12
+	{0x0fef0000, 0x03a00000, 2, arm_MOV_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_const}},                                    // MOV{S}<c> <Rd>,#<const> cond:4|0|0|1|1|1|0|1|S|0|0|0|0|Rd:4|imm12:12
+	{0x0fef0ff0, 0x01a00000, 2, arm_MOV_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}},                                      // MOV{S}<c> <Rd>,<Rm> cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|0|0|0|0|0|0|0|0|Rm:4
+	{0x0fff0fff, 0x010f0000, 4, arm_MRS_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_APSR}},                                         // MRS<c> <Rd>,APSR cond:4|0|0|0|1|0|0|0|0|(1)|(1)|(1)|(1)|Rd:4|(0)|(0)|(0)|(0)|0|0|0|0|(0)|(0)|(0)|(0)
+	{0x0ff000f0, 0x010f0000, 3, arm_MRS_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_APSR}},                                         // MRS<c> <Rd>,APSR cond:4|0|0|0|1|0|0|0|0|(1)|(1)|(1)|(1)|Rd:4|(0)|(0)|(0)|(0)|0|0|0|0|(0)|(0)|(0)|(0)
+	{0x0fe0f0f0, 0x00000090, 4, arm_MUL_EQ, 0x14011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}},                         // MUL{S}<c> <Rd>,<Rn>,<Rm> cond:4|0|0|0|0|0|0|0|S|Rd:4|(0)|(0)|(0)|(0)|Rm:4|1|0|0|1|Rn:4
+	{0x0fe000f0, 0x00000090, 3, arm_MUL_EQ, 0x14011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}},                         // MUL{S}<c> <Rd>,<Rn>,<Rm> cond:4|0|0|0|0|0|0|0|S|Rd:4|(0)|(0)|(0)|(0)|Rm:4|1|0|0|1|Rn:4
+	{0x0fef0000, 0x03e00000, 2, arm_MVN_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_const}},                                    // MVN{S}<c> <Rd>,#<const> cond:4|0|0|1|1|1|1|1|S|(0)|(0)|(0)|(0)|Rd:4|imm12:12
+	{0x0fe00000, 0x03e00000, 1, arm_MVN_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_const}},                                    // MVN{S}<c> <Rd>,#<const> cond:4|0|0|1|1|1|1|1|S|(0)|(0)|(0)|(0)|Rd:4|imm12:12
+	{0x0fef0090, 0x01e00010, 4, arm_MVN_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_shift_R}},                                // MVN{S}<c> <Rd>,<Rm>,<type> <Rs> cond:4|0|0|0|1|1|1|1|S|(0)|(0)|(0)|(0)|Rd:4|Rs:4|0|type:2|1|Rm:4
+	{0x0fe00090, 0x01e00010, 3, arm_MVN_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_shift_R}},                                // MVN{S}<c> <Rd>,<Rm>,<type> <Rs> cond:4|0|0|0|1|1|1|1|S|(0)|(0)|(0)|(0)|Rd:4|Rs:4|0|type:2|1|Rm:4
+	{0x0fef0010, 0x01e00000, 2, arm_MVN_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_shift_imm}},                              // MVN{S}<c> <Rd>,<Rm>{,<shift>} cond:4|0|0|0|1|1|1|1|S|(0)|(0)|(0)|(0)|Rd:4|imm5:5|type:2|0|Rm:4
+	{0x0fe00010, 0x01e00000, 1, arm_MVN_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_shift_imm}},                              // MVN{S}<c> <Rd>,<Rm>{,<shift>} cond:4|0|0|0|1|1|1|1|S|(0)|(0)|(0)|(0)|Rd:4|imm5:5|type:2|0|Rm:4
+	{0x0fffffff, 0x0320f000, 4, arm_NOP_EQ, 0x1c04, arm_instArgs{}},                                                                   // NOP<c> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|0|0|0|0|0
+	{0x0fff00ff, 0x0320f000, 3, arm_NOP_EQ, 0x1c04, arm_instArgs{}},                                                                   // NOP<c> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|0|0|0|0|0
+	{0x0fe00000, 0x03800000, 2, arm_ORR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_const}},                      // ORR{S}<c> <Rd>,<Rn>,#<const> cond:4|0|0|1|1|1|0|0|S|Rn:4|Rd:4|imm12:12
+	{0x0fe00090, 0x01800010, 4, arm_ORR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_R}},                  // ORR{S}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|1|1|0|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4
+	{0x0fe00010, 0x01800000, 2, arm_ORR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}},                // ORR{S}<c> <Rd>,<Rn>,<Rm>{,<shift>} cond:4|0|0|0|1|1|0|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4
+	{0x0ff00030, 0x06800010, 4, arm_PKHBT_EQ, 0x6011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}},               // PKH<BT,TB><c> <Rd>,<Rn>,<Rm>{,LSL #<imm5>} cond:4|0|1|1|0|1|0|0|0|Rn:4|Rd:4|imm5:5|tb|0|1|Rm:4
+	{0xff7ff000, 0xf55ff000, 4, arm_PLD, 0x0, arm_instArgs{arm_arg_label_pm_12}},                                                      // PLD <label+/-12> 1|1|1|1|0|1|0|1|U|(1)|0|1|1|1|1|1|(1)|(1)|(1)|(1)|imm12:12
+	{0xff3f0000, 0xf55ff000, 3, arm_PLD, 0x0, arm_instArgs{arm_arg_label_pm_12}},                                                      // PLD <label+/-12> 1|1|1|1|0|1|0|1|U|(1)|0|1|1|1|1|1|(1)|(1)|(1)|(1)|imm12:12
+	{0xff30f000, 0xf510f000, 2, arm_PLD_W, 0x1601, arm_instArgs{arm_arg_mem_R_pm_imm12_offset}},                                       // PLD{W} [<Rn>,#+/-<imm12>] 1|1|1|1|0|1|0|1|U|R|0|1|Rn:4|(1)|(1)|(1)|(1)|imm12:12
+	{0xff300000, 0xf510f000, 1, arm_PLD_W, 0x1601, arm_instArgs{arm_arg_mem_R_pm_imm12_offset}},                                       // PLD{W} [<Rn>,#+/-<imm12>] 1|1|1|1|0|1|0|1|U|R|0|1|Rn:4|(1)|(1)|(1)|(1)|imm12:12
+	{0xff30f010, 0xf710f000, 4, arm_PLD_W, 0x1601, arm_instArgs{arm_arg_mem_R_pm_R_shift_imm_offset}},                                 // PLD{W} [<Rn>,+/-<Rm>{, <shift>}] 1|1|1|1|0|1|1|1|U|R|0|1|Rn:4|(1)|(1)|(1)|(1)|imm5:5|type:2|0|Rm:4
+	{0xff300010, 0xf710f000, 3, arm_PLD_W, 0x1601, arm_instArgs{arm_arg_mem_R_pm_R_shift_imm_offset}},                                 // PLD{W} [<Rn>,+/-<Rm>{, <shift>}] 1|1|1|1|0|1|1|1|U|R|0|1|Rn:4|(1)|(1)|(1)|(1)|imm5:5|type:2|0|Rm:4
+	{0xff70f000, 0xf450f000, 4, arm_PLI, 0x0, arm_instArgs{arm_arg_mem_R_pm_imm12_offset}},                                            // PLI [<Rn>,#+/-<imm12>] 1|1|1|1|0|1|0|0|U|1|0|1|Rn:4|(1)|(1)|(1)|(1)|imm12:12
+	{0xff700000, 0xf450f000, 3, arm_PLI, 0x0, arm_instArgs{arm_arg_mem_R_pm_imm12_offset}},                                            // PLI [<Rn>,#+/-<imm12>] 1|1|1|1|0|1|0|0|U|1|0|1|Rn:4|(1)|(1)|(1)|(1)|imm12:12
+	{0xff70f010, 0xf650f000, 4, arm_PLI, 0x0, arm_instArgs{arm_arg_mem_R_pm_R_shift_imm_offset}},                                      // PLI [<Rn>,+/-<Rm>{, <shift>}] 1|1|1|1|0|1|1|0|U|1|0|1|Rn:4|(1)|(1)|(1)|(1)|imm5:5|type:2|0|Rm:4
+	{0xff700010, 0xf650f000, 3, arm_PLI, 0x0, arm_instArgs{arm_arg_mem_R_pm_R_shift_imm_offset}},                                      // PLI [<Rn>,+/-<Rm>{, <shift>}] 1|1|1|1|0|1|1|0|U|1|0|1|Rn:4|(1)|(1)|(1)|(1)|imm5:5|type:2|0|Rm:4
+	{0x0fff0000, 0x08bd0000, 4, arm_POP_EQ, 0x1c04, arm_instArgs{arm_arg_registers2}},                                                 // POP<c> <registers2> cond:4|1|0|0|0|1|0|1|1|1|1|0|1|register_list:16
+	{0x0fff0fff, 0x049d0004, 4, arm_POP_EQ, 0x1c04, arm_instArgs{arm_arg_registers1}},                                                 // POP<c> <registers1> cond:4|0|1|0|0|1|0|0|1|1|1|0|1|Rt:4|0|0|0|0|0|0|0|0|0|1|0|0
+	{0x0fff0000, 0x092d0000, 4, arm_PUSH_EQ, 0x1c04, arm_instArgs{arm_arg_registers2}},                                                // PUSH<c> <registers2> cond:4|1|0|0|1|0|0|1|0|1|1|0|1|register_list:16
+	{0x0fff0fff, 0x052d0004, 4, arm_PUSH_EQ, 0x1c04, arm_instArgs{arm_arg_registers1}},                                                // PUSH<c> <registers1> cond:4|0|1|0|1|0|0|1|0|1|1|0|1|Rt:4|0|0|0|0|0|0|0|0|0|1|0|0
+	{0x0ff00ff0, 0x06200f10, 4, arm_QADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // QADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+	{0x0ff000f0, 0x06200f10, 3, arm_QADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // QADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+	{0x0ff00ff0, 0x06200f90, 4, arm_QADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // QADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+	{0x0ff000f0, 0x06200f90, 3, arm_QADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // QADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+	{0x0ff00ff0, 0x01000050, 4, arm_QADD_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_R_16}},                           // QADD<c> <Rd>,<Rm>,<Rn> cond:4|0|0|0|1|0|0|0|0|Rn:4|Rd:4|(0)|(0)|(0)|(0)|0|1|0|1|Rm:4
+	{0x0ff000f0, 0x01000050, 3, arm_QADD_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_R_16}},                           // QADD<c> <Rd>,<Rm>,<Rn> cond:4|0|0|0|1|0|0|0|0|Rn:4|Rd:4|(0)|(0)|(0)|(0)|0|1|0|1|Rm:4
+	{0x0ff00ff0, 0x06200f30, 4, arm_QASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                           // QASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+	{0x0ff000f0, 0x06200f30, 3, arm_QASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                           // QASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+	{0x0ff00ff0, 0x01400050, 4, arm_QDADD_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_R_16}},                          // QDADD<c> <Rd>,<Rm>,<Rn> cond:4|0|0|0|1|0|1|0|0|Rn:4|Rd:4|(0)|(0)|(0)|(0)|0|1|0|1|Rm:4
+	{0x0ff000f0, 0x01400050, 3, arm_QDADD_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_R_16}},                          // QDADD<c> <Rd>,<Rm>,<Rn> cond:4|0|0|0|1|0|1|0|0|Rn:4|Rd:4|(0)|(0)|(0)|(0)|0|1|0|1|Rm:4
+	{0x0ff00ff0, 0x01600050, 4, arm_QDSUB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_R_16}},                          // QDSUB<c> <Rd>,<Rm>,<Rn> cond:4|0|0|0|1|0|1|1|0|Rn:4|Rd:4|0|0|0|0|0|1|0|1|Rm:4
+	{0x0ff00ff0, 0x06200f50, 4, arm_QSAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                           // QSAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+	{0x0ff000f0, 0x06200f50, 3, arm_QSAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                           // QSAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+	{0x0ff00ff0, 0x06200f70, 4, arm_QSUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // QSUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+	{0x0ff000f0, 0x06200f70, 3, arm_QSUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // QSUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+	{0x0ff00ff0, 0x06200ff0, 4, arm_QSUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // QSUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+	{0x0ff000f0, 0x06200ff0, 3, arm_QSUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // QSUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+	{0x0ff00ff0, 0x01200050, 4, arm_QSUB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_R_16}},                           // QSUB<c> <Rd>,<Rm>,<Rn> cond:4|0|0|0|1|0|0|1|0|Rn:4|Rd:4|0|0|0|0|0|1|0|1|Rm:4
+	{0x0fff0ff0, 0x06ff0f30, 4, arm_RBIT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}},                                         // RBIT<c> <Rd>,<Rm> cond:4|0|1|1|0|1|1|1|1|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+	{0x0ff000f0, 0x06ff0f30, 3, arm_RBIT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}},                                         // RBIT<c> <Rd>,<Rm> cond:4|0|1|1|0|1|1|1|1|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+	{0x0fff0ff0, 0x06bf0fb0, 4, arm_REV16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}},                                        // REV16<c> <Rd>,<Rm> cond:4|0|1|1|0|1|0|1|1|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|1|0|1|1|Rm:4
+	{0x0ff000f0, 0x06bf0fb0, 3, arm_REV16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}},                                        // REV16<c> <Rd>,<Rm> cond:4|0|1|1|0|1|0|1|1|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|1|0|1|1|Rm:4
+	{0x0fff0ff0, 0x06bf0f30, 4, arm_REV_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}},                                          // REV<c> <Rd>,<Rm> cond:4|0|1|1|0|1|0|1|1|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+	{0x0ff000f0, 0x06bf0f30, 3, arm_REV_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}},                                          // REV<c> <Rd>,<Rm> cond:4|0|1|1|0|1|0|1|1|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+	{0x0fff0ff0, 0x06ff0fb0, 4, arm_REVSH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}},                                        // REVSH<c> <Rd>,<Rm> cond:4|0|1|1|0|1|1|1|1|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|1|0|1|1|Rm:4
+	{0x0ff000f0, 0x06ff0fb0, 3, arm_REVSH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}},                                        // REVSH<c> <Rd>,<Rm> cond:4|0|1|1|0|1|1|1|1|(1)|(1)|(1)|(1)|Rd:4|(1)|(1)|(1)|(1)|1|0|1|1|Rm:4
+	{0x0fef0070, 0x01a00060, 2, arm_ROR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_imm5}},                        // ROR{S}<c> <Rd>,<Rm>,#<imm5> cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|imm5:5|1|1|0|Rm:4
+	{0x0fef00f0, 0x01a00070, 4, arm_ROR_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_R_8}},                         // ROR{S}<c> <Rd>,<Rn>,<Rm> cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|Rm:4|0|1|1|1|Rn:4
+	{0x0fef0ff0, 0x01a00060, 4, arm_RRX_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0}},                                      // RRX{S}<c> <Rd>,<Rm> cond:4|0|0|0|1|1|0|1|S|0|0|0|0|Rd:4|0|0|0|0|0|1|1|0|Rm:4
+	{0x0fe00000, 0x02600000, 2, arm_RSB_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_const}},                      // RSB{S}<c> <Rd>,<Rn>,#<const> cond:4|0|0|1|0|0|1|1|S|Rn:4|Rd:4|imm12:12
+	{0x0fe00090, 0x00600010, 4, arm_RSB_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_R}},                  // RSB{S}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|0|0|1|1|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4
+	{0x0fe00010, 0x00600000, 2, arm_RSB_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}},                // RSB{S}<c> <Rd>,<Rn>,<Rm>{,<shift>} cond:4|0|0|0|0|0|1|1|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4
+	{0x0fe00000, 0x02e00000, 2, arm_RSC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_const}},                      // RSC{S}<c> <Rd>,<Rn>,#<const> cond:4|0|0|1|0|1|1|1|S|Rn:4|Rd:4|imm12:12
+	{0x0fe00090, 0x00e00010, 4, arm_RSC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_R}},                  // RSC{S}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|0|1|1|1|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4
+	{0x0fe00010, 0x00e00000, 2, arm_RSC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}},                // RSC{S}<c> <Rd>,<Rn>,<Rm>{,<shift>} cond:4|0|0|0|0|1|1|1|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4
+	{0x0ff00ff0, 0x06100f10, 4, arm_SADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // SADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+	{0x0ff000f0, 0x06100f10, 3, arm_SADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // SADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+	{0x0ff00ff0, 0x06100f90, 4, arm_SADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // SADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+	{0x0ff000f0, 0x06100f90, 3, arm_SADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // SADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+	{0x0ff00ff0, 0x06100f30, 4, arm_SASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                           // SASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+	{0x0ff000f0, 0x06100f30, 3, arm_SASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                           // SASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+	{0x0fe00000, 0x02c00000, 2, arm_SBC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_const}},                      // SBC{S}<c> <Rd>,<Rn>,#<const> cond:4|0|0|1|0|1|1|0|S|Rn:4|Rd:4|imm12:12
+	{0x0fe00090, 0x00c00010, 4, arm_SBC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_R}},                  // SBC{S}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|0|1|1|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4
+	{0x0fe00010, 0x00c00000, 2, arm_SBC_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}},                // SBC{S}<c> <Rd>,<Rn>,<Rm>{,<shift>} cond:4|0|0|0|0|1|1|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4
+	{0x0fe00070, 0x07a00050, 4, arm_SBFX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_imm5, arm_arg_widthm1}},          // SBFX<c> <Rd>,<Rn>,#<lsb>,#<widthm1> cond:4|0|1|1|1|1|0|1|widthm1:5|Rd:4|lsb:5|1|0|1|Rn:4
+	{0x0ff00ff0, 0x06800fb0, 4, arm_SEL_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                            // SEL<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|1|0|0|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|1|1|Rm:4
+	{0x0ff000f0, 0x06800fb0, 3, arm_SEL_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                            // SEL<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|1|0|0|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|1|1|Rm:4
+	{0xfffffdff, 0xf1010000, 4, arm_SETEND, 0x0, arm_instArgs{arm_arg_endian}},                                                        // SETEND <endian_specifier> 1|1|1|1|0|0|0|1|0|0|0|0|0|0|0|1|0|0|0|0|0|0|E|(0)|(0)|(0)|(0)|(0)|(0)|(0)|(0)|(0)
+	{0xfffffc00, 0xf1010000, 3, arm_SETEND, 0x0, arm_instArgs{arm_arg_endian}},                                                        // SETEND <endian_specifier> 1|1|1|1|0|0|0|1|0|0|0|0|0|0|0|1|0|0|0|0|0|0|E|(0)|(0)|(0)|(0)|(0)|(0)|(0)|(0)|(0)
+	{0x0fffffff, 0x0320f004, 4, arm_SEV_EQ, 0x1c04, arm_instArgs{}},                                                                   // SEV<c> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|0|0|1|0|0
+	{0x0fff00ff, 0x0320f004, 3, arm_SEV_EQ, 0x1c04, arm_instArgs{}},                                                                   // SEV<c> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|0|0|1|0|0
+	{0x0ff00ff0, 0x06300f10, 4, arm_SHADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                        // SHADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+	{0x0ff000f0, 0x06300f10, 3, arm_SHADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                        // SHADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+	{0x0ff00ff0, 0x06300f90, 4, arm_SHADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // SHADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+	{0x0ff000f0, 0x06300f90, 3, arm_SHADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // SHADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+	{0x0ff00ff0, 0x06300f30, 4, arm_SHASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // SHASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+	{0x0ff000f0, 0x06300f30, 3, arm_SHASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // SHASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+	{0x0ff00ff0, 0x06300f50, 4, arm_SHSAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // SHSAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+	{0x0ff000f0, 0x06300f50, 3, arm_SHSAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // SHSAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+	{0x0ff00ff0, 0x06300f70, 4, arm_SHSUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                        // SHSUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+	{0x0ff000f0, 0x06300f70, 3, arm_SHSUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                        // SHSUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+	{0x0ff00ff0, 0x06300ff0, 4, arm_SHSUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // SHSUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+	{0x0ff000f0, 0x06300ff0, 3, arm_SHSUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // SHSUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+	{0x0ff00090, 0x01000080, 4, arm_SMLABB_EQ, 0x50106011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8, arm_arg_R_12}},     // SMLA<x><y><c> <Rd>,<Rn>,<Rm>,<Ra> cond:4|0|0|0|1|0|0|0|0|Rd:4|Ra:4|Rm:4|1|M|N|0|Rn:4
+	{0x0ff000d0, 0x07000010, 2, arm_SMLAD_EQ, 0x5011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8, arm_arg_R_12}},          // SMLAD{X}<c> <Rd>,<Rn>,<Rm>,<Ra> cond:4|0|1|1|1|0|0|0|0|Rd:4|Ra:4|Rm:4|0|0|M|1|Rn:4
+	{0x0ff00090, 0x01400080, 4, arm_SMLALBB_EQ, 0x50106011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}},    // SMLAL<x><y><c> <RdLo>,<RdHi>,<Rn>,<Rm> cond:4|0|0|0|1|0|1|0|0|RdHi:4|RdLo:4|Rm:4|1|M|N|0|Rn:4
+	{0x0ff000d0, 0x07400010, 4, arm_SMLALD_EQ, 0x5011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}},         // SMLALD{X}<c> <RdLo>,<RdHi>,<Rn>,<Rm> cond:4|0|1|1|1|0|1|0|0|RdHi:4|RdLo:4|Rm:4|0|0|M|1|Rn:4
+	{0x0fe000f0, 0x00e00090, 4, arm_SMLAL_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}},         // SMLAL{S}<c> <RdLo>,<RdHi>,<Rn>,<Rm> cond:4|0|0|0|0|1|1|1|S|RdHi:4|RdLo:4|Rm:4|1|0|0|1|Rn:4
+	{0x0ff000b0, 0x01200080, 4, arm_SMLAWB_EQ, 0x6011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8, arm_arg_R_12}},         // SMLAW<y><c> <Rd>,<Rn>,<Rm>,<Ra> cond:4|0|0|0|1|0|0|1|0|Rd:4|Ra:4|Rm:4|1|M|0|0|Rn:4
+	{0x0ff000d0, 0x07000050, 2, arm_SMLSD_EQ, 0x5011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8, arm_arg_R_12}},          // SMLSD{X}<c> <Rd>,<Rn>,<Rm>,<Ra> cond:4|0|1|1|1|0|0|0|0|Rd:4|Ra:4|Rm:4|0|1|M|1|Rn:4
+	{0x0ff000d0, 0x07400050, 4, arm_SMLSLD_EQ, 0x5011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}},         // SMLSLD{X}<c> <RdLo>,<RdHi>,<Rn>,<Rm> cond:4|0|1|1|1|0|1|0|0|RdHi:4|RdLo:4|Rm:4|0|1|M|1|Rn:4
+	{0x0ff000d0, 0x07500010, 2, arm_SMMLA_EQ, 0x5011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8, arm_arg_R_12}},          // SMMLA{R}<c> <Rd>,<Rn>,<Rm>,<Ra> cond:4|0|1|1|1|0|1|0|1|Rd:4|Ra:4|Rm:4|0|0|R|1|Rn:4
+	{0x0ff000d0, 0x075000d0, 4, arm_SMMLS_EQ, 0x5011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8, arm_arg_R_12}},          // SMMLS{R}<c> <Rd>,<Rn>,<Rm>,<Ra> cond:4|0|1|1|1|0|1|0|1|Rd:4|Ra:4|Rm:4|1|1|R|1|Rn:4
+	{0x0ff0f0d0, 0x0750f010, 4, arm_SMMUL_EQ, 0x5011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}},                        // SMMUL{R}<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|1|0|1|0|1|Rd:4|1|1|1|1|Rm:4|0|0|R|1|Rn:4
+	{0x0ff0f0d0, 0x0700f010, 4, arm_SMUAD_EQ, 0x5011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}},                        // SMUAD{X}<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|1|0|0|0|0|Rd:4|1|1|1|1|Rm:4|0|0|M|1|Rn:4
+	{0x0ff0f090, 0x01600080, 4, arm_SMULBB_EQ, 0x50106011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}},                   // SMUL<x><y><c> <Rd>,<Rn>,<Rm> cond:4|0|0|0|1|0|1|1|0|Rd:4|0|0|0|0|Rm:4|1|M|N|0|Rn:4
+	{0x0fe000f0, 0x00c00090, 4, arm_SMULL_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}},         // SMULL{S}<c> <RdLo>,<RdHi>,<Rn>,<Rm> cond:4|0|0|0|0|1|1|0|S|RdHi:4|RdLo:4|Rm:4|1|0|0|1|Rn:4
+	{0x0ff0f0b0, 0x012000a0, 4, arm_SMULWB_EQ, 0x6011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}},                       // SMULW<y><c> <Rd>,<Rn>,<Rm> cond:4|0|0|0|1|0|0|1|0|Rd:4|0|0|0|0|Rm:4|1|M|1|0|Rn:4
+	{0x0ff0f0d0, 0x0700f050, 4, arm_SMUSD_EQ, 0x5011c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}},                        // SMUSD{X}<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|1|0|0|0|0|Rd:4|1|1|1|1|Rm:4|0|1|M|1|Rn:4
+	{0x0ff00ff0, 0x06a00f30, 4, arm_SSAT16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_satimm4m1, arm_arg_R_0}},                    // SSAT16<c> <Rd>,#<sat_imm4m1>,<Rn> cond:4|0|1|1|0|1|0|1|0|sat_imm:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rn:4
+	{0x0ff000f0, 0x06a00f30, 3, arm_SSAT16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_satimm4m1, arm_arg_R_0}},                    // SSAT16<c> <Rd>,#<sat_imm4m1>,<Rn> cond:4|0|1|1|0|1|0|1|0|sat_imm:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rn:4
+	{0x0fe00030, 0x06a00010, 4, arm_SSAT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_satimm5m1, arm_arg_R_shift_imm}},              // SSAT<c> <Rd>,#<sat_imm5m1>,<Rn>{,<shift>} cond:4|0|1|1|0|1|0|1|sat_imm:5|Rd:4|imm5:5|sh|0|1|Rn:4
+	{0x0ff00ff0, 0x06100f50, 4, arm_SSAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                           // SSAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+	{0x0ff000f0, 0x06100f50, 3, arm_SSAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                           // SSAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+	{0x0ff00ff0, 0x06100f70, 4, arm_SSUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // SSUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+	{0x0ff000f0, 0x06100f70, 3, arm_SSUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // SSUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+	{0x0ff00ff0, 0x06100ff0, 4, arm_SSUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // SSUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+	{0x0ff000f0, 0x06100ff0, 3, arm_SSUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // SSUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|0|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+	{0x0fd00000, 0x08800000, 4, arm_STM_EQ, 0x1c04, arm_instArgs{arm_arg_R_16_WB, arm_arg_registers}},                                 // STM<c> <Rn>{!},<registers> cond:4|1|0|0|0|1|0|W|0|Rn:4|register_list:16
+	{0x0fd00000, 0x08000000, 4, arm_STMDA_EQ, 0x1c04, arm_instArgs{arm_arg_R_16_WB, arm_arg_registers}},                               // STMDA<c> <Rn>{!},<registers> cond:4|1|0|0|0|0|0|W|0|Rn:4|register_list:16
+	{0x0fd00000, 0x09000000, 2, arm_STMDB_EQ, 0x1c04, arm_instArgs{arm_arg_R_16_WB, arm_arg_registers}},                               // STMDB<c> <Rn>{!},<registers> cond:4|1|0|0|1|0|0|W|0|Rn:4|register_list:16
+	{0x0fd00000, 0x09800000, 4, arm_STMIB_EQ, 0x1c04, arm_instArgs{arm_arg_R_16_WB, arm_arg_registers}},                               // STMIB<c> <Rn>{!},<registers> cond:4|1|0|0|1|1|0|W|0|Rn:4|register_list:16
+	{0x0e500018, 0x06000000, 2, arm_STR_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_shift_imm_W}},                       // STR<c> <Rt>,[<Rn>,+/-<Rm>{, <shift>}]{!} cond:4|0|1|1|P|U|0|W|0|Rn:4|Rt:4|imm5:5|type:2|0|Rm:4
+	{0x0e500000, 0x04000000, 2, arm_STR_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm12_W}},                             // STR<c> <Rt>,[<Rn>{,#+/-<imm12>}]{!} cond:4|0|1|0|P|U|0|W|0|Rn:4|Rt:4|imm12:12
+	{0x0e500010, 0x06400000, 2, arm_STRB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_shift_imm_W}},                      // STRB<c> <Rt>,[<Rn>,+/-<Rm>{, <shift>}]{!} cond:4|0|1|1|P|U|1|W|0|Rn:4|Rt:4|imm5:5|type:2|0|Rm:4
+	{0x0e500000, 0x04400000, 2, arm_STRB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm12_W}},                            // STRB<c> <Rt>,[<Rn>{,#+/-<imm12>}]{!} cond:4|0|1|0|P|U|1|W|0|Rn:4|Rt:4|imm12:12
+	{0x0f700000, 0x04600000, 4, arm_STRBT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm12_postindex}},                   // STRBT<c> <Rt>,[<Rn>],#+/-<imm12> cond:4|0|1|0|0|U|1|1|0|Rn:4|Rt:4|imm12:12
+	{0x0f700010, 0x06600000, 4, arm_STRBT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_shift_imm_postindex}},             // STRBT<c> <Rt>,[<Rn>],+/-<Rm>{, <shift>} cond:4|0|1|1|0|U|1|1|0|Rn:4|Rt:4|imm5:5|type:2|0|Rm:4
+	{0x0e500ff0, 0x000000f0, 4, arm_STRD_EQ, 0x1c04, arm_instArgs{arm_arg_R1_12, arm_arg_R2_12, arm_arg_mem_R_pm_R_W}},                // STRD<c> <Rt1>,<Rt2>,[<Rn>,+/-<Rm>]{!} cond:4|0|0|0|P|U|0|W|0|Rn:4|Rt:4|(0)|(0)|(0)|(0)|1|1|1|1|Rm:4
+	{0x0e5000f0, 0x000000f0, 3, arm_STRD_EQ, 0x1c04, arm_instArgs{arm_arg_R1_12, arm_arg_R2_12, arm_arg_mem_R_pm_R_W}},                // STRD<c> <Rt1>,<Rt2>,[<Rn>,+/-<Rm>]{!} cond:4|0|0|0|P|U|0|W|0|Rn:4|Rt:4|(0)|(0)|(0)|(0)|1|1|1|1|Rm:4
+	{0x0e5000f0, 0x004000f0, 4, arm_STRD_EQ, 0x1c04, arm_instArgs{arm_arg_R1_12, arm_arg_R2_12, arm_arg_mem_R_pm_imm8_W}},             // STRD<c> <Rt1>,<Rt2>,[<Rn>{,#+/-<imm8>}]{!} cond:4|0|0|0|P|U|1|W|0|Rn:4|Rt:4|imm4H:4|1|1|1|1|imm4L:4
+	{0x0ff00ff0, 0x01800f90, 4, arm_STREX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_mem_R}},                         // STREX<c> <Rd>,<Rt>,[<Rn>] cond:4|0|0|0|1|1|0|0|0|Rn:4|Rd:4|1|1|1|1|1|0|0|1|Rt:4
+	{0x0ff00ff0, 0x01c00f90, 4, arm_STREXB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_mem_R}},                        // STREXB<c> <Rd>,<Rt>,[<Rn>] cond:4|0|0|0|1|1|1|0|0|Rn:4|Rd:4|1|1|1|1|1|0|0|1|Rt:4
+	{0x0ff00ff0, 0x01a00f90, 4, arm_STREXD_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R1_0, arm_arg_R2_0, arm_arg_mem_R}},         // STREXD<c> <Rd>,<Rt1>,<Rt2>,[<Rn>] cond:4|0|0|0|1|1|0|1|0|Rn:4|Rd:4|1|1|1|1|1|0|0|1|Rt:4
+	{0x0ff00ff0, 0x01e00f90, 4, arm_STREXH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_mem_R}},                        // STREXH<c> <Rd>,<Rt>,[<Rn>] cond:4|0|0|0|1|1|1|1|0|Rn:4|Rd:4|1|1|1|1|1|0|0|1|Rt:4
+	{0x0e500ff0, 0x000000b0, 2, arm_STRH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_W}},                                // STRH<c> <Rt>,[<Rn>,+/-<Rm>]{!} cond:4|0|0|0|P|U|0|W|0|Rn:4|Rt:4|0|0|0|0|1|0|1|1|Rm:4
+	{0x0e5000f0, 0x004000b0, 2, arm_STRH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm8_W}},                             // STRH<c> <Rt>,[<Rn>{,#+/-<imm8>}]{!} cond:4|0|0|0|P|U|1|W|0|Rn:4|Rt:4|imm4H:4|1|0|1|1|imm4L:4
+	{0x0f7000f0, 0x006000b0, 4, arm_STRHT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm8_postindex}},                    // STRHT<c> <Rt>, [<Rn>] {,#+/-<imm8>} cond:4|0|0|0|0|U|1|1|0|Rn:4|Rt:4|imm4H:4|1|0|1|1|imm4L:4
+	{0x0f700ff0, 0x002000b0, 4, arm_STRHT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_postindex}},                       // STRHT<c> <Rt>, [<Rn>], +/-<Rm> cond:4|0|0|0|0|U|0|1|0|Rn:4|Rt:4|0|0|0|0|1|0|1|1|Rm:4
+	{0x0f700000, 0x04200000, 4, arm_STRT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_imm12_postindex}},                    // STRT<c> <Rt>, [<Rn>] {,#+/-<imm12>} cond:4|0|1|0|0|U|0|1|0|Rn:4|Rt:4|imm12:12
+	{0x0f700010, 0x06200000, 4, arm_STRT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_mem_R_pm_R_shift_imm_postindex}},              // STRT<c> <Rt>,[<Rn>],+/-<Rm>{, <shift>} cond:4|0|1|1|0|U|0|1|0|Rn:4|Rt:4|imm5:5|type:2|0|Rm:4
+	{0x0fe00000, 0x02400000, 2, arm_SUB_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_const}},                      // SUB{S}<c> <Rd>,<Rn>,#<const> cond:4|0|0|1|0|0|1|0|S|Rn:4|Rd:4|imm12:12
+	{0x0fe00090, 0x00400010, 4, arm_SUB_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_R}},                  // SUB{S}<c> <Rd>,<Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|0|0|1|0|S|Rn:4|Rd:4|Rs:4|0|type:2|1|Rm:4
+	{0x0fe00010, 0x00400000, 2, arm_SUB_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_shift_imm}},                // SUB{S}<c> <Rd>,<Rn>,<Rm>{,<shift>} cond:4|0|0|0|0|0|1|0|S|Rn:4|Rd:4|imm5:5|type:2|0|Rm:4
+	{0x0fef0000, 0x024d0000, 2, arm_SUB_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_SP, arm_arg_const}},                        // SUB{S}<c> <Rd>,SP,#<const> cond:4|0|0|1|0|0|1|0|S|1|1|0|1|Rd:4|imm12:12
+	{0x0fef0010, 0x004d0000, 2, arm_SUB_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_SP, arm_arg_R_shift_imm}},                  // SUB{S}<c> <Rd>,SP,<Rm>{,<shift>} cond:4|0|0|0|0|0|1|0|S|1|1|0|1|Rd:4|imm5:5|type:2|0|Rm:4
+	{0x0f000000, 0x0f000000, 4, arm_SVC_EQ, 0x1c04, arm_instArgs{arm_arg_imm24}},                                                      // SVC<c> #<imm24> cond:4|1|1|1|1|imm24:24
+	{0x0fb00ff0, 0x01000090, 4, arm_SWP_EQ, 0x16011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_mem_R}},                       // SWP{B}<c> <Rt>,<Rm>,[<Rn>] cond:4|0|0|0|1|0|B|0|0|Rn:4|Rt:4|0|0|0|0|1|0|0|1|Rm:4
+	{0x0ff003f0, 0x06800070, 2, arm_SXTAB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_rotate}},                   // SXTAB16<c> <Rd>,<Rn>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|0|0|0|Rn:4|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+	{0x0ff003f0, 0x06a00070, 2, arm_SXTAB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_rotate}},                     // SXTAB<c> <Rd>,<Rn>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|0|1|0|Rn:4|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+	{0x0ff003f0, 0x06b00070, 2, arm_SXTAH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_rotate}},                     // SXTAH<c> <Rd>,<Rn>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|0|1|1|Rn:4|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+	{0x0fff03f0, 0x068f0070, 4, arm_SXTB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_rotate}},                                  // SXTB16<c> <Rd>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|0|0|0|1|1|1|1|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+	{0x0fff03f0, 0x06af0070, 4, arm_SXTB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_rotate}},                                    // SXTB<c> <Rd>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|0|1|0|1|1|1|1|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+	{0x0fff03f0, 0x06bf0070, 4, arm_SXTH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_rotate}},                                    // SXTH<c> <Rd>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|0|1|1|1|1|1|1|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+	{0x0ff0f000, 0x03300000, 4, arm_TEQ_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_const}},                                        // TEQ<c> <Rn>,#<const> cond:4|0|0|1|1|0|0|1|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12
+	{0x0ff00000, 0x03300000, 3, arm_TEQ_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_const}},                                        // TEQ<c> <Rn>,#<const> cond:4|0|0|1|1|0|0|1|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12
+	{0x0ff0f090, 0x01300010, 4, arm_TEQ_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_R}},                                    // TEQ<c> <Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|1|0|0|1|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4
+	{0x0ff00090, 0x01300010, 3, arm_TEQ_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_R}},                                    // TEQ<c> <Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|1|0|0|1|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4
+	{0x0ff0f010, 0x01300000, 4, arm_TEQ_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_imm}},                                  // TEQ<c> <Rn>,<Rm>{,<shift>} cond:4|0|0|0|1|0|0|1|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4
+	{0x0ff00010, 0x01300000, 3, arm_TEQ_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_imm}},                                  // TEQ<c> <Rn>,<Rm>{,<shift>} cond:4|0|0|0|1|0|0|1|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4
+	{0x0ff0f000, 0x03100000, 4, arm_TST_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_const}},                                        // TST<c> <Rn>,#<const> cond:4|0|0|1|1|0|0|0|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12
+	{0x0ff00000, 0x03100000, 3, arm_TST_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_const}},                                        // TST<c> <Rn>,#<const> cond:4|0|0|1|1|0|0|0|1|Rn:4|(0)|(0)|(0)|(0)|imm12:12
+	{0x0ff0f090, 0x01100010, 4, arm_TST_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_R}},                                    // TST<c> <Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|1|0|0|0|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4
+	{0x0ff00090, 0x01100010, 3, arm_TST_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_R}},                                    // TST<c> <Rn>,<Rm>,<type> <Rs> cond:4|0|0|0|1|0|0|0|1|Rn:4|(0)|(0)|(0)|(0)|Rs:4|0|type:2|1|Rm:4
+	{0x0ff0f010, 0x01100000, 4, arm_TST_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_imm}},                                  // TST<c> <Rn>,<Rm>{,<shift>} cond:4|0|0|0|1|0|0|0|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4
+	{0x0ff00010, 0x01100000, 3, arm_TST_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_shift_imm}},                                  // TST<c> <Rn>,<Rm>{,<shift>} cond:4|0|0|0|1|0|0|0|1|Rn:4|(0)|(0)|(0)|(0)|imm5:5|type:2|0|Rm:4
+	{0x0ff00ff0, 0x06500f10, 4, arm_UADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // UADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+	{0x0ff000f0, 0x06500f10, 3, arm_UADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // UADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+	{0x0ff00ff0, 0x06500f90, 4, arm_UADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // UADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+	{0x0ff000f0, 0x06500f90, 3, arm_UADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // UADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+	{0x0ff00ff0, 0x06500f30, 4, arm_UASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                           // UASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+	{0x0ff000f0, 0x06500f30, 3, arm_UASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                           // UASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+	{0x0fe00070, 0x07e00050, 4, arm_UBFX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_0, arm_arg_imm5, arm_arg_widthm1}},          // UBFX<c> <Rd>,<Rn>,#<lsb>,#<widthm1> cond:4|0|1|1|1|1|1|1|widthm1:5|Rd:4|lsb:5|1|0|1|Rn:4
+	{0x0ff00ff0, 0x06700f10, 4, arm_UHADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                        // UHADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+	{0x0ff000f0, 0x06700f10, 3, arm_UHADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                        // UHADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+	{0x0ff00ff0, 0x06700f90, 4, arm_UHADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // UHADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+	{0x0ff000f0, 0x06700f90, 3, arm_UHADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // UHADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+	{0x0ff00ff0, 0x06700f30, 4, arm_UHASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // UHASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+	{0x0ff000f0, 0x06700f30, 3, arm_UHASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // UHASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+	{0x0ff00ff0, 0x06700f50, 4, arm_UHSAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // UHSAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+	{0x0ff000f0, 0x06700f50, 3, arm_UHSAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // UHSAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+	{0x0ff00ff0, 0x06700f70, 4, arm_UHSUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                        // UHSUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+	{0x0ff000f0, 0x06700f70, 3, arm_UHSUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                        // UHSUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+	{0x0ff00ff0, 0x06700ff0, 4, arm_UHSUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // UHSUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+	{0x0ff000f0, 0x06700ff0, 3, arm_UHSUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // UHSUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+	{0x0ff000f0, 0x00400090, 4, arm_UMAAL_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}},             // UMAAL<c> <RdLo>,<RdHi>,<Rn>,<Rm> cond:4|0|0|0|0|0|1|0|0|RdHi:4|RdLo:4|Rm:4|1|0|0|1|Rn:4
+	{0x0fe000f0, 0x00a00090, 4, arm_UMLAL_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}},         // UMLAL{S}<c> <RdLo>,<RdHi>,<Rn>,<Rm> cond:4|0|0|0|0|1|0|1|S|RdHi:4|RdLo:4|Rm:4|1|0|0|1|Rn:4
+	{0x0fe000f0, 0x00800090, 4, arm_UMULL_EQ, 0x14011c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}},         // UMULL{S}<c> <RdLo>,<RdHi>,<Rn>,<Rm> cond:4|0|0|0|0|1|0|0|S|RdHi:4|RdLo:4|Rm:4|1|0|0|1|Rn:4
+	{0x0ff00ff0, 0x06600f10, 4, arm_UQADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                        // UQADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+	{0x0ff000f0, 0x06600f10, 3, arm_UQADD16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                        // UQADD16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|0|1|Rm:4
+	{0x0ff00ff0, 0x06600f90, 4, arm_UQADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // UQADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+	{0x0ff000f0, 0x06600f90, 3, arm_UQADD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // UQADD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|0|0|1|Rm:4
+	{0x0ff00ff0, 0x06600f30, 4, arm_UQASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // UQASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+	{0x0ff000f0, 0x06600f30, 3, arm_UQASX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // UQASX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rm:4
+	{0x0ff00ff0, 0x06600f50, 4, arm_UQSAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // UQSAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+	{0x0ff000f0, 0x06600f50, 3, arm_UQSAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // UQSAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+	{0x0ff00ff0, 0x06600f70, 4, arm_UQSUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                        // UQSUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+	{0x0ff000f0, 0x06600f70, 3, arm_UQSUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                        // UQSUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+	{0x0ff00ff0, 0x06600ff0, 4, arm_UQSUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // UQSUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+	{0x0ff000f0, 0x06600ff0, 3, arm_UQSUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // UQSUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|1|0|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+	{0x0ff0f0f0, 0x0780f010, 4, arm_USAD8_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8}},                           // USAD8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|1|1|0|0|0|Rd:4|1|1|1|1|Rm:4|0|0|0|1|Rn:4
+	{0x0ff000f0, 0x07800010, 2, arm_USADA8_EQ, 0x1c04, arm_instArgs{arm_arg_R_16, arm_arg_R_0, arm_arg_R_8, arm_arg_R_12}},            // USADA8<c> <Rd>,<Rn>,<Rm>,<Ra> cond:4|0|1|1|1|1|0|0|0|Rd:4|Ra:4|Rm:4|0|0|0|1|Rn:4
+	{0x0ff00ff0, 0x06e00f30, 4, arm_USAT16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_satimm4, arm_arg_R_0}},                      // USAT16<c> <Rd>,#<sat_imm4>,<Rn> cond:4|0|1|1|0|1|1|1|0|sat_imm:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rn:4
+	{0x0ff000f0, 0x06e00f30, 3, arm_USAT16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_satimm4, arm_arg_R_0}},                      // USAT16<c> <Rd>,#<sat_imm4>,<Rn> cond:4|0|1|1|0|1|1|1|0|sat_imm:4|Rd:4|(1)|(1)|(1)|(1)|0|0|1|1|Rn:4
+	{0x0fe00030, 0x06e00010, 4, arm_USAT_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_satimm5, arm_arg_R_shift_imm}},                // USAT<c> <Rd>,#<sat_imm5>,<Rn>{,<shift>} cond:4|0|1|1|0|1|1|1|sat_imm:5|Rd:4|imm5:5|sh|0|1|Rn:4
+	{0x0ff00ff0, 0x06500f50, 4, arm_USAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                           // USAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+	{0x0ff000f0, 0x06500f50, 3, arm_USAX_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                           // USAX<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|0|1|Rm:4
+	{0x0ff00ff0, 0x06500f70, 4, arm_USUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // USUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+	{0x0ff000f0, 0x06500f70, 3, arm_USUB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                         // USUB16<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|0|1|1|1|Rm:4
+	{0x0ff00ff0, 0x06500ff0, 4, arm_USUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // USUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+	{0x0ff000f0, 0x06500ff0, 3, arm_USUB8_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_0}},                          // USUB8<c> <Rd>,<Rn>,<Rm> cond:4|0|1|1|0|0|1|0|1|Rn:4|Rd:4|(1)|(1)|(1)|(1)|1|1|1|1|Rm:4
+	{0x0ff003f0, 0x06c00070, 2, arm_UXTAB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_rotate}},                   // UXTAB16<c> <Rd>,<Rn>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|1|0|0|Rn:4|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+	{0x0ff003f0, 0x06e00070, 2, arm_UXTAB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_rotate}},                     // UXTAB<c> <Rd>,<Rn>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|1|1|0|Rn:4|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+	{0x0ff003f0, 0x06f00070, 2, arm_UXTAH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_16, arm_arg_R_rotate}},                     // UXTAH<c> <Rd>,<Rn>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|1|1|1|Rn:4|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+	{0x0fff03f0, 0x06cf0070, 4, arm_UXTB16_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_rotate}},                                  // UXTB16<c> <Rd>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|1|0|0|1|1|1|1|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+	{0x0fff03f0, 0x06ef0070, 4, arm_UXTB_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_rotate}},                                    // UXTB<c> <Rd>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|1|1|0|1|1|1|1|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+	{0x0fff03f0, 0x06ff0070, 4, arm_UXTH_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_R_rotate}},                                    // UXTH<c> <Rd>,<Rm>{,<rotation>} cond:4|0|1|1|0|1|1|1|1|1|1|1|1|Rd:4|rotate:2|0|0|0|1|1|1|Rm:4
+	{0x0fb00e10, 0x0e000a00, 4, arm_VMLA_EQ_F32, 0x60108011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sn_Dn, arm_arg_Sm_Dm}},            // V<MLA,MLS><c>.F<32,64> <Sd,Dd>, <Sn,Dn>, <Sm,Dm> cond:4|1|1|1|0|0|D|0|0|Vn:4|Vd:4|1|0|1|sz|N|op|M|0|Vm:4
+	{0x0fbf0ed0, 0x0eb00ac0, 4, arm_VABS_EQ_F32, 0x8011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sm_Dm}},                               // VABS<c>.F<32,64> <Sd,Dd>, <Sm,Dm> cond:4|1|1|1|0|1|D|1|1|0|0|0|0|Vd:4|1|0|1|sz|1|1|M|0|Vm:4
+	{0x0fb00e50, 0x0e300a00, 4, arm_VADD_EQ_F32, 0x8011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sn_Dn, arm_arg_Sm_Dm}},                // VADD<c>.F<32,64> <Sd,Dd>, <Sn,Dn>, <Sm,Dm> cond:4|1|1|1|0|0|D|1|1|Vn:4|Vd:4|1|0|1|sz|N|0|M|0|Vm:4
+	{0x0fbf0e7f, 0x0eb50a40, 4, arm_VCMP_EQ_F32, 0x70108011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_fp_0}},                            // VCMP{E}<c>.F<32,64> <Sd,Dd>, #0.0 cond:4|1|1|1|0|1|D|1|1|0|1|0|1|Vd:4|1|0|1|sz|E|1|0|0|(0)|(0)|(0)|(0)
+	{0x0fbf0e70, 0x0eb50a40, 3, arm_VCMP_EQ_F32, 0x70108011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_fp_0}},                            // VCMP{E}<c>.F<32,64> <Sd,Dd>, #0.0 cond:4|1|1|1|0|1|D|1|1|0|1|0|1|Vd:4|1|0|1|sz|E|1|0|0|(0)|(0)|(0)|(0)
+	{0x0fbf0e50, 0x0eb40a40, 4, arm_VCMP_EQ_F32, 0x70108011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sm_Dm}},                           // VCMP{E}<c>.F<32,64> <Sd,Dd>, <Sm,Dm> cond:4|1|1|1|0|1|D|1|1|0|1|0|0|Vd:4|1|0|1|sz|E|1|M|0|Vm:4
+	{0x0fbe0e50, 0x0eba0a40, 4, arm_VCVT_EQ_F32_FXS16, 0x801100107011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sd_Dd, arm_arg_fbits}},  // VCVT<c>.F<32,64>.FX<S,U><16,32> <Sd,Dd>, <Sd,Dd>, #<fbits> cond:4|1|1|1|0|1|D|1|1|1|0|1|U|Vd:4|1|0|1|sz|sx|1|i|0|imm4:4
+	{0x0fbe0e50, 0x0ebe0a40, 4, arm_VCVT_EQ_FXS16_F32, 0x1001070108011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sd_Dd, arm_arg_fbits}}, // VCVT<c>.FX<S,U><16,32>.F<32,64> <Sd,Dd>, <Sd,Dd>, #<fbits> cond:4|1|1|1|0|1|D|1|1|1|1|1|U|Vd:4|1|0|1|sz|sx|1|i|0|imm4:4
+	{0x0fbf0ed0, 0x0eb70ac0, 4, arm_VCVT_EQ_F64_F32, 0x8011c04, arm_instArgs{arm_arg_Dd_Sd, arm_arg_Sm_Dm}},                           // VCVT<c>.<F64.F32,F32.F64> <Dd,Sd>, <Sm,Dm> cond:4|1|1|1|0|1|D|1|1|0|1|1|1|Vd:4|1|0|1|sz|1|1|M|0|Vm:4
+	{0x0fbe0f50, 0x0eb20a40, 4, arm_VCVTB_EQ_F32_F16, 0x70110011c04, arm_instArgs{arm_arg_Sd, arm_arg_Sm}},                            // VCVT<B,T><c>.<F32.F16,F16.F32> <Sd>, <Sm> cond:4|1|1|1|0|1|D|1|1|0|0|1|op|Vd:4|1|0|1|0|T|1|M|0|Vm:4
+	{0x0fbf0e50, 0x0eb80a40, 4, arm_VCVT_EQ_F32_U32, 0x80107011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sm}},                          // VCVT<c>.F<32,64>.<U,S>32 <Sd,Dd>, <Sm> cond:4|1|1|1|0|1|D|1|1|1|0|0|0|Vd:4|1|0|1|sz|op|1|M|0|Vm:4
+	{0x0fbe0e50, 0x0ebc0a40, 4, arm_VCVTR_EQ_U32_F32, 0x701100108011c04, arm_instArgs{arm_arg_Sd, arm_arg_Sm_Dm}},                     // VCVT<R,><c>.<U,S>32.F<32,64> <Sd>, <Sm,Dm> cond:4|1|1|1|0|1|D|1|1|1|1|0|signed|Vd:4|1|0|1|sz|op|1|M|0|Vm:4
+	{0x0fb00e50, 0x0e800a00, 4, arm_VDIV_EQ_F32, 0x8011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sn_Dn, arm_arg_Sm_Dm}},                // VDIV<c>.F<32,64> <Sd,Dd>, <Sn,Dn>, <Sm,Dm> cond:4|1|1|1|0|1|D|0|0|Vn:4|Vd:4|1|0|1|sz|N|0|M|0|Vm:4
+	{0x0f300e00, 0x0d100a00, 4, arm_VLDR_EQ, 0x1c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_mem_R_pm_imm8at0_offset}},                    // VLDR<c> <Sd,Dd>, [<Rn>{,#+/-<imm8>}] cond:4|1|1|0|1|U|D|0|1|Rn:4|Vd:4|1|0|1|sz|imm8:8
+	{0x0ff00f7f, 0x0e000a10, 4, arm_VMOV_EQ, 0x1c04, arm_instArgs{arm_arg_Sn, arm_arg_R_12}},                                          // VMOV<c> <Sn>, <Rt> cond:4|1|1|1|0|0|0|0|0|Vn:4|Rt:4|1|0|1|0|N|0|0|1|0|0|0|0
+	{0x0ff00f7f, 0x0e100a10, 4, arm_VMOV_EQ, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_Sn}},                                          // VMOV<c> <Rt>, <Sn> cond:4|1|1|1|0|0|0|0|1|Vn:4|Rt:4|1|0|1|0|N|0|0|1|0|0|0|0
+	{0x0fd00f7f, 0x0e100b10, 4, arm_VMOV_EQ_32, 0x1c04, arm_instArgs{arm_arg_R_12, arm_arg_Dn_half}},                                  // VMOV<c>.32 <Rt>, <Dn[x]> cond:4|1|1|1|0|0|0|opc1|1|Vn:4|Rt:4|1|0|1|1|N|0|0|1|0|0|0|0
+	{0x0fd00f7f, 0x0e000b10, 4, arm_VMOV_EQ_32, 0x1c04, arm_instArgs{arm_arg_Dn_half, arm_arg_R_12}},                                  // VMOV<c>.32 <Dd[x]>, <Rt> cond:4|1|1|1|0|0|0|opc1|0|Vd:4|Rt:4|1|0|1|1|D|0|0|1|0|0|0|0
+	{0x0fb00ef0, 0x0eb00a00, 4, arm_VMOV_EQ_F32, 0x8011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_imm_vfp}},                             // VMOV<c>.F<32,64> <Sd,Dd>, #<imm_vfp> cond:4|1|1|1|0|1|D|1|1|imm4H:4|Vd:4|1|0|1|sz|0|0|0|0|imm4L:4
+	{0x0fbf0ed0, 0x0eb00a40, 4, arm_VMOV_EQ_F32, 0x8011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sm_Dm}},                               // VMOV<c>.F<32,64> <Sd,Dd>, <Sm,Dm> cond:4|1|1|1|0|1|D|1|1|0|0|0|0|Vd:4|1|0|1|sz|0|1|M|0|Vm:4
+	{0x0fff0fff, 0x0ef10a10, 4, arm_VMRS_EQ, 0x1c04, arm_instArgs{arm_arg_R_12_nzcv, arm_arg_FPSCR}},                                  // VMRS<c> <Rt_nzcv>, FPSCR cond:4|1|1|1|0|1|1|1|1|0|0|0|1|Rt:4|1|0|1|0|0|0|0|1|0|0|0|0
+	{0x0fff0fff, 0x0ee10a10, 4, arm_VMSR_EQ, 0x1c04, arm_instArgs{arm_arg_FPSCR, arm_arg_R_12}},                                       // VMSR<c> FPSCR, <Rt> cond:4|1|1|1|0|1|1|1|0|0|0|0|1|Rt:4|1|0|1|0|0|0|0|1|0|0|0|0
+	{0x0fb00e50, 0x0e200a00, 4, arm_VMUL_EQ_F32, 0x8011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sn_Dn, arm_arg_Sm_Dm}},                // VMUL<c>.F<32,64> <Sd,Dd>, <Sn,Dn>, <Sm,Dm> cond:4|1|1|1|0|0|D|1|0|Vn:4|Vd:4|1|0|1|sz|N|0|M|0|Vm:4
+	{0x0fbf0ed0, 0x0eb10a40, 4, arm_VNEG_EQ_F32, 0x8011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sm_Dm}},                               // VNEG<c>.F<32,64> <Sd,Dd>, <Sm,Dm> cond:4|1|1|1|0|1|D|1|1|0|0|0|1|Vd:4|1|0|1|sz|0|1|M|0|Vm:4
+	{0x0fb00e10, 0x0e100a00, 4, arm_VNMLS_EQ_F32, 0x60108011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sn_Dn, arm_arg_Sm_Dm}},           // VN<MLS,MLA><c>.F<32,64> <Sd,Dd>, <Sn,Dn>, <Sm,Dm> cond:4|1|1|1|0|0|D|0|1|Vn:4|Vd:4|1|0|1|sz|N|op|M|0|Vm:4
+	{0x0fb00e50, 0x0e200a40, 4, arm_VNMUL_EQ_F32, 0x8011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sn_Dn, arm_arg_Sm_Dm}},               // VNMUL<c>.F<32,64> <Sd,Dd>, <Sn,Dn>, <Sm,Dm> cond:4|1|1|1|0|0|D|1|0|Vn:4|Vd:4|1|0|1|sz|N|1|M|0|Vm:4
+	{0x0fbf0ed0, 0x0eb10ac0, 4, arm_VSQRT_EQ_F32, 0x8011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sm_Dm}},                              // VSQRT<c>.F<32,64> <Sd,Dd>, <Sm,Dm> cond:4|1|1|1|0|1|D|1|1|0|0|0|1|Vd:4|1|0|1|sz|1|1|M|0|Vm:4
+	{0x0f300e00, 0x0d000a00, 4, arm_VSTR_EQ, 0x1c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_mem_R_pm_imm8at0_offset}},                    // VSTR<c> <Sd,Dd>, [<Rn>{,#+/-<imm8>}] cond:4|1|1|0|1|U|D|0|0|Rn:4|Vd:4|1|0|1|sz|imm8:8
+	{0x0fb00e50, 0x0e300a40, 4, arm_VSUB_EQ_F32, 0x8011c04, arm_instArgs{arm_arg_Sd_Dd, arm_arg_Sn_Dn, arm_arg_Sm_Dm}},                // VSUB<c>.F<32,64> <Sd,Dd>, <Sn,Dn>, <Sm,Dm> cond:4|1|1|1|0|0|D|1|1|Vn:4|Vd:4|1|0|1|sz|N|1|M|0|Vm:4
+	{0x0fffffff, 0x0320f002, 4, arm_WFE_EQ, 0x1c04, arm_instArgs{}},                                                                   // WFE<c> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|0|0|0|1|0
+	{0x0fff00ff, 0x0320f002, 3, arm_WFE_EQ, 0x1c04, arm_instArgs{}},                                                                   // WFE<c> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|0|0|0|1|0
+	{0x0fffffff, 0x0320f003, 4, arm_WFI_EQ, 0x1c04, arm_instArgs{}},                                                                   // WFI<c> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|0|0|0|1|1
+	{0x0fff00ff, 0x0320f003, 3, arm_WFI_EQ, 0x1c04, arm_instArgs{}},                                                                   // WFI<c> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|0|0|0|1|1
+	{0x0fffffff, 0x0320f001, 4, arm_YIELD_EQ, 0x1c04, arm_instArgs{}},                                                                 // YIELD<c> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|0|0|0|0|1
+	{0x0fff00ff, 0x0320f001, 3, arm_YIELD_EQ, 0x1c04, arm_instArgs{}},                                                                 // YIELD<c> cond:4|0|0|1|1|0|0|1|0|0|0|0|0|(1)|(1)|(1)|(1)|(0)|(0)|(0)|(0)|0|0|0|0|0|0|0|1
+	{0xffffffff, 0xf7fabcfd, 4, arm_UNDEF, 0x0, arm_instArgs{}},                                                                       // UNDEF 1|1|1|1|0|1|1|1|1|1|1|1|1|0|1|0|1|0|1|1|1|1|0|0|1|1|1|1|1|1|0|1
+}
diff --git a/src/cmd/objdump/elf.go b/src/cmd/objdump/elf.go
new file mode 100644
index 0000000..906e903
--- /dev/null
+++ b/src/cmd/objdump/elf.go
@@ -0,0 +1,65 @@
+// 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) (syms []Sym, goarch string) {
+	p, err := elf.NewFile(f)
+	if err != nil {
+		errorf("parsing %s: %v", f.Name(), err)
+		return
+	}
+
+	elfSyms, err := p.Symbols()
+	if err != nil {
+		errorf("parsing %s: %v", f.Name(), err)
+		return
+	}
+
+	switch p.Machine {
+	case elf.EM_X86_64:
+		goarch = "amd64"
+	case elf.EM_386:
+		goarch = "386"
+	case elf.EM_ARM:
+		goarch = "arm"
+	}
+
+	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
+}
diff --git a/src/cmd/objdump/macho.go b/src/cmd/objdump/macho.go
new file mode 100644
index 0000000..6e0ad22
--- /dev/null
+++ b/src/cmd/objdump/macho.go
@@ -0,0 +1,77 @@
+// 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) (syms []Sym, goarch string) {
+	p, err := macho.NewFile(f)
+	if err != nil {
+		errorf("parsing %s: %v", f.Name(), err)
+		return
+	}
+
+	if p.Symtab == nil {
+		errorf("%s: no symbol table", f.Name())
+		return
+	}
+
+	switch p.Cpu {
+	case macho.Cpu386:
+		goarch = "386"
+	case macho.CpuAmd64:
+		goarch = "amd64"
+	case macho.CpuArm:
+		goarch = "arm"
+	}
+
+	// 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))
+
+	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
+}
+
+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/objdump/main.c b/src/cmd/objdump/main.c
deleted file mode 100644
index b684be7..0000000
--- a/src/cmd/objdump/main.c
+++ /dev/null
@@ -1,68 +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.
-
-/*
- * objdump simulation - only enough to make pprof work on Macs
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-void
-usage(void)
-{
-	fprint(2, "usage: objdump binary start stop\n");
-	fprint(2, "Disassembles binary from PC start up to stop.\n");
-	exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
-	int fd, n;
-	uvlong pc, start, stop;
-	Fhdr fhdr;
-	Biobuf bout;
-	char buf[1024];
-	Map *text;
-
-	ARGBEGIN{
-	default:
-		usage();
-	}ARGEND
-
-	if(argc != 3)
-		usage();
-	start = strtoull(argv[1], 0, 16);
-	stop = strtoull(argv[2], 0, 16);
-
-	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");
-	text = loadmap(nil, fd, &fhdr);
-	if(text == nil)
-		sysfatal("loadmap: %r");
-
-	Binit(&bout, 1, OWRITE);
-	for(pc=start; pc<stop; ) {
-		if(fileline(buf, sizeof buf, pc))
-			Bprint(&bout, "%s\n", buf);
-		buf[0] = '\0';
-		machdata->das(text, pc, 0, buf, sizeof buf);
-		Bprint(&bout, " %llx: %s\n", pc, buf);
-		n = machdata->instsize(text, pc);
-		if(n <= 0)
-			break;
-		pc += n;
-	}
-	Bflush(&bout);
-	exits(0);
-}
diff --git a/src/cmd/objdump/main.go b/src/cmd/objdump/main.go
new file mode 100644
index 0000000..ade5436
--- /dev/null
+++ b/src/cmd/objdump/main.go
@@ -0,0 +1,519 @@
+// 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.
+
+// Objdump disassembles executable files.
+//
+// Usage:
+//
+//	go tool objdump [-s symregexp] binary
+//
+// Objdump prints a disassembly of all text symbols (code) in the binary.
+// If the -s option is present, objdump only disassembles
+// symbols with names matching the regular expression.
+//
+// Alternate usage:
+//
+//	go tool objdump binary start end
+//
+// In this mode, objdump disassembles the binary starting at the start address and
+// stopping at the end address. The start and end addresses are program
+// counters written in hexadecimal with optional leading 0x prefix.
+// In this mode, objdump prints a sequence of stanzas of the form:
+//
+//	file:line
+//	 address: assembly
+//	 address: assembly
+//	 ...
+//
+// Each stanza gives the disassembly for a contiguous range of addresses
+// all mapped to the same original source file and line number.
+// This mode is intended for use by pprof.
+//
+// The ARM disassembler is missing (golang.org/issue/7452) but will be added
+// before the Go 1.3 release.
+package main
+
+import (
+	"bufio"
+	"bytes"
+	"debug/elf"
+	"debug/gosym"
+	"debug/macho"
+	"debug/pe"
+	"debug/plan9obj"
+	"encoding/binary"
+	"flag"
+	"fmt"
+	"io"
+	"log"
+	"os"
+	"regexp"
+	"sort"
+	"strconv"
+	"strings"
+	"text/tabwriter"
+)
+
+var symregexp = flag.String("s", "", "only dump symbols matching this regexp")
+var symRE *regexp.Regexp
+
+func usage() {
+	fmt.Fprintf(os.Stderr, "usage: go tool objdump [-s symregexp] binary [start end]\n\n")
+	flag.PrintDefaults()
+	os.Exit(2)
+}
+
+type lookupFunc func(addr uint64) (sym string, base uint64)
+type disasmFunc func(code []byte, pc uint64, lookup lookupFunc) (text string, size int)
+
+func main() {
+	log.SetFlags(0)
+	log.SetPrefix("objdump: ")
+
+	flag.Usage = usage
+	flag.Parse()
+	if flag.NArg() != 1 && flag.NArg() != 3 {
+		usage()
+	}
+
+	if *symregexp != "" {
+		re, err := regexp.Compile(*symregexp)
+		if err != nil {
+			log.Fatalf("invalid -s regexp: %v", err)
+		}
+		symRE = re
+	}
+
+	f, err := os.Open(flag.Arg(0))
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	textStart, textData, symtab, pclntab, err := loadTables(f)
+	if err != nil {
+		log.Fatalf("reading %s: %v", flag.Arg(0), err)
+	}
+
+	syms, goarch, err := loadSymbols(f)
+	if err != nil {
+		log.Fatalf("reading %s: %v", flag.Arg(0), err)
+	}
+
+	// Filter out section symbols, overwriting syms in place.
+	keep := syms[:0]
+	for _, sym := range syms {
+		switch sym.Name {
+		case "text", "_text", "etext", "_etext":
+			// drop
+		default:
+			keep = append(keep, sym)
+		}
+	}
+	syms = keep
+
+	disasm := disasms[goarch]
+	if disasm == nil {
+		log.Fatalf("reading %s: unknown architecture", flag.Arg(0))
+	}
+
+	lookup := func(addr uint64) (string, uint64) {
+		i := sort.Search(len(syms), func(i int) bool { return syms[i].Addr > addr })
+		if i > 0 {
+			s := syms[i-1]
+			if s.Addr <= addr && addr < s.Addr+uint64(s.Size) && s.Name != "etext" && s.Name != "_etext" {
+				return s.Name, s.Addr
+			}
+		}
+		return "", 0
+	}
+
+	pcln := gosym.NewLineTable(pclntab, textStart)
+	tab, err := gosym.NewTable(symtab, pcln)
+	if err != nil {
+		log.Fatalf("reading %s: %v", flag.Arg(0), err)
+	}
+
+	if flag.NArg() == 1 {
+		// disassembly of entire object - our format
+		dump(tab, lookup, disasm, goarch, syms, textData, textStart)
+		os.Exit(exitCode)
+	}
+
+	// disassembly of specific piece of object - gnu objdump format for pprof
+	gnuDump(tab, lookup, disasm, textData, textStart)
+	os.Exit(exitCode)
+}
+
+// base returns the final element in the path.
+// It works on both Windows and Unix paths.
+func base(path string) string {
+	path = path[strings.LastIndex(path, "/")+1:]
+	path = path[strings.LastIndex(path, `\`)+1:]
+	return path
+}
+
+func dump(tab *gosym.Table, lookup lookupFunc, disasm disasmFunc, goarch string, syms []Sym, textData []byte, textStart uint64) {
+	stdout := bufio.NewWriter(os.Stdout)
+	defer stdout.Flush()
+
+	printed := false
+	for _, sym := range syms {
+		if sym.Code != 'T' || sym.Size == 0 || sym.Name == "_text" || sym.Name == "text" || sym.Addr < textStart || symRE != nil && !symRE.MatchString(sym.Name) {
+			continue
+		}
+		if sym.Addr >= textStart+uint64(len(textData)) || sym.Addr+uint64(sym.Size) > textStart+uint64(len(textData)) {
+			break
+		}
+		if printed {
+			fmt.Fprintf(stdout, "\n")
+		} else {
+			printed = true
+		}
+		file, _, _ := tab.PCToLine(sym.Addr)
+		fmt.Fprintf(stdout, "TEXT %s(SB) %s\n", sym.Name, file)
+		tw := tabwriter.NewWriter(stdout, 1, 8, 1, '\t', 0)
+		start := sym.Addr
+		end := sym.Addr + uint64(sym.Size)
+		for pc := start; pc < end; {
+			i := pc - textStart
+			text, size := disasm(textData[i:end-textStart], pc, lookup)
+			file, line, _ := tab.PCToLine(pc)
+
+			// ARM is word-based, so show actual word hex, not byte hex.
+			// Since ARM is little endian, they're different.
+			if goarch == "arm" && size == 4 {
+				fmt.Fprintf(tw, "\t%s:%d\t%#x\t%08x\t%s\n", base(file), line, pc, binary.LittleEndian.Uint32(textData[i:i+uint64(size)]), text)
+			} else {
+				fmt.Fprintf(tw, "\t%s:%d\t%#x\t%x\t%s\n", base(file), line, pc, textData[i:i+uint64(size)], text)
+			}
+			pc += uint64(size)
+		}
+		tw.Flush()
+	}
+}
+
+func disasm_386(code []byte, pc uint64, lookup lookupFunc) (string, int) {
+	return disasm_x86(code, pc, lookup, 32)
+}
+
+func disasm_amd64(code []byte, pc uint64, lookup lookupFunc) (string, int) {
+	return disasm_x86(code, pc, lookup, 64)
+}
+
+func disasm_x86(code []byte, pc uint64, lookup lookupFunc, arch int) (string, int) {
+	inst, err := x86_Decode(code, 64)
+	var text string
+	size := inst.Len
+	if err != nil || size == 0 || inst.Op == 0 {
+		size = 1
+		text = "?"
+	} else {
+		text = x86_plan9Syntax(inst, pc, lookup)
+	}
+	return text, size
+}
+
+type textReader struct {
+	code []byte
+	pc   uint64
+}
+
+func (r textReader) ReadAt(data []byte, off int64) (n int, err error) {
+	if off < 0 || uint64(off) < r.pc {
+		return 0, io.EOF
+	}
+	d := uint64(off) - r.pc
+	if d >= uint64(len(r.code)) {
+		return 0, io.EOF
+	}
+	n = copy(data, r.code[d:])
+	if n < len(data) {
+		err = io.ErrUnexpectedEOF
+	}
+	return
+}
+
+func disasm_arm(code []byte, pc uint64, lookup lookupFunc) (string, int) {
+	inst, err := arm_Decode(code, arm_ModeARM)
+	var text string
+	size := inst.Len
+	if err != nil || size == 0 || inst.Op == 0 {
+		size = 4
+		text = "?"
+	} else {
+		text = arm_plan9Syntax(inst, pc, lookup, textReader{code, pc})
+	}
+	return text, size
+}
+
+var disasms = map[string]disasmFunc{
+	"386":   disasm_386,
+	"amd64": disasm_amd64,
+	"arm":   disasm_arm,
+}
+
+func gnuDump(tab *gosym.Table, lookup lookupFunc, disasm disasmFunc, textData []byte, textStart uint64) {
+	start, err := strconv.ParseUint(strings.TrimPrefix(flag.Arg(1), "0x"), 16, 64)
+	if err != nil {
+		log.Fatalf("invalid start PC: %v", err)
+	}
+	end, err := strconv.ParseUint(strings.TrimPrefix(flag.Arg(2), "0x"), 16, 64)
+	if err != nil {
+		log.Fatalf("invalid end PC: %v", err)
+	}
+	if start < textStart {
+		start = textStart
+	}
+	if end < start {
+		end = start
+	}
+	if end > textStart+uint64(len(textData)) {
+		end = textStart + uint64(len(textData))
+	}
+
+	stdout := bufio.NewWriter(os.Stdout)
+	defer stdout.Flush()
+
+	// For now, find spans of same PC/line/fn and
+	// emit them as having dummy instructions.
+	var (
+		spanPC   uint64
+		spanFile string
+		spanLine int
+		spanFn   *gosym.Func
+	)
+
+	flush := func(endPC uint64) {
+		if spanPC == 0 {
+			return
+		}
+		fmt.Fprintf(stdout, "%s:%d\n", spanFile, spanLine)
+		for pc := spanPC; pc < endPC; {
+			text, size := disasm(textData[pc-textStart:], pc, lookup)
+			fmt.Fprintf(stdout, " %x: %s\n", pc, text)
+			pc += uint64(size)
+		}
+		spanPC = 0
+	}
+
+	for pc := start; pc < end; pc++ {
+		file, line, fn := tab.PCToLine(pc)
+		if file != spanFile || line != spanLine || fn != spanFn {
+			flush(pc)
+			spanPC, spanFile, spanLine, spanFn = pc, file, line, fn
+		}
+	}
+	flush(end)
+}
+
+func loadTables(f *os.File) (textStart uint64, textData, symtab, pclntab []byte, err error) {
+	if obj, err := elf.NewFile(f); err == nil {
+		if sect := obj.Section(".text"); sect != nil {
+			textStart = sect.Addr
+			textData, _ = sect.Data()
+		}
+		if sect := obj.Section(".gosymtab"); sect != nil {
+			if symtab, err = sect.Data(); err != nil {
+				return 0, nil, nil, nil, err
+			}
+		}
+		if sect := obj.Section(".gopclntab"); sect != nil {
+			if pclntab, err = sect.Data(); err != nil {
+				return 0, nil, nil, nil, err
+			}
+		}
+		return textStart, textData, symtab, pclntab, nil
+	}
+
+	if obj, err := macho.NewFile(f); err == nil {
+		if sect := obj.Section("__text"); sect != nil {
+			textStart = sect.Addr
+			textData, _ = sect.Data()
+		}
+		if sect := obj.Section("__gosymtab"); sect != nil {
+			if symtab, err = sect.Data(); err != nil {
+				return 0, nil, nil, nil, err
+			}
+		}
+		if sect := obj.Section("__gopclntab"); sect != nil {
+			if pclntab, err = sect.Data(); err != nil {
+				return 0, nil, nil, nil, err
+			}
+		}
+		return textStart, textData, 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, nil, fmt.Errorf("pe file format not recognized")
+		}
+		if sect := obj.Section(".text"); sect != nil {
+			textStart = imageBase + uint64(sect.VirtualAddress)
+			textData, _ = sect.Data()
+		}
+		if pclntab, err = loadPETable(obj, "pclntab", "epclntab"); err != nil {
+			return 0, nil, nil, nil, err
+		}
+		if symtab, err = loadPETable(obj, "symtab", "esymtab"); err != nil {
+			return 0, nil, nil, nil, err
+		}
+		return textStart, textData, symtab, pclntab, nil
+	}
+
+	if obj, err := plan9obj.NewFile(f); err == nil {
+		sym, err := findPlan9Symbol(obj, "text")
+		if err != nil {
+			return 0, nil, nil, nil, err
+		}
+		textStart = sym.Value
+		if sect := obj.Section("text"); sect != nil {
+			textData, _ = sect.Data()
+		}
+		if pclntab, err = loadPlan9Table(obj, "pclntab", "epclntab"); err != nil {
+			return 0, nil, nil, nil, err
+		}
+		if symtab, err = loadPlan9Table(obj, "symtab", "esymtab"); err != nil {
+			return 0, nil, nil, nil, err
+		}
+		return textStart, textData, symtab, pclntab, nil
+	}
+
+	return 0, nil, 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
+}
+
+// TODO(rsc): This code is taken from cmd/nm. Arrange some way to share the code.
+
+var exitCode = 0
+
+func errorf(format string, args ...interface{}) {
+	log.Printf(format, args...)
+	exitCode = 1
+}
+
+func loadSymbols(f *os.File) (syms []Sym, goarch string, err error) {
+	f.Seek(0, 0)
+	buf := make([]byte, 16)
+	io.ReadFull(f, buf)
+	f.Seek(0, 0)
+
+	for _, p := range parsers {
+		if bytes.HasPrefix(buf, p.prefix) {
+			syms, goarch = p.parse(f)
+			sort.Sort(byAddr(syms))
+			return
+		}
+	}
+	err = fmt.Errorf("unknown file format")
+	return
+}
+
+type Sym struct {
+	Addr uint64
+	Size int64
+	Code rune
+	Name string
+	Type string
+}
+
+var parsers = []struct {
+	prefix []byte
+	parse  func(*os.File) ([]Sym, string)
+}{
+	{[]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
+}
+
+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 }
diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go
new file mode 100644
index 0000000..82311bb
--- /dev/null
+++ b/src/cmd/objdump/objdump_test.go
@@ -0,0 +1,193 @@
+// 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"
+	"strconv"
+	"strings"
+	"testing"
+)
+
+func loadSyms(t *testing.T) map[string]string {
+	if runtime.GOOS == "nacl" {
+		t.Skip("skipping on nacl")
+	}
+
+	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 runObjDump(t *testing.T, exe, startaddr, endaddr string) (path, lineno string) {
+	if runtime.GOOS == "nacl" {
+		t.Skip("skipping on nacl")
+	}
+
+	cmd := exec.Command(exe, os.Args[0], startaddr, endaddr)
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("go tool objdump %v: %v\n%s", os.Args[0], err, string(out))
+	}
+	f := strings.Split(string(out), "\n")
+	if len(f) < 1 {
+		t.Fatal("objdump output must have at least one line")
+	}
+	pathAndLineNo := f[0]
+	f = strings.Split(pathAndLineNo, ":")
+	if runtime.GOOS == "windows" {
+		switch len(f) {
+		case 2:
+			return f[0], f[1]
+		case 3:
+			return 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 f[0], f[1]
+}
+
+func testObjDump(t *testing.T, exe, startaddr, endaddr string, line int) {
+	srcPath, srcLineNo := runObjDump(t, exe, startaddr, endaddr)
+	fi1, err := os.Stat("objdump_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("objdump_test.go and %s are not same file", srcPath)
+	}
+	if srcLineNo != fmt.Sprint(line) {
+		t.Fatalf("line number = %v; want %d", srcLineNo, line)
+	}
+}
+
+func TestObjDump(t *testing.T) {
+	_, _, line, _ := runtime.Caller(0)
+	syms := loadSyms(t)
+
+	tmp, exe := buildObjdump(t)
+	defer os.RemoveAll(tmp)
+
+	startaddr := syms["cmd/objdump.TestObjDump"]
+	addr, err := strconv.ParseUint(startaddr, 16, 64)
+	if err != nil {
+		t.Fatalf("invalid start address %v: %v", startaddr, err)
+	}
+	endaddr := fmt.Sprintf("%x", addr+10)
+	testObjDump(t, exe, startaddr, endaddr, line-1)
+	testObjDump(t, exe, "0x"+startaddr, "0x"+endaddr, line-1)
+}
+
+func buildObjdump(t *testing.T) (tmp, exe string) {
+	if runtime.GOOS == "nacl" {
+		t.Skip("skipping on nacl")
+	}
+
+	tmp, err := ioutil.TempDir("", "TestObjDump")
+	if err != nil {
+		t.Fatal("TempDir failed: ", err)
+	}
+
+	exe = filepath.Join(tmp, "testobjdump.exe")
+	out, err := exec.Command("go", "build", "-o", exe, "cmd/objdump").CombinedOutput()
+	if err != nil {
+		os.RemoveAll(tmp)
+		t.Fatalf("go build -o %v cmd/objdump: %v\n%s", exe, err, string(out))
+	}
+	return
+}
+
+var x86Need = []string{
+	"fmthello.go:6",
+	"TEXT main.main(SB)",
+	"JMP main.main(SB)",
+	"CALL fmt.Println(SB)",
+	"RET",
+}
+
+var armNeed = []string{
+	"fmthello.go:6",
+	"TEXT main.main(SB)",
+	"B.LS main.main(SB)",
+	"BL fmt.Println(SB)",
+	"RET",
+}
+
+// objdump is fully cross platform: it can handle binaries
+// from any known operating system and architecture.
+// We could in principle add binaries to testdata and check
+// all the supported systems during this test. However, the
+// binaries would be about 1 MB each, and we don't want to
+// add that much junk to the hg repository. Instead, build a
+// binary for the current system (only) and test that objdump
+// can handle that one.
+
+func TestDisasm(t *testing.T) {
+	tmp, exe := buildObjdump(t)
+	defer os.RemoveAll(tmp)
+
+	hello := filepath.Join(tmp, "hello.exe")
+	out, err := exec.Command("go", "build", "-o", hello, "testdata/fmthello.go").CombinedOutput()
+	if err != nil {
+		t.Fatalf("go build fmthello.go: %v\n%s", err, out)
+	}
+	need := []string{
+		"fmthello.go:6",
+		"TEXT main.main(SB)",
+	}
+	switch runtime.GOARCH {
+	case "amd64", "386":
+		need = append(need, x86Need...)
+	case "arm":
+		need = append(need, armNeed...)
+	}
+
+	out, err = exec.Command(exe, "-s", "main.main", hello).CombinedOutput()
+	if err != nil {
+		t.Fatalf("objdump fmthello.exe: %v\n%s", err, out)
+	}
+
+	text := string(out)
+	ok := true
+	for _, s := range need {
+		if !strings.Contains(text, s) {
+			t.Errorf("disassembly missing '%s'", s)
+			ok = false
+		}
+	}
+	if !ok {
+		t.Logf("full disassembly:\n%s", text)
+	}
+}
diff --git a/src/cmd/objdump/pe.go b/src/cmd/objdump/pe.go
new file mode 100644
index 0000000..3819009
--- /dev/null
+++ b/src/cmd/objdump/pe.go
@@ -0,0 +1,99 @@
+// 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) (syms []Sym, goarch string) {
+	p, err := pe.NewFile(f)
+	if err != nil {
+		errorf("parsing %s: %v", f.Name(), err)
+		return
+	}
+
+	// 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)
+		goarch = "386"
+	case *pe.OptionalHeader64:
+		imageBase = oh.ImageBase
+		goarch = "amd64"
+	default:
+		errorf("parsing %s: file format not recognized", f.Name())
+		return
+	}
+
+	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
+			}
+			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
+			}
+			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
+}
diff --git a/src/cmd/objdump/plan9obj.go b/src/cmd/objdump/plan9obj.go
new file mode 100644
index 0000000..34462f3
--- /dev/null
+++ b/src/cmd/objdump/plan9obj.go
@@ -0,0 +1,63 @@
+// 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"
+)
+
+var validSymType = map[rune]bool{
+	'T': true,
+	't': true,
+	'D': true,
+	'd': true,
+	'B': true,
+	'b': true,
+}
+
+func plan9Symbols(f *os.File) (syms []Sym, goarch string) {
+	p, err := plan9obj.NewFile(f)
+	if err != nil {
+		errorf("parsing %s: %v", f.Name(), err)
+		return
+	}
+
+	plan9Syms, err := p.Symbols()
+	if err != nil {
+		errorf("parsing %s: %v", f.Name(), err)
+		return
+	}
+
+	goarch = "386"
+
+	// 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 {
+		if !validSymType[s.Type] {
+			continue
+		}
+		addrs = append(addrs, s.Value)
+	}
+	sort.Sort(uint64s(addrs))
+
+	for _, s := range plan9Syms {
+		if !validSymType[s.Type] {
+			continue
+		}
+		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
+}
diff --git a/src/cmd/objdump/testdata/fmthello.go b/src/cmd/objdump/testdata/fmthello.go
new file mode 100644
index 0000000..635db7a
--- /dev/null
+++ b/src/cmd/objdump/testdata/fmthello.go
@@ -0,0 +1,7 @@
+package main
+
+import "fmt"
+
+func main() {
+	fmt.Println("hello, world")
+}
diff --git a/src/cmd/objdump/x86.go b/src/cmd/objdump/x86.go
new file mode 100644
index 0000000..8e74133
--- /dev/null
+++ b/src/cmd/objdump/x86.go
@@ -0,0 +1,13800 @@
+// DO NOT EDIT. Generated by code.google.com/p/rsc/cmd/bundle
+// bundle -p main -x x86_ rsc.io/x86/x86asm
+
+/* 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.
+
+// Table-driven decoding of x86 instructions.
+
+package main
+
+import (
+	"bytes"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"runtime"
+	"strings"
+)
+
+// Set trace to true to cause the decoder to print the PC sequence
+// of the executed instruction codes. This is typically only useful
+// when you are running a test of a single input case.
+const x86_trace = false
+
+// A decodeOp is a single instruction in the decoder bytecode program.
+//
+// The decodeOps correspond to consuming and conditionally branching
+// on input bytes, consuming additional fields, and then interpreting
+// consumed data as instruction arguments. The names of the xRead and xArg
+// operations are taken from the Intel manual conventions, for example
+// Volume 2, Section 3.1.1, page 487 of
+// http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf
+//
+// The actual decoding program is generated by ../x86map.
+//
+// TODO(rsc): We may be able to merge various of the memory operands
+// since we don't care about, say, the distinction between m80dec and m80bcd.
+// Similarly, mm and mm1 have identical meaning, as do xmm and xmm1.
+
+type x86_decodeOp uint16
+
+const (
+	x86_xFail  x86_decodeOp = iota // invalid instruction (return)
+	x86_xMatch                     // completed match
+	x86_xJump                      // jump to pc
+
+	x86_xCondByte     // switch on instruction byte value
+	x86_xCondSlashR   // read and switch on instruction /r value
+	x86_xCondPrefix   // switch on presence of instruction prefix
+	x86_xCondIs64     // switch on 64-bit processor mode
+	x86_xCondDataSize // switch on operand size
+	x86_xCondAddrSize // switch on address size
+	x86_xCondIsMem    // switch on memory vs register argument
+
+	x86_xSetOp // set instruction opcode
+
+	x86_xReadSlashR // read /r
+	x86_xReadIb     // read ib
+	x86_xReadIw     // read iw
+	x86_xReadId     // read id
+	x86_xReadIo     // read io
+	x86_xReadCb     // read cb
+	x86_xReadCw     // read cw
+	x86_xReadCd     // read cd
+	x86_xReadCp     // read cp
+	x86_xReadCm     // read cm
+
+	x86_xArg1            // arg 1
+	x86_xArg3            // arg 3
+	x86_xArgAL           // arg AL
+	x86_xArgAX           // arg AX
+	x86_xArgCL           // arg CL
+	x86_xArgCR0dashCR7   // arg CR0-CR7
+	x86_xArgCS           // arg CS
+	x86_xArgDR0dashDR7   // arg DR0-DR7
+	x86_xArgDS           // arg DS
+	x86_xArgDX           // arg DX
+	x86_xArgEAX          // arg EAX
+	x86_xArgEDX          // arg EDX
+	x86_xArgES           // arg ES
+	x86_xArgFS           // arg FS
+	x86_xArgGS           // arg GS
+	x86_xArgImm16        // arg imm16
+	x86_xArgImm32        // arg imm32
+	x86_xArgImm64        // arg imm64
+	x86_xArgImm8         // arg imm8
+	x86_xArgImm8u        // arg imm8 but record as unsigned
+	x86_xArgImm16u       // arg imm8 but record as unsigned
+	x86_xArgM            // arg m
+	x86_xArgM128         // arg m128
+	x86_xArgM1428byte    // arg m14/28byte
+	x86_xArgM16          // arg m16
+	x86_xArgM16and16     // arg m16&16
+	x86_xArgM16and32     // arg m16&32
+	x86_xArgM16and64     // arg m16&64
+	x86_xArgM16colon16   // arg m16:16
+	x86_xArgM16colon32   // arg m16:32
+	x86_xArgM16colon64   // arg m16:64
+	x86_xArgM16int       // arg m16int
+	x86_xArgM2byte       // arg m2byte
+	x86_xArgM32          // arg m32
+	x86_xArgM32and32     // arg m32&32
+	x86_xArgM32fp        // arg m32fp
+	x86_xArgM32int       // arg m32int
+	x86_xArgM512byte     // arg m512byte
+	x86_xArgM64          // arg m64
+	x86_xArgM64fp        // arg m64fp
+	x86_xArgM64int       // arg m64int
+	x86_xArgM8           // arg m8
+	x86_xArgM80bcd       // arg m80bcd
+	x86_xArgM80dec       // arg m80dec
+	x86_xArgM80fp        // arg m80fp
+	x86_xArgM94108byte   // arg m94/108byte
+	x86_xArgMm           // arg mm
+	x86_xArgMm1          // arg mm1
+	x86_xArgMm2          // arg mm2
+	x86_xArgMm2M64       // arg mm2/m64
+	x86_xArgMmM32        // arg mm/m32
+	x86_xArgMmM64        // arg mm/m64
+	x86_xArgMem          // arg mem
+	x86_xArgMoffs16      // arg moffs16
+	x86_xArgMoffs32      // arg moffs32
+	x86_xArgMoffs64      // arg moffs64
+	x86_xArgMoffs8       // arg moffs8
+	x86_xArgPtr16colon16 // arg ptr16:16
+	x86_xArgPtr16colon32 // arg ptr16:32
+	x86_xArgR16          // arg r16
+	x86_xArgR16op        // arg r16 with +rw in opcode
+	x86_xArgR32          // arg r32
+	x86_xArgR32M16       // arg r32/m16
+	x86_xArgR32M8        // arg r32/m8
+	x86_xArgR32op        // arg r32 with +rd in opcode
+	x86_xArgR64          // arg r64
+	x86_xArgR64M16       // arg r64/m16
+	x86_xArgR64op        // arg r64 with +rd in opcode
+	x86_xArgR8           // arg r8
+	x86_xArgR8op         // arg r8 with +rb in opcode
+	x86_xArgRAX          // arg RAX
+	x86_xArgRDX          // arg RDX
+	x86_xArgRM           // arg r/m
+	x86_xArgRM16         // arg r/m16
+	x86_xArgRM32         // arg r/m32
+	x86_xArgRM64         // arg r/m64
+	x86_xArgRM8          // arg r/m8
+	x86_xArgReg          // arg reg
+	x86_xArgRegM16       // arg reg/m16
+	x86_xArgRegM32       // arg reg/m32
+	x86_xArgRegM8        // arg reg/m8
+	x86_xArgRel16        // arg rel16
+	x86_xArgRel32        // arg rel32
+	x86_xArgRel8         // arg rel8
+	x86_xArgSS           // arg SS
+	x86_xArgST           // arg ST, aka ST(0)
+	x86_xArgSTi          // arg ST(i) with +i in opcode
+	x86_xArgSreg         // arg Sreg
+	x86_xArgTR0dashTR7   // arg TR0-TR7
+	x86_xArgXmm          // arg xmm
+	x86_xArgXMM0         // arg <XMM0>
+	x86_xArgXmm1         // arg xmm1
+	x86_xArgXmm2         // arg xmm2
+	x86_xArgXmm2M128     // arg xmm2/m128
+	x86_xArgXmm2M16      // arg xmm2/m16
+	x86_xArgXmm2M32      // arg xmm2/m32
+	x86_xArgXmm2M64      // arg xmm2/m64
+	x86_xArgXmmM128      // arg xmm/m128
+	x86_xArgXmmM32       // arg xmm/m32
+	x86_xArgXmmM64       // arg xmm/m64
+	x86_xArgRmf16        // arg r/m16 but force mod=3
+	x86_xArgRmf32        // arg r/m32 but force mod=3
+	x86_xArgRmf64        // arg r/m64 but force mod=3
+)
+
+// instPrefix returns an Inst describing just one prefix byte.
+// It is only used if there is a prefix followed by an unintelligible
+// or invalid instruction byte sequence.
+func x86_instPrefix(b byte, mode int) (x86_Inst, error) {
+	// When tracing it is useful to see what called instPrefix to report an error.
+	if x86_trace {
+		_, file, line, _ := runtime.Caller(1)
+		fmt.Printf("%s:%d\n", file, line)
+	}
+	p := x86_Prefix(b)
+	switch p {
+	case x86_PrefixDataSize:
+		if mode == 16 {
+			p = x86_PrefixData32
+		} else {
+			p = x86_PrefixData16
+		}
+	case x86_PrefixAddrSize:
+		if mode == 32 {
+			p = x86_PrefixAddr16
+		} else {
+			p = x86_PrefixAddr32
+		}
+	}
+	// Note: using composite literal with Prefix key confuses 'bundle' tool.
+	inst := x86_Inst{Len: 1}
+	inst.Prefix = x86_Prefixes{p}
+	return inst, nil
+}
+
+// truncated reports a truncated instruction.
+// For now we use instPrefix but perhaps later we will return
+// a specific error here.
+func x86_truncated(src []byte, mode int) (x86_Inst, error) {
+	//	return Inst{}, len(src), ErrTruncated
+	return x86_instPrefix(src[0], mode) // too long
+}
+
+// These are the errors returned by Decode.
+var (
+	x86_ErrInvalidMode  = errors.New("invalid x86 mode in Decode")
+	x86_ErrTruncated    = errors.New("truncated instruction")
+	x86_ErrUnrecognized = errors.New("unrecognized instruction")
+)
+
+// decoderCover records coverage information for which parts
+// of the byte code have been executed.
+// TODO(rsc): This is for testing. Only use this if a flag is given.
+var x86_decoderCover []bool
+
+// Decode decodes the leading bytes in src as a single instruction.
+// The mode arguments specifies the assumed processor mode:
+// 16, 32, or 64 for 16-, 32-, and 64-bit execution modes.
+func x86_Decode(src []byte, mode int) (inst x86_Inst, err error) {
+	return x86_decode1(src, mode, false)
+}
+
+// decode1 is the implementation of Decode but takes an extra
+// gnuCompat flag to cause it to change its behavior to mimic
+// bugs (or at least unique features) of GNU libopcodes as used
+// by objdump. We don't believe that logic is the right thing to do
+// in general, but when testing against libopcodes it simplifies the
+// comparison if we adjust a few small pieces of logic.
+// The affected logic is in the conditional branch for "mandatory" prefixes,
+// case xCondPrefix.
+func x86_decode1(src []byte, mode int, gnuCompat bool) (x86_Inst, error) {
+	switch mode {
+	case 16, 32, 64:
+		// ok
+		// TODO(rsc): 64-bit mode not tested, probably not working.
+	default:
+		return x86_Inst{}, x86_ErrInvalidMode
+	}
+
+	// Maximum instruction size is 15 bytes.
+	// If we need to read more, return 'truncated instruction.
+	if len(src) > 15 {
+		src = src[:15]
+	}
+
+	var (
+		// prefix decoding information
+		pos           = 0        // position reading src
+		nprefix       = 0        // number of prefixes
+		lockIndex     = -1       // index of LOCK prefix in src and inst.Prefix
+		repIndex      = -1       // index of REP/REPN prefix in src and inst.Prefix
+		segIndex      = -1       // index of Group 2 prefix in src and inst.Prefix
+		dataSizeIndex = -1       // index of Group 3 prefix in src and inst.Prefix
+		addrSizeIndex = -1       // index of Group 4 prefix in src and inst.Prefix
+		rex           x86_Prefix // rex byte if present (or 0)
+		rexUsed       x86_Prefix // bits used in rex byte
+		rexIndex      = -1       // index of rex byte
+
+		addrMode = mode // address mode (width in bits)
+		dataMode = mode // operand mode (width in bits)
+
+		// decoded ModR/M fields
+		haveModrm bool
+		modrm     int
+		mod       int
+		regop     int
+		rm        int
+
+		// if ModR/M is memory reference, Mem form
+		mem     x86_Mem
+		haveMem bool
+
+		// decoded SIB fields
+		haveSIB bool
+		sib     int
+		scale   int
+		index   int
+		base    int
+
+		// decoded immediate values
+		imm  int64
+		imm8 int8
+		immc int64
+
+		// output
+		opshift int
+		inst    x86_Inst
+		narg    int // number of arguments written to inst
+	)
+
+	if mode == 64 {
+		dataMode = 32
+	}
+
+	// Prefixes are certainly the most complex and underspecified part of
+	// decoding x86 instructions. Although the manuals say things like
+	// up to four prefixes, one from each group, nearly everyone seems to
+	// agree that in practice as many prefixes as possible, including multiple
+	// from a particular group or repetitions of a given prefix, can be used on
+	// an instruction, provided the total instruction length including prefixes
+	// does not exceed the agreed-upon maximum of 15 bytes.
+	// Everyone also agrees that if one of these prefixes is the LOCK prefix
+	// and the instruction is not one of the instructions that can be used with
+	// the LOCK prefix or if the destination is not a memory operand,
+	// then the instruction is invalid and produces the #UD exception.
+	// However, that is the end of any semblance of agreement.
+	//
+	// What happens if prefixes are given that conflict with other prefixes?
+	// For example, the memory segment overrides CS, DS, ES, FS, GS, SS
+	// conflict with each other: only one segment can be in effect.
+	// Disassemblers seem to agree that later prefixes take priority over
+	// earlier ones. I have not taken the time to write assembly programs
+	// to check to see if the hardware agrees.
+	//
+	// What happens if prefixes are given that have no meaning for the
+	// specific instruction to which they are attached? It depends.
+	// If they really have no meaning, they are ignored. However, a future
+	// processor may assign a different meaning. As a disassembler, we
+	// don't really know whether we're seeing a meaningless prefix or one
+	// whose meaning we simply haven't been told yet.
+	//
+	// Combining the two questions, what happens when conflicting
+	// extension prefixes are given? No one seems to know for sure.
+	// For example, MOVQ is 66 0F D6 /r, MOVDQ2Q is F2 0F D6 /r,
+	// and MOVQ2DQ is F3 0F D6 /r. What is '66 F2 F3 0F D6 /r'?
+	// Which prefix wins? See the xCondPrefix prefix for more.
+	//
+	// Writing assembly test cases to divine which interpretation the
+	// CPU uses might clarify the situation, but more likely it would
+	// make the situation even less clear.
+
+	// Read non-REX prefixes.
+ReadPrefixes:
+	for ; pos < len(src); pos++ {
+		p := x86_Prefix(src[pos])
+		switch p {
+		default:
+			nprefix = pos
+			break ReadPrefixes
+
+		// Group 1 - lock and repeat prefixes
+		// According to Intel, there should only be one from this set,
+		// but according to AMD both can be present.
+		case 0xF0:
+			if lockIndex >= 0 {
+				inst.Prefix[lockIndex] |= x86_PrefixIgnored
+			}
+			lockIndex = pos
+		case 0xF2, 0xF3:
+			if repIndex >= 0 {
+				inst.Prefix[repIndex] |= x86_PrefixIgnored
+			}
+			repIndex = pos
+
+		// Group 2 - segment override / branch hints
+		case 0x26, 0x2E, 0x36, 0x3E:
+			if mode == 64 {
+				p |= x86_PrefixIgnored
+				break
+			}
+			fallthrough
+		case 0x64, 0x65:
+			if segIndex >= 0 {
+				inst.Prefix[segIndex] |= x86_PrefixIgnored
+			}
+			segIndex = pos
+
+		// Group 3 - operand size override
+		case 0x66:
+			if mode == 16 {
+				dataMode = 32
+				p = x86_PrefixData32
+			} else {
+				dataMode = 16
+				p = x86_PrefixData16
+			}
+			if dataSizeIndex >= 0 {
+				inst.Prefix[dataSizeIndex] |= x86_PrefixIgnored
+			}
+			dataSizeIndex = pos
+
+		// Group 4 - address size override
+		case 0x67:
+			if mode == 32 {
+				addrMode = 16
+				p = x86_PrefixAddr16
+			} else {
+				addrMode = 32
+				p = x86_PrefixAddr32
+			}
+			if addrSizeIndex >= 0 {
+				inst.Prefix[addrSizeIndex] |= x86_PrefixIgnored
+			}
+			addrSizeIndex = pos
+		}
+
+		if pos >= len(inst.Prefix) {
+			return x86_instPrefix(src[0], mode) // too long
+		}
+
+		inst.Prefix[pos] = p
+	}
+
+	// Read REX prefix.
+	if pos < len(src) && mode == 64 && x86_Prefix(src[pos]).IsREX() {
+		rex = x86_Prefix(src[pos])
+		rexIndex = pos
+		if pos >= len(inst.Prefix) {
+			return x86_instPrefix(src[0], mode) // too long
+		}
+		inst.Prefix[pos] = rex
+		pos++
+		if rex&x86_PrefixREXW != 0 {
+			dataMode = 64
+			if dataSizeIndex >= 0 {
+				inst.Prefix[dataSizeIndex] |= x86_PrefixIgnored
+			}
+		}
+	}
+
+	// Decode instruction stream, interpreting decoding instructions.
+	// opshift gives the shift to use when saving the next
+	// opcode byte into inst.Opcode.
+	opshift = 24
+	if x86_decoderCover == nil {
+		x86_decoderCover = make([]bool, len(x86_decoder))
+	}
+
+	// Decode loop, executing decoder program.
+	var oldPC, prevPC int
+Decode:
+	for pc := 1; ; { // TODO uint
+		oldPC = prevPC
+		prevPC = pc
+		if x86_trace {
+			println("run", pc)
+		}
+		x := x86_decoder[pc]
+		x86_decoderCover[pc] = true
+		pc++
+
+		// Read and decode ModR/M if needed by opcode.
+		switch x86_decodeOp(x) {
+		case x86_xCondSlashR, x86_xReadSlashR:
+			if haveModrm {
+				return x86_Inst{Len: pos}, x86_errInternal
+			}
+			haveModrm = true
+			if pos >= len(src) {
+				return x86_truncated(src, mode)
+			}
+			modrm = int(src[pos])
+			pos++
+			if opshift >= 0 {
+				inst.Opcode |= uint32(modrm) << uint(opshift)
+				opshift -= 8
+			}
+			mod = modrm >> 6
+			regop = (modrm >> 3) & 07
+			rm = modrm & 07
+			if rex&x86_PrefixREXR != 0 {
+				rexUsed |= x86_PrefixREXR
+				regop |= 8
+			}
+			if addrMode == 16 {
+				// 16-bit modrm form
+				if mod != 3 {
+					haveMem = true
+					mem = x86_addr16[rm]
+					if rm == 6 && mod == 0 {
+						mem.Base = 0
+					}
+
+					// Consume disp16 if present.
+					if mod == 0 && rm == 6 || mod == 2 {
+						if pos+2 > len(src) {
+							return x86_truncated(src, mode)
+						}
+						mem.Disp = int64(binary.LittleEndian.Uint16(src[pos:]))
+						pos += 2
+					}
+
+					// Consume disp8 if present.
+					if mod == 1 {
+						if pos >= len(src) {
+							return x86_truncated(src, mode)
+						}
+						mem.Disp = int64(int8(src[pos]))
+						pos++
+					}
+				}
+			} else {
+				haveMem = mod != 3
+
+				// 32-bit or 64-bit form
+				// Consume SIB encoding if present.
+				if rm == 4 && mod != 3 {
+					haveSIB = true
+					if pos >= len(src) {
+						return x86_truncated(src, mode)
+					}
+					sib = int(src[pos])
+					pos++
+					if opshift >= 0 {
+						inst.Opcode |= uint32(sib) << uint(opshift)
+						opshift -= 8
+					}
+					scale = sib >> 6
+					index = (sib >> 3) & 07
+					base = sib & 07
+					if rex&x86_PrefixREXB != 0 {
+						rexUsed |= x86_PrefixREXB
+						base |= 8
+					}
+					if rex&x86_PrefixREXX != 0 {
+						rexUsed |= x86_PrefixREXX
+						index |= 8
+					}
+
+					mem.Scale = 1 << uint(scale)
+					if index == 4 {
+						// no mem.Index
+					} else {
+						mem.Index = x86_baseRegForBits(addrMode) + x86_Reg(index)
+					}
+					if base&7 == 5 && mod == 0 {
+						// no mem.Base
+					} else {
+						mem.Base = x86_baseRegForBits(addrMode) + x86_Reg(base)
+					}
+				} else {
+					if rex&x86_PrefixREXB != 0 {
+						rexUsed |= x86_PrefixREXB
+						rm |= 8
+					}
+					if mod == 0 && rm&7 == 5 || rm&7 == 4 {
+						// base omitted
+					} else if mod != 3 {
+						mem.Base = x86_baseRegForBits(addrMode) + x86_Reg(rm)
+					}
+				}
+
+				// Consume disp32 if present.
+				if mod == 0 && (rm&7 == 5 || haveSIB && base&7 == 5) || mod == 2 {
+					if pos+4 > len(src) {
+						return x86_truncated(src, mode)
+					}
+					mem.Disp = int64(binary.LittleEndian.Uint32(src[pos:]))
+					pos += 4
+				}
+
+				// Consume disp8 if present.
+				if mod == 1 {
+					if pos >= len(src) {
+						return x86_truncated(src, mode)
+					}
+					mem.Disp = int64(int8(src[pos]))
+					pos++
+				}
+
+				// In 64-bit, mod=0 rm=5 is PC-relative instead of just disp.
+				// See Vol 2A. Table 2-7.
+				if mode == 64 && mod == 0 && rm&7 == 5 {
+					if addrMode == 32 {
+						mem.Base = x86_EIP
+					} else {
+						mem.Base = x86_RIP
+					}
+				}
+			}
+
+			if segIndex >= 0 {
+				mem.Segment = x86_prefixToSegment(inst.Prefix[segIndex])
+			}
+		}
+
+		// Execute single opcode.
+		switch x86_decodeOp(x) {
+		default:
+			println("bad op", x, "at", pc-1, "from", oldPC)
+			return x86_Inst{Len: pos}, x86_errInternal
+
+		case x86_xFail:
+			inst.Op = 0
+			break Decode
+
+		case x86_xMatch:
+			break Decode
+
+		case x86_xJump:
+			pc = int(x86_decoder[pc])
+
+		// Conditional branches.
+
+		case x86_xCondByte:
+			if pos >= len(src) {
+				return x86_truncated(src, mode)
+			}
+			b := src[pos]
+			n := int(x86_decoder[pc])
+			pc++
+			for i := 0; i < n; i++ {
+				xb, xpc := x86_decoder[pc], int(x86_decoder[pc+1])
+				pc += 2
+				if b == byte(xb) {
+					pc = xpc
+					pos++
+					if opshift >= 0 {
+						inst.Opcode |= uint32(b) << uint(opshift)
+						opshift -= 8
+					}
+					continue Decode
+				}
+			}
+			// xCondByte is the only conditional with a fall through,
+			// so that it can be used to pick off special cases before
+			// an xCondSlash. If the fallthrough instruction is xFail,
+			// advance the position so that the decoded instruction
+			// size includes the byte we just compared against.
+			if x86_decodeOp(x86_decoder[pc]) == x86_xJump {
+				pc = int(x86_decoder[pc+1])
+			}
+			if x86_decodeOp(x86_decoder[pc]) == x86_xFail {
+				pos++
+			}
+
+		case x86_xCondIs64:
+			if mode == 64 {
+				pc = int(x86_decoder[pc+1])
+			} else {
+				pc = int(x86_decoder[pc])
+			}
+
+		case x86_xCondIsMem:
+			mem := haveMem
+			if !haveModrm {
+				if pos >= len(src) {
+					return x86_instPrefix(src[0], mode) // too long
+				}
+				mem = src[pos]>>6 != 3
+			}
+			if mem {
+				pc = int(x86_decoder[pc+1])
+			} else {
+				pc = int(x86_decoder[pc])
+			}
+
+		case x86_xCondDataSize:
+			switch dataMode {
+			case 16:
+				if dataSizeIndex >= 0 {
+					inst.Prefix[dataSizeIndex] |= x86_PrefixImplicit
+				}
+				pc = int(x86_decoder[pc])
+			case 32:
+				if dataSizeIndex >= 0 {
+					inst.Prefix[dataSizeIndex] |= x86_PrefixImplicit
+				}
+				pc = int(x86_decoder[pc+1])
+			case 64:
+				rexUsed |= x86_PrefixREXW
+				pc = int(x86_decoder[pc+2])
+			}
+
+		case x86_xCondAddrSize:
+			switch addrMode {
+			case 16:
+				if addrSizeIndex >= 0 {
+					inst.Prefix[addrSizeIndex] |= x86_PrefixImplicit
+				}
+				pc = int(x86_decoder[pc])
+			case 32:
+				if addrSizeIndex >= 0 {
+					inst.Prefix[addrSizeIndex] |= x86_PrefixImplicit
+				}
+				pc = int(x86_decoder[pc+1])
+			case 64:
+				pc = int(x86_decoder[pc+2])
+			}
+
+		case x86_xCondPrefix:
+			// Conditional branch based on presence or absence of prefixes.
+			// The conflict cases here are completely undocumented and
+			// differ significantly between GNU libopcodes and Intel xed.
+			// I have not written assembly code to divine what various CPUs
+			// do, but it wouldn't surprise me if they are not consistent either.
+			//
+			// The basic idea is to switch on the presence of a prefix, so that
+			// for example:
+			//
+			//	xCondPrefix, 4
+			//	0xF3, 123,
+			//	0xF2, 234,
+			//	0x66, 345,
+			//	0, 456
+			//
+			// branch to 123 if the F3 prefix is present, 234 if the F2 prefix
+			// is present, 66 if the 345 prefix is present, and 456 otherwise.
+			// The prefixes are given in descending order so that the 0 will be last.
+			//
+			// It is unclear what should happen if multiple conditions are
+			// satisfied: what if F2 and F3 are both present, or if 66 and F2
+			// are present, or if all three are present? The one chosen becomes
+			// part of the opcode and the others do not. Perhaps the answer
+			// depends on the specific opcodes in question.
+			//
+			// The only clear example is that CRC32 is F2 0F 38 F1 /r, and
+			// it comes in 16-bit and 32-bit forms based on the 66 prefix,
+			// so 66 F2 0F 38 F1 /r should be treated as F2 taking priority,
+			// with the 66 being only an operand size override, and probably
+			// F2 66 0F 38 F1 /r should be treated the same.
+			// Perhaps that rule is specific to the case of CRC32, since no
+			// 66 0F 38 F1 instruction is defined (today) (that we know of).
+			// However, both libopcodes and xed seem to generalize this
+			// example and choose F2/F3 in preference to 66, and we
+			// do the same.
+			//
+			// Next, what if both F2 and F3 are present? Which wins?
+			// The Intel xed rule, and ours, is that the one that occurs last wins.
+			// The GNU libopcodes rule, which we implement only in gnuCompat mode,
+			// is that F3 beats F2 unless F3 has no special meaning, in which
+			// case F3 can be a modified on an F2 special meaning.
+			//
+			// Concretely,
+			//	66 0F D6 /r is MOVQ
+			//	F2 0F D6 /r is MOVDQ2Q
+			//	F3 0F D6 /r is MOVQ2DQ.
+			//
+			//	F2 66 0F D6 /r is 66 + MOVDQ2Q always.
+			//	66 F2 0F D6 /r is 66 + MOVDQ2Q always.
+			//	F3 66 0F D6 /r is 66 + MOVQ2DQ always.
+			//	66 F3 0F D6 /r is 66 + MOVQ2DQ always.
+			//	F2 F3 0F D6 /r is F2 + MOVQ2DQ always.
+			//	F3 F2 0F D6 /r is F3 + MOVQ2DQ in Intel xed, but F2 + MOVQ2DQ in GNU libopcodes.
+			//	Adding 66 anywhere in the prefix section of the
+			//	last two cases does not change the outcome.
+			//
+			// Finally, what if there is a variant in which 66 is a mandatory
+			// prefix rather than an operand size override, but we know of
+			// no corresponding F2/F3 form, and we see both F2/F3 and 66.
+			// Does F2/F3 still take priority, so that the result is an unknown
+			// instruction, or does the 66 take priority, so that the extended
+			// 66 instruction should be interpreted as having a REP/REPN prefix?
+			// Intel xed does the former and GNU libopcodes does the latter.
+			// We side with Intel xed, unless we are trying to match libopcodes
+			// more closely during the comparison-based test suite.
+			//
+			// In 64-bit mode REX.W is another valid prefix to test for, but
+			// there is less ambiguity about that. When present, REX.W is
+			// always the first entry in the table.
+			n := int(x86_decoder[pc])
+			pc++
+			sawF3 := false
+			for j := 0; j < n; j++ {
+				prefix := x86_Prefix(x86_decoder[pc+2*j])
+				if prefix.IsREX() {
+					rexUsed |= prefix
+					if rex&prefix == prefix {
+						pc = int(x86_decoder[pc+2*j+1])
+						continue Decode
+					}
+					continue
+				}
+				ok := false
+				if prefix == 0 {
+					ok = true
+				} else if prefix.IsREX() {
+					rexUsed |= prefix
+					if rex&prefix == prefix {
+						ok = true
+					}
+				} else {
+					if prefix == 0xF3 {
+						sawF3 = true
+					}
+					switch prefix {
+					case x86_PrefixLOCK:
+						if lockIndex >= 0 {
+							inst.Prefix[lockIndex] |= x86_PrefixImplicit
+							ok = true
+						}
+					case x86_PrefixREP, x86_PrefixREPN:
+						if repIndex >= 0 && inst.Prefix[repIndex]&0xFF == prefix {
+							inst.Prefix[repIndex] |= x86_PrefixImplicit
+							ok = true
+						}
+						if gnuCompat && !ok && prefix == 0xF3 && repIndex >= 0 && (j+1 >= n || x86_decoder[pc+2*(j+1)] != 0xF2) {
+							// Check to see if earlier prefix F3 is present.
+							for i := repIndex - 1; i >= 0; i-- {
+								if inst.Prefix[i]&0xFF == prefix {
+									inst.Prefix[i] |= x86_PrefixImplicit
+									ok = true
+								}
+							}
+						}
+						if gnuCompat && !ok && prefix == 0xF2 && repIndex >= 0 && !sawF3 && inst.Prefix[repIndex]&0xFF == 0xF3 {
+							// Check to see if earlier prefix F2 is present.
+							for i := repIndex - 1; i >= 0; i-- {
+								if inst.Prefix[i]&0xFF == prefix {
+									inst.Prefix[i] |= x86_PrefixImplicit
+									ok = true
+								}
+							}
+						}
+					case x86_PrefixCS, x86_PrefixDS, x86_PrefixES, x86_PrefixFS, x86_PrefixGS, x86_PrefixSS:
+						if segIndex >= 0 && inst.Prefix[segIndex]&0xFF == prefix {
+							inst.Prefix[segIndex] |= x86_PrefixImplicit
+							ok = true
+						}
+					case x86_PrefixDataSize:
+						// Looking for 66 mandatory prefix.
+						// The F2/F3 mandatory prefixes take priority when both are present.
+						// If we got this far in the xCondPrefix table and an F2/F3 is present,
+						// it means the table didn't have any entry for that prefix. But if 66 has
+						// special meaning, perhaps F2/F3 have special meaning that we don't know.
+						// Intel xed works this way, treating the F2/F3 as inhibiting the 66.
+						// GNU libopcodes allows the 66 to match. We do what Intel xed does
+						// except in gnuCompat mode.
+						if repIndex >= 0 && !gnuCompat {
+							inst.Op = 0
+							break Decode
+						}
+						if dataSizeIndex >= 0 {
+							inst.Prefix[dataSizeIndex] |= x86_PrefixImplicit
+							ok = true
+						}
+					case x86_PrefixAddrSize:
+						if addrSizeIndex >= 0 {
+							inst.Prefix[addrSizeIndex] |= x86_PrefixImplicit
+							ok = true
+						}
+					}
+				}
+				if ok {
+					pc = int(x86_decoder[pc+2*j+1])
+					continue Decode
+				}
+			}
+			inst.Op = 0
+			break Decode
+
+		case x86_xCondSlashR:
+			pc = int(x86_decoder[pc+regop&7])
+
+		// Input.
+
+		case x86_xReadSlashR:
+			// done above
+
+		case x86_xReadIb:
+			if pos >= len(src) {
+				return x86_truncated(src, mode)
+			}
+			imm8 = int8(src[pos])
+			pos++
+
+		case x86_xReadIw:
+			if pos+2 > len(src) {
+				return x86_truncated(src, mode)
+			}
+			imm = int64(binary.LittleEndian.Uint16(src[pos:]))
+			pos += 2
+
+		case x86_xReadId:
+			if pos+4 > len(src) {
+				return x86_truncated(src, mode)
+			}
+			imm = int64(binary.LittleEndian.Uint32(src[pos:]))
+			pos += 4
+
+		case x86_xReadIo:
+			if pos+8 > len(src) {
+				return x86_truncated(src, mode)
+			}
+			imm = int64(binary.LittleEndian.Uint64(src[pos:]))
+			pos += 8
+
+		case x86_xReadCb:
+			if pos >= len(src) {
+				return x86_truncated(src, mode)
+			}
+			immc = int64(src[pos])
+			pos++
+
+		case x86_xReadCw:
+			if pos+2 > len(src) {
+				return x86_truncated(src, mode)
+			}
+			immc = int64(binary.LittleEndian.Uint16(src[pos:]))
+			pos += 2
+
+		case x86_xReadCm:
+			if addrMode == 16 {
+				if pos+2 > len(src) {
+					return x86_truncated(src, mode)
+				}
+				immc = int64(binary.LittleEndian.Uint16(src[pos:]))
+				pos += 2
+			} else if addrMode == 32 {
+				if pos+4 > len(src) {
+					return x86_truncated(src, mode)
+				}
+				immc = int64(binary.LittleEndian.Uint32(src[pos:]))
+				pos += 4
+			} else {
+				if pos+8 > len(src) {
+					return x86_truncated(src, mode)
+				}
+				immc = int64(binary.LittleEndian.Uint64(src[pos:]))
+				pos += 8
+			}
+		case x86_xReadCd:
+			if pos+4 > len(src) {
+				return x86_truncated(src, mode)
+			}
+			immc = int64(binary.LittleEndian.Uint32(src[pos:]))
+			pos += 4
+
+		case x86_xReadCp:
+			if pos+6 > len(src) {
+				return x86_truncated(src, mode)
+			}
+			w := binary.LittleEndian.Uint32(src[pos:])
+			w2 := binary.LittleEndian.Uint16(src[pos+4:])
+			immc = int64(w2)<<32 | int64(w)
+			pos += 6
+
+		// Output.
+
+		case x86_xSetOp:
+			inst.Op = x86_Op(x86_decoder[pc])
+			pc++
+
+		case x86_xArg1,
+			x86_xArg3,
+			x86_xArgAL,
+			x86_xArgAX,
+			x86_xArgCL,
+			x86_xArgCS,
+			x86_xArgDS,
+			x86_xArgDX,
+			x86_xArgEAX,
+			x86_xArgEDX,
+			x86_xArgES,
+			x86_xArgFS,
+			x86_xArgGS,
+			x86_xArgRAX,
+			x86_xArgRDX,
+			x86_xArgSS,
+			x86_xArgST,
+			x86_xArgXMM0:
+			inst.Args[narg] = x86_fixedArg[x]
+			narg++
+
+		case x86_xArgImm8:
+			inst.Args[narg] = x86_Imm(imm8)
+			narg++
+
+		case x86_xArgImm8u:
+			inst.Args[narg] = x86_Imm(uint8(imm8))
+			narg++
+
+		case x86_xArgImm16:
+			inst.Args[narg] = x86_Imm(int16(imm))
+			narg++
+
+		case x86_xArgImm16u:
+			inst.Args[narg] = x86_Imm(uint16(imm))
+			narg++
+
+		case x86_xArgImm32:
+			inst.Args[narg] = x86_Imm(int32(imm))
+			narg++
+
+		case x86_xArgImm64:
+			inst.Args[narg] = x86_Imm(imm)
+			narg++
+
+		case x86_xArgM,
+			x86_xArgM128,
+			x86_xArgM1428byte,
+			x86_xArgM16,
+			x86_xArgM16and16,
+			x86_xArgM16and32,
+			x86_xArgM16and64,
+			x86_xArgM16colon16,
+			x86_xArgM16colon32,
+			x86_xArgM16colon64,
+			x86_xArgM16int,
+			x86_xArgM2byte,
+			x86_xArgM32,
+			x86_xArgM32and32,
+			x86_xArgM32fp,
+			x86_xArgM32int,
+			x86_xArgM512byte,
+			x86_xArgM64,
+			x86_xArgM64fp,
+			x86_xArgM64int,
+			x86_xArgM8,
+			x86_xArgM80bcd,
+			x86_xArgM80dec,
+			x86_xArgM80fp,
+			x86_xArgM94108byte,
+			x86_xArgMem:
+			if !haveMem {
+				inst.Op = 0
+				break Decode
+			}
+			inst.Args[narg] = mem
+			inst.MemBytes = int(x86_memBytes[x86_decodeOp(x)])
+			narg++
+
+		case x86_xArgPtr16colon16:
+			inst.Args[narg] = x86_Imm(immc >> 16)
+			inst.Args[narg+1] = x86_Imm(immc & (1<<16 - 1))
+			narg += 2
+
+		case x86_xArgPtr16colon32:
+			inst.Args[narg] = x86_Imm(immc >> 32)
+			inst.Args[narg+1] = x86_Imm(immc & (1<<32 - 1))
+			narg += 2
+
+		case x86_xArgMoffs8, x86_xArgMoffs16, x86_xArgMoffs32, x86_xArgMoffs64:
+			// TODO(rsc): Can address be 64 bits?
+			mem = x86_Mem{Disp: int64(immc)}
+			if segIndex >= 0 {
+				mem.Segment = x86_prefixToSegment(inst.Prefix[segIndex])
+				inst.Prefix[segIndex] |= x86_PrefixImplicit
+			}
+			inst.Args[narg] = mem
+			inst.MemBytes = int(x86_memBytes[x86_decodeOp(x)])
+			narg++
+
+		case x86_xArgR8, x86_xArgR16, x86_xArgR32, x86_xArgR64, x86_xArgXmm, x86_xArgXmm1, x86_xArgDR0dashDR7:
+			base := x86_baseReg[x]
+			index := x86_Reg(regop)
+			if rex != 0 && base == x86_AL && index >= 4 {
+				rexUsed |= x86_PrefixREX
+				index -= 4
+				base = x86_SPB
+			}
+			inst.Args[narg] = base + index
+			narg++
+
+		case x86_xArgMm, x86_xArgMm1, x86_xArgTR0dashTR7:
+			inst.Args[narg] = x86_baseReg[x] + x86_Reg(regop&7)
+			narg++
+
+		case x86_xArgCR0dashCR7:
+			// AMD documents an extension that the LOCK prefix
+			// can be used in place of a REX prefix in order to access
+			// CR8 from 32-bit mode. The LOCK prefix is allowed in
+			// all modes, provided the corresponding CPUID bit is set.
+			if lockIndex >= 0 {
+				inst.Prefix[lockIndex] |= x86_PrefixImplicit
+				regop += 8
+			}
+			inst.Args[narg] = x86_CR0 + x86_Reg(regop)
+			narg++
+
+		case x86_xArgSreg:
+			regop &= 7
+			if regop >= 6 {
+				inst.Op = 0
+				break Decode
+			}
+			inst.Args[narg] = x86_ES + x86_Reg(regop)
+			narg++
+
+		case x86_xArgRmf16, x86_xArgRmf32, x86_xArgRmf64:
+			base := x86_baseReg[x]
+			index := x86_Reg(modrm & 07)
+			if rex&x86_PrefixREXB != 0 {
+				rexUsed |= x86_PrefixREXB
+				index += 8
+			}
+			inst.Args[narg] = base + index
+			narg++
+
+		case x86_xArgR8op, x86_xArgR16op, x86_xArgR32op, x86_xArgR64op, x86_xArgSTi:
+			n := inst.Opcode >> uint(opshift+8) & 07
+			base := x86_baseReg[x]
+			index := x86_Reg(n)
+			if rex&x86_PrefixREXB != 0 && x86_decodeOp(x) != x86_xArgSTi {
+				rexUsed |= x86_PrefixREXB
+				index += 8
+			}
+			if rex != 0 && base == x86_AL && index >= 4 {
+				rexUsed |= x86_PrefixREX
+				index -= 4
+				base = x86_SPB
+			}
+			inst.Args[narg] = base + index
+			narg++
+
+		case x86_xArgRM8, x86_xArgRM16, x86_xArgRM32, x86_xArgRM64, x86_xArgR32M16, x86_xArgR32M8, x86_xArgR64M16,
+			x86_xArgMmM32, x86_xArgMmM64, x86_xArgMm2M64,
+			x86_xArgXmm2M16, x86_xArgXmm2M32, x86_xArgXmm2M64, x86_xArgXmmM64, x86_xArgXmmM128, x86_xArgXmmM32, x86_xArgXmm2M128:
+			if haveMem {
+				inst.Args[narg] = mem
+				inst.MemBytes = int(x86_memBytes[x86_decodeOp(x)])
+			} else {
+				base := x86_baseReg[x]
+				index := x86_Reg(rm)
+				switch x86_decodeOp(x) {
+				case x86_xArgMmM32, x86_xArgMmM64, x86_xArgMm2M64:
+					// There are only 8 MMX registers, so these ignore the REX.X bit.
+					index &= 7
+				case x86_xArgRM8:
+					if rex != 0 && index >= 4 {
+						rexUsed |= x86_PrefixREX
+						index -= 4
+						base = x86_SPB
+					}
+				}
+				inst.Args[narg] = base + index
+			}
+			narg++
+
+		case x86_xArgMm2: // register only; TODO(rsc): Handle with tag modrm_regonly tag
+			if haveMem {
+				inst.Op = 0
+				break Decode
+			}
+			inst.Args[narg] = x86_baseReg[x] + x86_Reg(rm&7)
+			narg++
+
+		case x86_xArgXmm2: // register only; TODO(rsc): Handle with tag modrm_regonly tag
+			if haveMem {
+				inst.Op = 0
+				break Decode
+			}
+			inst.Args[narg] = x86_baseReg[x] + x86_Reg(rm)
+			narg++
+
+		case x86_xArgRel8:
+			inst.Args[narg] = x86_Rel(int8(immc))
+			narg++
+
+		case x86_xArgRel16:
+			inst.Args[narg] = x86_Rel(int16(immc))
+			narg++
+
+		case x86_xArgRel32:
+			inst.Args[narg] = x86_Rel(int32(immc))
+			narg++
+		}
+	}
+
+	if inst.Op == 0 {
+		// Invalid instruction.
+		if nprefix > 0 {
+			return x86_instPrefix(src[0], mode) // invalid instruction
+		}
+		return x86_Inst{Len: pos}, x86_ErrUnrecognized
+	}
+
+	// Matched! Hooray!
+
+	// 90 decodes as XCHG EAX, EAX but is NOP.
+	// 66 90 decodes as XCHG AX, AX and is NOP too.
+	// 48 90 decodes as XCHG RAX, RAX and is NOP too.
+	// 43 90 decodes as XCHG R8D, EAX and is *not* NOP.
+	// F3 90 decodes as REP XCHG EAX, EAX but is PAUSE.
+	// It's all too special to handle in the decoding tables, at least for now.
+	if inst.Op == x86_XCHG && inst.Opcode>>24 == 0x90 {
+		if inst.Args[0] == x86_RAX || inst.Args[0] == x86_EAX || inst.Args[0] == x86_AX {
+			inst.Op = x86_NOP
+			if dataSizeIndex >= 0 {
+				inst.Prefix[dataSizeIndex] &^= x86_PrefixImplicit
+			}
+			inst.Args[0] = nil
+			inst.Args[1] = nil
+		}
+		if repIndex >= 0 && inst.Prefix[repIndex] == 0xF3 {
+			inst.Prefix[repIndex] |= x86_PrefixImplicit
+			inst.Op = x86_PAUSE
+			inst.Args[0] = nil
+			inst.Args[1] = nil
+		} else if gnuCompat {
+			for i := nprefix - 1; i >= 0; i-- {
+				if inst.Prefix[i]&0xFF == 0xF3 {
+					inst.Prefix[i] |= x86_PrefixImplicit
+					inst.Op = x86_PAUSE
+					inst.Args[0] = nil
+					inst.Args[1] = nil
+					break
+				}
+			}
+		}
+	}
+
+	// defaultSeg returns the default segment for an implicit
+	// memory reference: the final override if present, or else DS.
+	defaultSeg := func() x86_Reg {
+		if segIndex >= 0 {
+			inst.Prefix[segIndex] |= x86_PrefixImplicit
+			return x86_prefixToSegment(inst.Prefix[segIndex])
+		}
+		return x86_DS
+	}
+
+	// Add implicit arguments not present in the tables.
+	// Normally we shy away from making implicit arguments explicit,
+	// following the Intel manuals, but adding the arguments seems
+	// the best way to express the effect of the segment override prefixes.
+	// TODO(rsc): Perhaps add these to the tables and
+	// create bytecode instructions for them.
+	usedAddrSize := false
+	switch inst.Op {
+	case x86_INSB, x86_INSW, x86_INSD:
+		inst.Args[0] = x86_Mem{Segment: x86_ES, Base: x86_baseRegForBits(addrMode) + x86_DI - x86_AX}
+		inst.Args[1] = x86_DX
+		usedAddrSize = true
+
+	case x86_OUTSB, x86_OUTSW, x86_OUTSD:
+		inst.Args[0] = x86_DX
+		inst.Args[1] = x86_Mem{Segment: defaultSeg(), Base: x86_baseRegForBits(addrMode) + x86_SI - x86_AX}
+		usedAddrSize = true
+
+	case x86_MOVSB, x86_MOVSW, x86_MOVSD, x86_MOVSQ:
+		inst.Args[0] = x86_Mem{Segment: x86_ES, Base: x86_baseRegForBits(addrMode) + x86_DI - x86_AX}
+		inst.Args[1] = x86_Mem{Segment: defaultSeg(), Base: x86_baseRegForBits(addrMode) + x86_SI - x86_AX}
+		usedAddrSize = true
+
+	case x86_CMPSB, x86_CMPSW, x86_CMPSD, x86_CMPSQ:
+		inst.Args[0] = x86_Mem{Segment: defaultSeg(), Base: x86_baseRegForBits(addrMode) + x86_SI - x86_AX}
+		inst.Args[1] = x86_Mem{Segment: x86_ES, Base: x86_baseRegForBits(addrMode) + x86_DI - x86_AX}
+		usedAddrSize = true
+
+	case x86_LODSB, x86_LODSW, x86_LODSD, x86_LODSQ:
+		switch inst.Op {
+		case x86_LODSB:
+			inst.Args[0] = x86_AL
+		case x86_LODSW:
+			inst.Args[0] = x86_AX
+		case x86_LODSD:
+			inst.Args[0] = x86_EAX
+		case x86_LODSQ:
+			inst.Args[0] = x86_RAX
+		}
+		inst.Args[1] = x86_Mem{Segment: defaultSeg(), Base: x86_baseRegForBits(addrMode) + x86_SI - x86_AX}
+		usedAddrSize = true
+
+	case x86_STOSB, x86_STOSW, x86_STOSD, x86_STOSQ:
+		inst.Args[0] = x86_Mem{Segment: x86_ES, Base: x86_baseRegForBits(addrMode) + x86_DI - x86_AX}
+		switch inst.Op {
+		case x86_STOSB:
+			inst.Args[1] = x86_AL
+		case x86_STOSW:
+			inst.Args[1] = x86_AX
+		case x86_STOSD:
+			inst.Args[1] = x86_EAX
+		case x86_STOSQ:
+			inst.Args[1] = x86_RAX
+		}
+		usedAddrSize = true
+
+	case x86_SCASB, x86_SCASW, x86_SCASD, x86_SCASQ:
+		inst.Args[1] = x86_Mem{Segment: x86_ES, Base: x86_baseRegForBits(addrMode) + x86_DI - x86_AX}
+		switch inst.Op {
+		case x86_SCASB:
+			inst.Args[0] = x86_AL
+		case x86_SCASW:
+			inst.Args[0] = x86_AX
+		case x86_SCASD:
+			inst.Args[0] = x86_EAX
+		case x86_SCASQ:
+			inst.Args[0] = x86_RAX
+		}
+		usedAddrSize = true
+
+	case x86_XLATB:
+		inst.Args[0] = x86_Mem{Segment: defaultSeg(), Base: x86_baseRegForBits(addrMode) + x86_BX - x86_AX}
+		usedAddrSize = true
+	}
+
+	// If we used the address size annotation to construct the
+	// argument list, mark that prefix as implicit: it doesn't need
+	// to be shown when printing the instruction.
+	if haveMem || usedAddrSize {
+		if addrSizeIndex >= 0 {
+			inst.Prefix[addrSizeIndex] |= x86_PrefixImplicit
+		}
+	}
+
+	// Similarly, if there's some memory operand, the segment
+	// will be shown there and doesn't need to be shown as an
+	// explicit prefix.
+	if haveMem {
+		if segIndex >= 0 {
+			inst.Prefix[segIndex] |= x86_PrefixImplicit
+		}
+	}
+
+	// Branch predict prefixes are overloaded segment prefixes,
+	// since segment prefixes don't make sense on conditional jumps.
+	// Rewrite final instance to prediction prefix.
+	// The set of instructions to which the prefixes apply (other then the
+	// Jcc conditional jumps) is not 100% clear from the manuals, but
+	// the disassemblers seem to agree about the LOOP and JCXZ instructions,
+	// so we'll follow along.
+	// TODO(rsc): Perhaps this instruction class should be derived from the CSV.
+	if x86_isCondJmp[inst.Op] || x86_isLoop[inst.Op] || inst.Op == x86_JCXZ || inst.Op == x86_JECXZ || inst.Op == x86_JRCXZ {
+	PredictLoop:
+		for i := nprefix - 1; i >= 0; i-- {
+			p := inst.Prefix[i]
+			switch p & 0xFF {
+			case x86_PrefixCS:
+				inst.Prefix[i] = x86_PrefixPN
+				break PredictLoop
+			case x86_PrefixDS:
+				inst.Prefix[i] = x86_PrefixPT
+				break PredictLoop
+			}
+		}
+	}
+
+	// The BND prefix is part of the Intel Memory Protection Extensions (MPX).
+	// A REPN applied to certain control transfers is a BND prefix to bound
+	// the range of possible destinations. There's surprisingly little documentation
+	// about this, so we just do what libopcodes and xed agree on.
+	// In particular, it's unclear why a REPN applied to LOOP or JCXZ instructions
+	// does not turn into a BND.
+	// TODO(rsc): Perhaps this instruction class should be derived from the CSV.
+	if x86_isCondJmp[inst.Op] || inst.Op == x86_JMP || inst.Op == x86_CALL || inst.Op == x86_RET {
+		for i := nprefix - 1; i >= 0; i-- {
+			p := inst.Prefix[i]
+			if p&^x86_PrefixIgnored == x86_PrefixREPN {
+				inst.Prefix[i] = x86_PrefixBND
+				break
+			}
+		}
+	}
+
+	// The LOCK prefix only applies to certain instructions, and then only
+	// to instances of the instruction with a memory destination.
+	// Other uses of LOCK are invalid and cause a processor exception,
+	// in contrast to the "just ignore it" spirit applied to all other prefixes.
+	// Mark invalid lock prefixes.
+	hasLock := false
+	if lockIndex >= 0 && inst.Prefix[lockIndex]&x86_PrefixImplicit == 0 {
+		switch inst.Op {
+		// TODO(rsc): Perhaps this instruction class should be derived from the CSV.
+		case x86_ADD, x86_ADC, x86_AND, x86_BTC, x86_BTR, x86_BTS, x86_CMPXCHG, x86_CMPXCHG8B, x86_CMPXCHG16B, x86_DEC, x86_INC, x86_NEG, x86_NOT, x86_OR, x86_SBB, x86_SUB, x86_XOR, x86_XADD, x86_XCHG:
+			if x86_isMem(inst.Args[0]) {
+				hasLock = true
+				break
+			}
+			fallthrough
+		default:
+			inst.Prefix[lockIndex] |= x86_PrefixInvalid
+		}
+	}
+
+	// In certain cases, all of which require a memory destination,
+	// the REPN and REP prefixes are interpreted as XACQUIRE and XRELEASE
+	// from the Intel Transactional Synchroniation Extensions (TSX).
+	//
+	// The specific rules are:
+	// (1) Any instruction with a valid LOCK prefix can have XACQUIRE or XRELEASE.
+	// (2) Any XCHG, which always has an implicit LOCK, can have XACQUIRE or XRELEASE.
+	// (3) Any 0x88-, 0x89-, 0xC6-, or 0xC7-opcode MOV can have XRELEASE.
+	if x86_isMem(inst.Args[0]) {
+		if inst.Op == x86_XCHG {
+			hasLock = true
+		}
+
+		for i := len(inst.Prefix) - 1; i >= 0; i-- {
+			p := inst.Prefix[i] &^ x86_PrefixIgnored
+			switch p {
+			case x86_PrefixREPN:
+				if hasLock {
+					inst.Prefix[i] = inst.Prefix[i]&x86_PrefixIgnored | x86_PrefixXACQUIRE
+				}
+
+			case x86_PrefixREP:
+				if hasLock {
+					inst.Prefix[i] = inst.Prefix[i]&x86_PrefixIgnored | x86_PrefixXRELEASE
+				}
+
+				if inst.Op == x86_MOV {
+					op := (inst.Opcode >> 24) &^ 1
+					if op == 0x88 || op == 0xC6 {
+						inst.Prefix[i] = inst.Prefix[i]&x86_PrefixIgnored | x86_PrefixXRELEASE
+					}
+				}
+			}
+		}
+	}
+
+	// If REP is used on a non-REP-able instruction, mark the prefix as ignored.
+	if repIndex >= 0 {
+		switch inst.Prefix[repIndex] {
+		case x86_PrefixREP, x86_PrefixREPN:
+			switch inst.Op {
+			// According to the manuals, the REP/REPE prefix applies to all of these,
+			// while the REPN applies only to some of them. However, both libopcodes
+			// and xed show both prefixes explicitly for all instructions, so we do the same.
+			// TODO(rsc): Perhaps this instruction class should be derived from the CSV.
+			case x86_INSB, x86_INSW, x86_INSD,
+				x86_MOVSB, x86_MOVSW, x86_MOVSD, x86_MOVSQ,
+				x86_OUTSB, x86_OUTSW, x86_OUTSD,
+				x86_LODSB, x86_LODSW, x86_LODSD, x86_LODSQ,
+				x86_CMPSB, x86_CMPSW, x86_CMPSD, x86_CMPSQ,
+				x86_SCASB, x86_SCASW, x86_SCASD, x86_SCASQ,
+				x86_STOSB, x86_STOSW, x86_STOSD, x86_STOSQ:
+				// ok
+			default:
+				inst.Prefix[repIndex] |= x86_PrefixIgnored
+			}
+		}
+	}
+
+	// If REX was present, mark implicit if all the 1 bits were consumed.
+	if rexIndex >= 0 {
+		if rexUsed != 0 {
+			rexUsed |= x86_PrefixREX
+		}
+		if rex&^rexUsed == 0 {
+			inst.Prefix[rexIndex] |= x86_PrefixImplicit
+		}
+	}
+
+	inst.DataSize = dataMode
+	inst.AddrSize = addrMode
+	inst.Mode = mode
+	inst.Len = pos
+	return inst, nil
+}
+
+var x86_errInternal = errors.New("internal error")
+
+// addr16 records the eight 16-bit addressing modes.
+var x86_addr16 = [8]x86_Mem{
+	{Base: x86_BX, Scale: 1, Index: x86_SI},
+	{Base: x86_BX, Scale: 1, Index: x86_DI},
+	{Base: x86_BP, Scale: 1, Index: x86_SI},
+	{Base: x86_BP, Scale: 1, Index: x86_DI},
+	{Base: x86_SI},
+	{Base: x86_DI},
+	{Base: x86_BP},
+	{Base: x86_BX},
+}
+
+// baseReg returns the base register for a given register size in bits.
+func x86_baseRegForBits(bits int) x86_Reg {
+	switch bits {
+	case 8:
+		return x86_AL
+	case 16:
+		return x86_AX
+	case 32:
+		return x86_EAX
+	case 64:
+		return x86_RAX
+	}
+	return 0
+}
+
+// baseReg records the base register for argument types that specify
+// a range of registers indexed by op, regop, or rm.
+var x86_baseReg = [...]x86_Reg{
+	x86_xArgDR0dashDR7: x86_DR0,
+	x86_xArgMm1:        x86_M0,
+	x86_xArgMm2:        x86_M0,
+	x86_xArgMm2M64:     x86_M0,
+	x86_xArgMm:         x86_M0,
+	x86_xArgMmM32:      x86_M0,
+	x86_xArgMmM64:      x86_M0,
+	x86_xArgR16:        x86_AX,
+	x86_xArgR16op:      x86_AX,
+	x86_xArgR32:        x86_EAX,
+	x86_xArgR32M16:     x86_EAX,
+	x86_xArgR32M8:      x86_EAX,
+	x86_xArgR32op:      x86_EAX,
+	x86_xArgR64:        x86_RAX,
+	x86_xArgR64M16:     x86_RAX,
+	x86_xArgR64op:      x86_RAX,
+	x86_xArgR8:         x86_AL,
+	x86_xArgR8op:       x86_AL,
+	x86_xArgRM16:       x86_AX,
+	x86_xArgRM32:       x86_EAX,
+	x86_xArgRM64:       x86_RAX,
+	x86_xArgRM8:        x86_AL,
+	x86_xArgRmf16:      x86_AX,
+	x86_xArgRmf32:      x86_EAX,
+	x86_xArgRmf64:      x86_RAX,
+	x86_xArgSTi:        x86_F0,
+	x86_xArgTR0dashTR7: x86_TR0,
+	x86_xArgXmm1:       x86_X0,
+	x86_xArgXmm2:       x86_X0,
+	x86_xArgXmm2M128:   x86_X0,
+	x86_xArgXmm2M16:    x86_X0,
+	x86_xArgXmm2M32:    x86_X0,
+	x86_xArgXmm2M64:    x86_X0,
+	x86_xArgXmm:        x86_X0,
+	x86_xArgXmmM128:    x86_X0,
+	x86_xArgXmmM32:     x86_X0,
+	x86_xArgXmmM64:     x86_X0,
+}
+
+// prefixToSegment returns the segment register
+// corresponding to a particular segment prefix.
+func x86_prefixToSegment(p x86_Prefix) x86_Reg {
+	switch p &^ x86_PrefixImplicit {
+	case x86_PrefixCS:
+		return x86_CS
+	case x86_PrefixDS:
+		return x86_DS
+	case x86_PrefixES:
+		return x86_ES
+	case x86_PrefixFS:
+		return x86_FS
+	case x86_PrefixGS:
+		return x86_GS
+	case x86_PrefixSS:
+		return x86_SS
+	}
+	return 0
+}
+
+// fixedArg records the fixed arguments corresponding to the given bytecodes.
+var x86_fixedArg = [...]x86_Arg{
+	x86_xArg1:    x86_Imm(1),
+	x86_xArg3:    x86_Imm(3),
+	x86_xArgAL:   x86_AL,
+	x86_xArgAX:   x86_AX,
+	x86_xArgDX:   x86_DX,
+	x86_xArgEAX:  x86_EAX,
+	x86_xArgEDX:  x86_EDX,
+	x86_xArgRAX:  x86_RAX,
+	x86_xArgRDX:  x86_RDX,
+	x86_xArgCL:   x86_CL,
+	x86_xArgCS:   x86_CS,
+	x86_xArgDS:   x86_DS,
+	x86_xArgES:   x86_ES,
+	x86_xArgFS:   x86_FS,
+	x86_xArgGS:   x86_GS,
+	x86_xArgSS:   x86_SS,
+	x86_xArgST:   x86_F0,
+	x86_xArgXMM0: x86_X0,
+}
+
+// memBytes records the size of the memory pointed at
+// by a memory argument of the given form.
+var x86_memBytes = [...]int8{
+	x86_xArgM128:       128 / 8,
+	x86_xArgM16:        16 / 8,
+	x86_xArgM16and16:   (16 + 16) / 8,
+	x86_xArgM16colon16: (16 + 16) / 8,
+	x86_xArgM16colon32: (16 + 32) / 8,
+	x86_xArgM16int:     16 / 8,
+	x86_xArgM2byte:     2,
+	x86_xArgM32:        32 / 8,
+	x86_xArgM32and32:   (32 + 32) / 8,
+	x86_xArgM32fp:      32 / 8,
+	x86_xArgM32int:     32 / 8,
+	x86_xArgM64:        64 / 8,
+	x86_xArgM64fp:      64 / 8,
+	x86_xArgM64int:     64 / 8,
+	x86_xArgMm2M64:     64 / 8,
+	x86_xArgMmM32:      32 / 8,
+	x86_xArgMmM64:      64 / 8,
+	x86_xArgMoffs16:    16 / 8,
+	x86_xArgMoffs32:    32 / 8,
+	x86_xArgMoffs64:    64 / 8,
+	x86_xArgMoffs8:     8 / 8,
+	x86_xArgR32M16:     16 / 8,
+	x86_xArgR32M8:      8 / 8,
+	x86_xArgR64M16:     16 / 8,
+	x86_xArgRM16:       16 / 8,
+	x86_xArgRM32:       32 / 8,
+	x86_xArgRM64:       64 / 8,
+	x86_xArgRM8:        8 / 8,
+	x86_xArgXmm2M128:   128 / 8,
+	x86_xArgXmm2M16:    16 / 8,
+	x86_xArgXmm2M32:    32 / 8,
+	x86_xArgXmm2M64:    64 / 8,
+	x86_xArgXmm:        128 / 8,
+	x86_xArgXmmM128:    128 / 8,
+	x86_xArgXmmM32:     32 / 8,
+	x86_xArgXmmM64:     64 / 8,
+}
+
+// isCondJmp records the conditional jumps.
+var x86_isCondJmp = [x86_maxOp + 1]bool{
+	x86_JA:  true,
+	x86_JAE: true,
+	x86_JB:  true,
+	x86_JBE: true,
+	x86_JE:  true,
+	x86_JG:  true,
+	x86_JGE: true,
+	x86_JL:  true,
+	x86_JLE: true,
+	x86_JNE: true,
+	x86_JNO: true,
+	x86_JNP: true,
+	x86_JNS: true,
+	x86_JO:  true,
+	x86_JP:  true,
+	x86_JS:  true,
+}
+
+// isLoop records the loop operators.
+var x86_isLoop = [x86_maxOp + 1]bool{
+	x86_LOOP:   true,
+	x86_LOOPE:  true,
+	x86_LOOPNE: true,
+	x86_JECXZ:  true,
+	x86_JRCXZ:  true,
+}
+
+/* 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.
+
+// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils.
+// This general form is often called ``AT&T syntax'' as a reference to AT&T System V Unix.
+func x86_GNUSyntax(inst x86_Inst) string {
+	// Rewrite instruction to mimic GNU peculiarities.
+	// Note that inst has been passed by value and contains
+	// no pointers, so any changes we make here are local
+	// and will not propagate back out to the caller.
+
+	// Adjust opcode [sic].
+	switch inst.Op {
+	case x86_FDIV, x86_FDIVR, x86_FSUB, x86_FSUBR, x86_FDIVP, x86_FDIVRP, x86_FSUBP, x86_FSUBRP:
+		// DC E0, DC F0: libopcodes swaps FSUBR/FSUB and FDIVR/FDIV, at least
+		// if you believe the Intel manual is correct (the encoding is irregular as given;
+		// libopcodes uses the more regular expected encoding).
+		// TODO(rsc): Test to ensure Intel manuals are correct and report to libopcodes maintainers?
+		// NOTE: iant thinks this is deliberate, but we can't find the history.
+		_, reg1 := inst.Args[0].(x86_Reg)
+		_, reg2 := inst.Args[1].(x86_Reg)
+		if reg1 && reg2 && (inst.Opcode>>24 == 0xDC || inst.Opcode>>24 == 0xDE) {
+			switch inst.Op {
+			case x86_FDIV:
+				inst.Op = x86_FDIVR
+			case x86_FDIVR:
+				inst.Op = x86_FDIV
+			case x86_FSUB:
+				inst.Op = x86_FSUBR
+			case x86_FSUBR:
+				inst.Op = x86_FSUB
+			case x86_FDIVP:
+				inst.Op = x86_FDIVRP
+			case x86_FDIVRP:
+				inst.Op = x86_FDIVP
+			case x86_FSUBP:
+				inst.Op = x86_FSUBRP
+			case x86_FSUBRP:
+				inst.Op = x86_FSUBP
+			}
+		}
+
+	case x86_MOVNTSD:
+		// MOVNTSD is F2 0F 2B /r.
+		// MOVNTSS is F3 0F 2B /r (supposedly; not in manuals).
+		// Usually inner prefixes win for display,
+		// so that F3 F2 0F 2B 11 is REP MOVNTSD
+		// and F2 F3 0F 2B 11 is REPN MOVNTSS.
+		// Libopcodes always prefers MOVNTSS regardless of prefix order.
+		if x86_countPrefix(&inst, 0xF3) > 0 {
+			found := false
+			for i := len(inst.Prefix) - 1; i >= 0; i-- {
+				switch inst.Prefix[i] & 0xFF {
+				case 0xF3:
+					if !found {
+						found = true
+						inst.Prefix[i] |= x86_PrefixImplicit
+					}
+				case 0xF2:
+					inst.Prefix[i] &^= x86_PrefixImplicit
+				}
+			}
+			inst.Op = x86_MOVNTSS
+		}
+	}
+
+	// Add implicit arguments.
+	switch inst.Op {
+	case x86_MONITOR:
+		inst.Args[0] = x86_EDX
+		inst.Args[1] = x86_ECX
+		inst.Args[2] = x86_EAX
+		if inst.AddrSize == 16 {
+			inst.Args[2] = x86_AX
+		}
+
+	case x86_MWAIT:
+		if inst.Mode == 64 {
+			inst.Args[0] = x86_RCX
+			inst.Args[1] = x86_RAX
+		} else {
+			inst.Args[0] = x86_ECX
+			inst.Args[1] = x86_EAX
+		}
+	}
+
+	// Adjust which prefixes will be displayed.
+	// The rule is to display all the prefixes not implied by
+	// the usual instruction display, that is, all the prefixes
+	// except the ones with PrefixImplicit set.
+	// However, of course, there are exceptions to the rule.
+	switch inst.Op {
+	case x86_CRC32:
+		// CRC32 has a mandatory F2 prefix.
+		// If there are multiple F2s and no F3s, the extra F2s do not print.
+		// (And Decode has already marked them implicit.)
+		// However, if there is an F3 anywhere, then the extra F2s do print.
+		// If there are multiple F2 prefixes *and* an (ignored) F3,
+		// then libopcodes prints the extra F2s as REPNs.
+		if x86_countPrefix(&inst, 0xF2) > 1 {
+			x86_unmarkImplicit(&inst, 0xF2)
+			x86_markLastImplicit(&inst, 0xF2)
+		}
+
+		// An unused data size override should probably be shown,
+		// to distinguish DATA16 CRC32B from plain CRC32B,
+		// but libopcodes always treats the final override as implicit
+		// and the others as explicit.
+		x86_unmarkImplicit(&inst, x86_PrefixDataSize)
+		x86_markLastImplicit(&inst, x86_PrefixDataSize)
+
+	case x86_CVTSI2SD, x86_CVTSI2SS:
+		if !x86_isMem(inst.Args[1]) {
+			x86_markLastImplicit(&inst, x86_PrefixDataSize)
+		}
+
+	case x86_CVTSD2SI, x86_CVTSS2SI, x86_CVTTSD2SI, x86_CVTTSS2SI,
+		x86_ENTER, x86_FLDENV, x86_FNSAVE, x86_FNSTENV, x86_FRSTOR, x86_LGDT, x86_LIDT, x86_LRET,
+		x86_POP, x86_PUSH, x86_RET, x86_SGDT, x86_SIDT, x86_SYSRET, x86_XBEGIN:
+		x86_markLastImplicit(&inst, x86_PrefixDataSize)
+
+	case x86_LOOP, x86_LOOPE, x86_LOOPNE, x86_MONITOR:
+		x86_markLastImplicit(&inst, x86_PrefixAddrSize)
+
+	case x86_MOV:
+		// The 16-bit and 32-bit forms of MOV Sreg, dst and MOV src, Sreg
+		// cannot be distinguished when src or dst refers to memory, because
+		// Sreg is always a 16-bit value, even when we're doing a 32-bit
+		// instruction. Because the instruction tables distinguished these two,
+		// any operand size prefix has been marked as used (to decide which
+		// branch to take). Unmark it, so that it will show up in disassembly,
+		// so that the reader can tell the size of memory operand.
+		// up with the same arguments
+		dst, _ := inst.Args[0].(x86_Reg)
+		src, _ := inst.Args[1].(x86_Reg)
+		if x86_ES <= src && src <= x86_GS && x86_isMem(inst.Args[0]) || x86_ES <= dst && dst <= x86_GS && x86_isMem(inst.Args[1]) {
+			x86_unmarkImplicit(&inst, x86_PrefixDataSize)
+		}
+
+	case x86_MOVDQU:
+		if x86_countPrefix(&inst, 0xF3) > 1 {
+			x86_unmarkImplicit(&inst, 0xF3)
+			x86_markLastImplicit(&inst, 0xF3)
+		}
+
+	case x86_MOVQ2DQ:
+		x86_markLastImplicit(&inst, x86_PrefixDataSize)
+
+	case x86_SLDT, x86_SMSW, x86_STR, x86_FXRSTOR, x86_XRSTOR, x86_XSAVE, x86_XSAVEOPT, x86_CMPXCHG8B:
+		if x86_isMem(inst.Args[0]) {
+			x86_unmarkImplicit(&inst, x86_PrefixDataSize)
+		}
+
+	case x86_SYSEXIT:
+		x86_unmarkImplicit(&inst, x86_PrefixDataSize)
+	}
+
+	if x86_isCondJmp[inst.Op] || x86_isLoop[inst.Op] || inst.Op == x86_JCXZ || inst.Op == x86_JECXZ || inst.Op == x86_JRCXZ {
+		if x86_countPrefix(&inst, x86_PrefixCS) > 0 && x86_countPrefix(&inst, x86_PrefixDS) > 0 {
+			for i, p := range inst.Prefix {
+				switch p & 0xFFF {
+				case x86_PrefixPN, x86_PrefixPT:
+					inst.Prefix[i] &= 0xF0FF // cut interpretation bits, producing original segment prefix
+				}
+			}
+		}
+	}
+
+	// XACQUIRE/XRELEASE adjustment.
+	if inst.Op == x86_MOV {
+		// MOV into memory is a candidate for turning REP into XRELEASE.
+		// However, if the REP is followed by a REPN, that REPN blocks the
+		// conversion.
+		haveREPN := false
+		for i := len(inst.Prefix) - 1; i >= 0; i-- {
+			switch inst.Prefix[i] &^ x86_PrefixIgnored {
+			case x86_PrefixREPN:
+				haveREPN = true
+			case x86_PrefixXRELEASE:
+				if haveREPN {
+					inst.Prefix[i] = x86_PrefixREP
+				}
+			}
+		}
+	}
+
+	// We only format the final F2/F3 as XRELEASE/XACQUIRE.
+	haveXA := false
+	haveXR := false
+	for i := len(inst.Prefix) - 1; i >= 0; i-- {
+		switch inst.Prefix[i] &^ x86_PrefixIgnored {
+		case x86_PrefixXRELEASE:
+			if !haveXR {
+				haveXR = true
+			} else {
+				inst.Prefix[i] = x86_PrefixREP
+			}
+
+		case x86_PrefixXACQUIRE:
+			if !haveXA {
+				haveXA = true
+			} else {
+				inst.Prefix[i] = x86_PrefixREPN
+			}
+		}
+	}
+
+	// Determine opcode.
+	op := strings.ToLower(inst.Op.String())
+	if alt := x86_gnuOp[inst.Op]; alt != "" {
+		op = alt
+	}
+
+	// Determine opcode suffix.
+	// Libopcodes omits the suffix if the width of the operation
+	// can be inferred from a register arguments. For example,
+	// add $1, %ebx has no suffix because you can tell from the
+	// 32-bit register destination that it is a 32-bit add,
+	// but in addl $1, (%ebx), the destination is memory, so the
+	// size is not evident without the l suffix.
+	needSuffix := true
+SuffixLoop:
+	for i, a := range inst.Args {
+		if a == nil {
+			break
+		}
+		switch a := a.(type) {
+		case x86_Reg:
+			switch inst.Op {
+			case x86_MOVSX, x86_MOVZX:
+				continue
+
+			case x86_SHL, x86_SHR, x86_RCL, x86_RCR, x86_ROL, x86_ROR, x86_SAR:
+				if i == 1 {
+					// shift count does not tell us operand size
+					continue
+				}
+
+			case x86_CRC32:
+				// The source argument does tell us operand size,
+				// but libopcodes still always puts a suffix on crc32.
+				continue
+
+			case x86_PUSH, x86_POP:
+				// Even though segment registers are 16-bit, push and pop
+				// can save/restore them from 32-bit slots, so they
+				// do not imply operand size.
+				if x86_ES <= a && a <= x86_GS {
+					continue
+				}
+
+			case x86_CVTSI2SD, x86_CVTSI2SS:
+				// The integer register argument takes priority.
+				if x86_X0 <= a && a <= x86_X15 {
+					continue
+				}
+			}
+
+			if x86_AL <= a && a <= x86_R15 || x86_ES <= a && a <= x86_GS || x86_X0 <= a && a <= x86_X15 || x86_M0 <= a && a <= x86_M7 {
+				needSuffix = false
+				break SuffixLoop
+			}
+		}
+	}
+
+	if needSuffix {
+		switch inst.Op {
+		case x86_CMPXCHG8B, x86_FLDCW, x86_FNSTCW, x86_FNSTSW, x86_LDMXCSR, x86_LLDT, x86_LMSW, x86_LTR, x86_PCLMULQDQ,
+			x86_SETA, x86_SETAE, x86_SETB, x86_SETBE, x86_SETE, x86_SETG, x86_SETGE, x86_SETL, x86_SETLE, x86_SETNE, x86_SETNO, x86_SETNP, x86_SETNS, x86_SETO, x86_SETP, x86_SETS,
+			x86_SLDT, x86_SMSW, x86_STMXCSR, x86_STR, x86_VERR, x86_VERW:
+			// For various reasons, libopcodes emits no suffix for these instructions.
+
+		case x86_CRC32:
+			op += x86_byteSizeSuffix(x86_argBytes(&inst, inst.Args[1]))
+
+		case x86_LGDT, x86_LIDT, x86_SGDT, x86_SIDT:
+			op += x86_byteSizeSuffix(inst.DataSize / 8)
+
+		case x86_MOVZX, x86_MOVSX:
+			// Integer size conversions get two suffixes.
+			op = op[:4] + x86_byteSizeSuffix(x86_argBytes(&inst, inst.Args[1])) + x86_byteSizeSuffix(x86_argBytes(&inst, inst.Args[0]))
+
+		case x86_LOOP, x86_LOOPE, x86_LOOPNE:
+			// Add w suffix to indicate use of CX register instead of ECX.
+			if inst.AddrSize == 16 {
+				op += "w"
+			}
+
+		case x86_CALL, x86_ENTER, x86_JMP, x86_LCALL, x86_LEAVE, x86_LJMP, x86_LRET, x86_RET, x86_SYSRET, x86_XBEGIN:
+			// Add w suffix to indicate use of 16-bit target.
+			// Exclude JMP rel8.
+			if inst.Opcode>>24 == 0xEB {
+				break
+			}
+			if inst.DataSize == 16 && inst.Mode != 16 {
+				x86_markLastImplicit(&inst, x86_PrefixDataSize)
+				op += "w"
+			} else if inst.Mode == 64 {
+				op += "q"
+			}
+
+		case x86_FRSTOR, x86_FNSAVE, x86_FNSTENV, x86_FLDENV:
+			// Add s suffix to indicate shortened FPU state (I guess).
+			if inst.DataSize == 16 {
+				op += "s"
+			}
+
+		case x86_PUSH, x86_POP:
+			if x86_markLastImplicit(&inst, x86_PrefixDataSize) {
+				op += x86_byteSizeSuffix(inst.DataSize / 8)
+			} else if inst.Mode == 64 {
+				op += "q"
+			} else {
+				op += x86_byteSizeSuffix(inst.MemBytes)
+			}
+
+		default:
+			if x86_isFloat(inst.Op) {
+				// I can't explain any of this, but it's what libopcodes does.
+				switch inst.MemBytes {
+				default:
+					if (inst.Op == x86_FLD || inst.Op == x86_FSTP) && x86_isMem(inst.Args[0]) {
+						op += "t"
+					}
+				case 4:
+					if x86_isFloatInt(inst.Op) {
+						op += "l"
+					} else {
+						op += "s"
+					}
+				case 8:
+					if x86_isFloatInt(inst.Op) {
+						op += "ll"
+					} else {
+						op += "l"
+					}
+				}
+				break
+			}
+
+			op += x86_byteSizeSuffix(inst.MemBytes)
+		}
+	}
+
+	// Adjust special case opcodes.
+	switch inst.Op {
+	case 0:
+		if inst.Prefix[0] != 0 {
+			return strings.ToLower(inst.Prefix[0].String())
+		}
+
+	case x86_INT:
+		if inst.Opcode>>24 == 0xCC {
+			inst.Args[0] = nil
+			op = "int3"
+		}
+
+	case x86_CMPPS, x86_CMPPD, x86_CMPSD_XMM, x86_CMPSS:
+		imm, ok := inst.Args[2].(x86_Imm)
+		if ok && 0 <= imm && imm < 8 {
+			inst.Args[2] = nil
+			op = x86_cmppsOps[imm] + op[3:]
+		}
+
+	case x86_PCLMULQDQ:
+		imm, ok := inst.Args[2].(x86_Imm)
+		if ok && imm&^0x11 == 0 {
+			inst.Args[2] = nil
+			op = x86_pclmulqOps[(imm&0x10)>>3|(imm&1)]
+		}
+
+	case x86_XLATB:
+		if x86_markLastImplicit(&inst, x86_PrefixAddrSize) {
+			op = "xlat" // not xlatb
+		}
+	}
+
+	// Build list of argument strings.
+	var (
+		usedPrefixes bool     // segment prefixes consumed by Mem formatting
+		args         []string // formatted arguments
+	)
+	for i, a := range inst.Args {
+		if a == nil {
+			break
+		}
+		switch inst.Op {
+		case x86_MOVSB, x86_MOVSW, x86_MOVSD, x86_MOVSQ, x86_OUTSB, x86_OUTSW, x86_OUTSD:
+			if i == 0 {
+				usedPrefixes = true // disable use of prefixes for first argument
+			} else {
+				usedPrefixes = false
+			}
+		}
+		if a == x86_Imm(1) && (inst.Opcode>>24)&^1 == 0xD0 {
+			continue
+		}
+		args = append(args, x86_gnuArg(&inst, a, &usedPrefixes))
+	}
+
+	// The default is to print the arguments in reverse Intel order.
+	// A few instructions inhibit this behavior.
+	switch inst.Op {
+	case x86_BOUND, x86_LCALL, x86_ENTER, x86_LJMP:
+		// no reverse
+	default:
+		// reverse args
+		for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
+			args[i], args[j] = args[j], args[i]
+		}
+	}
+
+	// Build prefix string.
+	// Must be after argument formatting, which can turn off segment prefixes.
+	var (
+		prefix       = "" // output string
+		numAddr      = 0
+		numData      = 0
+		implicitData = false
+	)
+	for _, p := range inst.Prefix {
+		if p&0xFF == x86_PrefixDataSize && p&x86_PrefixImplicit != 0 {
+			implicitData = true
+		}
+	}
+	for _, p := range inst.Prefix {
+		if p == 0 {
+			break
+		}
+		if p&x86_PrefixImplicit != 0 {
+			continue
+		}
+		switch p &^ (x86_PrefixIgnored | x86_PrefixInvalid) {
+		default:
+			if p.IsREX() {
+				if p&0xFF == x86_PrefixREX {
+					prefix += "rex "
+				} else {
+					prefix += "rex." + p.String()[4:] + " "
+				}
+				break
+			}
+			prefix += strings.ToLower(p.String()) + " "
+
+		case x86_PrefixPN:
+			op += ",pn"
+			continue
+
+		case x86_PrefixPT:
+			op += ",pt"
+			continue
+
+		case x86_PrefixAddrSize, x86_PrefixAddr16, x86_PrefixAddr32:
+			// For unknown reasons, if the addr16 prefix is repeated,
+			// libopcodes displays all but the last as addr32, even though
+			// the addressing form used in a memory reference is clearly
+			// still 16-bit.
+			n := 32
+			if inst.Mode == 32 {
+				n = 16
+			}
+			numAddr++
+			if x86_countPrefix(&inst, x86_PrefixAddrSize) > numAddr {
+				n = inst.Mode
+			}
+			prefix += fmt.Sprintf("addr%d ", n)
+			continue
+
+		case x86_PrefixData16, x86_PrefixData32:
+			if implicitData && x86_countPrefix(&inst, x86_PrefixDataSize) > 1 {
+				// Similar to the addr32 logic above, but it only kicks in
+				// when something used the data size prefix (one is implicit).
+				n := 16
+				if inst.Mode == 16 {
+					n = 32
+				}
+				numData++
+				if x86_countPrefix(&inst, x86_PrefixDataSize) > numData {
+					if inst.Mode == 16 {
+						n = 16
+					} else {
+						n = 32
+					}
+				}
+				prefix += fmt.Sprintf("data%d ", n)
+				continue
+			}
+			prefix += strings.ToLower(p.String()) + " "
+		}
+	}
+
+	// Finally! Put it all together.
+	text := prefix + op
+	if args != nil {
+		text += " "
+		// Indirect call/jmp gets a star to distinguish from direct jump address.
+		if (inst.Op == x86_CALL || inst.Op == x86_JMP || inst.Op == x86_LJMP || inst.Op == x86_LCALL) && (x86_isMem(inst.Args[0]) || x86_isReg(inst.Args[0])) {
+			text += "*"
+		}
+		text += strings.Join(args, ",")
+	}
+	return text
+}
+
+// gnuArg returns the GNU syntax for the argument x from the instruction inst.
+// If *usedPrefixes is false and x is a Mem, then the formatting
+// includes any segment prefixes and sets *usedPrefixes to true.
+func x86_gnuArg(inst *x86_Inst, x x86_Arg, usedPrefixes *bool) string {
+	if x == nil {
+		return "<nil>"
+	}
+	switch x := x.(type) {
+	case x86_Reg:
+		switch inst.Op {
+		case x86_CVTSI2SS, x86_CVTSI2SD, x86_CVTSS2SI, x86_CVTSD2SI, x86_CVTTSD2SI, x86_CVTTSS2SI:
+			if inst.DataSize == 16 && x86_EAX <= x && x <= x86_R15L {
+				x -= x86_EAX - x86_AX
+			}
+
+		case x86_IN, x86_INSB, x86_INSW, x86_INSD, x86_OUT, x86_OUTSB, x86_OUTSW, x86_OUTSD:
+			// DX is the port, but libopcodes prints it as if it were a memory reference.
+			if x == x86_DX {
+				return "(%dx)"
+			}
+		}
+		return x86_gccRegName[x]
+	case x86_Mem:
+		seg := ""
+		var haveCS, haveDS, haveES, haveFS, haveGS, haveSS bool
+		switch x.Segment {
+		case x86_CS:
+			haveCS = true
+		case x86_DS:
+			haveDS = true
+		case x86_ES:
+			haveES = true
+		case x86_FS:
+			haveFS = true
+		case x86_GS:
+			haveGS = true
+		case x86_SS:
+			haveSS = true
+		}
+		switch inst.Op {
+		case x86_INSB, x86_INSW, x86_INSD, x86_STOSB, x86_STOSW, x86_STOSD, x86_STOSQ, x86_SCASB, x86_SCASW, x86_SCASD, x86_SCASQ:
+			// These do not accept segment prefixes, at least in the GNU rendering.
+		default:
+			if *usedPrefixes {
+				break
+			}
+			for i := len(inst.Prefix) - 1; i >= 0; i-- {
+				p := inst.Prefix[i] &^ x86_PrefixIgnored
+				if p == 0 {
+					continue
+				}
+				switch p {
+				case x86_PrefixCS:
+					if !haveCS {
+						haveCS = true
+						inst.Prefix[i] |= x86_PrefixImplicit
+					}
+				case x86_PrefixDS:
+					if !haveDS {
+						haveDS = true
+						inst.Prefix[i] |= x86_PrefixImplicit
+					}
+				case x86_PrefixES:
+					if !haveES {
+						haveES = true
+						inst.Prefix[i] |= x86_PrefixImplicit
+					}
+				case x86_PrefixFS:
+					if !haveFS {
+						haveFS = true
+						inst.Prefix[i] |= x86_PrefixImplicit
+					}
+				case x86_PrefixGS:
+					if !haveGS {
+						haveGS = true
+						inst.Prefix[i] |= x86_PrefixImplicit
+					}
+				case x86_PrefixSS:
+					if !haveSS {
+						haveSS = true
+						inst.Prefix[i] |= x86_PrefixImplicit
+					}
+				}
+			}
+			*usedPrefixes = true
+		}
+		if haveCS {
+			seg += "%cs:"
+		}
+		if haveDS {
+			seg += "%ds:"
+		}
+		if haveSS {
+			seg += "%ss:"
+		}
+		if haveES {
+			seg += "%es:"
+		}
+		if haveFS {
+			seg += "%fs:"
+		}
+		if haveGS {
+			seg += "%gs:"
+		}
+		disp := ""
+		if x.Disp != 0 {
+			disp = fmt.Sprintf("%#x", x.Disp)
+		}
+		if x.Scale == 0 || x.Index == 0 && x.Scale == 1 && (x.Base == x86_ESP || x.Base == x86_RSP || x.Base == 0 && inst.Mode == 64) {
+			if x.Base == 0 {
+				return seg + disp
+			}
+			return fmt.Sprintf("%s%s(%s)", seg, disp, x86_gccRegName[x.Base])
+		}
+		base := x86_gccRegName[x.Base]
+		if x.Base == 0 {
+			base = ""
+		}
+		index := x86_gccRegName[x.Index]
+		if x.Index == 0 {
+			if inst.AddrSize == 64 {
+				index = "%riz"
+			} else {
+				index = "%eiz"
+			}
+		}
+		if x86_AX <= x.Base && x.Base <= x86_DI {
+			// 16-bit addressing - no scale
+			return fmt.Sprintf("%s%s(%s,%s)", seg, disp, base, index)
+		}
+		return fmt.Sprintf("%s%s(%s,%s,%d)", seg, disp, base, index, x.Scale)
+	case x86_Rel:
+		return fmt.Sprintf(".%+#x", int32(x))
+	case x86_Imm:
+		if inst.Mode == 32 {
+			return fmt.Sprintf("$%#x", uint32(x))
+		}
+		return fmt.Sprintf("$%#x", int64(x))
+	}
+	return x.String()
+}
+
+var x86_gccRegName = [...]string{
+	0:        "REG0",
+	x86_AL:   "%al",
+	x86_CL:   "%cl",
+	x86_BL:   "%bl",
+	x86_DL:   "%dl",
+	x86_AH:   "%ah",
+	x86_CH:   "%ch",
+	x86_BH:   "%bh",
+	x86_DH:   "%dh",
+	x86_SPB:  "%spl",
+	x86_BPB:  "%bpl",
+	x86_SIB:  "%sil",
+	x86_DIB:  "%dil",
+	x86_R8B:  "%r8b",
+	x86_R9B:  "%r9b",
+	x86_R10B: "%r10b",
+	x86_R11B: "%r11b",
+	x86_R12B: "%r12b",
+	x86_R13B: "%r13b",
+	x86_R14B: "%r14b",
+	x86_R15B: "%r15b",
+	x86_AX:   "%ax",
+	x86_CX:   "%cx",
+	x86_BX:   "%bx",
+	x86_DX:   "%dx",
+	x86_SP:   "%sp",
+	x86_BP:   "%bp",
+	x86_SI:   "%si",
+	x86_DI:   "%di",
+	x86_R8W:  "%r8w",
+	x86_R9W:  "%r9w",
+	x86_R10W: "%r10w",
+	x86_R11W: "%r11w",
+	x86_R12W: "%r12w",
+	x86_R13W: "%r13w",
+	x86_R14W: "%r14w",
+	x86_R15W: "%r15w",
+	x86_EAX:  "%eax",
+	x86_ECX:  "%ecx",
+	x86_EDX:  "%edx",
+	x86_EBX:  "%ebx",
+	x86_ESP:  "%esp",
+	x86_EBP:  "%ebp",
+	x86_ESI:  "%esi",
+	x86_EDI:  "%edi",
+	x86_R8L:  "%r8d",
+	x86_R9L:  "%r9d",
+	x86_R10L: "%r10d",
+	x86_R11L: "%r11d",
+	x86_R12L: "%r12d",
+	x86_R13L: "%r13d",
+	x86_R14L: "%r14d",
+	x86_R15L: "%r15d",
+	x86_RAX:  "%rax",
+	x86_RCX:  "%rcx",
+	x86_RDX:  "%rdx",
+	x86_RBX:  "%rbx",
+	x86_RSP:  "%rsp",
+	x86_RBP:  "%rbp",
+	x86_RSI:  "%rsi",
+	x86_RDI:  "%rdi",
+	x86_R8:   "%r8",
+	x86_R9:   "%r9",
+	x86_R10:  "%r10",
+	x86_R11:  "%r11",
+	x86_R12:  "%r12",
+	x86_R13:  "%r13",
+	x86_R14:  "%r14",
+	x86_R15:  "%r15",
+	x86_IP:   "%ip",
+	x86_EIP:  "%eip",
+	x86_RIP:  "%rip",
+	x86_F0:   "%st",
+	x86_F1:   "%st(1)",
+	x86_F2:   "%st(2)",
+	x86_F3:   "%st(3)",
+	x86_F4:   "%st(4)",
+	x86_F5:   "%st(5)",
+	x86_F6:   "%st(6)",
+	x86_F7:   "%st(7)",
+	x86_M0:   "%mm0",
+	x86_M1:   "%mm1",
+	x86_M2:   "%mm2",
+	x86_M3:   "%mm3",
+	x86_M4:   "%mm4",
+	x86_M5:   "%mm5",
+	x86_M6:   "%mm6",
+	x86_M7:   "%mm7",
+	x86_X0:   "%xmm0",
+	x86_X1:   "%xmm1",
+	x86_X2:   "%xmm2",
+	x86_X3:   "%xmm3",
+	x86_X4:   "%xmm4",
+	x86_X5:   "%xmm5",
+	x86_X6:   "%xmm6",
+	x86_X7:   "%xmm7",
+	x86_X8:   "%xmm8",
+	x86_X9:   "%xmm9",
+	x86_X10:  "%xmm10",
+	x86_X11:  "%xmm11",
+	x86_X12:  "%xmm12",
+	x86_X13:  "%xmm13",
+	x86_X14:  "%xmm14",
+	x86_X15:  "%xmm15",
+	x86_CS:   "%cs",
+	x86_SS:   "%ss",
+	x86_DS:   "%ds",
+	x86_ES:   "%es",
+	x86_FS:   "%fs",
+	x86_GS:   "%gs",
+	x86_GDTR: "%gdtr",
+	x86_IDTR: "%idtr",
+	x86_LDTR: "%ldtr",
+	x86_MSW:  "%msw",
+	x86_TASK: "%task",
+	x86_CR0:  "%cr0",
+	x86_CR1:  "%cr1",
+	x86_CR2:  "%cr2",
+	x86_CR3:  "%cr3",
+	x86_CR4:  "%cr4",
+	x86_CR5:  "%cr5",
+	x86_CR6:  "%cr6",
+	x86_CR7:  "%cr7",
+	x86_CR8:  "%cr8",
+	x86_CR9:  "%cr9",
+	x86_CR10: "%cr10",
+	x86_CR11: "%cr11",
+	x86_CR12: "%cr12",
+	x86_CR13: "%cr13",
+	x86_CR14: "%cr14",
+	x86_CR15: "%cr15",
+	x86_DR0:  "%db0",
+	x86_DR1:  "%db1",
+	x86_DR2:  "%db2",
+	x86_DR3:  "%db3",
+	x86_DR4:  "%db4",
+	x86_DR5:  "%db5",
+	x86_DR6:  "%db6",
+	x86_DR7:  "%db7",
+	x86_TR0:  "%tr0",
+	x86_TR1:  "%tr1",
+	x86_TR2:  "%tr2",
+	x86_TR3:  "%tr3",
+	x86_TR4:  "%tr4",
+	x86_TR5:  "%tr5",
+	x86_TR6:  "%tr6",
+	x86_TR7:  "%tr7",
+}
+
+var x86_gnuOp = map[x86_Op]string{
+	x86_CBW:       "cbtw",
+	x86_CDQ:       "cltd",
+	x86_CMPSD:     "cmpsl",
+	x86_CMPSD_XMM: "cmpsd",
+	x86_CWD:       "cwtd",
+	x86_CWDE:      "cwtl",
+	x86_CQO:       "cqto",
+	x86_INSD:      "insl",
+	x86_IRET:      "iretw",
+	x86_IRETD:     "iret",
+	x86_IRETQ:     "iretq",
+	x86_LODSB:     "lods",
+	x86_LODSD:     "lods",
+	x86_LODSQ:     "lods",
+	x86_LODSW:     "lods",
+	x86_MOVSD:     "movsl",
+	x86_MOVSD_XMM: "movsd",
+	x86_OUTSD:     "outsl",
+	x86_POPA:      "popaw",
+	x86_POPAD:     "popa",
+	x86_POPF:      "popfw",
+	x86_POPFD:     "popf",
+	x86_PUSHA:     "pushaw",
+	x86_PUSHAD:    "pusha",
+	x86_PUSHF:     "pushfw",
+	x86_PUSHFD:    "pushf",
+	x86_SCASB:     "scas",
+	x86_SCASD:     "scas",
+	x86_SCASQ:     "scas",
+	x86_SCASW:     "scas",
+	x86_STOSB:     "stos",
+	x86_STOSD:     "stos",
+	x86_STOSQ:     "stos",
+	x86_STOSW:     "stos",
+	x86_XLATB:     "xlat",
+}
+
+var x86_cmppsOps = []string{
+	"cmpeq",
+	"cmplt",
+	"cmple",
+	"cmpunord",
+	"cmpneq",
+	"cmpnlt",
+	"cmpnle",
+	"cmpord",
+}
+
+var x86_pclmulqOps = []string{
+	"pclmullqlqdq",
+	"pclmulhqlqdq",
+	"pclmullqhqdq",
+	"pclmulhqhqdq",
+}
+
+func x86_countPrefix(inst *x86_Inst, target x86_Prefix) int {
+	n := 0
+	for _, p := range inst.Prefix {
+		if p&0xFF == target&0xFF {
+			n++
+		}
+	}
+	return n
+}
+
+func x86_markLastImplicit(inst *x86_Inst, prefix x86_Prefix) bool {
+	for i := len(inst.Prefix) - 1; i >= 0; i-- {
+		p := inst.Prefix[i]
+		if p&0xFF == prefix {
+			inst.Prefix[i] |= x86_PrefixImplicit
+			return true
+		}
+	}
+	return false
+}
+
+func x86_unmarkImplicit(inst *x86_Inst, prefix x86_Prefix) {
+	for i := len(inst.Prefix) - 1; i >= 0; i-- {
+		p := inst.Prefix[i]
+		if p&0xFF == prefix {
+			inst.Prefix[i] &^= x86_PrefixImplicit
+		}
+	}
+}
+
+func x86_byteSizeSuffix(b int) string {
+	switch b {
+	case 1:
+		return "b"
+	case 2:
+		return "w"
+	case 4:
+		return "l"
+	case 8:
+		return "q"
+	}
+	return ""
+}
+
+func x86_argBytes(inst *x86_Inst, arg x86_Arg) int {
+	if x86_isMem(arg) {
+		return inst.MemBytes
+	}
+	return x86_regBytes(arg)
+}
+
+func x86_isFloat(op x86_Op) bool {
+	switch op {
+	case x86_FADD, x86_FCOM, x86_FCOMP, x86_FDIV, x86_FDIVR, x86_FIADD, x86_FICOM, x86_FICOMP, x86_FIDIV, x86_FIDIVR, x86_FILD, x86_FIMUL, x86_FIST, x86_FISTP, x86_FISTTP, x86_FISUB, x86_FISUBR, x86_FLD, x86_FMUL, x86_FST, x86_FSTP, x86_FSUB, x86_FSUBR:
+		return true
+	}
+	return false
+}
+
+func x86_isFloatInt(op x86_Op) bool {
+	switch op {
+	case x86_FIADD, x86_FICOM, x86_FICOMP, x86_FIDIV, x86_FIDIVR, x86_FILD, x86_FIMUL, x86_FIST, x86_FISTP, x86_FISTTP, x86_FISUB, x86_FISUBR:
+		return true
+	}
+	return false
+}
+
+/* inst.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 x86asm implements decoding of x86 machine code.
+
+// An Inst is a single instruction.
+type x86_Inst struct {
+	Prefix   x86_Prefixes // Prefixes applied to the instruction.
+	Op       x86_Op       // Opcode mnemonic
+	Opcode   uint32       // Encoded opcode bits, left aligned (first byte is Opcode>>24, etc)
+	Args     x86_Args     // Instruction arguments, in Intel order
+	Mode     int          // processor mode in bits: 16, 32, or 64
+	AddrSize int          // address size in bits: 16, 32, or 64
+	DataSize int          // operand size in bits: 16, 32, or 64
+	MemBytes int          // size of memory argument in bytes: 1, 2, 4, 8, 16, and so on.
+	Len      int          // length of encoded instruction in bytes
+}
+
+// Prefixes is an array of prefixes associated with a single instruction.
+// The prefixes are listed in the same order as found in the instruction:
+// each prefix byte corresponds to one slot in the array. The first zero
+// in the array marks the end of the prefixes.
+type x86_Prefixes [14]x86_Prefix
+
+// A Prefix represents an Intel instruction prefix.
+// The low 8 bits are the actual prefix byte encoding,
+// and the top 8 bits contain distinguishing bits and metadata.
+type x86_Prefix uint16
+
+const (
+	// Metadata about the role of a prefix in an instruction.
+	x86_PrefixImplicit x86_Prefix = 0x8000 // prefix is implied by instruction text
+	x86_PrefixIgnored  x86_Prefix = 0x4000 // prefix is ignored: either irrelevant or overridden by a later prefix
+	x86_PrefixInvalid  x86_Prefix = 0x2000 // prefix makes entire instruction invalid (bad LOCK)
+
+	// Memory segment overrides.
+	x86_PrefixES x86_Prefix = 0x26 // ES segment override
+	x86_PrefixCS x86_Prefix = 0x2E // CS segment override
+	x86_PrefixSS x86_Prefix = 0x36 // SS segment override
+	x86_PrefixDS x86_Prefix = 0x3E // DS segment override
+	x86_PrefixFS x86_Prefix = 0x64 // FS segment override
+	x86_PrefixGS x86_Prefix = 0x65 // GS segment override
+
+	// Branch prediction.
+	x86_PrefixPN x86_Prefix = 0x12E // predict not taken (conditional branch only)
+	x86_PrefixPT x86_Prefix = 0x13E // predict taken (conditional branch only)
+
+	// Size attributes.
+	x86_PrefixDataSize x86_Prefix = 0x66 // operand size override
+	x86_PrefixData16   x86_Prefix = 0x166
+	x86_PrefixData32   x86_Prefix = 0x266
+	x86_PrefixAddrSize x86_Prefix = 0x67 // address size override
+	x86_PrefixAddr16   x86_Prefix = 0x167
+	x86_PrefixAddr32   x86_Prefix = 0x267
+
+	// One of a kind.
+	x86_PrefixLOCK     x86_Prefix = 0xF0 // lock
+	x86_PrefixREPN     x86_Prefix = 0xF2 // repeat not zero
+	x86_PrefixXACQUIRE x86_Prefix = 0x1F2
+	x86_PrefixBND      x86_Prefix = 0x2F2
+	x86_PrefixREP      x86_Prefix = 0xF3 // repeat
+	x86_PrefixXRELEASE x86_Prefix = 0x1F3
+
+	// The REX prefixes must be in the range [PrefixREX, PrefixREX+0x10).
+	// the other bits are set or not according to the intended use.
+	x86_PrefixREX  x86_Prefix = 0x40 // REX 64-bit extension prefix
+	x86_PrefixREXW x86_Prefix = 0x08 // extension bit W (64-bit instruction width)
+	x86_PrefixREXR x86_Prefix = 0x04 // extension bit R (r field in modrm)
+	x86_PrefixREXX x86_Prefix = 0x02 // extension bit X (index field in sib)
+	x86_PrefixREXB x86_Prefix = 0x01 // extension bit B (r/m field in modrm or base field in sib)
+)
+
+// IsREX reports whether p is a REX prefix byte.
+func (p x86_Prefix) IsREX() bool {
+	return p&0xF0 == x86_PrefixREX
+}
+
+func (p x86_Prefix) String() string {
+	p &^= x86_PrefixImplicit | x86_PrefixIgnored | x86_PrefixInvalid
+	if s := x86_prefixNames[p]; s != "" {
+		return s
+	}
+
+	if p.IsREX() {
+		s := "REX."
+		if p&x86_PrefixREXW != 0 {
+			s += "W"
+		}
+		if p&x86_PrefixREXR != 0 {
+			s += "R"
+		}
+		if p&x86_PrefixREXX != 0 {
+			s += "X"
+		}
+		if p&x86_PrefixREXB != 0 {
+			s += "B"
+		}
+		return s
+	}
+
+	return fmt.Sprintf("Prefix(%#x)", int(p))
+}
+
+// An Op is an x86 opcode.
+type x86_Op uint32
+
+func (op x86_Op) String() string {
+	i := int(op)
+	if i < 0 || i >= len(x86_opNames) || x86_opNames[i] == "" {
+		return fmt.Sprintf("Op(%d)", i)
+	}
+	return x86_opNames[i]
+}
+
+// An Args holds the instruction arguments.
+// If an instruction has fewer than 4 arguments,
+// the final elements in the array are nil.
+type x86_Args [4]x86_Arg
+
+// An Arg is a single instruction argument,
+// one of these types: Reg, Mem, Imm, Rel.
+type x86_Arg interface {
+	String() string
+	isArg()
+}
+
+// Note that the implements of Arg that follow are all sized
+// so that on a 64-bit machine the data can be inlined in
+// the interface value instead of requiring an allocation.
+
+// A Reg is a single register.
+// The zero Reg value has no name but indicates ``no register.''
+type x86_Reg uint8
+
+const (
+	_ x86_Reg = iota
+
+	// 8-bit
+	x86_AL
+	x86_CL
+	x86_DL
+	x86_BL
+	x86_AH
+	x86_CH
+	x86_DH
+	x86_BH
+	x86_SPB
+	x86_BPB
+	x86_SIB
+	x86_DIB
+	x86_R8B
+	x86_R9B
+	x86_R10B
+	x86_R11B
+	x86_R12B
+	x86_R13B
+	x86_R14B
+	x86_R15B
+
+	// 16-bit
+	x86_AX
+	x86_CX
+	x86_DX
+	x86_BX
+	x86_SP
+	x86_BP
+	x86_SI
+	x86_DI
+	x86_R8W
+	x86_R9W
+	x86_R10W
+	x86_R11W
+	x86_R12W
+	x86_R13W
+	x86_R14W
+	x86_R15W
+
+	// 32-bit
+	x86_EAX
+	x86_ECX
+	x86_EDX
+	x86_EBX
+	x86_ESP
+	x86_EBP
+	x86_ESI
+	x86_EDI
+	x86_R8L
+	x86_R9L
+	x86_R10L
+	x86_R11L
+	x86_R12L
+	x86_R13L
+	x86_R14L
+	x86_R15L
+
+	// 64-bit
+	x86_RAX
+	x86_RCX
+	x86_RDX
+	x86_RBX
+	x86_RSP
+	x86_RBP
+	x86_RSI
+	x86_RDI
+	x86_R8
+	x86_R9
+	x86_R10
+	x86_R11
+	x86_R12
+	x86_R13
+	x86_R14
+	x86_R15
+
+	// Instruction pointer.
+	x86_IP  // 16-bit
+	x86_EIP // 32-bit
+	x86_RIP // 64-bit
+
+	// 387 floating point registers.
+	x86_F0
+	x86_F1
+	x86_F2
+	x86_F3
+	x86_F4
+	x86_F5
+	x86_F6
+	x86_F7
+
+	// MMX registers.
+	x86_M0
+	x86_M1
+	x86_M2
+	x86_M3
+	x86_M4
+	x86_M5
+	x86_M6
+	x86_M7
+
+	// XMM registers.
+	x86_X0
+	x86_X1
+	x86_X2
+	x86_X3
+	x86_X4
+	x86_X5
+	x86_X6
+	x86_X7
+	x86_X8
+	x86_X9
+	x86_X10
+	x86_X11
+	x86_X12
+	x86_X13
+	x86_X14
+	x86_X15
+
+	// Segment registers.
+	x86_ES
+	x86_CS
+	x86_SS
+	x86_DS
+	x86_FS
+	x86_GS
+
+	// System registers.
+	x86_GDTR
+	x86_IDTR
+	x86_LDTR
+	x86_MSW
+	x86_TASK
+
+	// Control registers.
+	x86_CR0
+	x86_CR1
+	x86_CR2
+	x86_CR3
+	x86_CR4
+	x86_CR5
+	x86_CR6
+	x86_CR7
+	x86_CR8
+	x86_CR9
+	x86_CR10
+	x86_CR11
+	x86_CR12
+	x86_CR13
+	x86_CR14
+	x86_CR15
+
+	// Debug registers.
+	x86_DR0
+	x86_DR1
+	x86_DR2
+	x86_DR3
+	x86_DR4
+	x86_DR5
+	x86_DR6
+	x86_DR7
+	x86_DR8
+	x86_DR9
+	x86_DR10
+	x86_DR11
+	x86_DR12
+	x86_DR13
+	x86_DR14
+	x86_DR15
+
+	// Task registers.
+	x86_TR0
+	x86_TR1
+	x86_TR2
+	x86_TR3
+	x86_TR4
+	x86_TR5
+	x86_TR6
+	x86_TR7
+)
+
+const x86_regMax = x86_TR7
+
+func (x86_Reg) isArg() {}
+
+func (r x86_Reg) String() string {
+	i := int(r)
+	if i < 0 || i >= len(x86_regNames) || x86_regNames[i] == "" {
+		return fmt.Sprintf("Reg(%d)", i)
+	}
+	return x86_regNames[i]
+}
+
+// A Mem is a memory reference.
+// The general form is Segment:[Base+Scale*Index+Disp].
+type x86_Mem struct {
+	Segment x86_Reg
+	Base    x86_Reg
+	Scale   uint8
+	Index   x86_Reg
+	Disp    int64
+}
+
+func (x86_Mem) isArg() {}
+
+func (m x86_Mem) String() string {
+	var base, plus, scale, index, disp string
+
+	if m.Base != 0 {
+		base = m.Base.String()
+	}
+	if m.Scale != 0 {
+		if m.Base != 0 {
+			plus = "+"
+		}
+		if m.Scale > 1 {
+			scale = fmt.Sprintf("%d*", m.Scale)
+		}
+		index = m.Index.String()
+	}
+	if m.Disp != 0 || m.Base == 0 && m.Scale == 0 {
+		disp = fmt.Sprintf("%+#x", m.Disp)
+	}
+	return "[" + base + plus + scale + index + disp + "]"
+}
+
+// A Rel is an offset relative to the current instruction pointer.
+type x86_Rel int32
+
+func (x86_Rel) isArg() {}
+
+func (r x86_Rel) String() string {
+	return fmt.Sprintf(".%+d", r)
+}
+
+// An Imm is an integer constant.
+type x86_Imm int64
+
+func (x86_Imm) isArg() {}
+
+func (i x86_Imm) String() string {
+	return fmt.Sprintf("%#x", int64(i))
+}
+
+func (i x86_Inst) String() string {
+	var buf bytes.Buffer
+	for _, p := range i.Prefix {
+		if p == 0 {
+			break
+		}
+		if p&x86_PrefixImplicit != 0 {
+			continue
+		}
+		fmt.Fprintf(&buf, "%v ", p)
+	}
+	fmt.Fprintf(&buf, "%v", i.Op)
+	sep := " "
+	for _, v := range i.Args {
+		if v == nil {
+			break
+		}
+		fmt.Fprintf(&buf, "%s%v", sep, v)
+		sep = ", "
+	}
+	return buf.String()
+}
+
+func x86_isReg(a x86_Arg) bool {
+	_, ok := a.(x86_Reg)
+	return ok
+}
+
+func x86_isSegReg(a x86_Arg) bool {
+	r, ok := a.(x86_Reg)
+	return ok && x86_ES <= r && r <= x86_GS
+}
+
+func x86_isMem(a x86_Arg) bool {
+	_, ok := a.(x86_Mem)
+	return ok
+}
+
+func x86_isImm(a x86_Arg) bool {
+	_, ok := a.(x86_Imm)
+	return ok
+}
+
+func x86_regBytes(a x86_Arg) int {
+	r, ok := a.(x86_Reg)
+	if !ok {
+		return 0
+	}
+	if x86_AL <= r && r <= x86_R15B {
+		return 1
+	}
+	if x86_AX <= r && r <= x86_R15W {
+		return 2
+	}
+	if x86_EAX <= r && r <= x86_R15L {
+		return 4
+	}
+	if x86_RAX <= r && r <= x86_R15 {
+		return 8
+	}
+	return 0
+}
+
+func x86_isSegment(p x86_Prefix) bool {
+	switch p {
+	case x86_PrefixCS, x86_PrefixDS, x86_PrefixES, x86_PrefixFS, x86_PrefixGS, x86_PrefixSS:
+		return true
+	}
+	return false
+}
+
+// The Op definitions and string list are in tables.go.
+
+var x86_prefixNames = map[x86_Prefix]string{
+	x86_PrefixCS:       "CS",
+	x86_PrefixDS:       "DS",
+	x86_PrefixES:       "ES",
+	x86_PrefixFS:       "FS",
+	x86_PrefixGS:       "GS",
+	x86_PrefixSS:       "SS",
+	x86_PrefixLOCK:     "LOCK",
+	x86_PrefixREP:      "REP",
+	x86_PrefixREPN:     "REPN",
+	x86_PrefixAddrSize: "ADDRSIZE",
+	x86_PrefixDataSize: "DATASIZE",
+	x86_PrefixAddr16:   "ADDR16",
+	x86_PrefixData16:   "DATA16",
+	x86_PrefixAddr32:   "ADDR32",
+	x86_PrefixData32:   "DATA32",
+	x86_PrefixBND:      "BND",
+	x86_PrefixXACQUIRE: "XACQUIRE",
+	x86_PrefixXRELEASE: "XRELEASE",
+	x86_PrefixREX:      "REX",
+	x86_PrefixPT:       "PT",
+	x86_PrefixPN:       "PN",
+}
+
+var x86_regNames = [...]string{
+	x86_AL:   "AL",
+	x86_CL:   "CL",
+	x86_BL:   "BL",
+	x86_DL:   "DL",
+	x86_AH:   "AH",
+	x86_CH:   "CH",
+	x86_BH:   "BH",
+	x86_DH:   "DH",
+	x86_SPB:  "SPB",
+	x86_BPB:  "BPB",
+	x86_SIB:  "SIB",
+	x86_DIB:  "DIB",
+	x86_R8B:  "R8B",
+	x86_R9B:  "R9B",
+	x86_R10B: "R10B",
+	x86_R11B: "R11B",
+	x86_R12B: "R12B",
+	x86_R13B: "R13B",
+	x86_R14B: "R14B",
+	x86_R15B: "R15B",
+	x86_AX:   "AX",
+	x86_CX:   "CX",
+	x86_BX:   "BX",
+	x86_DX:   "DX",
+	x86_SP:   "SP",
+	x86_BP:   "BP",
+	x86_SI:   "SI",
+	x86_DI:   "DI",
+	x86_R8W:  "R8W",
+	x86_R9W:  "R9W",
+	x86_R10W: "R10W",
+	x86_R11W: "R11W",
+	x86_R12W: "R12W",
+	x86_R13W: "R13W",
+	x86_R14W: "R14W",
+	x86_R15W: "R15W",
+	x86_EAX:  "EAX",
+	x86_ECX:  "ECX",
+	x86_EDX:  "EDX",
+	x86_EBX:  "EBX",
+	x86_ESP:  "ESP",
+	x86_EBP:  "EBP",
+	x86_ESI:  "ESI",
+	x86_EDI:  "EDI",
+	x86_R8L:  "R8L",
+	x86_R9L:  "R9L",
+	x86_R10L: "R10L",
+	x86_R11L: "R11L",
+	x86_R12L: "R12L",
+	x86_R13L: "R13L",
+	x86_R14L: "R14L",
+	x86_R15L: "R15L",
+	x86_RAX:  "RAX",
+	x86_RCX:  "RCX",
+	x86_RDX:  "RDX",
+	x86_RBX:  "RBX",
+	x86_RSP:  "RSP",
+	x86_RBP:  "RBP",
+	x86_RSI:  "RSI",
+	x86_RDI:  "RDI",
+	x86_R8:   "R8",
+	x86_R9:   "R9",
+	x86_R10:  "R10",
+	x86_R11:  "R11",
+	x86_R12:  "R12",
+	x86_R13:  "R13",
+	x86_R14:  "R14",
+	x86_R15:  "R15",
+	x86_IP:   "IP",
+	x86_EIP:  "EIP",
+	x86_RIP:  "RIP",
+	x86_F0:   "F0",
+	x86_F1:   "F1",
+	x86_F2:   "F2",
+	x86_F3:   "F3",
+	x86_F4:   "F4",
+	x86_F5:   "F5",
+	x86_F6:   "F6",
+	x86_F7:   "F7",
+	x86_M0:   "M0",
+	x86_M1:   "M1",
+	x86_M2:   "M2",
+	x86_M3:   "M3",
+	x86_M4:   "M4",
+	x86_M5:   "M5",
+	x86_M6:   "M6",
+	x86_M7:   "M7",
+	x86_X0:   "X0",
+	x86_X1:   "X1",
+	x86_X2:   "X2",
+	x86_X3:   "X3",
+	x86_X4:   "X4",
+	x86_X5:   "X5",
+	x86_X6:   "X6",
+	x86_X7:   "X7",
+	x86_X8:   "X8",
+	x86_X9:   "X9",
+	x86_X10:  "X10",
+	x86_X11:  "X11",
+	x86_X12:  "X12",
+	x86_X13:  "X13",
+	x86_X14:  "X14",
+	x86_X15:  "X15",
+	x86_CS:   "CS",
+	x86_SS:   "SS",
+	x86_DS:   "DS",
+	x86_ES:   "ES",
+	x86_FS:   "FS",
+	x86_GS:   "GS",
+	x86_GDTR: "GDTR",
+	x86_IDTR: "IDTR",
+	x86_LDTR: "LDTR",
+	x86_MSW:  "MSW",
+	x86_TASK: "TASK",
+	x86_CR0:  "CR0",
+	x86_CR1:  "CR1",
+	x86_CR2:  "CR2",
+	x86_CR3:  "CR3",
+	x86_CR4:  "CR4",
+	x86_CR5:  "CR5",
+	x86_CR6:  "CR6",
+	x86_CR7:  "CR7",
+	x86_CR8:  "CR8",
+	x86_CR9:  "CR9",
+	x86_CR10: "CR10",
+	x86_CR11: "CR11",
+	x86_CR12: "CR12",
+	x86_CR13: "CR13",
+	x86_CR14: "CR14",
+	x86_CR15: "CR15",
+	x86_DR0:  "DR0",
+	x86_DR1:  "DR1",
+	x86_DR2:  "DR2",
+	x86_DR3:  "DR3",
+	x86_DR4:  "DR4",
+	x86_DR5:  "DR5",
+	x86_DR6:  "DR6",
+	x86_DR7:  "DR7",
+	x86_DR8:  "DR8",
+	x86_DR9:  "DR9",
+	x86_DR10: "DR10",
+	x86_DR11: "DR11",
+	x86_DR12: "DR12",
+	x86_DR13: "DR13",
+	x86_DR14: "DR14",
+	x86_DR15: "DR15",
+	x86_TR0:  "TR0",
+	x86_TR1:  "TR1",
+	x86_TR2:  "TR2",
+	x86_TR3:  "TR3",
+	x86_TR4:  "TR4",
+	x86_TR5:  "TR5",
+	x86_TR6:  "TR6",
+	x86_TR7:  "TR7",
+}
+
+/* intel.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.
+
+// IntelSyntax returns the Intel assembler syntax for the instruction, as defined by Intel's XED tool.
+func x86_IntelSyntax(inst x86_Inst) string {
+	var iargs []x86_Arg
+	for _, a := range inst.Args {
+		if a == nil {
+			break
+		}
+		iargs = append(iargs, a)
+	}
+
+	switch inst.Op {
+	case x86_INSB, x86_INSD, x86_INSW, x86_OUTSB, x86_OUTSD, x86_OUTSW, x86_LOOPNE, x86_JCXZ, x86_JECXZ, x86_JRCXZ, x86_LOOP, x86_LOOPE, x86_MOV, x86_XLATB:
+		if inst.Op == x86_MOV && (inst.Opcode>>16)&0xFFFC != 0x0F20 {
+			break
+		}
+		for i, p := range inst.Prefix {
+			if p&0xFF == x86_PrefixAddrSize {
+				inst.Prefix[i] &^= x86_PrefixImplicit
+			}
+		}
+	}
+
+	switch inst.Op {
+	case x86_MOV:
+		dst, _ := inst.Args[0].(x86_Reg)
+		src, _ := inst.Args[1].(x86_Reg)
+		if x86_ES <= dst && dst <= x86_GS && x86_EAX <= src && src <= x86_R15L {
+			src -= x86_EAX - x86_AX
+			iargs[1] = src
+		}
+		if x86_ES <= dst && dst <= x86_GS && x86_RAX <= src && src <= x86_R15 {
+			src -= x86_RAX - x86_AX
+			iargs[1] = src
+		}
+
+		if inst.Opcode>>24&^3 == 0xA0 {
+			for i, p := range inst.Prefix {
+				if p&0xFF == x86_PrefixAddrSize {
+					inst.Prefix[i] |= x86_PrefixImplicit
+				}
+			}
+		}
+	}
+
+	switch inst.Op {
+	case x86_AAM, x86_AAD:
+		if imm, ok := iargs[0].(x86_Imm); ok {
+			if inst.DataSize == 32 {
+				iargs[0] = x86_Imm(uint32(int8(imm)))
+			} else if inst.DataSize == 16 {
+				iargs[0] = x86_Imm(uint16(int8(imm)))
+			}
+		}
+
+	case x86_PUSH:
+		if imm, ok := iargs[0].(x86_Imm); ok {
+			iargs[0] = x86_Imm(uint32(imm))
+		}
+	}
+
+	for _, p := range inst.Prefix {
+		if p&x86_PrefixImplicit != 0 {
+			for j, pj := range inst.Prefix {
+				if pj&0xFF == p&0xFF {
+					inst.Prefix[j] |= x86_PrefixImplicit
+				}
+			}
+		}
+	}
+
+	if inst.Op != 0 {
+		for i, p := range inst.Prefix {
+			switch p &^ x86_PrefixIgnored {
+			case x86_PrefixData16, x86_PrefixData32, x86_PrefixCS, x86_PrefixDS, x86_PrefixES, x86_PrefixSS:
+				inst.Prefix[i] |= x86_PrefixImplicit
+			}
+			if p.IsREX() {
+				inst.Prefix[i] |= x86_PrefixImplicit
+			}
+		}
+	}
+
+	if x86_isLoop[inst.Op] || inst.Op == x86_JCXZ || inst.Op == x86_JECXZ || inst.Op == x86_JRCXZ {
+		for i, p := range inst.Prefix {
+			if p == x86_PrefixPT || p == x86_PrefixPN {
+				inst.Prefix[i] |= x86_PrefixImplicit
+			}
+		}
+	}
+
+	switch inst.Op {
+	case x86_AAA, x86_AAS, x86_CBW, x86_CDQE, x86_CLC, x86_CLD, x86_CLI, x86_CLTS, x86_CMC, x86_CPUID, x86_CQO, x86_CWD, x86_DAA, x86_DAS,
+		x86_FDECSTP, x86_FINCSTP, x86_FNCLEX, x86_FNINIT, x86_FNOP, x86_FWAIT, x86_HLT,
+		x86_ICEBP, x86_INSB, x86_INSD, x86_INSW, x86_INT, x86_INTO, x86_INVD, x86_IRET, x86_IRETQ,
+		x86_LAHF, x86_LEAVE, x86_LRET, x86_MONITOR, x86_MWAIT, x86_NOP, x86_OUTSB, x86_OUTSD, x86_OUTSW,
+		x86_PAUSE, x86_POPA, x86_POPF, x86_POPFQ, x86_PUSHA, x86_PUSHF, x86_PUSHFQ,
+		x86_RDMSR, x86_RDPMC, x86_RDTSC, x86_RDTSCP, x86_RET, x86_RSM,
+		x86_SAHF, x86_STC, x86_STD, x86_STI, x86_SYSENTER, x86_SYSEXIT, x86_SYSRET,
+		x86_UD2, x86_WBINVD, x86_WRMSR, x86_XEND, x86_XLATB, x86_XTEST:
+
+		if inst.Op == x86_NOP && inst.Opcode>>24 != 0x90 {
+			break
+		}
+		if inst.Op == x86_RET && inst.Opcode>>24 != 0xC3 {
+			break
+		}
+		if inst.Op == x86_INT && inst.Opcode>>24 != 0xCC {
+			break
+		}
+		if inst.Op == x86_LRET && inst.Opcode>>24 != 0xcb {
+			break
+		}
+		for i, p := range inst.Prefix {
+			if p&0xFF == x86_PrefixDataSize {
+				inst.Prefix[i] &^= x86_PrefixImplicit | x86_PrefixIgnored
+			}
+		}
+
+	case 0:
+		// ok
+	}
+
+	switch inst.Op {
+	case x86_INSB, x86_INSD, x86_INSW, x86_OUTSB, x86_OUTSD, x86_OUTSW, x86_MONITOR, x86_MWAIT, x86_XLATB:
+		iargs = nil
+
+	case x86_STOSB, x86_STOSW, x86_STOSD, x86_STOSQ:
+		iargs = iargs[:1]
+
+	case x86_LODSB, x86_LODSW, x86_LODSD, x86_LODSQ, x86_SCASB, x86_SCASW, x86_SCASD, x86_SCASQ:
+		iargs = iargs[1:]
+	}
+
+	const (
+		haveData16 = 1 << iota
+		haveData32
+		haveAddr16
+		haveAddr32
+		haveXacquire
+		haveXrelease
+		haveLock
+		haveHintTaken
+		haveHintNotTaken
+		haveBnd
+	)
+	var prefixBits uint32
+	prefix := ""
+	for _, p := range inst.Prefix {
+		if p == 0 {
+			break
+		}
+		if p&0xFF == 0xF3 {
+			prefixBits &^= haveBnd
+		}
+		if p&(x86_PrefixImplicit|x86_PrefixIgnored) != 0 {
+			continue
+		}
+		switch p {
+		default:
+			prefix += strings.ToLower(p.String()) + " "
+		case x86_PrefixCS, x86_PrefixDS, x86_PrefixES, x86_PrefixFS, x86_PrefixGS, x86_PrefixSS:
+			if inst.Op == 0 {
+				prefix += strings.ToLower(p.String()) + " "
+			}
+		case x86_PrefixREPN:
+			prefix += "repne "
+		case x86_PrefixLOCK:
+			prefixBits |= haveLock
+		case x86_PrefixData16, x86_PrefixDataSize:
+			prefixBits |= haveData16
+		case x86_PrefixData32:
+			prefixBits |= haveData32
+		case x86_PrefixAddrSize, x86_PrefixAddr16:
+			prefixBits |= haveAddr16
+		case x86_PrefixAddr32:
+			prefixBits |= haveAddr32
+		case x86_PrefixXACQUIRE:
+			prefixBits |= haveXacquire
+		case x86_PrefixXRELEASE:
+			prefixBits |= haveXrelease
+		case x86_PrefixPT:
+			prefixBits |= haveHintTaken
+		case x86_PrefixPN:
+			prefixBits |= haveHintNotTaken
+		case x86_PrefixBND:
+			prefixBits |= haveBnd
+		}
+	}
+	switch inst.Op {
+	case x86_JMP:
+		if inst.Opcode>>24 == 0xEB {
+			prefixBits &^= haveBnd
+		}
+	case x86_RET, x86_LRET:
+		prefixBits &^= haveData16 | haveData32
+	}
+
+	if prefixBits&haveXacquire != 0 {
+		prefix += "xacquire "
+	}
+	if prefixBits&haveXrelease != 0 {
+		prefix += "xrelease "
+	}
+	if prefixBits&haveLock != 0 {
+		prefix += "lock "
+	}
+	if prefixBits&haveBnd != 0 {
+		prefix += "bnd "
+	}
+	if prefixBits&haveHintTaken != 0 {
+		prefix += "hint-taken "
+	}
+	if prefixBits&haveHintNotTaken != 0 {
+		prefix += "hint-not-taken "
+	}
+	if prefixBits&haveAddr16 != 0 {
+		prefix += "addr16 "
+	}
+	if prefixBits&haveAddr32 != 0 {
+		prefix += "addr32 "
+	}
+	if prefixBits&haveData16 != 0 {
+		prefix += "data16 "
+	}
+	if prefixBits&haveData32 != 0 {
+		prefix += "data32 "
+	}
+
+	if inst.Op == 0 {
+		if prefix == "" {
+			return "<no instruction>"
+		}
+		return prefix[:len(prefix)-1]
+	}
+
+	var args []string
+	for _, a := range iargs {
+		if a == nil {
+			break
+		}
+		args = append(args, x86_intelArg(&inst, a))
+	}
+
+	var op string
+	switch inst.Op {
+	case x86_NOP:
+		if inst.Opcode>>24 == 0x0F {
+			if inst.DataSize == 16 {
+				args = append(args, "ax")
+			} else {
+				args = append(args, "eax")
+			}
+		}
+
+	case x86_BLENDVPD, x86_BLENDVPS, x86_PBLENDVB:
+		args = args[:2]
+
+	case x86_INT:
+		if inst.Opcode>>24 == 0xCC {
+			args = nil
+			op = "int3"
+		}
+
+	case x86_LCALL, x86_LJMP:
+		if len(args) == 2 {
+			args[0], args[1] = args[1], args[0]
+		}
+
+	case x86_FCHS, x86_FABS, x86_FTST, x86_FLDPI, x86_FLDL2E, x86_FLDLG2, x86_F2XM1, x86_FXAM, x86_FLD1, x86_FLDL2T, x86_FSQRT, x86_FRNDINT, x86_FCOS, x86_FSIN:
+		if len(args) == 0 {
+			args = append(args, "st0")
+		}
+
+	case x86_FPTAN, x86_FSINCOS, x86_FUCOMPP, x86_FCOMPP, x86_FYL2X, x86_FPATAN, x86_FXTRACT, x86_FPREM1, x86_FPREM, x86_FYL2XP1, x86_FSCALE:
+		if len(args) == 0 {
+			args = []string{"st0", "st1"}
+		}
+
+	case x86_FST, x86_FSTP, x86_FISTTP, x86_FIST, x86_FISTP, x86_FBSTP:
+		if len(args) == 1 {
+			args = append(args, "st0")
+		}
+
+	case x86_FLD, x86_FXCH, x86_FCOM, x86_FCOMP, x86_FIADD, x86_FIMUL, x86_FICOM, x86_FICOMP, x86_FISUBR, x86_FIDIV, x86_FUCOM, x86_FUCOMP, x86_FILD, x86_FBLD, x86_FADD, x86_FMUL, x86_FSUB, x86_FSUBR, x86_FISUB, x86_FDIV, x86_FDIVR, x86_FIDIVR:
+		if len(args) == 1 {
+			args = []string{"st0", args[0]}
+		}
+
+	case x86_MASKMOVDQU, x86_MASKMOVQ, x86_XLATB, x86_OUTSB, x86_OUTSW, x86_OUTSD:
+	FixSegment:
+		for i := len(inst.Prefix) - 1; i >= 0; i-- {
+			p := inst.Prefix[i] & 0xFF
+			switch p {
+			case x86_PrefixCS, x86_PrefixES, x86_PrefixFS, x86_PrefixGS, x86_PrefixSS:
+				if inst.Mode != 64 || p == x86_PrefixFS || p == x86_PrefixGS {
+					args = append(args, strings.ToLower((inst.Prefix[i] & 0xFF).String()))
+					break FixSegment
+				}
+			case x86_PrefixDS:
+				if inst.Mode != 64 {
+					break FixSegment
+				}
+			}
+		}
+	}
+
+	if op == "" {
+		op = x86_intelOp[inst.Op]
+	}
+	if op == "" {
+		op = strings.ToLower(inst.Op.String())
+	}
+	if args != nil {
+		op += " " + strings.Join(args, ", ")
+	}
+	return prefix + op
+}
+
+func x86_intelArg(inst *x86_Inst, arg x86_Arg) string {
+	switch a := arg.(type) {
+	case x86_Imm:
+		if inst.Mode == 32 {
+			return fmt.Sprintf("%#x", uint32(a))
+		}
+		if x86_Imm(int32(a)) == a {
+			return fmt.Sprintf("%#x", int64(a))
+		}
+		return fmt.Sprintf("%#x", uint64(a))
+	case x86_Mem:
+		if a.Base == x86_EIP {
+			a.Base = x86_RIP
+		}
+		prefix := ""
+		switch inst.MemBytes {
+		case 1:
+			prefix = "byte "
+		case 2:
+			prefix = "word "
+		case 4:
+			prefix = "dword "
+		case 8:
+			prefix = "qword "
+		case 16:
+			prefix = "xmmword "
+		}
+		switch inst.Op {
+		case x86_INVLPG:
+			prefix = "byte "
+		case x86_STOSB, x86_MOVSB, x86_CMPSB, x86_LODSB, x86_SCASB:
+			prefix = "byte "
+		case x86_STOSW, x86_MOVSW, x86_CMPSW, x86_LODSW, x86_SCASW:
+			prefix = "word "
+		case x86_STOSD, x86_MOVSD, x86_CMPSD, x86_LODSD, x86_SCASD:
+			prefix = "dword "
+		case x86_STOSQ, x86_MOVSQ, x86_CMPSQ, x86_LODSQ, x86_SCASQ:
+			prefix = "qword "
+		case x86_LAR:
+			prefix = "word "
+		case x86_BOUND:
+			if inst.Mode == 32 {
+				prefix = "qword "
+			} else {
+				prefix = "dword "
+			}
+		case x86_PREFETCHW, x86_PREFETCHNTA, x86_PREFETCHT0, x86_PREFETCHT1, x86_PREFETCHT2, x86_CLFLUSH:
+			prefix = "zmmword "
+		}
+		switch inst.Op {
+		case x86_MOVSB, x86_MOVSW, x86_MOVSD, x86_MOVSQ, x86_CMPSB, x86_CMPSW, x86_CMPSD, x86_CMPSQ, x86_STOSB, x86_STOSW, x86_STOSD, x86_STOSQ, x86_SCASB, x86_SCASW, x86_SCASD, x86_SCASQ, x86_LODSB, x86_LODSW, x86_LODSD, x86_LODSQ:
+			switch a.Base {
+			case x86_DI, x86_EDI, x86_RDI:
+				if a.Segment == x86_ES {
+					a.Segment = 0
+				}
+			case x86_SI, x86_ESI, x86_RSI:
+				if a.Segment == x86_DS {
+					a.Segment = 0
+				}
+			}
+		case x86_LEA:
+			a.Segment = 0
+		default:
+			switch a.Base {
+			case x86_SP, x86_ESP, x86_RSP, x86_BP, x86_EBP, x86_RBP:
+				if a.Segment == x86_SS {
+					a.Segment = 0
+				}
+			default:
+				if a.Segment == x86_DS {
+					a.Segment = 0
+				}
+			}
+		}
+
+		if inst.Mode == 64 && a.Segment != x86_FS && a.Segment != x86_GS {
+			a.Segment = 0
+		}
+
+		prefix += "ptr "
+		if a.Segment != 0 {
+			prefix += strings.ToLower(a.Segment.String()) + ":"
+		}
+		prefix += "["
+		if a.Base != 0 {
+			prefix += x86_intelArg(inst, a.Base)
+		}
+		if a.Scale != 0 && a.Index != 0 {
+			if a.Base != 0 {
+				prefix += "+"
+			}
+			prefix += fmt.Sprintf("%s*%d", x86_intelArg(inst, a.Index), a.Scale)
+		}
+		if a.Disp != 0 {
+			if prefix[len(prefix)-1] == '[' && (a.Disp >= 0 || int64(int32(a.Disp)) != a.Disp) {
+				prefix += fmt.Sprintf("%#x", uint64(a.Disp))
+			} else {
+				prefix += fmt.Sprintf("%+#x", a.Disp)
+			}
+		}
+		prefix += "]"
+		return prefix
+	case x86_Rel:
+		return fmt.Sprintf(".%+#x", int64(a))
+	case x86_Reg:
+		if int(a) < len(x86_intelReg) && x86_intelReg[a] != "" {
+			return x86_intelReg[a]
+		}
+	}
+	return strings.ToLower(arg.String())
+}
+
+var x86_intelOp = map[x86_Op]string{
+	x86_JAE:       "jnb",
+	x86_JA:        "jnbe",
+	x86_JGE:       "jnl",
+	x86_JNE:       "jnz",
+	x86_JG:        "jnle",
+	x86_JE:        "jz",
+	x86_SETAE:     "setnb",
+	x86_SETA:      "setnbe",
+	x86_SETGE:     "setnl",
+	x86_SETNE:     "setnz",
+	x86_SETG:      "setnle",
+	x86_SETE:      "setz",
+	x86_CMOVAE:    "cmovnb",
+	x86_CMOVA:     "cmovnbe",
+	x86_CMOVGE:    "cmovnl",
+	x86_CMOVNE:    "cmovnz",
+	x86_CMOVG:     "cmovnle",
+	x86_CMOVE:     "cmovz",
+	x86_LCALL:     "call far",
+	x86_LJMP:      "jmp far",
+	x86_LRET:      "ret far",
+	x86_ICEBP:     "int1",
+	x86_MOVSD_XMM: "movsd",
+	x86_XLATB:     "xlat",
+}
+
+var x86_intelReg = [...]string{
+	x86_F0:  "st0",
+	x86_F1:  "st1",
+	x86_F2:  "st2",
+	x86_F3:  "st3",
+	x86_F4:  "st4",
+	x86_F5:  "st5",
+	x86_F6:  "st6",
+	x86_F7:  "st7",
+	x86_M0:  "mmx0",
+	x86_M1:  "mmx1",
+	x86_M2:  "mmx2",
+	x86_M3:  "mmx3",
+	x86_M4:  "mmx4",
+	x86_M5:  "mmx5",
+	x86_M6:  "mmx6",
+	x86_M7:  "mmx7",
+	x86_X0:  "xmm0",
+	x86_X1:  "xmm1",
+	x86_X2:  "xmm2",
+	x86_X3:  "xmm3",
+	x86_X4:  "xmm4",
+	x86_X5:  "xmm5",
+	x86_X6:  "xmm6",
+	x86_X7:  "xmm7",
+	x86_X8:  "xmm8",
+	x86_X9:  "xmm9",
+	x86_X10: "xmm10",
+	x86_X11: "xmm11",
+	x86_X12: "xmm12",
+	x86_X13: "xmm13",
+	x86_X14: "xmm14",
+	x86_X15: "xmm15",
+
+	// TODO: Maybe the constants are named wrong.
+	x86_SPB: "spl",
+	x86_BPB: "bpl",
+	x86_SIB: "sil",
+	x86_DIB: "dil",
+
+	x86_R8L:  "r8d",
+	x86_R9L:  "r9d",
+	x86_R10L: "r10d",
+	x86_R11L: "r11d",
+	x86_R12L: "r12d",
+	x86_R13L: "r13d",
+	x86_R14L: "r14d",
+	x86_R15L: "r15d",
+}
+
+/* plan9x.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.
+
+// plan9Syntax returns the Go assembler syntax for the instruction.
+// The syntax was originally defined by Plan 9.
+// The pc is the program counter of the instruction, used for expanding
+// PC-relative addresses into absolute ones.
+// The symname function queries the symbol table for the program
+// being disassembled. Given a target address it returns the name and base
+// address of the symbol containing the target, if any; otherwise it returns "", 0.
+func x86_plan9Syntax(inst x86_Inst, pc uint64, symname func(uint64) (string, uint64)) string {
+	if symname == nil {
+		symname = func(uint64) (string, uint64) { return "", 0 }
+	}
+	var args []string
+	for i := len(inst.Args) - 1; i >= 0; i-- {
+		a := inst.Args[i]
+		if a == nil {
+			continue
+		}
+		args = append(args, x86_plan9Arg(&inst, pc, symname, a))
+	}
+
+	var last x86_Prefix
+	for _, p := range inst.Prefix {
+		if p == 0 || p.IsREX() {
+			break
+		}
+		last = p
+	}
+
+	prefix := ""
+	switch last & 0xFF {
+	case 0, 0x66, 0x67:
+		// ignore
+	case x86_PrefixREPN:
+		prefix += "REPNE "
+	default:
+		prefix += last.String() + " "
+	}
+
+	op := inst.Op.String()
+	if x86_plan9Suffix[inst.Op] {
+		switch inst.DataSize {
+		case 8:
+			op += "B"
+		case 16:
+			op += "W"
+		case 32:
+			op += "L"
+		case 64:
+			op += "Q"
+		}
+	}
+
+	if args != nil {
+		op += " " + strings.Join(args, ", ")
+	}
+
+	return prefix + op
+}
+
+func x86_plan9Arg(inst *x86_Inst, pc uint64, symname func(uint64) (string, uint64), arg x86_Arg) string {
+	switch a := arg.(type) {
+	case x86_Reg:
+		return x86_plan9Reg[a]
+	case x86_Rel:
+		if pc == 0 {
+			break
+		}
+		// If the absolute address is the start of a symbol, use the name.
+		// Otherwise use the raw address, so that things like relative
+		// jumps show up as JMP 0x123 instead of JMP f+10(SB).
+		// It is usually easier to search for 0x123 than to do the mental
+		// arithmetic to find f+10.
+		addr := pc + uint64(inst.Len) + uint64(a)
+		if s, base := symname(addr); s != "" && addr == base {
+			return fmt.Sprintf("%s(SB)", s)
+		}
+		return fmt.Sprintf("%#x", addr)
+
+	case x86_Imm:
+		if s, base := symname(uint64(a)); s != "" {
+			suffix := ""
+			if uint64(a) != base {
+				suffix = fmt.Sprintf("%+d", uint64(a)-base)
+			}
+			return fmt.Sprintf("$%s%s(SB)", s, suffix)
+		}
+		if inst.Mode == 32 {
+			return fmt.Sprintf("$%#x", uint32(a))
+		}
+		if x86_Imm(int32(a)) == a {
+			return fmt.Sprintf("$%#x", int64(a))
+		}
+		return fmt.Sprintf("$%#x", uint64(a))
+	case x86_Mem:
+		if a.Segment == 0 && a.Disp != 0 && a.Base == 0 && (a.Index == 0 || a.Scale == 0) {
+			if s, base := symname(uint64(a.Disp)); s != "" {
+				suffix := ""
+				if uint64(a.Disp) != base {
+					suffix = fmt.Sprintf("%+d", uint64(a.Disp)-base)
+				}
+				return fmt.Sprintf("%s%s(SB)", s, suffix)
+			}
+		}
+		s := ""
+		if a.Segment != 0 {
+			s += fmt.Sprintf("%s:", x86_plan9Reg[a.Segment])
+		}
+		if a.Disp != 0 {
+			s += fmt.Sprintf("%#x", a.Disp)
+		} else {
+			s += "0"
+		}
+		if a.Base != 0 {
+			s += fmt.Sprintf("(%s)", x86_plan9Reg[a.Base])
+		}
+		if a.Index != 0 && a.Scale != 0 {
+			s += fmt.Sprintf("(%s*%d)", x86_plan9Reg[a.Index], a.Scale)
+		}
+		return s
+	}
+	return arg.String()
+}
+
+var x86_plan9Suffix = [x86_maxOp + 1]bool{
+	x86_ADC:       true,
+	x86_ADD:       true,
+	x86_AND:       true,
+	x86_BSF:       true,
+	x86_BSR:       true,
+	x86_BT:        true,
+	x86_BTC:       true,
+	x86_BTR:       true,
+	x86_BTS:       true,
+	x86_CMP:       true,
+	x86_CMPXCHG:   true,
+	x86_CVTSI2SD:  true,
+	x86_CVTSI2SS:  true,
+	x86_CVTSD2SI:  true,
+	x86_CVTSS2SI:  true,
+	x86_CVTTSD2SI: true,
+	x86_CVTTSS2SI: true,
+	x86_DEC:       true,
+	x86_DIV:       true,
+	x86_FLDENV:    true,
+	x86_FRSTOR:    true,
+	x86_IDIV:      true,
+	x86_IMUL:      true,
+	x86_IN:        true,
+	x86_INC:       true,
+	x86_LEA:       true,
+	x86_MOV:       true,
+	x86_MOVNTI:    true,
+	x86_MUL:       true,
+	x86_NEG:       true,
+	x86_NOP:       true,
+	x86_NOT:       true,
+	x86_OR:        true,
+	x86_OUT:       true,
+	x86_POP:       true,
+	x86_POPA:      true,
+	x86_PUSH:      true,
+	x86_PUSHA:     true,
+	x86_RCL:       true,
+	x86_RCR:       true,
+	x86_ROL:       true,
+	x86_ROR:       true,
+	x86_SAR:       true,
+	x86_SBB:       true,
+	x86_SHL:       true,
+	x86_SHLD:      true,
+	x86_SHR:       true,
+	x86_SHRD:      true,
+	x86_SUB:       true,
+	x86_TEST:      true,
+	x86_XADD:      true,
+	x86_XCHG:      true,
+	x86_XOR:       true,
+}
+
+var x86_plan9Reg = [...]string{
+	x86_AL:   "AL",
+	x86_CL:   "CL",
+	x86_BL:   "BL",
+	x86_DL:   "DL",
+	x86_AH:   "AH",
+	x86_CH:   "CH",
+	x86_BH:   "BH",
+	x86_DH:   "DH",
+	x86_SPB:  "SP",
+	x86_BPB:  "BP",
+	x86_SIB:  "SI",
+	x86_DIB:  "DI",
+	x86_R8B:  "R8",
+	x86_R9B:  "R9",
+	x86_R10B: "R10",
+	x86_R11B: "R11",
+	x86_R12B: "R12",
+	x86_R13B: "R13",
+	x86_R14B: "R14",
+	x86_R15B: "R15",
+	x86_AX:   "AX",
+	x86_CX:   "CX",
+	x86_BX:   "BX",
+	x86_DX:   "DX",
+	x86_SP:   "SP",
+	x86_BP:   "BP",
+	x86_SI:   "SI",
+	x86_DI:   "DI",
+	x86_R8W:  "R8",
+	x86_R9W:  "R9",
+	x86_R10W: "R10",
+	x86_R11W: "R11",
+	x86_R12W: "R12",
+	x86_R13W: "R13",
+	x86_R14W: "R14",
+	x86_R15W: "R15",
+	x86_EAX:  "AX",
+	x86_ECX:  "CX",
+	x86_EDX:  "DX",
+	x86_EBX:  "BX",
+	x86_ESP:  "SP",
+	x86_EBP:  "BP",
+	x86_ESI:  "SI",
+	x86_EDI:  "DI",
+	x86_R8L:  "R8",
+	x86_R9L:  "R9",
+	x86_R10L: "R10",
+	x86_R11L: "R11",
+	x86_R12L: "R12",
+	x86_R13L: "R13",
+	x86_R14L: "R14",
+	x86_R15L: "R15",
+	x86_RAX:  "AX",
+	x86_RCX:  "CX",
+	x86_RDX:  "DX",
+	x86_RBX:  "BX",
+	x86_RSP:  "SP",
+	x86_RBP:  "BP",
+	x86_RSI:  "SI",
+	x86_RDI:  "DI",
+	x86_R8:   "R8",
+	x86_R9:   "R9",
+	x86_R10:  "R10",
+	x86_R11:  "R11",
+	x86_R12:  "R12",
+	x86_R13:  "R13",
+	x86_R14:  "R14",
+	x86_R15:  "R15",
+	x86_IP:   "IP",
+	x86_EIP:  "IP",
+	x86_RIP:  "IP",
+	x86_F0:   "F0",
+	x86_F1:   "F1",
+	x86_F2:   "F2",
+	x86_F3:   "F3",
+	x86_F4:   "F4",
+	x86_F5:   "F5",
+	x86_F6:   "F6",
+	x86_F7:   "F7",
+	x86_M0:   "M0",
+	x86_M1:   "M1",
+	x86_M2:   "M2",
+	x86_M3:   "M3",
+	x86_M4:   "M4",
+	x86_M5:   "M5",
+	x86_M6:   "M6",
+	x86_M7:   "M7",
+	x86_X0:   "X0",
+	x86_X1:   "X1",
+	x86_X2:   "X2",
+	x86_X3:   "X3",
+	x86_X4:   "X4",
+	x86_X5:   "X5",
+	x86_X6:   "X6",
+	x86_X7:   "X7",
+	x86_X8:   "X8",
+	x86_X9:   "X9",
+	x86_X10:  "X10",
+	x86_X11:  "X11",
+	x86_X12:  "X12",
+	x86_X13:  "X13",
+	x86_X14:  "X14",
+	x86_X15:  "X15",
+	x86_CS:   "CS",
+	x86_SS:   "SS",
+	x86_DS:   "DS",
+	x86_ES:   "ES",
+	x86_FS:   "FS",
+	x86_GS:   "GS",
+	x86_GDTR: "GDTR",
+	x86_IDTR: "IDTR",
+	x86_LDTR: "LDTR",
+	x86_MSW:  "MSW",
+	x86_TASK: "TASK",
+	x86_CR0:  "CR0",
+	x86_CR1:  "CR1",
+	x86_CR2:  "CR2",
+	x86_CR3:  "CR3",
+	x86_CR4:  "CR4",
+	x86_CR5:  "CR5",
+	x86_CR6:  "CR6",
+	x86_CR7:  "CR7",
+	x86_CR8:  "CR8",
+	x86_CR9:  "CR9",
+	x86_CR10: "CR10",
+	x86_CR11: "CR11",
+	x86_CR12: "CR12",
+	x86_CR13: "CR13",
+	x86_CR14: "CR14",
+	x86_CR15: "CR15",
+	x86_DR0:  "DR0",
+	x86_DR1:  "DR1",
+	x86_DR2:  "DR2",
+	x86_DR3:  "DR3",
+	x86_DR4:  "DR4",
+	x86_DR5:  "DR5",
+	x86_DR6:  "DR6",
+	x86_DR7:  "DR7",
+	x86_DR8:  "DR8",
+	x86_DR9:  "DR9",
+	x86_DR10: "DR10",
+	x86_DR11: "DR11",
+	x86_DR12: "DR12",
+	x86_DR13: "DR13",
+	x86_DR14: "DR14",
+	x86_DR15: "DR15",
+	x86_TR0:  "TR0",
+	x86_TR1:  "TR1",
+	x86_TR2:  "TR2",
+	x86_TR3:  "TR3",
+	x86_TR4:  "TR4",
+	x86_TR5:  "TR5",
+	x86_TR6:  "TR6",
+	x86_TR7:  "TR7",
+}
+
+/* tables.go */
+
+// DO NOT EDIT
+// generated by: x86map -fmt=decoder ../x86.csv
+
+var x86_decoder = [...]uint16{
+	uint16(x86_xFail),
+	/*1*/ uint16(x86_xCondByte), 243,
+	0x00, 490,
+	0x01, 496,
+	0x02, 525,
+	0x03, 531,
+	0x04, 560,
+	0x05, 566,
+	0x06, 595,
+	0x07, 602,
+	0x08, 609,
+	0x09, 615,
+	0x0A, 644,
+	0x0B, 650,
+	0x0C, 679,
+	0x0D, 685,
+	0x0E, 714,
+	0x0F, 721,
+	0x10, 8026,
+	0x11, 8032,
+	0x12, 8061,
+	0x13, 8067,
+	0x14, 8096,
+	0x15, 8102,
+	0x16, 8131,
+	0x17, 8138,
+	0x18, 8145,
+	0x19, 8151,
+	0x1A, 8180,
+	0x1B, 8186,
+	0x1C, 8215,
+	0x1D, 8221,
+	0x1E, 8250,
+	0x1F, 8257,
+	0x20, 8264,
+	0x21, 8270,
+	0x22, 8299,
+	0x23, 8305,
+	0x24, 8334,
+	0x25, 8340,
+	0x27, 8369,
+	0x28, 8375,
+	0x29, 8381,
+	0x2A, 8410,
+	0x2B, 8416,
+	0x2C, 8445,
+	0x2D, 8451,
+	0x2F, 8480,
+	0x30, 8486,
+	0x31, 8492,
+	0x32, 8521,
+	0x33, 8527,
+	0x34, 8556,
+	0x35, 8562,
+	0x37, 8591,
+	0x38, 8597,
+	0x39, 8603,
+	0x3A, 8632,
+	0x3B, 8638,
+	0x3C, 8667,
+	0x3D, 8673,
+	0x3F, 8702,
+	0x40, 8708,
+	0x41, 8708,
+	0x42, 8708,
+	0x43, 8708,
+	0x44, 8708,
+	0x45, 8708,
+	0x46, 8708,
+	0x47, 8708,
+	0x48, 8723,
+	0x49, 8723,
+	0x4a, 8723,
+	0x4b, 8723,
+	0x4c, 8723,
+	0x4d, 8723,
+	0x4e, 8723,
+	0x4f, 8723,
+	0x50, 8738,
+	0x51, 8738,
+	0x52, 8738,
+	0x53, 8738,
+	0x54, 8738,
+	0x55, 8738,
+	0x56, 8738,
+	0x57, 8738,
+	0x58, 8765,
+	0x59, 8765,
+	0x5a, 8765,
+	0x5b, 8765,
+	0x5c, 8765,
+	0x5d, 8765,
+	0x5e, 8765,
+	0x5f, 8765,
+	0x60, 8792,
+	0x61, 8805,
+	0x62, 8818,
+	0x63, 8837,
+	0x68, 8868,
+	0x69, 8887,
+	0x6A, 8922,
+	0x6B, 8927,
+	0x6C, 8962,
+	0x6D, 8965,
+	0x6E, 8978,
+	0x6F, 8981,
+	0x70, 8994,
+	0x71, 8999,
+	0x72, 9004,
+	0x73, 9009,
+	0x74, 9014,
+	0x75, 9019,
+	0x76, 9024,
+	0x77, 9029,
+	0x78, 9034,
+	0x79, 9039,
+	0x7A, 9044,
+	0x7B, 9049,
+	0x7C, 9054,
+	0x7D, 9059,
+	0x7E, 9064,
+	0x7F, 9069,
+	0x80, 9074,
+	0x81, 9131,
+	0x83, 9372,
+	0x84, 9613,
+	0x85, 9619,
+	0x86, 9648,
+	0x87, 9654,
+	0x88, 9683,
+	0x89, 9689,
+	0x8A, 9711,
+	0x8B, 9717,
+	0x8C, 9739,
+	0x8D, 9768,
+	0x8E, 9797,
+	0x8F, 9826,
+	0x90, 9862,
+	0x91, 9862,
+	0x92, 9862,
+	0x93, 9862,
+	0x94, 9862,
+	0x95, 9862,
+	0x96, 9862,
+	0x97, 9862,
+	0x98, 9888,
+	0x99, 9908,
+	0x9A, 9928,
+	0x9B, 9945,
+	0x9C, 9948,
+	0x9D, 9971,
+	0x9E, 9994,
+	0x9F, 9997,
+	0xA0, 10000,
+	0xA1, 10019,
+	0xA2, 10041,
+	0xA3, 10060,
+	0xA4, 10082,
+	0xA5, 10085,
+	0xA6, 10105,
+	0xA7, 10108,
+	0xA8, 10128,
+	0xA9, 10134,
+	0xAA, 10163,
+	0xAB, 10166,
+	0xAC, 10186,
+	0xAD, 10189,
+	0xAE, 10209,
+	0xAF, 10212,
+	0xb0, 10232,
+	0xb1, 10232,
+	0xb2, 10232,
+	0xb3, 10232,
+	0xb4, 10232,
+	0xb5, 10232,
+	0xb6, 10232,
+	0xb7, 10232,
+	0xb8, 10238,
+	0xb9, 10238,
+	0xba, 10238,
+	0xbb, 10238,
+	0xbc, 10238,
+	0xbd, 10238,
+	0xbe, 10238,
+	0xbf, 10238,
+	0xC0, 10267,
+	0xC1, 10318,
+	0xC2, 10516,
+	0xC3, 10521,
+	0xC4, 10524,
+	0xC5, 10543,
+	0xC6, 10562,
+	0xC7, 10586,
+	0xC8, 10647,
+	0xC9, 10654,
+	0xCA, 10677,
+	0xCB, 10682,
+	0xCC, 10685,
+	0xCD, 10689,
+	0xCE, 10694,
+	0xCF, 10700,
+	0xD0, 10720,
+	0xD1, 10764,
+	0xD2, 10955,
+	0xD3, 10999,
+	0xD4, 11190,
+	0xD5, 11198,
+	0xD7, 11206,
+	0xD8, 11219,
+	0xD9, 11428,
+	0xDA, 11637,
+	0xDB, 11769,
+	0xDC, 11940,
+	0xDD, 12109,
+	0xDE, 12248,
+	0xDF, 12422,
+	0xE0, 12533,
+	0xE1, 12538,
+	0xE2, 12543,
+	0xE3, 12548,
+	0xE4, 12574,
+	0xE5, 12580,
+	0xE6, 12602,
+	0xE7, 12608,
+	0xE8, 12630,
+	0xE9, 12661,
+	0xEA, 12692,
+	0xEB, 12709,
+	0xEC, 12714,
+	0xED, 12719,
+	0xEE, 12738,
+	0xEF, 12743,
+	0xF1, 12762,
+	0xF4, 12765,
+	0xF5, 12768,
+	0xF6, 12771,
+	0xF7, 12810,
+	0xF8, 12986,
+	0xF9, 12989,
+	0xFA, 12992,
+	0xFB, 12995,
+	0xFC, 12998,
+	0xFD, 13001,
+	0xFE, 13004,
+	0xFF, 13021,
+	uint16(x86_xFail),
+	/*490*/ uint16(x86_xSetOp), uint16(x86_ADD),
+	/*492*/ uint16(x86_xReadSlashR),
+	/*493*/ uint16(x86_xArgRM8),
+	/*494*/ uint16(x86_xArgR8),
+	/*495*/ uint16(x86_xMatch),
+	/*496*/ uint16(x86_xCondIs64), 499, 515,
+	/*499*/ uint16(x86_xCondDataSize), 503, 509, 0,
+	/*503*/ uint16(x86_xSetOp), uint16(x86_ADD),
+	/*505*/ uint16(x86_xReadSlashR),
+	/*506*/ uint16(x86_xArgRM16),
+	/*507*/ uint16(x86_xArgR16),
+	/*508*/ uint16(x86_xMatch),
+	/*509*/ uint16(x86_xSetOp), uint16(x86_ADD),
+	/*511*/ uint16(x86_xReadSlashR),
+	/*512*/ uint16(x86_xArgRM32),
+	/*513*/ uint16(x86_xArgR32),
+	/*514*/ uint16(x86_xMatch),
+	/*515*/ uint16(x86_xCondDataSize), 503, 509, 519,
+	/*519*/ uint16(x86_xSetOp), uint16(x86_ADD),
+	/*521*/ uint16(x86_xReadSlashR),
+	/*522*/ uint16(x86_xArgRM64),
+	/*523*/ uint16(x86_xArgR64),
+	/*524*/ uint16(x86_xMatch),
+	/*525*/ uint16(x86_xSetOp), uint16(x86_ADD),
+	/*527*/ uint16(x86_xReadSlashR),
+	/*528*/ uint16(x86_xArgR8),
+	/*529*/ uint16(x86_xArgRM8),
+	/*530*/ uint16(x86_xMatch),
+	/*531*/ uint16(x86_xCondIs64), 534, 550,
+	/*534*/ uint16(x86_xCondDataSize), 538, 544, 0,
+	/*538*/ uint16(x86_xSetOp), uint16(x86_ADD),
+	/*540*/ uint16(x86_xReadSlashR),
+	/*541*/ uint16(x86_xArgR16),
+	/*542*/ uint16(x86_xArgRM16),
+	/*543*/ uint16(x86_xMatch),
+	/*544*/ uint16(x86_xSetOp), uint16(x86_ADD),
+	/*546*/ uint16(x86_xReadSlashR),
+	/*547*/ uint16(x86_xArgR32),
+	/*548*/ uint16(x86_xArgRM32),
+	/*549*/ uint16(x86_xMatch),
+	/*550*/ uint16(x86_xCondDataSize), 538, 544, 554,
+	/*554*/ uint16(x86_xSetOp), uint16(x86_ADD),
+	/*556*/ uint16(x86_xReadSlashR),
+	/*557*/ uint16(x86_xArgR64),
+	/*558*/ uint16(x86_xArgRM64),
+	/*559*/ uint16(x86_xMatch),
+	/*560*/ uint16(x86_xSetOp), uint16(x86_ADD),
+	/*562*/ uint16(x86_xReadIb),
+	/*563*/ uint16(x86_xArgAL),
+	/*564*/ uint16(x86_xArgImm8u),
+	/*565*/ uint16(x86_xMatch),
+	/*566*/ uint16(x86_xCondIs64), 569, 585,
+	/*569*/ uint16(x86_xCondDataSize), 573, 579, 0,
+	/*573*/ uint16(x86_xSetOp), uint16(x86_ADD),
+	/*575*/ uint16(x86_xReadIw),
+	/*576*/ uint16(x86_xArgAX),
+	/*577*/ uint16(x86_xArgImm16),
+	/*578*/ uint16(x86_xMatch),
+	/*579*/ uint16(x86_xSetOp), uint16(x86_ADD),
+	/*581*/ uint16(x86_xReadId),
+	/*582*/ uint16(x86_xArgEAX),
+	/*583*/ uint16(x86_xArgImm32),
+	/*584*/ uint16(x86_xMatch),
+	/*585*/ uint16(x86_xCondDataSize), 573, 579, 589,
+	/*589*/ uint16(x86_xSetOp), uint16(x86_ADD),
+	/*591*/ uint16(x86_xReadId),
+	/*592*/ uint16(x86_xArgRAX),
+	/*593*/ uint16(x86_xArgImm32),
+	/*594*/ uint16(x86_xMatch),
+	/*595*/ uint16(x86_xCondIs64), 598, 0,
+	/*598*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+	/*600*/ uint16(x86_xArgES),
+	/*601*/ uint16(x86_xMatch),
+	/*602*/ uint16(x86_xCondIs64), 605, 0,
+	/*605*/ uint16(x86_xSetOp), uint16(x86_POP),
+	/*607*/ uint16(x86_xArgES),
+	/*608*/ uint16(x86_xMatch),
+	/*609*/ uint16(x86_xSetOp), uint16(x86_OR),
+	/*611*/ uint16(x86_xReadSlashR),
+	/*612*/ uint16(x86_xArgRM8),
+	/*613*/ uint16(x86_xArgR8),
+	/*614*/ uint16(x86_xMatch),
+	/*615*/ uint16(x86_xCondIs64), 618, 634,
+	/*618*/ uint16(x86_xCondDataSize), 622, 628, 0,
+	/*622*/ uint16(x86_xSetOp), uint16(x86_OR),
+	/*624*/ uint16(x86_xReadSlashR),
+	/*625*/ uint16(x86_xArgRM16),
+	/*626*/ uint16(x86_xArgR16),
+	/*627*/ uint16(x86_xMatch),
+	/*628*/ uint16(x86_xSetOp), uint16(x86_OR),
+	/*630*/ uint16(x86_xReadSlashR),
+	/*631*/ uint16(x86_xArgRM32),
+	/*632*/ uint16(x86_xArgR32),
+	/*633*/ uint16(x86_xMatch),
+	/*634*/ uint16(x86_xCondDataSize), 622, 628, 638,
+	/*638*/ uint16(x86_xSetOp), uint16(x86_OR),
+	/*640*/ uint16(x86_xReadSlashR),
+	/*641*/ uint16(x86_xArgRM64),
+	/*642*/ uint16(x86_xArgR64),
+	/*643*/ uint16(x86_xMatch),
+	/*644*/ uint16(x86_xSetOp), uint16(x86_OR),
+	/*646*/ uint16(x86_xReadSlashR),
+	/*647*/ uint16(x86_xArgR8),
+	/*648*/ uint16(x86_xArgRM8),
+	/*649*/ uint16(x86_xMatch),
+	/*650*/ uint16(x86_xCondIs64), 653, 669,
+	/*653*/ uint16(x86_xCondDataSize), 657, 663, 0,
+	/*657*/ uint16(x86_xSetOp), uint16(x86_OR),
+	/*659*/ uint16(x86_xReadSlashR),
+	/*660*/ uint16(x86_xArgR16),
+	/*661*/ uint16(x86_xArgRM16),
+	/*662*/ uint16(x86_xMatch),
+	/*663*/ uint16(x86_xSetOp), uint16(x86_OR),
+	/*665*/ uint16(x86_xReadSlashR),
+	/*666*/ uint16(x86_xArgR32),
+	/*667*/ uint16(x86_xArgRM32),
+	/*668*/ uint16(x86_xMatch),
+	/*669*/ uint16(x86_xCondDataSize), 657, 663, 673,
+	/*673*/ uint16(x86_xSetOp), uint16(x86_OR),
+	/*675*/ uint16(x86_xReadSlashR),
+	/*676*/ uint16(x86_xArgR64),
+	/*677*/ uint16(x86_xArgRM64),
+	/*678*/ uint16(x86_xMatch),
+	/*679*/ uint16(x86_xSetOp), uint16(x86_OR),
+	/*681*/ uint16(x86_xReadIb),
+	/*682*/ uint16(x86_xArgAL),
+	/*683*/ uint16(x86_xArgImm8u),
+	/*684*/ uint16(x86_xMatch),
+	/*685*/ uint16(x86_xCondIs64), 688, 704,
+	/*688*/ uint16(x86_xCondDataSize), 692, 698, 0,
+	/*692*/ uint16(x86_xSetOp), uint16(x86_OR),
+	/*694*/ uint16(x86_xReadIw),
+	/*695*/ uint16(x86_xArgAX),
+	/*696*/ uint16(x86_xArgImm16),
+	/*697*/ uint16(x86_xMatch),
+	/*698*/ uint16(x86_xSetOp), uint16(x86_OR),
+	/*700*/ uint16(x86_xReadId),
+	/*701*/ uint16(x86_xArgEAX),
+	/*702*/ uint16(x86_xArgImm32),
+	/*703*/ uint16(x86_xMatch),
+	/*704*/ uint16(x86_xCondDataSize), 692, 698, 708,
+	/*708*/ uint16(x86_xSetOp), uint16(x86_OR),
+	/*710*/ uint16(x86_xReadId),
+	/*711*/ uint16(x86_xArgRAX),
+	/*712*/ uint16(x86_xArgImm32),
+	/*713*/ uint16(x86_xMatch),
+	/*714*/ uint16(x86_xCondIs64), 717, 0,
+	/*717*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+	/*719*/ uint16(x86_xArgCS),
+	/*720*/ uint16(x86_xMatch),
+	/*721*/ uint16(x86_xCondByte), 228,
+	0x00, 1180,
+	0x01, 1237,
+	0x02, 1345,
+	0x03, 1367,
+	0x05, 1389,
+	0x06, 1395,
+	0x07, 1398,
+	0x08, 1404,
+	0x09, 1407,
+	0x0B, 1410,
+	0x0D, 1413,
+	0x10, 1426,
+	0x11, 1460,
+	0x12, 1494,
+	0x13, 1537,
+	0x14, 1555,
+	0x15, 1573,
+	0x16, 1591,
+	0x17, 1626,
+	0x18, 1644,
+	0x1F, 1669,
+	0x20, 1690,
+	0x21, 1705,
+	0x22, 1720,
+	0x23, 1735,
+	0x24, 1750,
+	0x26, 1765,
+	0x28, 1780,
+	0x29, 1798,
+	0x2A, 1816,
+	0x2B, 1903,
+	0x2C, 1937,
+	0x2D, 2024,
+	0x2E, 2111,
+	0x2F, 2129,
+	0x30, 2147,
+	0x31, 2150,
+	0x32, 2153,
+	0x33, 2156,
+	0x34, 2159,
+	0x35, 2162,
+	0x38, 2172,
+	0x3A, 3073,
+	0x40, 3484,
+	0x41, 3513,
+	0x42, 3542,
+	0x43, 3571,
+	0x44, 3600,
+	0x45, 3629,
+	0x46, 3658,
+	0x47, 3687,
+	0x48, 3716,
+	0x49, 3745,
+	0x4A, 3774,
+	0x4B, 3803,
+	0x4C, 3832,
+	0x4D, 3861,
+	0x4E, 3890,
+	0x4F, 3919,
+	0x50, 3948,
+	0x51, 3966,
+	0x52, 4000,
+	0x53, 4018,
+	0x54, 4036,
+	0x55, 4054,
+	0x56, 4072,
+	0x57, 4090,
+	0x58, 4108,
+	0x59, 4142,
+	0x5A, 4176,
+	0x5B, 4210,
+	0x5C, 4236,
+	0x5D, 4270,
+	0x5E, 4304,
+	0x5F, 4338,
+	0x60, 4372,
+	0x61, 4390,
+	0x62, 4408,
+	0x63, 4426,
+	0x64, 4444,
+	0x65, 4462,
+	0x66, 4480,
+	0x67, 4498,
+	0x68, 4516,
+	0x69, 4534,
+	0x6A, 4552,
+	0x6B, 4570,
+	0x6C, 4588,
+	0x6D, 4598,
+	0x6E, 4608,
+	0x6F, 4675,
+	0x70, 4701,
+	0x71, 4743,
+	0x72, 4806,
+	0x73, 4869,
+	0x74, 4934,
+	0x75, 4952,
+	0x76, 4970,
+	0x77, 4988,
+	0x7C, 4991,
+	0x7D, 5009,
+	0x7E, 5027,
+	0x7F, 5104,
+	0x80, 5130,
+	0x81, 5161,
+	0x82, 5192,
+	0x83, 5223,
+	0x84, 5254,
+	0x85, 5285,
+	0x86, 5316,
+	0x87, 5347,
+	0x88, 5378,
+	0x89, 5409,
+	0x8A, 5440,
+	0x8B, 5471,
+	0x8C, 5502,
+	0x8D, 5533,
+	0x8E, 5564,
+	0x8F, 5595,
+	0x90, 5626,
+	0x91, 5631,
+	0x92, 5636,
+	0x93, 5641,
+	0x94, 5646,
+	0x95, 5651,
+	0x96, 5656,
+	0x97, 5661,
+	0x98, 5666,
+	0x99, 5671,
+	0x9A, 5676,
+	0x9B, 5681,
+	0x9C, 5686,
+	0x9D, 5691,
+	0x9E, 5696,
+	0x9F, 5701,
+	0xA0, 5706,
+	0xA1, 5710,
+	0xA2, 5737,
+	0xA3, 5740,
+	0xA4, 5769,
+	0xA5, 5804,
+	0xA8, 5836,
+	0xA9, 5840,
+	0xAA, 5867,
+	0xAB, 5870,
+	0xAC, 5899,
+	0xAD, 5934,
+	0xAE, 5966,
+	0xAF, 6224,
+	0xB0, 6253,
+	0xB1, 6259,
+	0xB2, 6288,
+	0xB3, 6317,
+	0xB4, 6346,
+	0xB5, 6375,
+	0xB6, 6404,
+	0xB7, 6433,
+	0xB8, 6462,
+	0xB9, 6499,
+	0xBA, 6502,
+	0xBB, 6627,
+	0xBC, 6656,
+	0xBD, 6723,
+	0xBE, 6790,
+	0xBF, 6819,
+	0xC0, 6848,
+	0xC1, 6854,
+	0xC2, 6883,
+	0xC3, 6925,
+	0xC4, 6954,
+	0xC5, 6976,
+	0xC6, 6998,
+	0xC7, 7020,
+	0xc8, 7149,
+	0xc9, 7149,
+	0xca, 7149,
+	0xcb, 7149,
+	0xcc, 7149,
+	0xcd, 7149,
+	0xce, 7149,
+	0xcf, 7149,
+	0xD0, 7172,
+	0xD1, 7190,
+	0xD2, 7208,
+	0xD3, 7226,
+	0xD4, 7244,
+	0xD5, 7262,
+	0xD6, 7280,
+	0xD7, 7306,
+	0xD8, 7324,
+	0xD9, 7342,
+	0xDA, 7360,
+	0xDB, 7378,
+	0xDC, 7396,
+	0xDD, 7414,
+	0xDE, 7432,
+	0xDF, 7450,
+	0xE0, 7468,
+	0xE1, 7486,
+	0xE2, 7504,
+	0xE3, 7522,
+	0xE4, 7540,
+	0xE5, 7558,
+	0xE6, 7576,
+	0xE7, 7602,
+	0xE8, 7620,
+	0xE9, 7638,
+	0xEA, 7656,
+	0xEB, 7674,
+	0xEC, 7692,
+	0xED, 7710,
+	0xEE, 7728,
+	0xEF, 7746,
+	0xF0, 7764,
+	0xF1, 7774,
+	0xF2, 7792,
+	0xF3, 7810,
+	0xF4, 7828,
+	0xF5, 7846,
+	0xF6, 7864,
+	0xF7, 7882,
+	0xF8, 7900,
+	0xF9, 7918,
+	0xFA, 7936,
+	0xFB, 7954,
+	0xFC, 7972,
+	0xFD, 7990,
+	0xFE, 8008,
+	uint16(x86_xFail),
+	/*1180*/ uint16(x86_xCondSlashR),
+	1189, // 0
+	1205, // 1
+	1221, // 2
+	1225, // 3
+	1229, // 4
+	1233, // 5
+	0,    // 6
+	0,    // 7
+	/*1189*/ uint16(x86_xCondDataSize), 1193, 1197, 1201,
+	/*1193*/ uint16(x86_xSetOp), uint16(x86_SLDT),
+	/*1195*/ uint16(x86_xArgRM16),
+	/*1196*/ uint16(x86_xMatch),
+	/*1197*/ uint16(x86_xSetOp), uint16(x86_SLDT),
+	/*1199*/ uint16(x86_xArgR32M16),
+	/*1200*/ uint16(x86_xMatch),
+	/*1201*/ uint16(x86_xSetOp), uint16(x86_SLDT),
+	/*1203*/ uint16(x86_xArgR64M16),
+	/*1204*/ uint16(x86_xMatch),
+	/*1205*/ uint16(x86_xCondDataSize), 1209, 1213, 1217,
+	/*1209*/ uint16(x86_xSetOp), uint16(x86_STR),
+	/*1211*/ uint16(x86_xArgRM16),
+	/*1212*/ uint16(x86_xMatch),
+	/*1213*/ uint16(x86_xSetOp), uint16(x86_STR),
+	/*1215*/ uint16(x86_xArgR32M16),
+	/*1216*/ uint16(x86_xMatch),
+	/*1217*/ uint16(x86_xSetOp), uint16(x86_STR),
+	/*1219*/ uint16(x86_xArgR64M16),
+	/*1220*/ uint16(x86_xMatch),
+	/*1221*/ uint16(x86_xSetOp), uint16(x86_LLDT),
+	/*1223*/ uint16(x86_xArgRM16),
+	/*1224*/ uint16(x86_xMatch),
+	/*1225*/ uint16(x86_xSetOp), uint16(x86_LTR),
+	/*1227*/ uint16(x86_xArgRM16),
+	/*1228*/ uint16(x86_xMatch),
+	/*1229*/ uint16(x86_xSetOp), uint16(x86_VERR),
+	/*1231*/ uint16(x86_xArgRM16),
+	/*1232*/ uint16(x86_xMatch),
+	/*1233*/ uint16(x86_xSetOp), uint16(x86_VERW),
+	/*1235*/ uint16(x86_xArgRM16),
+	/*1236*/ uint16(x86_xMatch),
+	/*1237*/ uint16(x86_xCondByte), 8,
+	0xC8, 1318,
+	0xC9, 1321,
+	0xD0, 1324,
+	0xD1, 1327,
+	0xD5, 1330,
+	0xD6, 1333,
+	0xF8, 1336,
+	0xF9, 1342,
+	/*1255*/ uint16(x86_xCondSlashR),
+	1264, // 0
+	1268, // 1
+	1272, // 2
+	1283, // 3
+	1294, // 4
+	0,    // 5
+	1310, // 6
+	1314, // 7
+	/*1264*/ uint16(x86_xSetOp), uint16(x86_SGDT),
+	/*1266*/ uint16(x86_xArgM),
+	/*1267*/ uint16(x86_xMatch),
+	/*1268*/ uint16(x86_xSetOp), uint16(x86_SIDT),
+	/*1270*/ uint16(x86_xArgM),
+	/*1271*/ uint16(x86_xMatch),
+	/*1272*/ uint16(x86_xCondIs64), 1275, 1279,
+	/*1275*/ uint16(x86_xSetOp), uint16(x86_LGDT),
+	/*1277*/ uint16(x86_xArgM16and32),
+	/*1278*/ uint16(x86_xMatch),
+	/*1279*/ uint16(x86_xSetOp), uint16(x86_LGDT),
+	/*1281*/ uint16(x86_xArgM16and64),
+	/*1282*/ uint16(x86_xMatch),
+	/*1283*/ uint16(x86_xCondIs64), 1286, 1290,
+	/*1286*/ uint16(x86_xSetOp), uint16(x86_LIDT),
+	/*1288*/ uint16(x86_xArgM16and32),
+	/*1289*/ uint16(x86_xMatch),
+	/*1290*/ uint16(x86_xSetOp), uint16(x86_LIDT),
+	/*1292*/ uint16(x86_xArgM16and64),
+	/*1293*/ uint16(x86_xMatch),
+	/*1294*/ uint16(x86_xCondDataSize), 1298, 1302, 1306,
+	/*1298*/ uint16(x86_xSetOp), uint16(x86_SMSW),
+	/*1300*/ uint16(x86_xArgRM16),
+	/*1301*/ uint16(x86_xMatch),
+	/*1302*/ uint16(x86_xSetOp), uint16(x86_SMSW),
+	/*1304*/ uint16(x86_xArgR32M16),
+	/*1305*/ uint16(x86_xMatch),
+	/*1306*/ uint16(x86_xSetOp), uint16(x86_SMSW),
+	/*1308*/ uint16(x86_xArgR64M16),
+	/*1309*/ uint16(x86_xMatch),
+	/*1310*/ uint16(x86_xSetOp), uint16(x86_LMSW),
+	/*1312*/ uint16(x86_xArgRM16),
+	/*1313*/ uint16(x86_xMatch),
+	/*1314*/ uint16(x86_xSetOp), uint16(x86_INVLPG),
+	/*1316*/ uint16(x86_xArgM),
+	/*1317*/ uint16(x86_xMatch),
+	/*1318*/ uint16(x86_xSetOp), uint16(x86_MONITOR),
+	/*1320*/ uint16(x86_xMatch),
+	/*1321*/ uint16(x86_xSetOp), uint16(x86_MWAIT),
+	/*1323*/ uint16(x86_xMatch),
+	/*1324*/ uint16(x86_xSetOp), uint16(x86_XGETBV),
+	/*1326*/ uint16(x86_xMatch),
+	/*1327*/ uint16(x86_xSetOp), uint16(x86_XSETBV),
+	/*1329*/ uint16(x86_xMatch),
+	/*1330*/ uint16(x86_xSetOp), uint16(x86_XEND),
+	/*1332*/ uint16(x86_xMatch),
+	/*1333*/ uint16(x86_xSetOp), uint16(x86_XTEST),
+	/*1335*/ uint16(x86_xMatch),
+	/*1336*/ uint16(x86_xCondIs64), 0, 1339,
+	/*1339*/ uint16(x86_xSetOp), uint16(x86_SWAPGS),
+	/*1341*/ uint16(x86_xMatch),
+	/*1342*/ uint16(x86_xSetOp), uint16(x86_RDTSCP),
+	/*1344*/ uint16(x86_xMatch),
+	/*1345*/ uint16(x86_xCondDataSize), 1349, 1355, 1361,
+	/*1349*/ uint16(x86_xSetOp), uint16(x86_LAR),
+	/*1351*/ uint16(x86_xReadSlashR),
+	/*1352*/ uint16(x86_xArgR16),
+	/*1353*/ uint16(x86_xArgRM16),
+	/*1354*/ uint16(x86_xMatch),
+	/*1355*/ uint16(x86_xSetOp), uint16(x86_LAR),
+	/*1357*/ uint16(x86_xReadSlashR),
+	/*1358*/ uint16(x86_xArgR32),
+	/*1359*/ uint16(x86_xArgR32M16),
+	/*1360*/ uint16(x86_xMatch),
+	/*1361*/ uint16(x86_xSetOp), uint16(x86_LAR),
+	/*1363*/ uint16(x86_xReadSlashR),
+	/*1364*/ uint16(x86_xArgR64),
+	/*1365*/ uint16(x86_xArgR64M16),
+	/*1366*/ uint16(x86_xMatch),
+	/*1367*/ uint16(x86_xCondDataSize), 1371, 1377, 1383,
+	/*1371*/ uint16(x86_xSetOp), uint16(x86_LSL),
+	/*1373*/ uint16(x86_xReadSlashR),
+	/*1374*/ uint16(x86_xArgR16),
+	/*1375*/ uint16(x86_xArgRM16),
+	/*1376*/ uint16(x86_xMatch),
+	/*1377*/ uint16(x86_xSetOp), uint16(x86_LSL),
+	/*1379*/ uint16(x86_xReadSlashR),
+	/*1380*/ uint16(x86_xArgR32),
+	/*1381*/ uint16(x86_xArgR32M16),
+	/*1382*/ uint16(x86_xMatch),
+	/*1383*/ uint16(x86_xSetOp), uint16(x86_LSL),
+	/*1385*/ uint16(x86_xReadSlashR),
+	/*1386*/ uint16(x86_xArgR64),
+	/*1387*/ uint16(x86_xArgR32M16),
+	/*1388*/ uint16(x86_xMatch),
+	/*1389*/ uint16(x86_xCondIs64), 0, 1392,
+	/*1392*/ uint16(x86_xSetOp), uint16(x86_SYSCALL),
+	/*1394*/ uint16(x86_xMatch),
+	/*1395*/ uint16(x86_xSetOp), uint16(x86_CLTS),
+	/*1397*/ uint16(x86_xMatch),
+	/*1398*/ uint16(x86_xCondIs64), 0, 1401,
+	/*1401*/ uint16(x86_xSetOp), uint16(x86_SYSRET),
+	/*1403*/ uint16(x86_xMatch),
+	/*1404*/ uint16(x86_xSetOp), uint16(x86_INVD),
+	/*1406*/ uint16(x86_xMatch),
+	/*1407*/ uint16(x86_xSetOp), uint16(x86_WBINVD),
+	/*1409*/ uint16(x86_xMatch),
+	/*1410*/ uint16(x86_xSetOp), uint16(x86_UD2),
+	/*1412*/ uint16(x86_xMatch),
+	/*1413*/ uint16(x86_xCondSlashR),
+	0,    // 0
+	1422, // 1
+	0,    // 2
+	0,    // 3
+	0,    // 4
+	0,    // 5
+	0,    // 6
+	0,    // 7
+	/*1422*/ uint16(x86_xSetOp), uint16(x86_PREFETCHW),
+	/*1424*/ uint16(x86_xArgM8),
+	/*1425*/ uint16(x86_xMatch),
+	/*1426*/ uint16(x86_xCondPrefix), 4,
+	0xF3, 1454,
+	0xF2, 1448,
+	0x66, 1442,
+	0x0, 1436,
+	/*1436*/ uint16(x86_xSetOp), uint16(x86_MOVUPS),
+	/*1438*/ uint16(x86_xReadSlashR),
+	/*1439*/ uint16(x86_xArgXmm1),
+	/*1440*/ uint16(x86_xArgXmm2M128),
+	/*1441*/ uint16(x86_xMatch),
+	/*1442*/ uint16(x86_xSetOp), uint16(x86_MOVUPD),
+	/*1444*/ uint16(x86_xReadSlashR),
+	/*1445*/ uint16(x86_xArgXmm1),
+	/*1446*/ uint16(x86_xArgXmm2M128),
+	/*1447*/ uint16(x86_xMatch),
+	/*1448*/ uint16(x86_xSetOp), uint16(x86_MOVSD_XMM),
+	/*1450*/ uint16(x86_xReadSlashR),
+	/*1451*/ uint16(x86_xArgXmm1),
+	/*1452*/ uint16(x86_xArgXmm2M64),
+	/*1453*/ uint16(x86_xMatch),
+	/*1454*/ uint16(x86_xSetOp), uint16(x86_MOVSS),
+	/*1456*/ uint16(x86_xReadSlashR),
+	/*1457*/ uint16(x86_xArgXmm1),
+	/*1458*/ uint16(x86_xArgXmm2M32),
+	/*1459*/ uint16(x86_xMatch),
+	/*1460*/ uint16(x86_xCondPrefix), 4,
+	0xF3, 1488,
+	0xF2, 1482,
+	0x66, 1476,
+	0x0, 1470,
+	/*1470*/ uint16(x86_xSetOp), uint16(x86_MOVUPS),
+	/*1472*/ uint16(x86_xReadSlashR),
+	/*1473*/ uint16(x86_xArgXmm2M128),
+	/*1474*/ uint16(x86_xArgXmm1),
+	/*1475*/ uint16(x86_xMatch),
+	/*1476*/ uint16(x86_xSetOp), uint16(x86_MOVUPD),
+	/*1478*/ uint16(x86_xReadSlashR),
+	/*1479*/ uint16(x86_xArgXmm2M128),
+	/*1480*/ uint16(x86_xArgXmm),
+	/*1481*/ uint16(x86_xMatch),
+	/*1482*/ uint16(x86_xSetOp), uint16(x86_MOVSD_XMM),
+	/*1484*/ uint16(x86_xReadSlashR),
+	/*1485*/ uint16(x86_xArgXmm2M64),
+	/*1486*/ uint16(x86_xArgXmm1),
+	/*1487*/ uint16(x86_xMatch),
+	/*1488*/ uint16(x86_xSetOp), uint16(x86_MOVSS),
+	/*1490*/ uint16(x86_xReadSlashR),
+	/*1491*/ uint16(x86_xArgXmm2M32),
+	/*1492*/ uint16(x86_xArgXmm),
+	/*1493*/ uint16(x86_xMatch),
+	/*1494*/ uint16(x86_xCondPrefix), 4,
+	0xF3, 1531,
+	0xF2, 1525,
+	0x66, 1519,
+	0x0, 1504,
+	/*1504*/ uint16(x86_xCondIsMem), 1507, 1513,
+	/*1507*/ uint16(x86_xSetOp), uint16(x86_MOVHLPS),
+	/*1509*/ uint16(x86_xReadSlashR),
+	/*1510*/ uint16(x86_xArgXmm1),
+	/*1511*/ uint16(x86_xArgXmm2),
+	/*1512*/ uint16(x86_xMatch),
+	/*1513*/ uint16(x86_xSetOp), uint16(x86_MOVLPS),
+	/*1515*/ uint16(x86_xReadSlashR),
+	/*1516*/ uint16(x86_xArgXmm),
+	/*1517*/ uint16(x86_xArgM64),
+	/*1518*/ uint16(x86_xMatch),
+	/*1519*/ uint16(x86_xSetOp), uint16(x86_MOVLPD),
+	/*1521*/ uint16(x86_xReadSlashR),
+	/*1522*/ uint16(x86_xArgXmm),
+	/*1523*/ uint16(x86_xArgXmm2M64),
+	/*1524*/ uint16(x86_xMatch),
+	/*1525*/ uint16(x86_xSetOp), uint16(x86_MOVDDUP),
+	/*1527*/ uint16(x86_xReadSlashR),
+	/*1528*/ uint16(x86_xArgXmm1),
+	/*1529*/ uint16(x86_xArgXmm2M64),
+	/*1530*/ uint16(x86_xMatch),
+	/*1531*/ uint16(x86_xSetOp), uint16(x86_MOVSLDUP),
+	/*1533*/ uint16(x86_xReadSlashR),
+	/*1534*/ uint16(x86_xArgXmm1),
+	/*1535*/ uint16(x86_xArgXmm2M128),
+	/*1536*/ uint16(x86_xMatch),
+	/*1537*/ uint16(x86_xCondPrefix), 2,
+	0x66, 1549,
+	0x0, 1543,
+	/*1543*/ uint16(x86_xSetOp), uint16(x86_MOVLPS),
+	/*1545*/ uint16(x86_xReadSlashR),
+	/*1546*/ uint16(x86_xArgM64),
+	/*1547*/ uint16(x86_xArgXmm),
+	/*1548*/ uint16(x86_xMatch),
+	/*1549*/ uint16(x86_xSetOp), uint16(x86_MOVLPD),
+	/*1551*/ uint16(x86_xReadSlashR),
+	/*1552*/ uint16(x86_xArgXmm2M64),
+	/*1553*/ uint16(x86_xArgXmm),
+	/*1554*/ uint16(x86_xMatch),
+	/*1555*/ uint16(x86_xCondPrefix), 2,
+	0x66, 1567,
+	0x0, 1561,
+	/*1561*/ uint16(x86_xSetOp), uint16(x86_UNPCKLPS),
+	/*1563*/ uint16(x86_xReadSlashR),
+	/*1564*/ uint16(x86_xArgXmm1),
+	/*1565*/ uint16(x86_xArgXmm2M128),
+	/*1566*/ uint16(x86_xMatch),
+	/*1567*/ uint16(x86_xSetOp), uint16(x86_UNPCKLPD),
+	/*1569*/ uint16(x86_xReadSlashR),
+	/*1570*/ uint16(x86_xArgXmm1),
+	/*1571*/ uint16(x86_xArgXmm2M128),
+	/*1572*/ uint16(x86_xMatch),
+	/*1573*/ uint16(x86_xCondPrefix), 2,
+	0x66, 1585,
+	0x0, 1579,
+	/*1579*/ uint16(x86_xSetOp), uint16(x86_UNPCKHPS),
+	/*1581*/ uint16(x86_xReadSlashR),
+	/*1582*/ uint16(x86_xArgXmm1),
+	/*1583*/ uint16(x86_xArgXmm2M128),
+	/*1584*/ uint16(x86_xMatch),
+	/*1585*/ uint16(x86_xSetOp), uint16(x86_UNPCKHPD),
+	/*1587*/ uint16(x86_xReadSlashR),
+	/*1588*/ uint16(x86_xArgXmm1),
+	/*1589*/ uint16(x86_xArgXmm2M128),
+	/*1590*/ uint16(x86_xMatch),
+	/*1591*/ uint16(x86_xCondPrefix), 3,
+	0xF3, 1620,
+	0x66, 1614,
+	0x0, 1599,
+	/*1599*/ uint16(x86_xCondIsMem), 1602, 1608,
+	/*1602*/ uint16(x86_xSetOp), uint16(x86_MOVLHPS),
+	/*1604*/ uint16(x86_xReadSlashR),
+	/*1605*/ uint16(x86_xArgXmm1),
+	/*1606*/ uint16(x86_xArgXmm2),
+	/*1607*/ uint16(x86_xMatch),
+	/*1608*/ uint16(x86_xSetOp), uint16(x86_MOVHPS),
+	/*1610*/ uint16(x86_xReadSlashR),
+	/*1611*/ uint16(x86_xArgXmm),
+	/*1612*/ uint16(x86_xArgM64),
+	/*1613*/ uint16(x86_xMatch),
+	/*1614*/ uint16(x86_xSetOp), uint16(x86_MOVHPD),
+	/*1616*/ uint16(x86_xReadSlashR),
+	/*1617*/ uint16(x86_xArgXmm),
+	/*1618*/ uint16(x86_xArgXmm2M64),
+	/*1619*/ uint16(x86_xMatch),
+	/*1620*/ uint16(x86_xSetOp), uint16(x86_MOVSHDUP),
+	/*1622*/ uint16(x86_xReadSlashR),
+	/*1623*/ uint16(x86_xArgXmm1),
+	/*1624*/ uint16(x86_xArgXmm2M128),
+	/*1625*/ uint16(x86_xMatch),
+	/*1626*/ uint16(x86_xCondPrefix), 2,
+	0x66, 1638,
+	0x0, 1632,
+	/*1632*/ uint16(x86_xSetOp), uint16(x86_MOVHPS),
+	/*1634*/ uint16(x86_xReadSlashR),
+	/*1635*/ uint16(x86_xArgM64),
+	/*1636*/ uint16(x86_xArgXmm),
+	/*1637*/ uint16(x86_xMatch),
+	/*1638*/ uint16(x86_xSetOp), uint16(x86_MOVHPD),
+	/*1640*/ uint16(x86_xReadSlashR),
+	/*1641*/ uint16(x86_xArgXmm2M64),
+	/*1642*/ uint16(x86_xArgXmm),
+	/*1643*/ uint16(x86_xMatch),
+	/*1644*/ uint16(x86_xCondSlashR),
+	1653, // 0
+	1657, // 1
+	1661, // 2
+	1665, // 3
+	0,    // 4
+	0,    // 5
+	0,    // 6
+	0,    // 7
+	/*1653*/ uint16(x86_xSetOp), uint16(x86_PREFETCHNTA),
+	/*1655*/ uint16(x86_xArgM8),
+	/*1656*/ uint16(x86_xMatch),
+	/*1657*/ uint16(x86_xSetOp), uint16(x86_PREFETCHT0),
+	/*1659*/ uint16(x86_xArgM8),
+	/*1660*/ uint16(x86_xMatch),
+	/*1661*/ uint16(x86_xSetOp), uint16(x86_PREFETCHT1),
+	/*1663*/ uint16(x86_xArgM8),
+	/*1664*/ uint16(x86_xMatch),
+	/*1665*/ uint16(x86_xSetOp), uint16(x86_PREFETCHT2),
+	/*1667*/ uint16(x86_xArgM8),
+	/*1668*/ uint16(x86_xMatch),
+	/*1669*/ uint16(x86_xCondSlashR),
+	1678, // 0
+	0,    // 1
+	0,    // 2
+	0,    // 3
+	0,    // 4
+	0,    // 5
+	0,    // 6
+	0,    // 7
+	/*1678*/ uint16(x86_xCondDataSize), 1682, 1686, 0,
+	/*1682*/ uint16(x86_xSetOp), uint16(x86_NOP),
+	/*1684*/ uint16(x86_xArgRM16),
+	/*1685*/ uint16(x86_xMatch),
+	/*1686*/ uint16(x86_xSetOp), uint16(x86_NOP),
+	/*1688*/ uint16(x86_xArgRM32),
+	/*1689*/ uint16(x86_xMatch),
+	/*1690*/ uint16(x86_xCondIs64), 1693, 1699,
+	/*1693*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*1695*/ uint16(x86_xReadSlashR),
+	/*1696*/ uint16(x86_xArgRmf32),
+	/*1697*/ uint16(x86_xArgCR0dashCR7),
+	/*1698*/ uint16(x86_xMatch),
+	/*1699*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*1701*/ uint16(x86_xReadSlashR),
+	/*1702*/ uint16(x86_xArgRmf64),
+	/*1703*/ uint16(x86_xArgCR0dashCR7),
+	/*1704*/ uint16(x86_xMatch),
+	/*1705*/ uint16(x86_xCondIs64), 1708, 1714,
+	/*1708*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*1710*/ uint16(x86_xReadSlashR),
+	/*1711*/ uint16(x86_xArgRmf32),
+	/*1712*/ uint16(x86_xArgDR0dashDR7),
+	/*1713*/ uint16(x86_xMatch),
+	/*1714*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*1716*/ uint16(x86_xReadSlashR),
+	/*1717*/ uint16(x86_xArgRmf64),
+	/*1718*/ uint16(x86_xArgDR0dashDR7),
+	/*1719*/ uint16(x86_xMatch),
+	/*1720*/ uint16(x86_xCondIs64), 1723, 1729,
+	/*1723*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*1725*/ uint16(x86_xReadSlashR),
+	/*1726*/ uint16(x86_xArgCR0dashCR7),
+	/*1727*/ uint16(x86_xArgRmf32),
+	/*1728*/ uint16(x86_xMatch),
+	/*1729*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*1731*/ uint16(x86_xReadSlashR),
+	/*1732*/ uint16(x86_xArgCR0dashCR7),
+	/*1733*/ uint16(x86_xArgRmf64),
+	/*1734*/ uint16(x86_xMatch),
+	/*1735*/ uint16(x86_xCondIs64), 1738, 1744,
+	/*1738*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*1740*/ uint16(x86_xReadSlashR),
+	/*1741*/ uint16(x86_xArgDR0dashDR7),
+	/*1742*/ uint16(x86_xArgRmf32),
+	/*1743*/ uint16(x86_xMatch),
+	/*1744*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*1746*/ uint16(x86_xReadSlashR),
+	/*1747*/ uint16(x86_xArgDR0dashDR7),
+	/*1748*/ uint16(x86_xArgRmf64),
+	/*1749*/ uint16(x86_xMatch),
+	/*1750*/ uint16(x86_xCondIs64), 1753, 1759,
+	/*1753*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*1755*/ uint16(x86_xReadSlashR),
+	/*1756*/ uint16(x86_xArgRmf32),
+	/*1757*/ uint16(x86_xArgTR0dashTR7),
+	/*1758*/ uint16(x86_xMatch),
+	/*1759*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*1761*/ uint16(x86_xReadSlashR),
+	/*1762*/ uint16(x86_xArgRmf64),
+	/*1763*/ uint16(x86_xArgTR0dashTR7),
+	/*1764*/ uint16(x86_xMatch),
+	/*1765*/ uint16(x86_xCondIs64), 1768, 1774,
+	/*1768*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*1770*/ uint16(x86_xReadSlashR),
+	/*1771*/ uint16(x86_xArgTR0dashTR7),
+	/*1772*/ uint16(x86_xArgRmf32),
+	/*1773*/ uint16(x86_xMatch),
+	/*1774*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*1776*/ uint16(x86_xReadSlashR),
+	/*1777*/ uint16(x86_xArgTR0dashTR7),
+	/*1778*/ uint16(x86_xArgRmf64),
+	/*1779*/ uint16(x86_xMatch),
+	/*1780*/ uint16(x86_xCondPrefix), 2,
+	0x66, 1792,
+	0x0, 1786,
+	/*1786*/ uint16(x86_xSetOp), uint16(x86_MOVAPS),
+	/*1788*/ uint16(x86_xReadSlashR),
+	/*1789*/ uint16(x86_xArgXmm1),
+	/*1790*/ uint16(x86_xArgXmm2M128),
+	/*1791*/ uint16(x86_xMatch),
+	/*1792*/ uint16(x86_xSetOp), uint16(x86_MOVAPD),
+	/*1794*/ uint16(x86_xReadSlashR),
+	/*1795*/ uint16(x86_xArgXmm1),
+	/*1796*/ uint16(x86_xArgXmm2M128),
+	/*1797*/ uint16(x86_xMatch),
+	/*1798*/ uint16(x86_xCondPrefix), 2,
+	0x66, 1810,
+	0x0, 1804,
+	/*1804*/ uint16(x86_xSetOp), uint16(x86_MOVAPS),
+	/*1806*/ uint16(x86_xReadSlashR),
+	/*1807*/ uint16(x86_xArgXmm2M128),
+	/*1808*/ uint16(x86_xArgXmm1),
+	/*1809*/ uint16(x86_xMatch),
+	/*1810*/ uint16(x86_xSetOp), uint16(x86_MOVAPD),
+	/*1812*/ uint16(x86_xReadSlashR),
+	/*1813*/ uint16(x86_xArgXmm2M128),
+	/*1814*/ uint16(x86_xArgXmm1),
+	/*1815*/ uint16(x86_xMatch),
+	/*1816*/ uint16(x86_xCondIs64), 1819, 1873,
+	/*1819*/ uint16(x86_xCondPrefix), 4,
+	0xF3, 1857,
+	0xF2, 1841,
+	0x66, 1835,
+	0x0, 1829,
+	/*1829*/ uint16(x86_xSetOp), uint16(x86_CVTPI2PS),
+	/*1831*/ uint16(x86_xReadSlashR),
+	/*1832*/ uint16(x86_xArgXmm),
+	/*1833*/ uint16(x86_xArgMmM64),
+	/*1834*/ uint16(x86_xMatch),
+	/*1835*/ uint16(x86_xSetOp), uint16(x86_CVTPI2PD),
+	/*1837*/ uint16(x86_xReadSlashR),
+	/*1838*/ uint16(x86_xArgXmm),
+	/*1839*/ uint16(x86_xArgMmM64),
+	/*1840*/ uint16(x86_xMatch),
+	/*1841*/ uint16(x86_xCondDataSize), 1845, 1851, 0,
+	/*1845*/ uint16(x86_xSetOp), uint16(x86_CVTSI2SD),
+	/*1847*/ uint16(x86_xReadSlashR),
+	/*1848*/ uint16(x86_xArgXmm),
+	/*1849*/ uint16(x86_xArgRM32),
+	/*1850*/ uint16(x86_xMatch),
+	/*1851*/ uint16(x86_xSetOp), uint16(x86_CVTSI2SD),
+	/*1853*/ uint16(x86_xReadSlashR),
+	/*1854*/ uint16(x86_xArgXmm),
+	/*1855*/ uint16(x86_xArgRM32),
+	/*1856*/ uint16(x86_xMatch),
+	/*1857*/ uint16(x86_xCondDataSize), 1861, 1867, 0,
+	/*1861*/ uint16(x86_xSetOp), uint16(x86_CVTSI2SS),
+	/*1863*/ uint16(x86_xReadSlashR),
+	/*1864*/ uint16(x86_xArgXmm),
+	/*1865*/ uint16(x86_xArgRM32),
+	/*1866*/ uint16(x86_xMatch),
+	/*1867*/ uint16(x86_xSetOp), uint16(x86_CVTSI2SS),
+	/*1869*/ uint16(x86_xReadSlashR),
+	/*1870*/ uint16(x86_xArgXmm),
+	/*1871*/ uint16(x86_xArgRM32),
+	/*1872*/ uint16(x86_xMatch),
+	/*1873*/ uint16(x86_xCondPrefix), 4,
+	0xF3, 1893,
+	0xF2, 1883,
+	0x66, 1835,
+	0x0, 1829,
+	/*1883*/ uint16(x86_xCondDataSize), 1845, 1851, 1887,
+	/*1887*/ uint16(x86_xSetOp), uint16(x86_CVTSI2SD),
+	/*1889*/ uint16(x86_xReadSlashR),
+	/*1890*/ uint16(x86_xArgXmm),
+	/*1891*/ uint16(x86_xArgRM64),
+	/*1892*/ uint16(x86_xMatch),
+	/*1893*/ uint16(x86_xCondDataSize), 1861, 1867, 1897,
+	/*1897*/ uint16(x86_xSetOp), uint16(x86_CVTSI2SS),
+	/*1899*/ uint16(x86_xReadSlashR),
+	/*1900*/ uint16(x86_xArgXmm),
+	/*1901*/ uint16(x86_xArgRM64),
+	/*1902*/ uint16(x86_xMatch),
+	/*1903*/ uint16(x86_xCondPrefix), 4,
+	0xF3, 1931,
+	0xF2, 1925,
+	0x66, 1919,
+	0x0, 1913,
+	/*1913*/ uint16(x86_xSetOp), uint16(x86_MOVNTPS),
+	/*1915*/ uint16(x86_xReadSlashR),
+	/*1916*/ uint16(x86_xArgM128),
+	/*1917*/ uint16(x86_xArgXmm),
+	/*1918*/ uint16(x86_xMatch),
+	/*1919*/ uint16(x86_xSetOp), uint16(x86_MOVNTPD),
+	/*1921*/ uint16(x86_xReadSlashR),
+	/*1922*/ uint16(x86_xArgM128),
+	/*1923*/ uint16(x86_xArgXmm),
+	/*1924*/ uint16(x86_xMatch),
+	/*1925*/ uint16(x86_xSetOp), uint16(x86_MOVNTSD),
+	/*1927*/ uint16(x86_xReadSlashR),
+	/*1928*/ uint16(x86_xArgM64),
+	/*1929*/ uint16(x86_xArgXmm),
+	/*1930*/ uint16(x86_xMatch),
+	/*1931*/ uint16(x86_xSetOp), uint16(x86_MOVNTSS),
+	/*1933*/ uint16(x86_xReadSlashR),
+	/*1934*/ uint16(x86_xArgM32),
+	/*1935*/ uint16(x86_xArgXmm),
+	/*1936*/ uint16(x86_xMatch),
+	/*1937*/ uint16(x86_xCondIs64), 1940, 1994,
+	/*1940*/ uint16(x86_xCondPrefix), 4,
+	0xF3, 1978,
+	0xF2, 1962,
+	0x66, 1956,
+	0x0, 1950,
+	/*1950*/ uint16(x86_xSetOp), uint16(x86_CVTTPS2PI),
+	/*1952*/ uint16(x86_xReadSlashR),
+	/*1953*/ uint16(x86_xArgMm),
+	/*1954*/ uint16(x86_xArgXmmM64),
+	/*1955*/ uint16(x86_xMatch),
+	/*1956*/ uint16(x86_xSetOp), uint16(x86_CVTTPD2PI),
+	/*1958*/ uint16(x86_xReadSlashR),
+	/*1959*/ uint16(x86_xArgMm),
+	/*1960*/ uint16(x86_xArgXmmM128),
+	/*1961*/ uint16(x86_xMatch),
+	/*1962*/ uint16(x86_xCondDataSize), 1966, 1972, 0,
+	/*1966*/ uint16(x86_xSetOp), uint16(x86_CVTTSD2SI),
+	/*1968*/ uint16(x86_xReadSlashR),
+	/*1969*/ uint16(x86_xArgR32),
+	/*1970*/ uint16(x86_xArgXmmM64),
+	/*1971*/ uint16(x86_xMatch),
+	/*1972*/ uint16(x86_xSetOp), uint16(x86_CVTTSD2SI),
+	/*1974*/ uint16(x86_xReadSlashR),
+	/*1975*/ uint16(x86_xArgR32),
+	/*1976*/ uint16(x86_xArgXmmM64),
+	/*1977*/ uint16(x86_xMatch),
+	/*1978*/ uint16(x86_xCondDataSize), 1982, 1988, 0,
+	/*1982*/ uint16(x86_xSetOp), uint16(x86_CVTTSS2SI),
+	/*1984*/ uint16(x86_xReadSlashR),
+	/*1985*/ uint16(x86_xArgR32),
+	/*1986*/ uint16(x86_xArgXmmM32),
+	/*1987*/ uint16(x86_xMatch),
+	/*1988*/ uint16(x86_xSetOp), uint16(x86_CVTTSS2SI),
+	/*1990*/ uint16(x86_xReadSlashR),
+	/*1991*/ uint16(x86_xArgR32),
+	/*1992*/ uint16(x86_xArgXmmM32),
+	/*1993*/ uint16(x86_xMatch),
+	/*1994*/ uint16(x86_xCondPrefix), 4,
+	0xF3, 2014,
+	0xF2, 2004,
+	0x66, 1956,
+	0x0, 1950,
+	/*2004*/ uint16(x86_xCondDataSize), 1966, 1972, 2008,
+	/*2008*/ uint16(x86_xSetOp), uint16(x86_CVTTSD2SI),
+	/*2010*/ uint16(x86_xReadSlashR),
+	/*2011*/ uint16(x86_xArgR64),
+	/*2012*/ uint16(x86_xArgXmmM64),
+	/*2013*/ uint16(x86_xMatch),
+	/*2014*/ uint16(x86_xCondDataSize), 1982, 1988, 2018,
+	/*2018*/ uint16(x86_xSetOp), uint16(x86_CVTTSS2SI),
+	/*2020*/ uint16(x86_xReadSlashR),
+	/*2021*/ uint16(x86_xArgR64),
+	/*2022*/ uint16(x86_xArgXmmM32),
+	/*2023*/ uint16(x86_xMatch),
+	/*2024*/ uint16(x86_xCondIs64), 2027, 2081,
+	/*2027*/ uint16(x86_xCondPrefix), 4,
+	0xF3, 2065,
+	0xF2, 2049,
+	0x66, 2043,
+	0x0, 2037,
+	/*2037*/ uint16(x86_xSetOp), uint16(x86_CVTPS2PI),
+	/*2039*/ uint16(x86_xReadSlashR),
+	/*2040*/ uint16(x86_xArgMm),
+	/*2041*/ uint16(x86_xArgXmmM64),
+	/*2042*/ uint16(x86_xMatch),
+	/*2043*/ uint16(x86_xSetOp), uint16(x86_CVTPD2PI),
+	/*2045*/ uint16(x86_xReadSlashR),
+	/*2046*/ uint16(x86_xArgMm),
+	/*2047*/ uint16(x86_xArgXmmM128),
+	/*2048*/ uint16(x86_xMatch),
+	/*2049*/ uint16(x86_xCondDataSize), 2053, 2059, 0,
+	/*2053*/ uint16(x86_xSetOp), uint16(x86_CVTSD2SI),
+	/*2055*/ uint16(x86_xReadSlashR),
+	/*2056*/ uint16(x86_xArgR32),
+	/*2057*/ uint16(x86_xArgXmmM64),
+	/*2058*/ uint16(x86_xMatch),
+	/*2059*/ uint16(x86_xSetOp), uint16(x86_CVTSD2SI),
+	/*2061*/ uint16(x86_xReadSlashR),
+	/*2062*/ uint16(x86_xArgR32),
+	/*2063*/ uint16(x86_xArgXmmM64),
+	/*2064*/ uint16(x86_xMatch),
+	/*2065*/ uint16(x86_xCondDataSize), 2069, 2075, 0,
+	/*2069*/ uint16(x86_xSetOp), uint16(x86_CVTSS2SI),
+	/*2071*/ uint16(x86_xReadSlashR),
+	/*2072*/ uint16(x86_xArgR32),
+	/*2073*/ uint16(x86_xArgXmmM32),
+	/*2074*/ uint16(x86_xMatch),
+	/*2075*/ uint16(x86_xSetOp), uint16(x86_CVTSS2SI),
+	/*2077*/ uint16(x86_xReadSlashR),
+	/*2078*/ uint16(x86_xArgR32),
+	/*2079*/ uint16(x86_xArgXmmM32),
+	/*2080*/ uint16(x86_xMatch),
+	/*2081*/ uint16(x86_xCondPrefix), 4,
+	0xF3, 2101,
+	0xF2, 2091,
+	0x66, 2043,
+	0x0, 2037,
+	/*2091*/ uint16(x86_xCondDataSize), 2053, 2059, 2095,
+	/*2095*/ uint16(x86_xSetOp), uint16(x86_CVTSD2SI),
+	/*2097*/ uint16(x86_xReadSlashR),
+	/*2098*/ uint16(x86_xArgR64),
+	/*2099*/ uint16(x86_xArgXmmM64),
+	/*2100*/ uint16(x86_xMatch),
+	/*2101*/ uint16(x86_xCondDataSize), 2069, 2075, 2105,
+	/*2105*/ uint16(x86_xSetOp), uint16(x86_CVTSS2SI),
+	/*2107*/ uint16(x86_xReadSlashR),
+	/*2108*/ uint16(x86_xArgR64),
+	/*2109*/ uint16(x86_xArgXmmM32),
+	/*2110*/ uint16(x86_xMatch),
+	/*2111*/ uint16(x86_xCondPrefix), 2,
+	0x66, 2123,
+	0x0, 2117,
+	/*2117*/ uint16(x86_xSetOp), uint16(x86_UCOMISS),
+	/*2119*/ uint16(x86_xReadSlashR),
+	/*2120*/ uint16(x86_xArgXmm1),
+	/*2121*/ uint16(x86_xArgXmm2M32),
+	/*2122*/ uint16(x86_xMatch),
+	/*2123*/ uint16(x86_xSetOp), uint16(x86_UCOMISD),
+	/*2125*/ uint16(x86_xReadSlashR),
+	/*2126*/ uint16(x86_xArgXmm1),
+	/*2127*/ uint16(x86_xArgXmm2M64),
+	/*2128*/ uint16(x86_xMatch),
+	/*2129*/ uint16(x86_xCondPrefix), 2,
+	0x66, 2141,
+	0x0, 2135,
+	/*2135*/ uint16(x86_xSetOp), uint16(x86_COMISS),
+	/*2137*/ uint16(x86_xReadSlashR),
+	/*2138*/ uint16(x86_xArgXmm1),
+	/*2139*/ uint16(x86_xArgXmm2M32),
+	/*2140*/ uint16(x86_xMatch),
+	/*2141*/ uint16(x86_xSetOp), uint16(x86_COMISD),
+	/*2143*/ uint16(x86_xReadSlashR),
+	/*2144*/ uint16(x86_xArgXmm1),
+	/*2145*/ uint16(x86_xArgXmm2M64),
+	/*2146*/ uint16(x86_xMatch),
+	/*2147*/ uint16(x86_xSetOp), uint16(x86_WRMSR),
+	/*2149*/ uint16(x86_xMatch),
+	/*2150*/ uint16(x86_xSetOp), uint16(x86_RDTSC),
+	/*2152*/ uint16(x86_xMatch),
+	/*2153*/ uint16(x86_xSetOp), uint16(x86_RDMSR),
+	/*2155*/ uint16(x86_xMatch),
+	/*2156*/ uint16(x86_xSetOp), uint16(x86_RDPMC),
+	/*2158*/ uint16(x86_xMatch),
+	/*2159*/ uint16(x86_xSetOp), uint16(x86_SYSENTER),
+	/*2161*/ uint16(x86_xMatch),
+	/*2162*/ uint16(x86_xCondDataSize), 2166, 2166, 2169,
+	/*2166*/ uint16(x86_xSetOp), uint16(x86_SYSEXIT),
+	/*2168*/ uint16(x86_xMatch),
+	/*2169*/ uint16(x86_xSetOp), uint16(x86_SYSEXIT),
+	/*2171*/ uint16(x86_xMatch),
+	/*2172*/ uint16(x86_xCondByte), 54,
+	0x00, 2283,
+	0x01, 2301,
+	0x02, 2319,
+	0x03, 2337,
+	0x04, 2355,
+	0x05, 2373,
+	0x06, 2391,
+	0x07, 2409,
+	0x08, 2427,
+	0x09, 2445,
+	0x0A, 2463,
+	0x0B, 2481,
+	0x10, 2499,
+	0x14, 2510,
+	0x15, 2521,
+	0x17, 2532,
+	0x1C, 2542,
+	0x1D, 2560,
+	0x1E, 2578,
+	0x20, 2596,
+	0x21, 2606,
+	0x22, 2616,
+	0x23, 2626,
+	0x24, 2636,
+	0x25, 2646,
+	0x28, 2656,
+	0x29, 2666,
+	0x2A, 2676,
+	0x2B, 2686,
+	0x30, 2696,
+	0x31, 2706,
+	0x32, 2716,
+	0x33, 2726,
+	0x34, 2736,
+	0x35, 2746,
+	0x37, 2756,
+	0x38, 2766,
+	0x39, 2776,
+	0x3A, 2786,
+	0x3B, 2796,
+	0x3C, 2806,
+	0x3D, 2816,
+	0x3E, 2826,
+	0x3F, 2836,
+	0x40, 2846,
+	0x41, 2856,
+	0x82, 2866,
+	0xDB, 2889,
+	0xDC, 2899,
+	0xDD, 2909,
+	0xDE, 2919,
+	0xDF, 2929,
+	0xF0, 2939,
+	0xF1, 3006,
+	uint16(x86_xFail),
+	/*2283*/ uint16(x86_xCondPrefix), 2,
+	0x66, 2295,
+	0x0, 2289,
+	/*2289*/ uint16(x86_xSetOp), uint16(x86_PSHUFB),
+	/*2291*/ uint16(x86_xReadSlashR),
+	/*2292*/ uint16(x86_xArgMm1),
+	/*2293*/ uint16(x86_xArgMm2M64),
+	/*2294*/ uint16(x86_xMatch),
+	/*2295*/ uint16(x86_xSetOp), uint16(x86_PSHUFB),
+	/*2297*/ uint16(x86_xReadSlashR),
+	/*2298*/ uint16(x86_xArgXmm1),
+	/*2299*/ uint16(x86_xArgXmm2M128),
+	/*2300*/ uint16(x86_xMatch),
+	/*2301*/ uint16(x86_xCondPrefix), 2,
+	0x66, 2313,
+	0x0, 2307,
+	/*2307*/ uint16(x86_xSetOp), uint16(x86_PHADDW),
+	/*2309*/ uint16(x86_xReadSlashR),
+	/*2310*/ uint16(x86_xArgMm1),
+	/*2311*/ uint16(x86_xArgMm2M64),
+	/*2312*/ uint16(x86_xMatch),
+	/*2313*/ uint16(x86_xSetOp), uint16(x86_PHADDW),
+	/*2315*/ uint16(x86_xReadSlashR),
+	/*2316*/ uint16(x86_xArgXmm1),
+	/*2317*/ uint16(x86_xArgXmm2M128),
+	/*2318*/ uint16(x86_xMatch),
+	/*2319*/ uint16(x86_xCondPrefix), 2,
+	0x66, 2331,
+	0x0, 2325,
+	/*2325*/ uint16(x86_xSetOp), uint16(x86_PHADDD),
+	/*2327*/ uint16(x86_xReadSlashR),
+	/*2328*/ uint16(x86_xArgMm1),
+	/*2329*/ uint16(x86_xArgMm2M64),
+	/*2330*/ uint16(x86_xMatch),
+	/*2331*/ uint16(x86_xSetOp), uint16(x86_PHADDD),
+	/*2333*/ uint16(x86_xReadSlashR),
+	/*2334*/ uint16(x86_xArgXmm1),
+	/*2335*/ uint16(x86_xArgXmm2M128),
+	/*2336*/ uint16(x86_xMatch),
+	/*2337*/ uint16(x86_xCondPrefix), 2,
+	0x66, 2349,
+	0x0, 2343,
+	/*2343*/ uint16(x86_xSetOp), uint16(x86_PHADDSW),
+	/*2345*/ uint16(x86_xReadSlashR),
+	/*2346*/ uint16(x86_xArgMm1),
+	/*2347*/ uint16(x86_xArgMm2M64),
+	/*2348*/ uint16(x86_xMatch),
+	/*2349*/ uint16(x86_xSetOp), uint16(x86_PHADDSW),
+	/*2351*/ uint16(x86_xReadSlashR),
+	/*2352*/ uint16(x86_xArgXmm1),
+	/*2353*/ uint16(x86_xArgXmm2M128),
+	/*2354*/ uint16(x86_xMatch),
+	/*2355*/ uint16(x86_xCondPrefix), 2,
+	0x66, 2367,
+	0x0, 2361,
+	/*2361*/ uint16(x86_xSetOp), uint16(x86_PMADDUBSW),
+	/*2363*/ uint16(x86_xReadSlashR),
+	/*2364*/ uint16(x86_xArgMm1),
+	/*2365*/ uint16(x86_xArgMm2M64),
+	/*2366*/ uint16(x86_xMatch),
+	/*2367*/ uint16(x86_xSetOp), uint16(x86_PMADDUBSW),
+	/*2369*/ uint16(x86_xReadSlashR),
+	/*2370*/ uint16(x86_xArgXmm1),
+	/*2371*/ uint16(x86_xArgXmm2M128),
+	/*2372*/ uint16(x86_xMatch),
+	/*2373*/ uint16(x86_xCondPrefix), 2,
+	0x66, 2385,
+	0x0, 2379,
+	/*2379*/ uint16(x86_xSetOp), uint16(x86_PHSUBW),
+	/*2381*/ uint16(x86_xReadSlashR),
+	/*2382*/ uint16(x86_xArgMm1),
+	/*2383*/ uint16(x86_xArgMm2M64),
+	/*2384*/ uint16(x86_xMatch),
+	/*2385*/ uint16(x86_xSetOp), uint16(x86_PHSUBW),
+	/*2387*/ uint16(x86_xReadSlashR),
+	/*2388*/ uint16(x86_xArgXmm1),
+	/*2389*/ uint16(x86_xArgXmm2M128),
+	/*2390*/ uint16(x86_xMatch),
+	/*2391*/ uint16(x86_xCondPrefix), 2,
+	0x66, 2403,
+	0x0, 2397,
+	/*2397*/ uint16(x86_xSetOp), uint16(x86_PHSUBD),
+	/*2399*/ uint16(x86_xReadSlashR),
+	/*2400*/ uint16(x86_xArgMm1),
+	/*2401*/ uint16(x86_xArgMm2M64),
+	/*2402*/ uint16(x86_xMatch),
+	/*2403*/ uint16(x86_xSetOp), uint16(x86_PHSUBD),
+	/*2405*/ uint16(x86_xReadSlashR),
+	/*2406*/ uint16(x86_xArgXmm1),
+	/*2407*/ uint16(x86_xArgXmm2M128),
+	/*2408*/ uint16(x86_xMatch),
+	/*2409*/ uint16(x86_xCondPrefix), 2,
+	0x66, 2421,
+	0x0, 2415,
+	/*2415*/ uint16(x86_xSetOp), uint16(x86_PHSUBSW),
+	/*2417*/ uint16(x86_xReadSlashR),
+	/*2418*/ uint16(x86_xArgMm1),
+	/*2419*/ uint16(x86_xArgMm2M64),
+	/*2420*/ uint16(x86_xMatch),
+	/*2421*/ uint16(x86_xSetOp), uint16(x86_PHSUBSW),
+	/*2423*/ uint16(x86_xReadSlashR),
+	/*2424*/ uint16(x86_xArgXmm1),
+	/*2425*/ uint16(x86_xArgXmm2M128),
+	/*2426*/ uint16(x86_xMatch),
+	/*2427*/ uint16(x86_xCondPrefix), 2,
+	0x66, 2439,
+	0x0, 2433,
+	/*2433*/ uint16(x86_xSetOp), uint16(x86_PSIGNB),
+	/*2435*/ uint16(x86_xReadSlashR),
+	/*2436*/ uint16(x86_xArgMm1),
+	/*2437*/ uint16(x86_xArgMm2M64),
+	/*2438*/ uint16(x86_xMatch),
+	/*2439*/ uint16(x86_xSetOp), uint16(x86_PSIGNB),
+	/*2441*/ uint16(x86_xReadSlashR),
+	/*2442*/ uint16(x86_xArgXmm1),
+	/*2443*/ uint16(x86_xArgXmm2M128),
+	/*2444*/ uint16(x86_xMatch),
+	/*2445*/ uint16(x86_xCondPrefix), 2,
+	0x66, 2457,
+	0x0, 2451,
+	/*2451*/ uint16(x86_xSetOp), uint16(x86_PSIGNW),
+	/*2453*/ uint16(x86_xReadSlashR),
+	/*2454*/ uint16(x86_xArgMm1),
+	/*2455*/ uint16(x86_xArgMm2M64),
+	/*2456*/ uint16(x86_xMatch),
+	/*2457*/ uint16(x86_xSetOp), uint16(x86_PSIGNW),
+	/*2459*/ uint16(x86_xReadSlashR),
+	/*2460*/ uint16(x86_xArgXmm1),
+	/*2461*/ uint16(x86_xArgXmm2M128),
+	/*2462*/ uint16(x86_xMatch),
+	/*2463*/ uint16(x86_xCondPrefix), 2,
+	0x66, 2475,
+	0x0, 2469,
+	/*2469*/ uint16(x86_xSetOp), uint16(x86_PSIGND),
+	/*2471*/ uint16(x86_xReadSlashR),
+	/*2472*/ uint16(x86_xArgMm1),
+	/*2473*/ uint16(x86_xArgMm2M64),
+	/*2474*/ uint16(x86_xMatch),
+	/*2475*/ uint16(x86_xSetOp), uint16(x86_PSIGND),
+	/*2477*/ uint16(x86_xReadSlashR),
+	/*2478*/ uint16(x86_xArgXmm1),
+	/*2479*/ uint16(x86_xArgXmm2M128),
+	/*2480*/ uint16(x86_xMatch),
+	/*2481*/ uint16(x86_xCondPrefix), 2,
+	0x66, 2493,
+	0x0, 2487,
+	/*2487*/ uint16(x86_xSetOp), uint16(x86_PMULHRSW),
+	/*2489*/ uint16(x86_xReadSlashR),
+	/*2490*/ uint16(x86_xArgMm1),
+	/*2491*/ uint16(x86_xArgMm2M64),
+	/*2492*/ uint16(x86_xMatch),
+	/*2493*/ uint16(x86_xSetOp), uint16(x86_PMULHRSW),
+	/*2495*/ uint16(x86_xReadSlashR),
+	/*2496*/ uint16(x86_xArgXmm1),
+	/*2497*/ uint16(x86_xArgXmm2M128),
+	/*2498*/ uint16(x86_xMatch),
+	/*2499*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2503,
+	/*2503*/ uint16(x86_xSetOp), uint16(x86_PBLENDVB),
+	/*2505*/ uint16(x86_xReadSlashR),
+	/*2506*/ uint16(x86_xArgXmm1),
+	/*2507*/ uint16(x86_xArgXmm2M128),
+	/*2508*/ uint16(x86_xArgXMM0),
+	/*2509*/ uint16(x86_xMatch),
+	/*2510*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2514,
+	/*2514*/ uint16(x86_xSetOp), uint16(x86_BLENDVPS),
+	/*2516*/ uint16(x86_xReadSlashR),
+	/*2517*/ uint16(x86_xArgXmm1),
+	/*2518*/ uint16(x86_xArgXmm2M128),
+	/*2519*/ uint16(x86_xArgXMM0),
+	/*2520*/ uint16(x86_xMatch),
+	/*2521*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2525,
+	/*2525*/ uint16(x86_xSetOp), uint16(x86_BLENDVPD),
+	/*2527*/ uint16(x86_xReadSlashR),
+	/*2528*/ uint16(x86_xArgXmm1),
+	/*2529*/ uint16(x86_xArgXmm2M128),
+	/*2530*/ uint16(x86_xArgXMM0),
+	/*2531*/ uint16(x86_xMatch),
+	/*2532*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2536,
+	/*2536*/ uint16(x86_xSetOp), uint16(x86_PTEST),
+	/*2538*/ uint16(x86_xReadSlashR),
+	/*2539*/ uint16(x86_xArgXmm1),
+	/*2540*/ uint16(x86_xArgXmm2M128),
+	/*2541*/ uint16(x86_xMatch),
+	/*2542*/ uint16(x86_xCondPrefix), 2,
+	0x66, 2554,
+	0x0, 2548,
+	/*2548*/ uint16(x86_xSetOp), uint16(x86_PABSB),
+	/*2550*/ uint16(x86_xReadSlashR),
+	/*2551*/ uint16(x86_xArgMm1),
+	/*2552*/ uint16(x86_xArgMm2M64),
+	/*2553*/ uint16(x86_xMatch),
+	/*2554*/ uint16(x86_xSetOp), uint16(x86_PABSB),
+	/*2556*/ uint16(x86_xReadSlashR),
+	/*2557*/ uint16(x86_xArgXmm1),
+	/*2558*/ uint16(x86_xArgXmm2M128),
+	/*2559*/ uint16(x86_xMatch),
+	/*2560*/ uint16(x86_xCondPrefix), 2,
+	0x66, 2572,
+	0x0, 2566,
+	/*2566*/ uint16(x86_xSetOp), uint16(x86_PABSW),
+	/*2568*/ uint16(x86_xReadSlashR),
+	/*2569*/ uint16(x86_xArgMm1),
+	/*2570*/ uint16(x86_xArgMm2M64),
+	/*2571*/ uint16(x86_xMatch),
+	/*2572*/ uint16(x86_xSetOp), uint16(x86_PABSW),
+	/*2574*/ uint16(x86_xReadSlashR),
+	/*2575*/ uint16(x86_xArgXmm1),
+	/*2576*/ uint16(x86_xArgXmm2M128),
+	/*2577*/ uint16(x86_xMatch),
+	/*2578*/ uint16(x86_xCondPrefix), 2,
+	0x66, 2590,
+	0x0, 2584,
+	/*2584*/ uint16(x86_xSetOp), uint16(x86_PABSD),
+	/*2586*/ uint16(x86_xReadSlashR),
+	/*2587*/ uint16(x86_xArgMm1),
+	/*2588*/ uint16(x86_xArgMm2M64),
+	/*2589*/ uint16(x86_xMatch),
+	/*2590*/ uint16(x86_xSetOp), uint16(x86_PABSD),
+	/*2592*/ uint16(x86_xReadSlashR),
+	/*2593*/ uint16(x86_xArgXmm1),
+	/*2594*/ uint16(x86_xArgXmm2M128),
+	/*2595*/ uint16(x86_xMatch),
+	/*2596*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2600,
+	/*2600*/ uint16(x86_xSetOp), uint16(x86_PMOVSXBW),
+	/*2602*/ uint16(x86_xReadSlashR),
+	/*2603*/ uint16(x86_xArgXmm1),
+	/*2604*/ uint16(x86_xArgXmm2M64),
+	/*2605*/ uint16(x86_xMatch),
+	/*2606*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2610,
+	/*2610*/ uint16(x86_xSetOp), uint16(x86_PMOVSXBD),
+	/*2612*/ uint16(x86_xReadSlashR),
+	/*2613*/ uint16(x86_xArgXmm1),
+	/*2614*/ uint16(x86_xArgXmm2M32),
+	/*2615*/ uint16(x86_xMatch),
+	/*2616*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2620,
+	/*2620*/ uint16(x86_xSetOp), uint16(x86_PMOVSXBQ),
+	/*2622*/ uint16(x86_xReadSlashR),
+	/*2623*/ uint16(x86_xArgXmm1),
+	/*2624*/ uint16(x86_xArgXmm2M16),
+	/*2625*/ uint16(x86_xMatch),
+	/*2626*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2630,
+	/*2630*/ uint16(x86_xSetOp), uint16(x86_PMOVSXWD),
+	/*2632*/ uint16(x86_xReadSlashR),
+	/*2633*/ uint16(x86_xArgXmm1),
+	/*2634*/ uint16(x86_xArgXmm2M64),
+	/*2635*/ uint16(x86_xMatch),
+	/*2636*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2640,
+	/*2640*/ uint16(x86_xSetOp), uint16(x86_PMOVSXWQ),
+	/*2642*/ uint16(x86_xReadSlashR),
+	/*2643*/ uint16(x86_xArgXmm1),
+	/*2644*/ uint16(x86_xArgXmm2M32),
+	/*2645*/ uint16(x86_xMatch),
+	/*2646*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2650,
+	/*2650*/ uint16(x86_xSetOp), uint16(x86_PMOVSXDQ),
+	/*2652*/ uint16(x86_xReadSlashR),
+	/*2653*/ uint16(x86_xArgXmm1),
+	/*2654*/ uint16(x86_xArgXmm2M64),
+	/*2655*/ uint16(x86_xMatch),
+	/*2656*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2660,
+	/*2660*/ uint16(x86_xSetOp), uint16(x86_PMULDQ),
+	/*2662*/ uint16(x86_xReadSlashR),
+	/*2663*/ uint16(x86_xArgXmm1),
+	/*2664*/ uint16(x86_xArgXmm2M128),
+	/*2665*/ uint16(x86_xMatch),
+	/*2666*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2670,
+	/*2670*/ uint16(x86_xSetOp), uint16(x86_PCMPEQQ),
+	/*2672*/ uint16(x86_xReadSlashR),
+	/*2673*/ uint16(x86_xArgXmm1),
+	/*2674*/ uint16(x86_xArgXmm2M128),
+	/*2675*/ uint16(x86_xMatch),
+	/*2676*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2680,
+	/*2680*/ uint16(x86_xSetOp), uint16(x86_MOVNTDQA),
+	/*2682*/ uint16(x86_xReadSlashR),
+	/*2683*/ uint16(x86_xArgXmm1),
+	/*2684*/ uint16(x86_xArgM128),
+	/*2685*/ uint16(x86_xMatch),
+	/*2686*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2690,
+	/*2690*/ uint16(x86_xSetOp), uint16(x86_PACKUSDW),
+	/*2692*/ uint16(x86_xReadSlashR),
+	/*2693*/ uint16(x86_xArgXmm1),
+	/*2694*/ uint16(x86_xArgXmm2M128),
+	/*2695*/ uint16(x86_xMatch),
+	/*2696*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2700,
+	/*2700*/ uint16(x86_xSetOp), uint16(x86_PMOVZXBW),
+	/*2702*/ uint16(x86_xReadSlashR),
+	/*2703*/ uint16(x86_xArgXmm1),
+	/*2704*/ uint16(x86_xArgXmm2M64),
+	/*2705*/ uint16(x86_xMatch),
+	/*2706*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2710,
+	/*2710*/ uint16(x86_xSetOp), uint16(x86_PMOVZXBD),
+	/*2712*/ uint16(x86_xReadSlashR),
+	/*2713*/ uint16(x86_xArgXmm1),
+	/*2714*/ uint16(x86_xArgXmm2M32),
+	/*2715*/ uint16(x86_xMatch),
+	/*2716*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2720,
+	/*2720*/ uint16(x86_xSetOp), uint16(x86_PMOVZXBQ),
+	/*2722*/ uint16(x86_xReadSlashR),
+	/*2723*/ uint16(x86_xArgXmm1),
+	/*2724*/ uint16(x86_xArgXmm2M16),
+	/*2725*/ uint16(x86_xMatch),
+	/*2726*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2730,
+	/*2730*/ uint16(x86_xSetOp), uint16(x86_PMOVZXWD),
+	/*2732*/ uint16(x86_xReadSlashR),
+	/*2733*/ uint16(x86_xArgXmm1),
+	/*2734*/ uint16(x86_xArgXmm2M64),
+	/*2735*/ uint16(x86_xMatch),
+	/*2736*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2740,
+	/*2740*/ uint16(x86_xSetOp), uint16(x86_PMOVZXWQ),
+	/*2742*/ uint16(x86_xReadSlashR),
+	/*2743*/ uint16(x86_xArgXmm1),
+	/*2744*/ uint16(x86_xArgXmm2M32),
+	/*2745*/ uint16(x86_xMatch),
+	/*2746*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2750,
+	/*2750*/ uint16(x86_xSetOp), uint16(x86_PMOVZXDQ),
+	/*2752*/ uint16(x86_xReadSlashR),
+	/*2753*/ uint16(x86_xArgXmm1),
+	/*2754*/ uint16(x86_xArgXmm2M64),
+	/*2755*/ uint16(x86_xMatch),
+	/*2756*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2760,
+	/*2760*/ uint16(x86_xSetOp), uint16(x86_PCMPGTQ),
+	/*2762*/ uint16(x86_xReadSlashR),
+	/*2763*/ uint16(x86_xArgXmm1),
+	/*2764*/ uint16(x86_xArgXmm2M128),
+	/*2765*/ uint16(x86_xMatch),
+	/*2766*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2770,
+	/*2770*/ uint16(x86_xSetOp), uint16(x86_PMINSB),
+	/*2772*/ uint16(x86_xReadSlashR),
+	/*2773*/ uint16(x86_xArgXmm1),
+	/*2774*/ uint16(x86_xArgXmm2M128),
+	/*2775*/ uint16(x86_xMatch),
+	/*2776*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2780,
+	/*2780*/ uint16(x86_xSetOp), uint16(x86_PMINSD),
+	/*2782*/ uint16(x86_xReadSlashR),
+	/*2783*/ uint16(x86_xArgXmm1),
+	/*2784*/ uint16(x86_xArgXmm2M128),
+	/*2785*/ uint16(x86_xMatch),
+	/*2786*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2790,
+	/*2790*/ uint16(x86_xSetOp), uint16(x86_PMINUW),
+	/*2792*/ uint16(x86_xReadSlashR),
+	/*2793*/ uint16(x86_xArgXmm1),
+	/*2794*/ uint16(x86_xArgXmm2M128),
+	/*2795*/ uint16(x86_xMatch),
+	/*2796*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2800,
+	/*2800*/ uint16(x86_xSetOp), uint16(x86_PMINUD),
+	/*2802*/ uint16(x86_xReadSlashR),
+	/*2803*/ uint16(x86_xArgXmm1),
+	/*2804*/ uint16(x86_xArgXmm2M128),
+	/*2805*/ uint16(x86_xMatch),
+	/*2806*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2810,
+	/*2810*/ uint16(x86_xSetOp), uint16(x86_PMAXSB),
+	/*2812*/ uint16(x86_xReadSlashR),
+	/*2813*/ uint16(x86_xArgXmm1),
+	/*2814*/ uint16(x86_xArgXmm2M128),
+	/*2815*/ uint16(x86_xMatch),
+	/*2816*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2820,
+	/*2820*/ uint16(x86_xSetOp), uint16(x86_PMAXSD),
+	/*2822*/ uint16(x86_xReadSlashR),
+	/*2823*/ uint16(x86_xArgXmm1),
+	/*2824*/ uint16(x86_xArgXmm2M128),
+	/*2825*/ uint16(x86_xMatch),
+	/*2826*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2830,
+	/*2830*/ uint16(x86_xSetOp), uint16(x86_PMAXUW),
+	/*2832*/ uint16(x86_xReadSlashR),
+	/*2833*/ uint16(x86_xArgXmm1),
+	/*2834*/ uint16(x86_xArgXmm2M128),
+	/*2835*/ uint16(x86_xMatch),
+	/*2836*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2840,
+	/*2840*/ uint16(x86_xSetOp), uint16(x86_PMAXUD),
+	/*2842*/ uint16(x86_xReadSlashR),
+	/*2843*/ uint16(x86_xArgXmm1),
+	/*2844*/ uint16(x86_xArgXmm2M128),
+	/*2845*/ uint16(x86_xMatch),
+	/*2846*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2850,
+	/*2850*/ uint16(x86_xSetOp), uint16(x86_PMULLD),
+	/*2852*/ uint16(x86_xReadSlashR),
+	/*2853*/ uint16(x86_xArgXmm1),
+	/*2854*/ uint16(x86_xArgXmm2M128),
+	/*2855*/ uint16(x86_xMatch),
+	/*2856*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2860,
+	/*2860*/ uint16(x86_xSetOp), uint16(x86_PHMINPOSUW),
+	/*2862*/ uint16(x86_xReadSlashR),
+	/*2863*/ uint16(x86_xArgXmm1),
+	/*2864*/ uint16(x86_xArgXmm2M128),
+	/*2865*/ uint16(x86_xMatch),
+	/*2866*/ uint16(x86_xCondIs64), 2869, 2879,
+	/*2869*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2873,
+	/*2873*/ uint16(x86_xSetOp), uint16(x86_INVPCID),
+	/*2875*/ uint16(x86_xReadSlashR),
+	/*2876*/ uint16(x86_xArgR32),
+	/*2877*/ uint16(x86_xArgM128),
+	/*2878*/ uint16(x86_xMatch),
+	/*2879*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2883,
+	/*2883*/ uint16(x86_xSetOp), uint16(x86_INVPCID),
+	/*2885*/ uint16(x86_xReadSlashR),
+	/*2886*/ uint16(x86_xArgR64),
+	/*2887*/ uint16(x86_xArgM128),
+	/*2888*/ uint16(x86_xMatch),
+	/*2889*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2893,
+	/*2893*/ uint16(x86_xSetOp), uint16(x86_AESIMC),
+	/*2895*/ uint16(x86_xReadSlashR),
+	/*2896*/ uint16(x86_xArgXmm1),
+	/*2897*/ uint16(x86_xArgXmm2M128),
+	/*2898*/ uint16(x86_xMatch),
+	/*2899*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2903,
+	/*2903*/ uint16(x86_xSetOp), uint16(x86_AESENC),
+	/*2905*/ uint16(x86_xReadSlashR),
+	/*2906*/ uint16(x86_xArgXmm1),
+	/*2907*/ uint16(x86_xArgXmm2M128),
+	/*2908*/ uint16(x86_xMatch),
+	/*2909*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2913,
+	/*2913*/ uint16(x86_xSetOp), uint16(x86_AESENCLAST),
+	/*2915*/ uint16(x86_xReadSlashR),
+	/*2916*/ uint16(x86_xArgXmm1),
+	/*2917*/ uint16(x86_xArgXmm2M128),
+	/*2918*/ uint16(x86_xMatch),
+	/*2919*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2923,
+	/*2923*/ uint16(x86_xSetOp), uint16(x86_AESDEC),
+	/*2925*/ uint16(x86_xReadSlashR),
+	/*2926*/ uint16(x86_xArgXmm1),
+	/*2927*/ uint16(x86_xArgXmm2M128),
+	/*2928*/ uint16(x86_xMatch),
+	/*2929*/ uint16(x86_xCondPrefix), 1,
+	0x66, 2933,
+	/*2933*/ uint16(x86_xSetOp), uint16(x86_AESDECLAST),
+	/*2935*/ uint16(x86_xReadSlashR),
+	/*2936*/ uint16(x86_xArgXmm1),
+	/*2937*/ uint16(x86_xArgXmm2M128),
+	/*2938*/ uint16(x86_xMatch),
+	/*2939*/ uint16(x86_xCondIs64), 2942, 2980,
+	/*2942*/ uint16(x86_xCondPrefix), 2,
+	0xF2, 2964,
+	0x0, 2948,
+	/*2948*/ uint16(x86_xCondDataSize), 2952, 2958, 0,
+	/*2952*/ uint16(x86_xSetOp), uint16(x86_MOVBE),
+	/*2954*/ uint16(x86_xReadSlashR),
+	/*2955*/ uint16(x86_xArgR16),
+	/*2956*/ uint16(x86_xArgM16),
+	/*2957*/ uint16(x86_xMatch),
+	/*2958*/ uint16(x86_xSetOp), uint16(x86_MOVBE),
+	/*2960*/ uint16(x86_xReadSlashR),
+	/*2961*/ uint16(x86_xArgR32),
+	/*2962*/ uint16(x86_xArgM32),
+	/*2963*/ uint16(x86_xMatch),
+	/*2964*/ uint16(x86_xCondDataSize), 2968, 2974, 0,
+	/*2968*/ uint16(x86_xSetOp), uint16(x86_CRC32),
+	/*2970*/ uint16(x86_xReadSlashR),
+	/*2971*/ uint16(x86_xArgR32),
+	/*2972*/ uint16(x86_xArgRM8),
+	/*2973*/ uint16(x86_xMatch),
+	/*2974*/ uint16(x86_xSetOp), uint16(x86_CRC32),
+	/*2976*/ uint16(x86_xReadSlashR),
+	/*2977*/ uint16(x86_xArgR32),
+	/*2978*/ uint16(x86_xArgRM8),
+	/*2979*/ uint16(x86_xMatch),
+	/*2980*/ uint16(x86_xCondPrefix), 2,
+	0xF2, 2996,
+	0x0, 2986,
+	/*2986*/ uint16(x86_xCondDataSize), 2952, 2958, 2990,
+	/*2990*/ uint16(x86_xSetOp), uint16(x86_MOVBE),
+	/*2992*/ uint16(x86_xReadSlashR),
+	/*2993*/ uint16(x86_xArgR64),
+	/*2994*/ uint16(x86_xArgM64),
+	/*2995*/ uint16(x86_xMatch),
+	/*2996*/ uint16(x86_xCondDataSize), 2968, 2974, 3000,
+	/*3000*/ uint16(x86_xSetOp), uint16(x86_CRC32),
+	/*3002*/ uint16(x86_xReadSlashR),
+	/*3003*/ uint16(x86_xArgR64),
+	/*3004*/ uint16(x86_xArgRM8),
+	/*3005*/ uint16(x86_xMatch),
+	/*3006*/ uint16(x86_xCondIs64), 3009, 3047,
+	/*3009*/ uint16(x86_xCondPrefix), 2,
+	0xF2, 3031,
+	0x0, 3015,
+	/*3015*/ uint16(x86_xCondDataSize), 3019, 3025, 0,
+	/*3019*/ uint16(x86_xSetOp), uint16(x86_MOVBE),
+	/*3021*/ uint16(x86_xReadSlashR),
+	/*3022*/ uint16(x86_xArgM16),
+	/*3023*/ uint16(x86_xArgR16),
+	/*3024*/ uint16(x86_xMatch),
+	/*3025*/ uint16(x86_xSetOp), uint16(x86_MOVBE),
+	/*3027*/ uint16(x86_xReadSlashR),
+	/*3028*/ uint16(x86_xArgM32),
+	/*3029*/ uint16(x86_xArgR32),
+	/*3030*/ uint16(x86_xMatch),
+	/*3031*/ uint16(x86_xCondDataSize), 3035, 3041, 0,
+	/*3035*/ uint16(x86_xSetOp), uint16(x86_CRC32),
+	/*3037*/ uint16(x86_xReadSlashR),
+	/*3038*/ uint16(x86_xArgR32),
+	/*3039*/ uint16(x86_xArgRM16),
+	/*3040*/ uint16(x86_xMatch),
+	/*3041*/ uint16(x86_xSetOp), uint16(x86_CRC32),
+	/*3043*/ uint16(x86_xReadSlashR),
+	/*3044*/ uint16(x86_xArgR32),
+	/*3045*/ uint16(x86_xArgRM32),
+	/*3046*/ uint16(x86_xMatch),
+	/*3047*/ uint16(x86_xCondPrefix), 2,
+	0xF2, 3063,
+	0x0, 3053,
+	/*3053*/ uint16(x86_xCondDataSize), 3019, 3025, 3057,
+	/*3057*/ uint16(x86_xSetOp), uint16(x86_MOVBE),
+	/*3059*/ uint16(x86_xReadSlashR),
+	/*3060*/ uint16(x86_xArgM64),
+	/*3061*/ uint16(x86_xArgR64),
+	/*3062*/ uint16(x86_xMatch),
+	/*3063*/ uint16(x86_xCondDataSize), 3035, 3041, 3067,
+	/*3067*/ uint16(x86_xSetOp), uint16(x86_CRC32),
+	/*3069*/ uint16(x86_xReadSlashR),
+	/*3070*/ uint16(x86_xArgR64),
+	/*3071*/ uint16(x86_xArgRM64),
+	/*3072*/ uint16(x86_xMatch),
+	/*3073*/ uint16(x86_xCondByte), 24,
+	0x08, 3124,
+	0x09, 3136,
+	0x0A, 3148,
+	0x0B, 3160,
+	0x0C, 3172,
+	0x0D, 3184,
+	0x0E, 3196,
+	0x0F, 3208,
+	0x14, 3230,
+	0x15, 3242,
+	0x16, 3254,
+	0x17, 3297,
+	0x20, 3309,
+	0x21, 3321,
+	0x22, 3333,
+	0x40, 3376,
+	0x41, 3388,
+	0x42, 3400,
+	0x44, 3412,
+	0x60, 3424,
+	0x61, 3436,
+	0x62, 3448,
+	0x63, 3460,
+	0xDF, 3472,
+	uint16(x86_xFail),
+	/*3124*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3128,
+	/*3128*/ uint16(x86_xSetOp), uint16(x86_ROUNDPS),
+	/*3130*/ uint16(x86_xReadSlashR),
+	/*3131*/ uint16(x86_xReadIb),
+	/*3132*/ uint16(x86_xArgXmm1),
+	/*3133*/ uint16(x86_xArgXmm2M128),
+	/*3134*/ uint16(x86_xArgImm8u),
+	/*3135*/ uint16(x86_xMatch),
+	/*3136*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3140,
+	/*3140*/ uint16(x86_xSetOp), uint16(x86_ROUNDPD),
+	/*3142*/ uint16(x86_xReadSlashR),
+	/*3143*/ uint16(x86_xReadIb),
+	/*3144*/ uint16(x86_xArgXmm1),
+	/*3145*/ uint16(x86_xArgXmm2M128),
+	/*3146*/ uint16(x86_xArgImm8u),
+	/*3147*/ uint16(x86_xMatch),
+	/*3148*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3152,
+	/*3152*/ uint16(x86_xSetOp), uint16(x86_ROUNDSS),
+	/*3154*/ uint16(x86_xReadSlashR),
+	/*3155*/ uint16(x86_xReadIb),
+	/*3156*/ uint16(x86_xArgXmm1),
+	/*3157*/ uint16(x86_xArgXmm2M32),
+	/*3158*/ uint16(x86_xArgImm8u),
+	/*3159*/ uint16(x86_xMatch),
+	/*3160*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3164,
+	/*3164*/ uint16(x86_xSetOp), uint16(x86_ROUNDSD),
+	/*3166*/ uint16(x86_xReadSlashR),
+	/*3167*/ uint16(x86_xReadIb),
+	/*3168*/ uint16(x86_xArgXmm1),
+	/*3169*/ uint16(x86_xArgXmm2M64),
+	/*3170*/ uint16(x86_xArgImm8u),
+	/*3171*/ uint16(x86_xMatch),
+	/*3172*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3176,
+	/*3176*/ uint16(x86_xSetOp), uint16(x86_BLENDPS),
+	/*3178*/ uint16(x86_xReadSlashR),
+	/*3179*/ uint16(x86_xReadIb),
+	/*3180*/ uint16(x86_xArgXmm1),
+	/*3181*/ uint16(x86_xArgXmm2M128),
+	/*3182*/ uint16(x86_xArgImm8u),
+	/*3183*/ uint16(x86_xMatch),
+	/*3184*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3188,
+	/*3188*/ uint16(x86_xSetOp), uint16(x86_BLENDPD),
+	/*3190*/ uint16(x86_xReadSlashR),
+	/*3191*/ uint16(x86_xReadIb),
+	/*3192*/ uint16(x86_xArgXmm1),
+	/*3193*/ uint16(x86_xArgXmm2M128),
+	/*3194*/ uint16(x86_xArgImm8u),
+	/*3195*/ uint16(x86_xMatch),
+	/*3196*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3200,
+	/*3200*/ uint16(x86_xSetOp), uint16(x86_PBLENDW),
+	/*3202*/ uint16(x86_xReadSlashR),
+	/*3203*/ uint16(x86_xReadIb),
+	/*3204*/ uint16(x86_xArgXmm1),
+	/*3205*/ uint16(x86_xArgXmm2M128),
+	/*3206*/ uint16(x86_xArgImm8u),
+	/*3207*/ uint16(x86_xMatch),
+	/*3208*/ uint16(x86_xCondPrefix), 2,
+	0x66, 3222,
+	0x0, 3214,
+	/*3214*/ uint16(x86_xSetOp), uint16(x86_PALIGNR),
+	/*3216*/ uint16(x86_xReadSlashR),
+	/*3217*/ uint16(x86_xReadIb),
+	/*3218*/ uint16(x86_xArgMm1),
+	/*3219*/ uint16(x86_xArgMm2M64),
+	/*3220*/ uint16(x86_xArgImm8u),
+	/*3221*/ uint16(x86_xMatch),
+	/*3222*/ uint16(x86_xSetOp), uint16(x86_PALIGNR),
+	/*3224*/ uint16(x86_xReadSlashR),
+	/*3225*/ uint16(x86_xReadIb),
+	/*3226*/ uint16(x86_xArgXmm1),
+	/*3227*/ uint16(x86_xArgXmm2M128),
+	/*3228*/ uint16(x86_xArgImm8u),
+	/*3229*/ uint16(x86_xMatch),
+	/*3230*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3234,
+	/*3234*/ uint16(x86_xSetOp), uint16(x86_PEXTRB),
+	/*3236*/ uint16(x86_xReadSlashR),
+	/*3237*/ uint16(x86_xReadIb),
+	/*3238*/ uint16(x86_xArgR32M8),
+	/*3239*/ uint16(x86_xArgXmm1),
+	/*3240*/ uint16(x86_xArgImm8u),
+	/*3241*/ uint16(x86_xMatch),
+	/*3242*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3246,
+	/*3246*/ uint16(x86_xSetOp), uint16(x86_PEXTRW),
+	/*3248*/ uint16(x86_xReadSlashR),
+	/*3249*/ uint16(x86_xReadIb),
+	/*3250*/ uint16(x86_xArgR32M16),
+	/*3251*/ uint16(x86_xArgXmm1),
+	/*3252*/ uint16(x86_xArgImm8u),
+	/*3253*/ uint16(x86_xMatch),
+	/*3254*/ uint16(x86_xCondIs64), 3257, 3281,
+	/*3257*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3261,
+	/*3261*/ uint16(x86_xCondDataSize), 3265, 3273, 0,
+	/*3265*/ uint16(x86_xSetOp), uint16(x86_PEXTRD),
+	/*3267*/ uint16(x86_xReadSlashR),
+	/*3268*/ uint16(x86_xReadIb),
+	/*3269*/ uint16(x86_xArgRM32),
+	/*3270*/ uint16(x86_xArgXmm1),
+	/*3271*/ uint16(x86_xArgImm8u),
+	/*3272*/ uint16(x86_xMatch),
+	/*3273*/ uint16(x86_xSetOp), uint16(x86_PEXTRD),
+	/*3275*/ uint16(x86_xReadSlashR),
+	/*3276*/ uint16(x86_xReadIb),
+	/*3277*/ uint16(x86_xArgRM32),
+	/*3278*/ uint16(x86_xArgXmm1),
+	/*3279*/ uint16(x86_xArgImm8u),
+	/*3280*/ uint16(x86_xMatch),
+	/*3281*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3285,
+	/*3285*/ uint16(x86_xCondDataSize), 3265, 3273, 3289,
+	/*3289*/ uint16(x86_xSetOp), uint16(x86_PEXTRQ),
+	/*3291*/ uint16(x86_xReadSlashR),
+	/*3292*/ uint16(x86_xReadIb),
+	/*3293*/ uint16(x86_xArgRM64),
+	/*3294*/ uint16(x86_xArgXmm1),
+	/*3295*/ uint16(x86_xArgImm8u),
+	/*3296*/ uint16(x86_xMatch),
+	/*3297*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3301,
+	/*3301*/ uint16(x86_xSetOp), uint16(x86_EXTRACTPS),
+	/*3303*/ uint16(x86_xReadSlashR),
+	/*3304*/ uint16(x86_xReadIb),
+	/*3305*/ uint16(x86_xArgRM32),
+	/*3306*/ uint16(x86_xArgXmm1),
+	/*3307*/ uint16(x86_xArgImm8u),
+	/*3308*/ uint16(x86_xMatch),
+	/*3309*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3313,
+	/*3313*/ uint16(x86_xSetOp), uint16(x86_PINSRB),
+	/*3315*/ uint16(x86_xReadSlashR),
+	/*3316*/ uint16(x86_xReadIb),
+	/*3317*/ uint16(x86_xArgXmm1),
+	/*3318*/ uint16(x86_xArgR32M8),
+	/*3319*/ uint16(x86_xArgImm8u),
+	/*3320*/ uint16(x86_xMatch),
+	/*3321*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3325,
+	/*3325*/ uint16(x86_xSetOp), uint16(x86_INSERTPS),
+	/*3327*/ uint16(x86_xReadSlashR),
+	/*3328*/ uint16(x86_xReadIb),
+	/*3329*/ uint16(x86_xArgXmm1),
+	/*3330*/ uint16(x86_xArgXmm2M32),
+	/*3331*/ uint16(x86_xArgImm8u),
+	/*3332*/ uint16(x86_xMatch),
+	/*3333*/ uint16(x86_xCondIs64), 3336, 3360,
+	/*3336*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3340,
+	/*3340*/ uint16(x86_xCondDataSize), 3344, 3352, 0,
+	/*3344*/ uint16(x86_xSetOp), uint16(x86_PINSRD),
+	/*3346*/ uint16(x86_xReadSlashR),
+	/*3347*/ uint16(x86_xReadIb),
+	/*3348*/ uint16(x86_xArgXmm1),
+	/*3349*/ uint16(x86_xArgRM32),
+	/*3350*/ uint16(x86_xArgImm8u),
+	/*3351*/ uint16(x86_xMatch),
+	/*3352*/ uint16(x86_xSetOp), uint16(x86_PINSRD),
+	/*3354*/ uint16(x86_xReadSlashR),
+	/*3355*/ uint16(x86_xReadIb),
+	/*3356*/ uint16(x86_xArgXmm1),
+	/*3357*/ uint16(x86_xArgRM32),
+	/*3358*/ uint16(x86_xArgImm8u),
+	/*3359*/ uint16(x86_xMatch),
+	/*3360*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3364,
+	/*3364*/ uint16(x86_xCondDataSize), 3344, 3352, 3368,
+	/*3368*/ uint16(x86_xSetOp), uint16(x86_PINSRQ),
+	/*3370*/ uint16(x86_xReadSlashR),
+	/*3371*/ uint16(x86_xReadIb),
+	/*3372*/ uint16(x86_xArgXmm1),
+	/*3373*/ uint16(x86_xArgRM64),
+	/*3374*/ uint16(x86_xArgImm8u),
+	/*3375*/ uint16(x86_xMatch),
+	/*3376*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3380,
+	/*3380*/ uint16(x86_xSetOp), uint16(x86_DPPS),
+	/*3382*/ uint16(x86_xReadSlashR),
+	/*3383*/ uint16(x86_xReadIb),
+	/*3384*/ uint16(x86_xArgXmm1),
+	/*3385*/ uint16(x86_xArgXmm2M128),
+	/*3386*/ uint16(x86_xArgImm8u),
+	/*3387*/ uint16(x86_xMatch),
+	/*3388*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3392,
+	/*3392*/ uint16(x86_xSetOp), uint16(x86_DPPD),
+	/*3394*/ uint16(x86_xReadSlashR),
+	/*3395*/ uint16(x86_xReadIb),
+	/*3396*/ uint16(x86_xArgXmm1),
+	/*3397*/ uint16(x86_xArgXmm2M128),
+	/*3398*/ uint16(x86_xArgImm8u),
+	/*3399*/ uint16(x86_xMatch),
+	/*3400*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3404,
+	/*3404*/ uint16(x86_xSetOp), uint16(x86_MPSADBW),
+	/*3406*/ uint16(x86_xReadSlashR),
+	/*3407*/ uint16(x86_xReadIb),
+	/*3408*/ uint16(x86_xArgXmm1),
+	/*3409*/ uint16(x86_xArgXmm2M128),
+	/*3410*/ uint16(x86_xArgImm8u),
+	/*3411*/ uint16(x86_xMatch),
+	/*3412*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3416,
+	/*3416*/ uint16(x86_xSetOp), uint16(x86_PCLMULQDQ),
+	/*3418*/ uint16(x86_xReadSlashR),
+	/*3419*/ uint16(x86_xReadIb),
+	/*3420*/ uint16(x86_xArgXmm1),
+	/*3421*/ uint16(x86_xArgXmm2M128),
+	/*3422*/ uint16(x86_xArgImm8u),
+	/*3423*/ uint16(x86_xMatch),
+	/*3424*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3428,
+	/*3428*/ uint16(x86_xSetOp), uint16(x86_PCMPESTRM),
+	/*3430*/ uint16(x86_xReadSlashR),
+	/*3431*/ uint16(x86_xReadIb),
+	/*3432*/ uint16(x86_xArgXmm1),
+	/*3433*/ uint16(x86_xArgXmm2M128),
+	/*3434*/ uint16(x86_xArgImm8u),
+	/*3435*/ uint16(x86_xMatch),
+	/*3436*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3440,
+	/*3440*/ uint16(x86_xSetOp), uint16(x86_PCMPESTRI),
+	/*3442*/ uint16(x86_xReadSlashR),
+	/*3443*/ uint16(x86_xReadIb),
+	/*3444*/ uint16(x86_xArgXmm1),
+	/*3445*/ uint16(x86_xArgXmm2M128),
+	/*3446*/ uint16(x86_xArgImm8u),
+	/*3447*/ uint16(x86_xMatch),
+	/*3448*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3452,
+	/*3452*/ uint16(x86_xSetOp), uint16(x86_PCMPISTRM),
+	/*3454*/ uint16(x86_xReadSlashR),
+	/*3455*/ uint16(x86_xReadIb),
+	/*3456*/ uint16(x86_xArgXmm1),
+	/*3457*/ uint16(x86_xArgXmm2M128),
+	/*3458*/ uint16(x86_xArgImm8u),
+	/*3459*/ uint16(x86_xMatch),
+	/*3460*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3464,
+	/*3464*/ uint16(x86_xSetOp), uint16(x86_PCMPISTRI),
+	/*3466*/ uint16(x86_xReadSlashR),
+	/*3467*/ uint16(x86_xReadIb),
+	/*3468*/ uint16(x86_xArgXmm1),
+	/*3469*/ uint16(x86_xArgXmm2M128),
+	/*3470*/ uint16(x86_xArgImm8u),
+	/*3471*/ uint16(x86_xMatch),
+	/*3472*/ uint16(x86_xCondPrefix), 1,
+	0x66, 3476,
+	/*3476*/ uint16(x86_xSetOp), uint16(x86_AESKEYGENASSIST),
+	/*3478*/ uint16(x86_xReadSlashR),
+	/*3479*/ uint16(x86_xReadIb),
+	/*3480*/ uint16(x86_xArgXmm1),
+	/*3481*/ uint16(x86_xArgXmm2M128),
+	/*3482*/ uint16(x86_xArgImm8u),
+	/*3483*/ uint16(x86_xMatch),
+	/*3484*/ uint16(x86_xCondIs64), 3487, 3503,
+	/*3487*/ uint16(x86_xCondDataSize), 3491, 3497, 0,
+	/*3491*/ uint16(x86_xSetOp), uint16(x86_CMOVO),
+	/*3493*/ uint16(x86_xReadSlashR),
+	/*3494*/ uint16(x86_xArgR16),
+	/*3495*/ uint16(x86_xArgRM16),
+	/*3496*/ uint16(x86_xMatch),
+	/*3497*/ uint16(x86_xSetOp), uint16(x86_CMOVO),
+	/*3499*/ uint16(x86_xReadSlashR),
+	/*3500*/ uint16(x86_xArgR32),
+	/*3501*/ uint16(x86_xArgRM32),
+	/*3502*/ uint16(x86_xMatch),
+	/*3503*/ uint16(x86_xCondDataSize), 3491, 3497, 3507,
+	/*3507*/ uint16(x86_xSetOp), uint16(x86_CMOVO),
+	/*3509*/ uint16(x86_xReadSlashR),
+	/*3510*/ uint16(x86_xArgR64),
+	/*3511*/ uint16(x86_xArgRM64),
+	/*3512*/ uint16(x86_xMatch),
+	/*3513*/ uint16(x86_xCondIs64), 3516, 3532,
+	/*3516*/ uint16(x86_xCondDataSize), 3520, 3526, 0,
+	/*3520*/ uint16(x86_xSetOp), uint16(x86_CMOVNO),
+	/*3522*/ uint16(x86_xReadSlashR),
+	/*3523*/ uint16(x86_xArgR16),
+	/*3524*/ uint16(x86_xArgRM16),
+	/*3525*/ uint16(x86_xMatch),
+	/*3526*/ uint16(x86_xSetOp), uint16(x86_CMOVNO),
+	/*3528*/ uint16(x86_xReadSlashR),
+	/*3529*/ uint16(x86_xArgR32),
+	/*3530*/ uint16(x86_xArgRM32),
+	/*3531*/ uint16(x86_xMatch),
+	/*3532*/ uint16(x86_xCondDataSize), 3520, 3526, 3536,
+	/*3536*/ uint16(x86_xSetOp), uint16(x86_CMOVNO),
+	/*3538*/ uint16(x86_xReadSlashR),
+	/*3539*/ uint16(x86_xArgR64),
+	/*3540*/ uint16(x86_xArgRM64),
+	/*3541*/ uint16(x86_xMatch),
+	/*3542*/ uint16(x86_xCondIs64), 3545, 3561,
+	/*3545*/ uint16(x86_xCondDataSize), 3549, 3555, 0,
+	/*3549*/ uint16(x86_xSetOp), uint16(x86_CMOVB),
+	/*3551*/ uint16(x86_xReadSlashR),
+	/*3552*/ uint16(x86_xArgR16),
+	/*3553*/ uint16(x86_xArgRM16),
+	/*3554*/ uint16(x86_xMatch),
+	/*3555*/ uint16(x86_xSetOp), uint16(x86_CMOVB),
+	/*3557*/ uint16(x86_xReadSlashR),
+	/*3558*/ uint16(x86_xArgR32),
+	/*3559*/ uint16(x86_xArgRM32),
+	/*3560*/ uint16(x86_xMatch),
+	/*3561*/ uint16(x86_xCondDataSize), 3549, 3555, 3565,
+	/*3565*/ uint16(x86_xSetOp), uint16(x86_CMOVB),
+	/*3567*/ uint16(x86_xReadSlashR),
+	/*3568*/ uint16(x86_xArgR64),
+	/*3569*/ uint16(x86_xArgRM64),
+	/*3570*/ uint16(x86_xMatch),
+	/*3571*/ uint16(x86_xCondIs64), 3574, 3590,
+	/*3574*/ uint16(x86_xCondDataSize), 3578, 3584, 0,
+	/*3578*/ uint16(x86_xSetOp), uint16(x86_CMOVAE),
+	/*3580*/ uint16(x86_xReadSlashR),
+	/*3581*/ uint16(x86_xArgR16),
+	/*3582*/ uint16(x86_xArgRM16),
+	/*3583*/ uint16(x86_xMatch),
+	/*3584*/ uint16(x86_xSetOp), uint16(x86_CMOVAE),
+	/*3586*/ uint16(x86_xReadSlashR),
+	/*3587*/ uint16(x86_xArgR32),
+	/*3588*/ uint16(x86_xArgRM32),
+	/*3589*/ uint16(x86_xMatch),
+	/*3590*/ uint16(x86_xCondDataSize), 3578, 3584, 3594,
+	/*3594*/ uint16(x86_xSetOp), uint16(x86_CMOVAE),
+	/*3596*/ uint16(x86_xReadSlashR),
+	/*3597*/ uint16(x86_xArgR64),
+	/*3598*/ uint16(x86_xArgRM64),
+	/*3599*/ uint16(x86_xMatch),
+	/*3600*/ uint16(x86_xCondIs64), 3603, 3619,
+	/*3603*/ uint16(x86_xCondDataSize), 3607, 3613, 0,
+	/*3607*/ uint16(x86_xSetOp), uint16(x86_CMOVE),
+	/*3609*/ uint16(x86_xReadSlashR),
+	/*3610*/ uint16(x86_xArgR16),
+	/*3611*/ uint16(x86_xArgRM16),
+	/*3612*/ uint16(x86_xMatch),
+	/*3613*/ uint16(x86_xSetOp), uint16(x86_CMOVE),
+	/*3615*/ uint16(x86_xReadSlashR),
+	/*3616*/ uint16(x86_xArgR32),
+	/*3617*/ uint16(x86_xArgRM32),
+	/*3618*/ uint16(x86_xMatch),
+	/*3619*/ uint16(x86_xCondDataSize), 3607, 3613, 3623,
+	/*3623*/ uint16(x86_xSetOp), uint16(x86_CMOVE),
+	/*3625*/ uint16(x86_xReadSlashR),
+	/*3626*/ uint16(x86_xArgR64),
+	/*3627*/ uint16(x86_xArgRM64),
+	/*3628*/ uint16(x86_xMatch),
+	/*3629*/ uint16(x86_xCondIs64), 3632, 3648,
+	/*3632*/ uint16(x86_xCondDataSize), 3636, 3642, 0,
+	/*3636*/ uint16(x86_xSetOp), uint16(x86_CMOVNE),
+	/*3638*/ uint16(x86_xReadSlashR),
+	/*3639*/ uint16(x86_xArgR16),
+	/*3640*/ uint16(x86_xArgRM16),
+	/*3641*/ uint16(x86_xMatch),
+	/*3642*/ uint16(x86_xSetOp), uint16(x86_CMOVNE),
+	/*3644*/ uint16(x86_xReadSlashR),
+	/*3645*/ uint16(x86_xArgR32),
+	/*3646*/ uint16(x86_xArgRM32),
+	/*3647*/ uint16(x86_xMatch),
+	/*3648*/ uint16(x86_xCondDataSize), 3636, 3642, 3652,
+	/*3652*/ uint16(x86_xSetOp), uint16(x86_CMOVNE),
+	/*3654*/ uint16(x86_xReadSlashR),
+	/*3655*/ uint16(x86_xArgR64),
+	/*3656*/ uint16(x86_xArgRM64),
+	/*3657*/ uint16(x86_xMatch),
+	/*3658*/ uint16(x86_xCondIs64), 3661, 3677,
+	/*3661*/ uint16(x86_xCondDataSize), 3665, 3671, 0,
+	/*3665*/ uint16(x86_xSetOp), uint16(x86_CMOVBE),
+	/*3667*/ uint16(x86_xReadSlashR),
+	/*3668*/ uint16(x86_xArgR16),
+	/*3669*/ uint16(x86_xArgRM16),
+	/*3670*/ uint16(x86_xMatch),
+	/*3671*/ uint16(x86_xSetOp), uint16(x86_CMOVBE),
+	/*3673*/ uint16(x86_xReadSlashR),
+	/*3674*/ uint16(x86_xArgR32),
+	/*3675*/ uint16(x86_xArgRM32),
+	/*3676*/ uint16(x86_xMatch),
+	/*3677*/ uint16(x86_xCondDataSize), 3665, 3671, 3681,
+	/*3681*/ uint16(x86_xSetOp), uint16(x86_CMOVBE),
+	/*3683*/ uint16(x86_xReadSlashR),
+	/*3684*/ uint16(x86_xArgR64),
+	/*3685*/ uint16(x86_xArgRM64),
+	/*3686*/ uint16(x86_xMatch),
+	/*3687*/ uint16(x86_xCondIs64), 3690, 3706,
+	/*3690*/ uint16(x86_xCondDataSize), 3694, 3700, 0,
+	/*3694*/ uint16(x86_xSetOp), uint16(x86_CMOVA),
+	/*3696*/ uint16(x86_xReadSlashR),
+	/*3697*/ uint16(x86_xArgR16),
+	/*3698*/ uint16(x86_xArgRM16),
+	/*3699*/ uint16(x86_xMatch),
+	/*3700*/ uint16(x86_xSetOp), uint16(x86_CMOVA),
+	/*3702*/ uint16(x86_xReadSlashR),
+	/*3703*/ uint16(x86_xArgR32),
+	/*3704*/ uint16(x86_xArgRM32),
+	/*3705*/ uint16(x86_xMatch),
+	/*3706*/ uint16(x86_xCondDataSize), 3694, 3700, 3710,
+	/*3710*/ uint16(x86_xSetOp), uint16(x86_CMOVA),
+	/*3712*/ uint16(x86_xReadSlashR),
+	/*3713*/ uint16(x86_xArgR64),
+	/*3714*/ uint16(x86_xArgRM64),
+	/*3715*/ uint16(x86_xMatch),
+	/*3716*/ uint16(x86_xCondIs64), 3719, 3735,
+	/*3719*/ uint16(x86_xCondDataSize), 3723, 3729, 0,
+	/*3723*/ uint16(x86_xSetOp), uint16(x86_CMOVS),
+	/*3725*/ uint16(x86_xReadSlashR),
+	/*3726*/ uint16(x86_xArgR16),
+	/*3727*/ uint16(x86_xArgRM16),
+	/*3728*/ uint16(x86_xMatch),
+	/*3729*/ uint16(x86_xSetOp), uint16(x86_CMOVS),
+	/*3731*/ uint16(x86_xReadSlashR),
+	/*3732*/ uint16(x86_xArgR32),
+	/*3733*/ uint16(x86_xArgRM32),
+	/*3734*/ uint16(x86_xMatch),
+	/*3735*/ uint16(x86_xCondDataSize), 3723, 3729, 3739,
+	/*3739*/ uint16(x86_xSetOp), uint16(x86_CMOVS),
+	/*3741*/ uint16(x86_xReadSlashR),
+	/*3742*/ uint16(x86_xArgR64),
+	/*3743*/ uint16(x86_xArgRM64),
+	/*3744*/ uint16(x86_xMatch),
+	/*3745*/ uint16(x86_xCondIs64), 3748, 3764,
+	/*3748*/ uint16(x86_xCondDataSize), 3752, 3758, 0,
+	/*3752*/ uint16(x86_xSetOp), uint16(x86_CMOVNS),
+	/*3754*/ uint16(x86_xReadSlashR),
+	/*3755*/ uint16(x86_xArgR16),
+	/*3756*/ uint16(x86_xArgRM16),
+	/*3757*/ uint16(x86_xMatch),
+	/*3758*/ uint16(x86_xSetOp), uint16(x86_CMOVNS),
+	/*3760*/ uint16(x86_xReadSlashR),
+	/*3761*/ uint16(x86_xArgR32),
+	/*3762*/ uint16(x86_xArgRM32),
+	/*3763*/ uint16(x86_xMatch),
+	/*3764*/ uint16(x86_xCondDataSize), 3752, 3758, 3768,
+	/*3768*/ uint16(x86_xSetOp), uint16(x86_CMOVNS),
+	/*3770*/ uint16(x86_xReadSlashR),
+	/*3771*/ uint16(x86_xArgR64),
+	/*3772*/ uint16(x86_xArgRM64),
+	/*3773*/ uint16(x86_xMatch),
+	/*3774*/ uint16(x86_xCondIs64), 3777, 3793,
+	/*3777*/ uint16(x86_xCondDataSize), 3781, 3787, 0,
+	/*3781*/ uint16(x86_xSetOp), uint16(x86_CMOVP),
+	/*3783*/ uint16(x86_xReadSlashR),
+	/*3784*/ uint16(x86_xArgR16),
+	/*3785*/ uint16(x86_xArgRM16),
+	/*3786*/ uint16(x86_xMatch),
+	/*3787*/ uint16(x86_xSetOp), uint16(x86_CMOVP),
+	/*3789*/ uint16(x86_xReadSlashR),
+	/*3790*/ uint16(x86_xArgR32),
+	/*3791*/ uint16(x86_xArgRM32),
+	/*3792*/ uint16(x86_xMatch),
+	/*3793*/ uint16(x86_xCondDataSize), 3781, 3787, 3797,
+	/*3797*/ uint16(x86_xSetOp), uint16(x86_CMOVP),
+	/*3799*/ uint16(x86_xReadSlashR),
+	/*3800*/ uint16(x86_xArgR64),
+	/*3801*/ uint16(x86_xArgRM64),
+	/*3802*/ uint16(x86_xMatch),
+	/*3803*/ uint16(x86_xCondIs64), 3806, 3822,
+	/*3806*/ uint16(x86_xCondDataSize), 3810, 3816, 0,
+	/*3810*/ uint16(x86_xSetOp), uint16(x86_CMOVNP),
+	/*3812*/ uint16(x86_xReadSlashR),
+	/*3813*/ uint16(x86_xArgR16),
+	/*3814*/ uint16(x86_xArgRM16),
+	/*3815*/ uint16(x86_xMatch),
+	/*3816*/ uint16(x86_xSetOp), uint16(x86_CMOVNP),
+	/*3818*/ uint16(x86_xReadSlashR),
+	/*3819*/ uint16(x86_xArgR32),
+	/*3820*/ uint16(x86_xArgRM32),
+	/*3821*/ uint16(x86_xMatch),
+	/*3822*/ uint16(x86_xCondDataSize), 3810, 3816, 3826,
+	/*3826*/ uint16(x86_xSetOp), uint16(x86_CMOVNP),
+	/*3828*/ uint16(x86_xReadSlashR),
+	/*3829*/ uint16(x86_xArgR64),
+	/*3830*/ uint16(x86_xArgRM64),
+	/*3831*/ uint16(x86_xMatch),
+	/*3832*/ uint16(x86_xCondIs64), 3835, 3851,
+	/*3835*/ uint16(x86_xCondDataSize), 3839, 3845, 0,
+	/*3839*/ uint16(x86_xSetOp), uint16(x86_CMOVL),
+	/*3841*/ uint16(x86_xReadSlashR),
+	/*3842*/ uint16(x86_xArgR16),
+	/*3843*/ uint16(x86_xArgRM16),
+	/*3844*/ uint16(x86_xMatch),
+	/*3845*/ uint16(x86_xSetOp), uint16(x86_CMOVL),
+	/*3847*/ uint16(x86_xReadSlashR),
+	/*3848*/ uint16(x86_xArgR32),
+	/*3849*/ uint16(x86_xArgRM32),
+	/*3850*/ uint16(x86_xMatch),
+	/*3851*/ uint16(x86_xCondDataSize), 3839, 3845, 3855,
+	/*3855*/ uint16(x86_xSetOp), uint16(x86_CMOVL),
+	/*3857*/ uint16(x86_xReadSlashR),
+	/*3858*/ uint16(x86_xArgR64),
+	/*3859*/ uint16(x86_xArgRM64),
+	/*3860*/ uint16(x86_xMatch),
+	/*3861*/ uint16(x86_xCondIs64), 3864, 3880,
+	/*3864*/ uint16(x86_xCondDataSize), 3868, 3874, 0,
+	/*3868*/ uint16(x86_xSetOp), uint16(x86_CMOVGE),
+	/*3870*/ uint16(x86_xReadSlashR),
+	/*3871*/ uint16(x86_xArgR16),
+	/*3872*/ uint16(x86_xArgRM16),
+	/*3873*/ uint16(x86_xMatch),
+	/*3874*/ uint16(x86_xSetOp), uint16(x86_CMOVGE),
+	/*3876*/ uint16(x86_xReadSlashR),
+	/*3877*/ uint16(x86_xArgR32),
+	/*3878*/ uint16(x86_xArgRM32),
+	/*3879*/ uint16(x86_xMatch),
+	/*3880*/ uint16(x86_xCondDataSize), 3868, 3874, 3884,
+	/*3884*/ uint16(x86_xSetOp), uint16(x86_CMOVGE),
+	/*3886*/ uint16(x86_xReadSlashR),
+	/*3887*/ uint16(x86_xArgR64),
+	/*3888*/ uint16(x86_xArgRM64),
+	/*3889*/ uint16(x86_xMatch),
+	/*3890*/ uint16(x86_xCondIs64), 3893, 3909,
+	/*3893*/ uint16(x86_xCondDataSize), 3897, 3903, 0,
+	/*3897*/ uint16(x86_xSetOp), uint16(x86_CMOVLE),
+	/*3899*/ uint16(x86_xReadSlashR),
+	/*3900*/ uint16(x86_xArgR16),
+	/*3901*/ uint16(x86_xArgRM16),
+	/*3902*/ uint16(x86_xMatch),
+	/*3903*/ uint16(x86_xSetOp), uint16(x86_CMOVLE),
+	/*3905*/ uint16(x86_xReadSlashR),
+	/*3906*/ uint16(x86_xArgR32),
+	/*3907*/ uint16(x86_xArgRM32),
+	/*3908*/ uint16(x86_xMatch),
+	/*3909*/ uint16(x86_xCondDataSize), 3897, 3903, 3913,
+	/*3913*/ uint16(x86_xSetOp), uint16(x86_CMOVLE),
+	/*3915*/ uint16(x86_xReadSlashR),
+	/*3916*/ uint16(x86_xArgR64),
+	/*3917*/ uint16(x86_xArgRM64),
+	/*3918*/ uint16(x86_xMatch),
+	/*3919*/ uint16(x86_xCondIs64), 3922, 3938,
+	/*3922*/ uint16(x86_xCondDataSize), 3926, 3932, 0,
+	/*3926*/ uint16(x86_xSetOp), uint16(x86_CMOVG),
+	/*3928*/ uint16(x86_xReadSlashR),
+	/*3929*/ uint16(x86_xArgR16),
+	/*3930*/ uint16(x86_xArgRM16),
+	/*3931*/ uint16(x86_xMatch),
+	/*3932*/ uint16(x86_xSetOp), uint16(x86_CMOVG),
+	/*3934*/ uint16(x86_xReadSlashR),
+	/*3935*/ uint16(x86_xArgR32),
+	/*3936*/ uint16(x86_xArgRM32),
+	/*3937*/ uint16(x86_xMatch),
+	/*3938*/ uint16(x86_xCondDataSize), 3926, 3932, 3942,
+	/*3942*/ uint16(x86_xSetOp), uint16(x86_CMOVG),
+	/*3944*/ uint16(x86_xReadSlashR),
+	/*3945*/ uint16(x86_xArgR64),
+	/*3946*/ uint16(x86_xArgRM64),
+	/*3947*/ uint16(x86_xMatch),
+	/*3948*/ uint16(x86_xCondPrefix), 2,
+	0x66, 3960,
+	0x0, 3954,
+	/*3954*/ uint16(x86_xSetOp), uint16(x86_MOVMSKPS),
+	/*3956*/ uint16(x86_xReadSlashR),
+	/*3957*/ uint16(x86_xArgR32),
+	/*3958*/ uint16(x86_xArgXmm2),
+	/*3959*/ uint16(x86_xMatch),
+	/*3960*/ uint16(x86_xSetOp), uint16(x86_MOVMSKPD),
+	/*3962*/ uint16(x86_xReadSlashR),
+	/*3963*/ uint16(x86_xArgR32),
+	/*3964*/ uint16(x86_xArgXmm2),
+	/*3965*/ uint16(x86_xMatch),
+	/*3966*/ uint16(x86_xCondPrefix), 4,
+	0xF3, 3994,
+	0xF2, 3988,
+	0x66, 3982,
+	0x0, 3976,
+	/*3976*/ uint16(x86_xSetOp), uint16(x86_SQRTPS),
+	/*3978*/ uint16(x86_xReadSlashR),
+	/*3979*/ uint16(x86_xArgXmm1),
+	/*3980*/ uint16(x86_xArgXmm2M128),
+	/*3981*/ uint16(x86_xMatch),
+	/*3982*/ uint16(x86_xSetOp), uint16(x86_SQRTPD),
+	/*3984*/ uint16(x86_xReadSlashR),
+	/*3985*/ uint16(x86_xArgXmm1),
+	/*3986*/ uint16(x86_xArgXmm2M128),
+	/*3987*/ uint16(x86_xMatch),
+	/*3988*/ uint16(x86_xSetOp), uint16(x86_SQRTSD),
+	/*3990*/ uint16(x86_xReadSlashR),
+	/*3991*/ uint16(x86_xArgXmm1),
+	/*3992*/ uint16(x86_xArgXmm2M64),
+	/*3993*/ uint16(x86_xMatch),
+	/*3994*/ uint16(x86_xSetOp), uint16(x86_SQRTSS),
+	/*3996*/ uint16(x86_xReadSlashR),
+	/*3997*/ uint16(x86_xArgXmm1),
+	/*3998*/ uint16(x86_xArgXmm2M32),
+	/*3999*/ uint16(x86_xMatch),
+	/*4000*/ uint16(x86_xCondPrefix), 2,
+	0xF3, 4012,
+	0x0, 4006,
+	/*4006*/ uint16(x86_xSetOp), uint16(x86_RSQRTPS),
+	/*4008*/ uint16(x86_xReadSlashR),
+	/*4009*/ uint16(x86_xArgXmm1),
+	/*4010*/ uint16(x86_xArgXmm2M128),
+	/*4011*/ uint16(x86_xMatch),
+	/*4012*/ uint16(x86_xSetOp), uint16(x86_RSQRTSS),
+	/*4014*/ uint16(x86_xReadSlashR),
+	/*4015*/ uint16(x86_xArgXmm1),
+	/*4016*/ uint16(x86_xArgXmm2M32),
+	/*4017*/ uint16(x86_xMatch),
+	/*4018*/ uint16(x86_xCondPrefix), 2,
+	0xF3, 4030,
+	0x0, 4024,
+	/*4024*/ uint16(x86_xSetOp), uint16(x86_RCPPS),
+	/*4026*/ uint16(x86_xReadSlashR),
+	/*4027*/ uint16(x86_xArgXmm1),
+	/*4028*/ uint16(x86_xArgXmm2M128),
+	/*4029*/ uint16(x86_xMatch),
+	/*4030*/ uint16(x86_xSetOp), uint16(x86_RCPSS),
+	/*4032*/ uint16(x86_xReadSlashR),
+	/*4033*/ uint16(x86_xArgXmm1),
+	/*4034*/ uint16(x86_xArgXmm2M32),
+	/*4035*/ uint16(x86_xMatch),
+	/*4036*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4048,
+	0x0, 4042,
+	/*4042*/ uint16(x86_xSetOp), uint16(x86_ANDPS),
+	/*4044*/ uint16(x86_xReadSlashR),
+	/*4045*/ uint16(x86_xArgXmm1),
+	/*4046*/ uint16(x86_xArgXmm2M128),
+	/*4047*/ uint16(x86_xMatch),
+	/*4048*/ uint16(x86_xSetOp), uint16(x86_ANDPD),
+	/*4050*/ uint16(x86_xReadSlashR),
+	/*4051*/ uint16(x86_xArgXmm1),
+	/*4052*/ uint16(x86_xArgXmm2M128),
+	/*4053*/ uint16(x86_xMatch),
+	/*4054*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4066,
+	0x0, 4060,
+	/*4060*/ uint16(x86_xSetOp), uint16(x86_ANDNPS),
+	/*4062*/ uint16(x86_xReadSlashR),
+	/*4063*/ uint16(x86_xArgXmm1),
+	/*4064*/ uint16(x86_xArgXmm2M128),
+	/*4065*/ uint16(x86_xMatch),
+	/*4066*/ uint16(x86_xSetOp), uint16(x86_ANDNPD),
+	/*4068*/ uint16(x86_xReadSlashR),
+	/*4069*/ uint16(x86_xArgXmm1),
+	/*4070*/ uint16(x86_xArgXmm2M128),
+	/*4071*/ uint16(x86_xMatch),
+	/*4072*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4084,
+	0x0, 4078,
+	/*4078*/ uint16(x86_xSetOp), uint16(x86_ORPS),
+	/*4080*/ uint16(x86_xReadSlashR),
+	/*4081*/ uint16(x86_xArgXmm1),
+	/*4082*/ uint16(x86_xArgXmm2M128),
+	/*4083*/ uint16(x86_xMatch),
+	/*4084*/ uint16(x86_xSetOp), uint16(x86_ORPD),
+	/*4086*/ uint16(x86_xReadSlashR),
+	/*4087*/ uint16(x86_xArgXmm1),
+	/*4088*/ uint16(x86_xArgXmm2M128),
+	/*4089*/ uint16(x86_xMatch),
+	/*4090*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4102,
+	0x0, 4096,
+	/*4096*/ uint16(x86_xSetOp), uint16(x86_XORPS),
+	/*4098*/ uint16(x86_xReadSlashR),
+	/*4099*/ uint16(x86_xArgXmm1),
+	/*4100*/ uint16(x86_xArgXmm2M128),
+	/*4101*/ uint16(x86_xMatch),
+	/*4102*/ uint16(x86_xSetOp), uint16(x86_XORPD),
+	/*4104*/ uint16(x86_xReadSlashR),
+	/*4105*/ uint16(x86_xArgXmm1),
+	/*4106*/ uint16(x86_xArgXmm2M128),
+	/*4107*/ uint16(x86_xMatch),
+	/*4108*/ uint16(x86_xCondPrefix), 4,
+	0xF3, 4136,
+	0xF2, 4130,
+	0x66, 4124,
+	0x0, 4118,
+	/*4118*/ uint16(x86_xSetOp), uint16(x86_ADDPS),
+	/*4120*/ uint16(x86_xReadSlashR),
+	/*4121*/ uint16(x86_xArgXmm1),
+	/*4122*/ uint16(x86_xArgXmm2M128),
+	/*4123*/ uint16(x86_xMatch),
+	/*4124*/ uint16(x86_xSetOp), uint16(x86_ADDPD),
+	/*4126*/ uint16(x86_xReadSlashR),
+	/*4127*/ uint16(x86_xArgXmm1),
+	/*4128*/ uint16(x86_xArgXmm2M128),
+	/*4129*/ uint16(x86_xMatch),
+	/*4130*/ uint16(x86_xSetOp), uint16(x86_ADDSD),
+	/*4132*/ uint16(x86_xReadSlashR),
+	/*4133*/ uint16(x86_xArgXmm1),
+	/*4134*/ uint16(x86_xArgXmm2M64),
+	/*4135*/ uint16(x86_xMatch),
+	/*4136*/ uint16(x86_xSetOp), uint16(x86_ADDSS),
+	/*4138*/ uint16(x86_xReadSlashR),
+	/*4139*/ uint16(x86_xArgXmm1),
+	/*4140*/ uint16(x86_xArgXmm2M32),
+	/*4141*/ uint16(x86_xMatch),
+	/*4142*/ uint16(x86_xCondPrefix), 4,
+	0xF3, 4170,
+	0xF2, 4164,
+	0x66, 4158,
+	0x0, 4152,
+	/*4152*/ uint16(x86_xSetOp), uint16(x86_MULPS),
+	/*4154*/ uint16(x86_xReadSlashR),
+	/*4155*/ uint16(x86_xArgXmm1),
+	/*4156*/ uint16(x86_xArgXmm2M128),
+	/*4157*/ uint16(x86_xMatch),
+	/*4158*/ uint16(x86_xSetOp), uint16(x86_MULPD),
+	/*4160*/ uint16(x86_xReadSlashR),
+	/*4161*/ uint16(x86_xArgXmm1),
+	/*4162*/ uint16(x86_xArgXmm2M128),
+	/*4163*/ uint16(x86_xMatch),
+	/*4164*/ uint16(x86_xSetOp), uint16(x86_MULSD),
+	/*4166*/ uint16(x86_xReadSlashR),
+	/*4167*/ uint16(x86_xArgXmm1),
+	/*4168*/ uint16(x86_xArgXmm2M64),
+	/*4169*/ uint16(x86_xMatch),
+	/*4170*/ uint16(x86_xSetOp), uint16(x86_MULSS),
+	/*4172*/ uint16(x86_xReadSlashR),
+	/*4173*/ uint16(x86_xArgXmm1),
+	/*4174*/ uint16(x86_xArgXmm2M32),
+	/*4175*/ uint16(x86_xMatch),
+	/*4176*/ uint16(x86_xCondPrefix), 4,
+	0xF3, 4204,
+	0xF2, 4198,
+	0x66, 4192,
+	0x0, 4186,
+	/*4186*/ uint16(x86_xSetOp), uint16(x86_CVTPS2PD),
+	/*4188*/ uint16(x86_xReadSlashR),
+	/*4189*/ uint16(x86_xArgXmm1),
+	/*4190*/ uint16(x86_xArgXmm2M64),
+	/*4191*/ uint16(x86_xMatch),
+	/*4192*/ uint16(x86_xSetOp), uint16(x86_CVTPD2PS),
+	/*4194*/ uint16(x86_xReadSlashR),
+	/*4195*/ uint16(x86_xArgXmm1),
+	/*4196*/ uint16(x86_xArgXmm2M128),
+	/*4197*/ uint16(x86_xMatch),
+	/*4198*/ uint16(x86_xSetOp), uint16(x86_CVTSD2SS),
+	/*4200*/ uint16(x86_xReadSlashR),
+	/*4201*/ uint16(x86_xArgXmm1),
+	/*4202*/ uint16(x86_xArgXmm2M64),
+	/*4203*/ uint16(x86_xMatch),
+	/*4204*/ uint16(x86_xSetOp), uint16(x86_CVTSS2SD),
+	/*4206*/ uint16(x86_xReadSlashR),
+	/*4207*/ uint16(x86_xArgXmm1),
+	/*4208*/ uint16(x86_xArgXmm2M32),
+	/*4209*/ uint16(x86_xMatch),
+	/*4210*/ uint16(x86_xCondPrefix), 3,
+	0xF3, 4230,
+	0x66, 4224,
+	0x0, 4218,
+	/*4218*/ uint16(x86_xSetOp), uint16(x86_CVTDQ2PS),
+	/*4220*/ uint16(x86_xReadSlashR),
+	/*4221*/ uint16(x86_xArgXmm1),
+	/*4222*/ uint16(x86_xArgXmm2M128),
+	/*4223*/ uint16(x86_xMatch),
+	/*4224*/ uint16(x86_xSetOp), uint16(x86_CVTPS2DQ),
+	/*4226*/ uint16(x86_xReadSlashR),
+	/*4227*/ uint16(x86_xArgXmm1),
+	/*4228*/ uint16(x86_xArgXmm2M128),
+	/*4229*/ uint16(x86_xMatch),
+	/*4230*/ uint16(x86_xSetOp), uint16(x86_CVTTPS2DQ),
+	/*4232*/ uint16(x86_xReadSlashR),
+	/*4233*/ uint16(x86_xArgXmm1),
+	/*4234*/ uint16(x86_xArgXmm2M128),
+	/*4235*/ uint16(x86_xMatch),
+	/*4236*/ uint16(x86_xCondPrefix), 4,
+	0xF3, 4264,
+	0xF2, 4258,
+	0x66, 4252,
+	0x0, 4246,
+	/*4246*/ uint16(x86_xSetOp), uint16(x86_SUBPS),
+	/*4248*/ uint16(x86_xReadSlashR),
+	/*4249*/ uint16(x86_xArgXmm1),
+	/*4250*/ uint16(x86_xArgXmm2M128),
+	/*4251*/ uint16(x86_xMatch),
+	/*4252*/ uint16(x86_xSetOp), uint16(x86_SUBPD),
+	/*4254*/ uint16(x86_xReadSlashR),
+	/*4255*/ uint16(x86_xArgXmm1),
+	/*4256*/ uint16(x86_xArgXmm2M128),
+	/*4257*/ uint16(x86_xMatch),
+	/*4258*/ uint16(x86_xSetOp), uint16(x86_SUBSD),
+	/*4260*/ uint16(x86_xReadSlashR),
+	/*4261*/ uint16(x86_xArgXmm1),
+	/*4262*/ uint16(x86_xArgXmm2M64),
+	/*4263*/ uint16(x86_xMatch),
+	/*4264*/ uint16(x86_xSetOp), uint16(x86_SUBSS),
+	/*4266*/ uint16(x86_xReadSlashR),
+	/*4267*/ uint16(x86_xArgXmm1),
+	/*4268*/ uint16(x86_xArgXmm2M32),
+	/*4269*/ uint16(x86_xMatch),
+	/*4270*/ uint16(x86_xCondPrefix), 4,
+	0xF3, 4298,
+	0xF2, 4292,
+	0x66, 4286,
+	0x0, 4280,
+	/*4280*/ uint16(x86_xSetOp), uint16(x86_MINPS),
+	/*4282*/ uint16(x86_xReadSlashR),
+	/*4283*/ uint16(x86_xArgXmm1),
+	/*4284*/ uint16(x86_xArgXmm2M128),
+	/*4285*/ uint16(x86_xMatch),
+	/*4286*/ uint16(x86_xSetOp), uint16(x86_MINPD),
+	/*4288*/ uint16(x86_xReadSlashR),
+	/*4289*/ uint16(x86_xArgXmm1),
+	/*4290*/ uint16(x86_xArgXmm2M128),
+	/*4291*/ uint16(x86_xMatch),
+	/*4292*/ uint16(x86_xSetOp), uint16(x86_MINSD),
+	/*4294*/ uint16(x86_xReadSlashR),
+	/*4295*/ uint16(x86_xArgXmm1),
+	/*4296*/ uint16(x86_xArgXmm2M64),
+	/*4297*/ uint16(x86_xMatch),
+	/*4298*/ uint16(x86_xSetOp), uint16(x86_MINSS),
+	/*4300*/ uint16(x86_xReadSlashR),
+	/*4301*/ uint16(x86_xArgXmm1),
+	/*4302*/ uint16(x86_xArgXmm2M32),
+	/*4303*/ uint16(x86_xMatch),
+	/*4304*/ uint16(x86_xCondPrefix), 4,
+	0xF3, 4332,
+	0xF2, 4326,
+	0x66, 4320,
+	0x0, 4314,
+	/*4314*/ uint16(x86_xSetOp), uint16(x86_DIVPS),
+	/*4316*/ uint16(x86_xReadSlashR),
+	/*4317*/ uint16(x86_xArgXmm1),
+	/*4318*/ uint16(x86_xArgXmm2M128),
+	/*4319*/ uint16(x86_xMatch),
+	/*4320*/ uint16(x86_xSetOp), uint16(x86_DIVPD),
+	/*4322*/ uint16(x86_xReadSlashR),
+	/*4323*/ uint16(x86_xArgXmm1),
+	/*4324*/ uint16(x86_xArgXmm2M128),
+	/*4325*/ uint16(x86_xMatch),
+	/*4326*/ uint16(x86_xSetOp), uint16(x86_DIVSD),
+	/*4328*/ uint16(x86_xReadSlashR),
+	/*4329*/ uint16(x86_xArgXmm1),
+	/*4330*/ uint16(x86_xArgXmm2M64),
+	/*4331*/ uint16(x86_xMatch),
+	/*4332*/ uint16(x86_xSetOp), uint16(x86_DIVSS),
+	/*4334*/ uint16(x86_xReadSlashR),
+	/*4335*/ uint16(x86_xArgXmm1),
+	/*4336*/ uint16(x86_xArgXmm2M32),
+	/*4337*/ uint16(x86_xMatch),
+	/*4338*/ uint16(x86_xCondPrefix), 4,
+	0xF3, 4366,
+	0xF2, 4360,
+	0x66, 4354,
+	0x0, 4348,
+	/*4348*/ uint16(x86_xSetOp), uint16(x86_MAXPS),
+	/*4350*/ uint16(x86_xReadSlashR),
+	/*4351*/ uint16(x86_xArgXmm1),
+	/*4352*/ uint16(x86_xArgXmm2M128),
+	/*4353*/ uint16(x86_xMatch),
+	/*4354*/ uint16(x86_xSetOp), uint16(x86_MAXPD),
+	/*4356*/ uint16(x86_xReadSlashR),
+	/*4357*/ uint16(x86_xArgXmm1),
+	/*4358*/ uint16(x86_xArgXmm2M128),
+	/*4359*/ uint16(x86_xMatch),
+	/*4360*/ uint16(x86_xSetOp), uint16(x86_MAXSD),
+	/*4362*/ uint16(x86_xReadSlashR),
+	/*4363*/ uint16(x86_xArgXmm1),
+	/*4364*/ uint16(x86_xArgXmm2M64),
+	/*4365*/ uint16(x86_xMatch),
+	/*4366*/ uint16(x86_xSetOp), uint16(x86_MAXSS),
+	/*4368*/ uint16(x86_xReadSlashR),
+	/*4369*/ uint16(x86_xArgXmm1),
+	/*4370*/ uint16(x86_xArgXmm2M32),
+	/*4371*/ uint16(x86_xMatch),
+	/*4372*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4384,
+	0x0, 4378,
+	/*4378*/ uint16(x86_xSetOp), uint16(x86_PUNPCKLBW),
+	/*4380*/ uint16(x86_xReadSlashR),
+	/*4381*/ uint16(x86_xArgMm),
+	/*4382*/ uint16(x86_xArgMmM32),
+	/*4383*/ uint16(x86_xMatch),
+	/*4384*/ uint16(x86_xSetOp), uint16(x86_PUNPCKLBW),
+	/*4386*/ uint16(x86_xReadSlashR),
+	/*4387*/ uint16(x86_xArgXmm1),
+	/*4388*/ uint16(x86_xArgXmm2M128),
+	/*4389*/ uint16(x86_xMatch),
+	/*4390*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4402,
+	0x0, 4396,
+	/*4396*/ uint16(x86_xSetOp), uint16(x86_PUNPCKLWD),
+	/*4398*/ uint16(x86_xReadSlashR),
+	/*4399*/ uint16(x86_xArgMm),
+	/*4400*/ uint16(x86_xArgMmM32),
+	/*4401*/ uint16(x86_xMatch),
+	/*4402*/ uint16(x86_xSetOp), uint16(x86_PUNPCKLWD),
+	/*4404*/ uint16(x86_xReadSlashR),
+	/*4405*/ uint16(x86_xArgXmm1),
+	/*4406*/ uint16(x86_xArgXmm2M128),
+	/*4407*/ uint16(x86_xMatch),
+	/*4408*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4420,
+	0x0, 4414,
+	/*4414*/ uint16(x86_xSetOp), uint16(x86_PUNPCKLDQ),
+	/*4416*/ uint16(x86_xReadSlashR),
+	/*4417*/ uint16(x86_xArgMm),
+	/*4418*/ uint16(x86_xArgMmM32),
+	/*4419*/ uint16(x86_xMatch),
+	/*4420*/ uint16(x86_xSetOp), uint16(x86_PUNPCKLDQ),
+	/*4422*/ uint16(x86_xReadSlashR),
+	/*4423*/ uint16(x86_xArgXmm1),
+	/*4424*/ uint16(x86_xArgXmm2M128),
+	/*4425*/ uint16(x86_xMatch),
+	/*4426*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4438,
+	0x0, 4432,
+	/*4432*/ uint16(x86_xSetOp), uint16(x86_PACKSSWB),
+	/*4434*/ uint16(x86_xReadSlashR),
+	/*4435*/ uint16(x86_xArgMm1),
+	/*4436*/ uint16(x86_xArgMm2M64),
+	/*4437*/ uint16(x86_xMatch),
+	/*4438*/ uint16(x86_xSetOp), uint16(x86_PACKSSWB),
+	/*4440*/ uint16(x86_xReadSlashR),
+	/*4441*/ uint16(x86_xArgXmm1),
+	/*4442*/ uint16(x86_xArgXmm2M128),
+	/*4443*/ uint16(x86_xMatch),
+	/*4444*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4456,
+	0x0, 4450,
+	/*4450*/ uint16(x86_xSetOp), uint16(x86_PCMPGTB),
+	/*4452*/ uint16(x86_xReadSlashR),
+	/*4453*/ uint16(x86_xArgMm),
+	/*4454*/ uint16(x86_xArgMmM64),
+	/*4455*/ uint16(x86_xMatch),
+	/*4456*/ uint16(x86_xSetOp), uint16(x86_PCMPGTB),
+	/*4458*/ uint16(x86_xReadSlashR),
+	/*4459*/ uint16(x86_xArgXmm1),
+	/*4460*/ uint16(x86_xArgXmm2M128),
+	/*4461*/ uint16(x86_xMatch),
+	/*4462*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4474,
+	0x0, 4468,
+	/*4468*/ uint16(x86_xSetOp), uint16(x86_PCMPGTW),
+	/*4470*/ uint16(x86_xReadSlashR),
+	/*4471*/ uint16(x86_xArgMm),
+	/*4472*/ uint16(x86_xArgMmM64),
+	/*4473*/ uint16(x86_xMatch),
+	/*4474*/ uint16(x86_xSetOp), uint16(x86_PCMPGTW),
+	/*4476*/ uint16(x86_xReadSlashR),
+	/*4477*/ uint16(x86_xArgXmm1),
+	/*4478*/ uint16(x86_xArgXmm2M128),
+	/*4479*/ uint16(x86_xMatch),
+	/*4480*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4492,
+	0x0, 4486,
+	/*4486*/ uint16(x86_xSetOp), uint16(x86_PCMPGTD),
+	/*4488*/ uint16(x86_xReadSlashR),
+	/*4489*/ uint16(x86_xArgMm),
+	/*4490*/ uint16(x86_xArgMmM64),
+	/*4491*/ uint16(x86_xMatch),
+	/*4492*/ uint16(x86_xSetOp), uint16(x86_PCMPGTD),
+	/*4494*/ uint16(x86_xReadSlashR),
+	/*4495*/ uint16(x86_xArgXmm1),
+	/*4496*/ uint16(x86_xArgXmm2M128),
+	/*4497*/ uint16(x86_xMatch),
+	/*4498*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4510,
+	0x0, 4504,
+	/*4504*/ uint16(x86_xSetOp), uint16(x86_PACKUSWB),
+	/*4506*/ uint16(x86_xReadSlashR),
+	/*4507*/ uint16(x86_xArgMm),
+	/*4508*/ uint16(x86_xArgMmM64),
+	/*4509*/ uint16(x86_xMatch),
+	/*4510*/ uint16(x86_xSetOp), uint16(x86_PACKUSWB),
+	/*4512*/ uint16(x86_xReadSlashR),
+	/*4513*/ uint16(x86_xArgXmm1),
+	/*4514*/ uint16(x86_xArgXmm2M128),
+	/*4515*/ uint16(x86_xMatch),
+	/*4516*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4528,
+	0x0, 4522,
+	/*4522*/ uint16(x86_xSetOp), uint16(x86_PUNPCKHBW),
+	/*4524*/ uint16(x86_xReadSlashR),
+	/*4525*/ uint16(x86_xArgMm),
+	/*4526*/ uint16(x86_xArgMmM64),
+	/*4527*/ uint16(x86_xMatch),
+	/*4528*/ uint16(x86_xSetOp), uint16(x86_PUNPCKHBW),
+	/*4530*/ uint16(x86_xReadSlashR),
+	/*4531*/ uint16(x86_xArgXmm1),
+	/*4532*/ uint16(x86_xArgXmm2M128),
+	/*4533*/ uint16(x86_xMatch),
+	/*4534*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4546,
+	0x0, 4540,
+	/*4540*/ uint16(x86_xSetOp), uint16(x86_PUNPCKHWD),
+	/*4542*/ uint16(x86_xReadSlashR),
+	/*4543*/ uint16(x86_xArgMm),
+	/*4544*/ uint16(x86_xArgMmM64),
+	/*4545*/ uint16(x86_xMatch),
+	/*4546*/ uint16(x86_xSetOp), uint16(x86_PUNPCKHWD),
+	/*4548*/ uint16(x86_xReadSlashR),
+	/*4549*/ uint16(x86_xArgXmm1),
+	/*4550*/ uint16(x86_xArgXmm2M128),
+	/*4551*/ uint16(x86_xMatch),
+	/*4552*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4564,
+	0x0, 4558,
+	/*4558*/ uint16(x86_xSetOp), uint16(x86_PUNPCKHDQ),
+	/*4560*/ uint16(x86_xReadSlashR),
+	/*4561*/ uint16(x86_xArgMm),
+	/*4562*/ uint16(x86_xArgMmM64),
+	/*4563*/ uint16(x86_xMatch),
+	/*4564*/ uint16(x86_xSetOp), uint16(x86_PUNPCKHDQ),
+	/*4566*/ uint16(x86_xReadSlashR),
+	/*4567*/ uint16(x86_xArgXmm1),
+	/*4568*/ uint16(x86_xArgXmm2M128),
+	/*4569*/ uint16(x86_xMatch),
+	/*4570*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4582,
+	0x0, 4576,
+	/*4576*/ uint16(x86_xSetOp), uint16(x86_PACKSSDW),
+	/*4578*/ uint16(x86_xReadSlashR),
+	/*4579*/ uint16(x86_xArgMm1),
+	/*4580*/ uint16(x86_xArgMm2M64),
+	/*4581*/ uint16(x86_xMatch),
+	/*4582*/ uint16(x86_xSetOp), uint16(x86_PACKSSDW),
+	/*4584*/ uint16(x86_xReadSlashR),
+	/*4585*/ uint16(x86_xArgXmm1),
+	/*4586*/ uint16(x86_xArgXmm2M128),
+	/*4587*/ uint16(x86_xMatch),
+	/*4588*/ uint16(x86_xCondPrefix), 1,
+	0x66, 4592,
+	/*4592*/ uint16(x86_xSetOp), uint16(x86_PUNPCKLQDQ),
+	/*4594*/ uint16(x86_xReadSlashR),
+	/*4595*/ uint16(x86_xArgXmm1),
+	/*4596*/ uint16(x86_xArgXmm2M128),
+	/*4597*/ uint16(x86_xMatch),
+	/*4598*/ uint16(x86_xCondPrefix), 1,
+	0x66, 4602,
+	/*4602*/ uint16(x86_xSetOp), uint16(x86_PUNPCKHQDQ),
+	/*4604*/ uint16(x86_xReadSlashR),
+	/*4605*/ uint16(x86_xArgXmm1),
+	/*4606*/ uint16(x86_xArgXmm2M128),
+	/*4607*/ uint16(x86_xMatch),
+	/*4608*/ uint16(x86_xCondIs64), 4611, 4649,
+	/*4611*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4633,
+	0x0, 4617,
+	/*4617*/ uint16(x86_xCondDataSize), 4621, 4627, 0,
+	/*4621*/ uint16(x86_xSetOp), uint16(x86_MOVD),
+	/*4623*/ uint16(x86_xReadSlashR),
+	/*4624*/ uint16(x86_xArgMm),
+	/*4625*/ uint16(x86_xArgRM32),
+	/*4626*/ uint16(x86_xMatch),
+	/*4627*/ uint16(x86_xSetOp), uint16(x86_MOVD),
+	/*4629*/ uint16(x86_xReadSlashR),
+	/*4630*/ uint16(x86_xArgMm),
+	/*4631*/ uint16(x86_xArgRM32),
+	/*4632*/ uint16(x86_xMatch),
+	/*4633*/ uint16(x86_xCondDataSize), 4637, 4643, 0,
+	/*4637*/ uint16(x86_xSetOp), uint16(x86_MOVD),
+	/*4639*/ uint16(x86_xReadSlashR),
+	/*4640*/ uint16(x86_xArgXmm),
+	/*4641*/ uint16(x86_xArgRM32),
+	/*4642*/ uint16(x86_xMatch),
+	/*4643*/ uint16(x86_xSetOp), uint16(x86_MOVD),
+	/*4645*/ uint16(x86_xReadSlashR),
+	/*4646*/ uint16(x86_xArgXmm),
+	/*4647*/ uint16(x86_xArgRM32),
+	/*4648*/ uint16(x86_xMatch),
+	/*4649*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4665,
+	0x0, 4655,
+	/*4655*/ uint16(x86_xCondDataSize), 4621, 4627, 4659,
+	/*4659*/ uint16(x86_xSetOp), uint16(x86_MOVQ),
+	/*4661*/ uint16(x86_xReadSlashR),
+	/*4662*/ uint16(x86_xArgMm),
+	/*4663*/ uint16(x86_xArgRM64),
+	/*4664*/ uint16(x86_xMatch),
+	/*4665*/ uint16(x86_xCondDataSize), 4637, 4643, 4669,
+	/*4669*/ uint16(x86_xSetOp), uint16(x86_MOVQ),
+	/*4671*/ uint16(x86_xReadSlashR),
+	/*4672*/ uint16(x86_xArgXmm),
+	/*4673*/ uint16(x86_xArgRM64),
+	/*4674*/ uint16(x86_xMatch),
+	/*4675*/ uint16(x86_xCondPrefix), 3,
+	0xF3, 4695,
+	0x66, 4689,
+	0x0, 4683,
+	/*4683*/ uint16(x86_xSetOp), uint16(x86_MOVQ),
+	/*4685*/ uint16(x86_xReadSlashR),
+	/*4686*/ uint16(x86_xArgMm),
+	/*4687*/ uint16(x86_xArgMmM64),
+	/*4688*/ uint16(x86_xMatch),
+	/*4689*/ uint16(x86_xSetOp), uint16(x86_MOVDQA),
+	/*4691*/ uint16(x86_xReadSlashR),
+	/*4692*/ uint16(x86_xArgXmm1),
+	/*4693*/ uint16(x86_xArgXmm2M128),
+	/*4694*/ uint16(x86_xMatch),
+	/*4695*/ uint16(x86_xSetOp), uint16(x86_MOVDQU),
+	/*4697*/ uint16(x86_xReadSlashR),
+	/*4698*/ uint16(x86_xArgXmm1),
+	/*4699*/ uint16(x86_xArgXmm2M128),
+	/*4700*/ uint16(x86_xMatch),
+	/*4701*/ uint16(x86_xCondPrefix), 4,
+	0xF3, 4735,
+	0xF2, 4727,
+	0x66, 4719,
+	0x0, 4711,
+	/*4711*/ uint16(x86_xSetOp), uint16(x86_PSHUFW),
+	/*4713*/ uint16(x86_xReadSlashR),
+	/*4714*/ uint16(x86_xReadIb),
+	/*4715*/ uint16(x86_xArgMm1),
+	/*4716*/ uint16(x86_xArgMm2M64),
+	/*4717*/ uint16(x86_xArgImm8u),
+	/*4718*/ uint16(x86_xMatch),
+	/*4719*/ uint16(x86_xSetOp), uint16(x86_PSHUFD),
+	/*4721*/ uint16(x86_xReadSlashR),
+	/*4722*/ uint16(x86_xReadIb),
+	/*4723*/ uint16(x86_xArgXmm1),
+	/*4724*/ uint16(x86_xArgXmm2M128),
+	/*4725*/ uint16(x86_xArgImm8u),
+	/*4726*/ uint16(x86_xMatch),
+	/*4727*/ uint16(x86_xSetOp), uint16(x86_PSHUFLW),
+	/*4729*/ uint16(x86_xReadSlashR),
+	/*4730*/ uint16(x86_xReadIb),
+	/*4731*/ uint16(x86_xArgXmm1),
+	/*4732*/ uint16(x86_xArgXmm2M128),
+	/*4733*/ uint16(x86_xArgImm8u),
+	/*4734*/ uint16(x86_xMatch),
+	/*4735*/ uint16(x86_xSetOp), uint16(x86_PSHUFHW),
+	/*4737*/ uint16(x86_xReadSlashR),
+	/*4738*/ uint16(x86_xReadIb),
+	/*4739*/ uint16(x86_xArgXmm1),
+	/*4740*/ uint16(x86_xArgXmm2M128),
+	/*4741*/ uint16(x86_xArgImm8u),
+	/*4742*/ uint16(x86_xMatch),
+	/*4743*/ uint16(x86_xCondSlashR),
+	0,    // 0
+	0,    // 1
+	4752, // 2
+	0,    // 3
+	4770, // 4
+	0,    // 5
+	4788, // 6
+	0,    // 7
+	/*4752*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4764,
+	0x0, 4758,
+	/*4758*/ uint16(x86_xSetOp), uint16(x86_PSRLW),
+	/*4760*/ uint16(x86_xReadIb),
+	/*4761*/ uint16(x86_xArgMm2),
+	/*4762*/ uint16(x86_xArgImm8u),
+	/*4763*/ uint16(x86_xMatch),
+	/*4764*/ uint16(x86_xSetOp), uint16(x86_PSRLW),
+	/*4766*/ uint16(x86_xReadIb),
+	/*4767*/ uint16(x86_xArgXmm2),
+	/*4768*/ uint16(x86_xArgImm8u),
+	/*4769*/ uint16(x86_xMatch),
+	/*4770*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4782,
+	0x0, 4776,
+	/*4776*/ uint16(x86_xSetOp), uint16(x86_PSRAW),
+	/*4778*/ uint16(x86_xReadIb),
+	/*4779*/ uint16(x86_xArgMm2),
+	/*4780*/ uint16(x86_xArgImm8u),
+	/*4781*/ uint16(x86_xMatch),
+	/*4782*/ uint16(x86_xSetOp), uint16(x86_PSRAW),
+	/*4784*/ uint16(x86_xReadIb),
+	/*4785*/ uint16(x86_xArgXmm2),
+	/*4786*/ uint16(x86_xArgImm8u),
+	/*4787*/ uint16(x86_xMatch),
+	/*4788*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4800,
+	0x0, 4794,
+	/*4794*/ uint16(x86_xSetOp), uint16(x86_PSLLW),
+	/*4796*/ uint16(x86_xReadIb),
+	/*4797*/ uint16(x86_xArgMm2),
+	/*4798*/ uint16(x86_xArgImm8u),
+	/*4799*/ uint16(x86_xMatch),
+	/*4800*/ uint16(x86_xSetOp), uint16(x86_PSLLW),
+	/*4802*/ uint16(x86_xReadIb),
+	/*4803*/ uint16(x86_xArgXmm2),
+	/*4804*/ uint16(x86_xArgImm8u),
+	/*4805*/ uint16(x86_xMatch),
+	/*4806*/ uint16(x86_xCondSlashR),
+	0,    // 0
+	0,    // 1
+	4815, // 2
+	0,    // 3
+	4833, // 4
+	0,    // 5
+	4851, // 6
+	0,    // 7
+	/*4815*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4827,
+	0x0, 4821,
+	/*4821*/ uint16(x86_xSetOp), uint16(x86_PSRLD),
+	/*4823*/ uint16(x86_xReadIb),
+	/*4824*/ uint16(x86_xArgMm2),
+	/*4825*/ uint16(x86_xArgImm8u),
+	/*4826*/ uint16(x86_xMatch),
+	/*4827*/ uint16(x86_xSetOp), uint16(x86_PSRLD),
+	/*4829*/ uint16(x86_xReadIb),
+	/*4830*/ uint16(x86_xArgXmm2),
+	/*4831*/ uint16(x86_xArgImm8u),
+	/*4832*/ uint16(x86_xMatch),
+	/*4833*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4845,
+	0x0, 4839,
+	/*4839*/ uint16(x86_xSetOp), uint16(x86_PSRAD),
+	/*4841*/ uint16(x86_xReadIb),
+	/*4842*/ uint16(x86_xArgMm2),
+	/*4843*/ uint16(x86_xArgImm8u),
+	/*4844*/ uint16(x86_xMatch),
+	/*4845*/ uint16(x86_xSetOp), uint16(x86_PSRAD),
+	/*4847*/ uint16(x86_xReadIb),
+	/*4848*/ uint16(x86_xArgXmm2),
+	/*4849*/ uint16(x86_xArgImm8u),
+	/*4850*/ uint16(x86_xMatch),
+	/*4851*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4863,
+	0x0, 4857,
+	/*4857*/ uint16(x86_xSetOp), uint16(x86_PSLLD),
+	/*4859*/ uint16(x86_xReadIb),
+	/*4860*/ uint16(x86_xArgMm2),
+	/*4861*/ uint16(x86_xArgImm8u),
+	/*4862*/ uint16(x86_xMatch),
+	/*4863*/ uint16(x86_xSetOp), uint16(x86_PSLLD),
+	/*4865*/ uint16(x86_xReadIb),
+	/*4866*/ uint16(x86_xArgXmm2),
+	/*4867*/ uint16(x86_xArgImm8u),
+	/*4868*/ uint16(x86_xMatch),
+	/*4869*/ uint16(x86_xCondSlashR),
+	0,    // 0
+	0,    // 1
+	4878, // 2
+	4896, // 3
+	0,    // 4
+	0,    // 5
+	4906, // 6
+	4924, // 7
+	/*4878*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4890,
+	0x0, 4884,
+	/*4884*/ uint16(x86_xSetOp), uint16(x86_PSRLQ),
+	/*4886*/ uint16(x86_xReadIb),
+	/*4887*/ uint16(x86_xArgMm2),
+	/*4888*/ uint16(x86_xArgImm8u),
+	/*4889*/ uint16(x86_xMatch),
+	/*4890*/ uint16(x86_xSetOp), uint16(x86_PSRLQ),
+	/*4892*/ uint16(x86_xReadIb),
+	/*4893*/ uint16(x86_xArgXmm2),
+	/*4894*/ uint16(x86_xArgImm8u),
+	/*4895*/ uint16(x86_xMatch),
+	/*4896*/ uint16(x86_xCondPrefix), 1,
+	0x66, 4900,
+	/*4900*/ uint16(x86_xSetOp), uint16(x86_PSRLDQ),
+	/*4902*/ uint16(x86_xReadIb),
+	/*4903*/ uint16(x86_xArgXmm2),
+	/*4904*/ uint16(x86_xArgImm8u),
+	/*4905*/ uint16(x86_xMatch),
+	/*4906*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4918,
+	0x0, 4912,
+	/*4912*/ uint16(x86_xSetOp), uint16(x86_PSLLQ),
+	/*4914*/ uint16(x86_xReadIb),
+	/*4915*/ uint16(x86_xArgMm2),
+	/*4916*/ uint16(x86_xArgImm8u),
+	/*4917*/ uint16(x86_xMatch),
+	/*4918*/ uint16(x86_xSetOp), uint16(x86_PSLLQ),
+	/*4920*/ uint16(x86_xReadIb),
+	/*4921*/ uint16(x86_xArgXmm2),
+	/*4922*/ uint16(x86_xArgImm8u),
+	/*4923*/ uint16(x86_xMatch),
+	/*4924*/ uint16(x86_xCondPrefix), 1,
+	0x66, 4928,
+	/*4928*/ uint16(x86_xSetOp), uint16(x86_PSLLDQ),
+	/*4930*/ uint16(x86_xReadIb),
+	/*4931*/ uint16(x86_xArgXmm2),
+	/*4932*/ uint16(x86_xArgImm8u),
+	/*4933*/ uint16(x86_xMatch),
+	/*4934*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4946,
+	0x0, 4940,
+	/*4940*/ uint16(x86_xSetOp), uint16(x86_PCMPEQB),
+	/*4942*/ uint16(x86_xReadSlashR),
+	/*4943*/ uint16(x86_xArgMm),
+	/*4944*/ uint16(x86_xArgMmM64),
+	/*4945*/ uint16(x86_xMatch),
+	/*4946*/ uint16(x86_xSetOp), uint16(x86_PCMPEQB),
+	/*4948*/ uint16(x86_xReadSlashR),
+	/*4949*/ uint16(x86_xArgXmm1),
+	/*4950*/ uint16(x86_xArgXmm2M128),
+	/*4951*/ uint16(x86_xMatch),
+	/*4952*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4964,
+	0x0, 4958,
+	/*4958*/ uint16(x86_xSetOp), uint16(x86_PCMPEQW),
+	/*4960*/ uint16(x86_xReadSlashR),
+	/*4961*/ uint16(x86_xArgMm),
+	/*4962*/ uint16(x86_xArgMmM64),
+	/*4963*/ uint16(x86_xMatch),
+	/*4964*/ uint16(x86_xSetOp), uint16(x86_PCMPEQW),
+	/*4966*/ uint16(x86_xReadSlashR),
+	/*4967*/ uint16(x86_xArgXmm1),
+	/*4968*/ uint16(x86_xArgXmm2M128),
+	/*4969*/ uint16(x86_xMatch),
+	/*4970*/ uint16(x86_xCondPrefix), 2,
+	0x66, 4982,
+	0x0, 4976,
+	/*4976*/ uint16(x86_xSetOp), uint16(x86_PCMPEQD),
+	/*4978*/ uint16(x86_xReadSlashR),
+	/*4979*/ uint16(x86_xArgMm),
+	/*4980*/ uint16(x86_xArgMmM64),
+	/*4981*/ uint16(x86_xMatch),
+	/*4982*/ uint16(x86_xSetOp), uint16(x86_PCMPEQD),
+	/*4984*/ uint16(x86_xReadSlashR),
+	/*4985*/ uint16(x86_xArgXmm1),
+	/*4986*/ uint16(x86_xArgXmm2M128),
+	/*4987*/ uint16(x86_xMatch),
+	/*4988*/ uint16(x86_xSetOp), uint16(x86_EMMS),
+	/*4990*/ uint16(x86_xMatch),
+	/*4991*/ uint16(x86_xCondPrefix), 2,
+	0xF2, 5003,
+	0x66, 4997,
+	/*4997*/ uint16(x86_xSetOp), uint16(x86_HADDPD),
+	/*4999*/ uint16(x86_xReadSlashR),
+	/*5000*/ uint16(x86_xArgXmm1),
+	/*5001*/ uint16(x86_xArgXmm2M128),
+	/*5002*/ uint16(x86_xMatch),
+	/*5003*/ uint16(x86_xSetOp), uint16(x86_HADDPS),
+	/*5005*/ uint16(x86_xReadSlashR),
+	/*5006*/ uint16(x86_xArgXmm1),
+	/*5007*/ uint16(x86_xArgXmm2M128),
+	/*5008*/ uint16(x86_xMatch),
+	/*5009*/ uint16(x86_xCondPrefix), 2,
+	0xF2, 5021,
+	0x66, 5015,
+	/*5015*/ uint16(x86_xSetOp), uint16(x86_HSUBPD),
+	/*5017*/ uint16(x86_xReadSlashR),
+	/*5018*/ uint16(x86_xArgXmm1),
+	/*5019*/ uint16(x86_xArgXmm2M128),
+	/*5020*/ uint16(x86_xMatch),
+	/*5021*/ uint16(x86_xSetOp), uint16(x86_HSUBPS),
+	/*5023*/ uint16(x86_xReadSlashR),
+	/*5024*/ uint16(x86_xArgXmm1),
+	/*5025*/ uint16(x86_xArgXmm2M128),
+	/*5026*/ uint16(x86_xMatch),
+	/*5027*/ uint16(x86_xCondIs64), 5030, 5076,
+	/*5030*/ uint16(x86_xCondPrefix), 3,
+	0xF3, 5070,
+	0x66, 5054,
+	0x0, 5038,
+	/*5038*/ uint16(x86_xCondDataSize), 5042, 5048, 0,
+	/*5042*/ uint16(x86_xSetOp), uint16(x86_MOVD),
+	/*5044*/ uint16(x86_xReadSlashR),
+	/*5045*/ uint16(x86_xArgRM32),
+	/*5046*/ uint16(x86_xArgMm),
+	/*5047*/ uint16(x86_xMatch),
+	/*5048*/ uint16(x86_xSetOp), uint16(x86_MOVD),
+	/*5050*/ uint16(x86_xReadSlashR),
+	/*5051*/ uint16(x86_xArgRM32),
+	/*5052*/ uint16(x86_xArgMm),
+	/*5053*/ uint16(x86_xMatch),
+	/*5054*/ uint16(x86_xCondDataSize), 5058, 5064, 0,
+	/*5058*/ uint16(x86_xSetOp), uint16(x86_MOVD),
+	/*5060*/ uint16(x86_xReadSlashR),
+	/*5061*/ uint16(x86_xArgRM32),
+	/*5062*/ uint16(x86_xArgXmm),
+	/*5063*/ uint16(x86_xMatch),
+	/*5064*/ uint16(x86_xSetOp), uint16(x86_MOVD),
+	/*5066*/ uint16(x86_xReadSlashR),
+	/*5067*/ uint16(x86_xArgRM32),
+	/*5068*/ uint16(x86_xArgXmm),
+	/*5069*/ uint16(x86_xMatch),
+	/*5070*/ uint16(x86_xSetOp), uint16(x86_MOVQ),
+	/*5072*/ uint16(x86_xReadSlashR),
+	/*5073*/ uint16(x86_xArgXmm1),
+	/*5074*/ uint16(x86_xArgXmm2M64),
+	/*5075*/ uint16(x86_xMatch),
+	/*5076*/ uint16(x86_xCondPrefix), 3,
+	0xF3, 5070,
+	0x66, 5094,
+	0x0, 5084,
+	/*5084*/ uint16(x86_xCondDataSize), 5042, 5048, 5088,
+	/*5088*/ uint16(x86_xSetOp), uint16(x86_MOVQ),
+	/*5090*/ uint16(x86_xReadSlashR),
+	/*5091*/ uint16(x86_xArgRM64),
+	/*5092*/ uint16(x86_xArgMm),
+	/*5093*/ uint16(x86_xMatch),
+	/*5094*/ uint16(x86_xCondDataSize), 5058, 5064, 5098,
+	/*5098*/ uint16(x86_xSetOp), uint16(x86_MOVQ),
+	/*5100*/ uint16(x86_xReadSlashR),
+	/*5101*/ uint16(x86_xArgRM64),
+	/*5102*/ uint16(x86_xArgXmm),
+	/*5103*/ uint16(x86_xMatch),
+	/*5104*/ uint16(x86_xCondPrefix), 3,
+	0xF3, 5124,
+	0x66, 5118,
+	0x0, 5112,
+	/*5112*/ uint16(x86_xSetOp), uint16(x86_MOVQ),
+	/*5114*/ uint16(x86_xReadSlashR),
+	/*5115*/ uint16(x86_xArgMmM64),
+	/*5116*/ uint16(x86_xArgMm),
+	/*5117*/ uint16(x86_xMatch),
+	/*5118*/ uint16(x86_xSetOp), uint16(x86_MOVDQA),
+	/*5120*/ uint16(x86_xReadSlashR),
+	/*5121*/ uint16(x86_xArgXmm2M128),
+	/*5122*/ uint16(x86_xArgXmm1),
+	/*5123*/ uint16(x86_xMatch),
+	/*5124*/ uint16(x86_xSetOp), uint16(x86_MOVDQU),
+	/*5126*/ uint16(x86_xReadSlashR),
+	/*5127*/ uint16(x86_xArgXmm2M128),
+	/*5128*/ uint16(x86_xArgXmm1),
+	/*5129*/ uint16(x86_xMatch),
+	/*5130*/ uint16(x86_xCondIs64), 5133, 5147,
+	/*5133*/ uint16(x86_xCondDataSize), 5137, 5142, 0,
+	/*5137*/ uint16(x86_xSetOp), uint16(x86_JO),
+	/*5139*/ uint16(x86_xReadCw),
+	/*5140*/ uint16(x86_xArgRel16),
+	/*5141*/ uint16(x86_xMatch),
+	/*5142*/ uint16(x86_xSetOp), uint16(x86_JO),
+	/*5144*/ uint16(x86_xReadCd),
+	/*5145*/ uint16(x86_xArgRel32),
+	/*5146*/ uint16(x86_xMatch),
+	/*5147*/ uint16(x86_xCondDataSize), 5151, 5142, 5156,
+	/*5151*/ uint16(x86_xSetOp), uint16(x86_JO),
+	/*5153*/ uint16(x86_xReadCd),
+	/*5154*/ uint16(x86_xArgRel32),
+	/*5155*/ uint16(x86_xMatch),
+	/*5156*/ uint16(x86_xSetOp), uint16(x86_JO),
+	/*5158*/ uint16(x86_xReadCd),
+	/*5159*/ uint16(x86_xArgRel32),
+	/*5160*/ uint16(x86_xMatch),
+	/*5161*/ uint16(x86_xCondIs64), 5164, 5178,
+	/*5164*/ uint16(x86_xCondDataSize), 5168, 5173, 0,
+	/*5168*/ uint16(x86_xSetOp), uint16(x86_JNO),
+	/*5170*/ uint16(x86_xReadCw),
+	/*5171*/ uint16(x86_xArgRel16),
+	/*5172*/ uint16(x86_xMatch),
+	/*5173*/ uint16(x86_xSetOp), uint16(x86_JNO),
+	/*5175*/ uint16(x86_xReadCd),
+	/*5176*/ uint16(x86_xArgRel32),
+	/*5177*/ uint16(x86_xMatch),
+	/*5178*/ uint16(x86_xCondDataSize), 5182, 5173, 5187,
+	/*5182*/ uint16(x86_xSetOp), uint16(x86_JNO),
+	/*5184*/ uint16(x86_xReadCd),
+	/*5185*/ uint16(x86_xArgRel32),
+	/*5186*/ uint16(x86_xMatch),
+	/*5187*/ uint16(x86_xSetOp), uint16(x86_JNO),
+	/*5189*/ uint16(x86_xReadCd),
+	/*5190*/ uint16(x86_xArgRel32),
+	/*5191*/ uint16(x86_xMatch),
+	/*5192*/ uint16(x86_xCondIs64), 5195, 5209,
+	/*5195*/ uint16(x86_xCondDataSize), 5199, 5204, 0,
+	/*5199*/ uint16(x86_xSetOp), uint16(x86_JB),
+	/*5201*/ uint16(x86_xReadCw),
+	/*5202*/ uint16(x86_xArgRel16),
+	/*5203*/ uint16(x86_xMatch),
+	/*5204*/ uint16(x86_xSetOp), uint16(x86_JB),
+	/*5206*/ uint16(x86_xReadCd),
+	/*5207*/ uint16(x86_xArgRel32),
+	/*5208*/ uint16(x86_xMatch),
+	/*5209*/ uint16(x86_xCondDataSize), 5213, 5204, 5218,
+	/*5213*/ uint16(x86_xSetOp), uint16(x86_JB),
+	/*5215*/ uint16(x86_xReadCd),
+	/*5216*/ uint16(x86_xArgRel32),
+	/*5217*/ uint16(x86_xMatch),
+	/*5218*/ uint16(x86_xSetOp), uint16(x86_JB),
+	/*5220*/ uint16(x86_xReadCd),
+	/*5221*/ uint16(x86_xArgRel32),
+	/*5222*/ uint16(x86_xMatch),
+	/*5223*/ uint16(x86_xCondIs64), 5226, 5240,
+	/*5226*/ uint16(x86_xCondDataSize), 5230, 5235, 0,
+	/*5230*/ uint16(x86_xSetOp), uint16(x86_JAE),
+	/*5232*/ uint16(x86_xReadCw),
+	/*5233*/ uint16(x86_xArgRel16),
+	/*5234*/ uint16(x86_xMatch),
+	/*5235*/ uint16(x86_xSetOp), uint16(x86_JAE),
+	/*5237*/ uint16(x86_xReadCd),
+	/*5238*/ uint16(x86_xArgRel32),
+	/*5239*/ uint16(x86_xMatch),
+	/*5240*/ uint16(x86_xCondDataSize), 5244, 5235, 5249,
+	/*5244*/ uint16(x86_xSetOp), uint16(x86_JAE),
+	/*5246*/ uint16(x86_xReadCd),
+	/*5247*/ uint16(x86_xArgRel32),
+	/*5248*/ uint16(x86_xMatch),
+	/*5249*/ uint16(x86_xSetOp), uint16(x86_JAE),
+	/*5251*/ uint16(x86_xReadCd),
+	/*5252*/ uint16(x86_xArgRel32),
+	/*5253*/ uint16(x86_xMatch),
+	/*5254*/ uint16(x86_xCondIs64), 5257, 5271,
+	/*5257*/ uint16(x86_xCondDataSize), 5261, 5266, 0,
+	/*5261*/ uint16(x86_xSetOp), uint16(x86_JE),
+	/*5263*/ uint16(x86_xReadCw),
+	/*5264*/ uint16(x86_xArgRel16),
+	/*5265*/ uint16(x86_xMatch),
+	/*5266*/ uint16(x86_xSetOp), uint16(x86_JE),
+	/*5268*/ uint16(x86_xReadCd),
+	/*5269*/ uint16(x86_xArgRel32),
+	/*5270*/ uint16(x86_xMatch),
+	/*5271*/ uint16(x86_xCondDataSize), 5275, 5266, 5280,
+	/*5275*/ uint16(x86_xSetOp), uint16(x86_JE),
+	/*5277*/ uint16(x86_xReadCd),
+	/*5278*/ uint16(x86_xArgRel32),
+	/*5279*/ uint16(x86_xMatch),
+	/*5280*/ uint16(x86_xSetOp), uint16(x86_JE),
+	/*5282*/ uint16(x86_xReadCd),
+	/*5283*/ uint16(x86_xArgRel32),
+	/*5284*/ uint16(x86_xMatch),
+	/*5285*/ uint16(x86_xCondIs64), 5288, 5302,
+	/*5288*/ uint16(x86_xCondDataSize), 5292, 5297, 0,
+	/*5292*/ uint16(x86_xSetOp), uint16(x86_JNE),
+	/*5294*/ uint16(x86_xReadCw),
+	/*5295*/ uint16(x86_xArgRel16),
+	/*5296*/ uint16(x86_xMatch),
+	/*5297*/ uint16(x86_xSetOp), uint16(x86_JNE),
+	/*5299*/ uint16(x86_xReadCd),
+	/*5300*/ uint16(x86_xArgRel32),
+	/*5301*/ uint16(x86_xMatch),
+	/*5302*/ uint16(x86_xCondDataSize), 5306, 5297, 5311,
+	/*5306*/ uint16(x86_xSetOp), uint16(x86_JNE),
+	/*5308*/ uint16(x86_xReadCd),
+	/*5309*/ uint16(x86_xArgRel32),
+	/*5310*/ uint16(x86_xMatch),
+	/*5311*/ uint16(x86_xSetOp), uint16(x86_JNE),
+	/*5313*/ uint16(x86_xReadCd),
+	/*5314*/ uint16(x86_xArgRel32),
+	/*5315*/ uint16(x86_xMatch),
+	/*5316*/ uint16(x86_xCondIs64), 5319, 5333,
+	/*5319*/ uint16(x86_xCondDataSize), 5323, 5328, 0,
+	/*5323*/ uint16(x86_xSetOp), uint16(x86_JBE),
+	/*5325*/ uint16(x86_xReadCw),
+	/*5326*/ uint16(x86_xArgRel16),
+	/*5327*/ uint16(x86_xMatch),
+	/*5328*/ uint16(x86_xSetOp), uint16(x86_JBE),
+	/*5330*/ uint16(x86_xReadCd),
+	/*5331*/ uint16(x86_xArgRel32),
+	/*5332*/ uint16(x86_xMatch),
+	/*5333*/ uint16(x86_xCondDataSize), 5337, 5328, 5342,
+	/*5337*/ uint16(x86_xSetOp), uint16(x86_JBE),
+	/*5339*/ uint16(x86_xReadCd),
+	/*5340*/ uint16(x86_xArgRel32),
+	/*5341*/ uint16(x86_xMatch),
+	/*5342*/ uint16(x86_xSetOp), uint16(x86_JBE),
+	/*5344*/ uint16(x86_xReadCd),
+	/*5345*/ uint16(x86_xArgRel32),
+	/*5346*/ uint16(x86_xMatch),
+	/*5347*/ uint16(x86_xCondIs64), 5350, 5364,
+	/*5350*/ uint16(x86_xCondDataSize), 5354, 5359, 0,
+	/*5354*/ uint16(x86_xSetOp), uint16(x86_JA),
+	/*5356*/ uint16(x86_xReadCw),
+	/*5357*/ uint16(x86_xArgRel16),
+	/*5358*/ uint16(x86_xMatch),
+	/*5359*/ uint16(x86_xSetOp), uint16(x86_JA),
+	/*5361*/ uint16(x86_xReadCd),
+	/*5362*/ uint16(x86_xArgRel32),
+	/*5363*/ uint16(x86_xMatch),
+	/*5364*/ uint16(x86_xCondDataSize), 5368, 5359, 5373,
+	/*5368*/ uint16(x86_xSetOp), uint16(x86_JA),
+	/*5370*/ uint16(x86_xReadCd),
+	/*5371*/ uint16(x86_xArgRel32),
+	/*5372*/ uint16(x86_xMatch),
+	/*5373*/ uint16(x86_xSetOp), uint16(x86_JA),
+	/*5375*/ uint16(x86_xReadCd),
+	/*5376*/ uint16(x86_xArgRel32),
+	/*5377*/ uint16(x86_xMatch),
+	/*5378*/ uint16(x86_xCondIs64), 5381, 5395,
+	/*5381*/ uint16(x86_xCondDataSize), 5385, 5390, 0,
+	/*5385*/ uint16(x86_xSetOp), uint16(x86_JS),
+	/*5387*/ uint16(x86_xReadCw),
+	/*5388*/ uint16(x86_xArgRel16),
+	/*5389*/ uint16(x86_xMatch),
+	/*5390*/ uint16(x86_xSetOp), uint16(x86_JS),
+	/*5392*/ uint16(x86_xReadCd),
+	/*5393*/ uint16(x86_xArgRel32),
+	/*5394*/ uint16(x86_xMatch),
+	/*5395*/ uint16(x86_xCondDataSize), 5399, 5390, 5404,
+	/*5399*/ uint16(x86_xSetOp), uint16(x86_JS),
+	/*5401*/ uint16(x86_xReadCd),
+	/*5402*/ uint16(x86_xArgRel32),
+	/*5403*/ uint16(x86_xMatch),
+	/*5404*/ uint16(x86_xSetOp), uint16(x86_JS),
+	/*5406*/ uint16(x86_xReadCd),
+	/*5407*/ uint16(x86_xArgRel32),
+	/*5408*/ uint16(x86_xMatch),
+	/*5409*/ uint16(x86_xCondIs64), 5412, 5426,
+	/*5412*/ uint16(x86_xCondDataSize), 5416, 5421, 0,
+	/*5416*/ uint16(x86_xSetOp), uint16(x86_JNS),
+	/*5418*/ uint16(x86_xReadCw),
+	/*5419*/ uint16(x86_xArgRel16),
+	/*5420*/ uint16(x86_xMatch),
+	/*5421*/ uint16(x86_xSetOp), uint16(x86_JNS),
+	/*5423*/ uint16(x86_xReadCd),
+	/*5424*/ uint16(x86_xArgRel32),
+	/*5425*/ uint16(x86_xMatch),
+	/*5426*/ uint16(x86_xCondDataSize), 5430, 5421, 5435,
+	/*5430*/ uint16(x86_xSetOp), uint16(x86_JNS),
+	/*5432*/ uint16(x86_xReadCd),
+	/*5433*/ uint16(x86_xArgRel32),
+	/*5434*/ uint16(x86_xMatch),
+	/*5435*/ uint16(x86_xSetOp), uint16(x86_JNS),
+	/*5437*/ uint16(x86_xReadCd),
+	/*5438*/ uint16(x86_xArgRel32),
+	/*5439*/ uint16(x86_xMatch),
+	/*5440*/ uint16(x86_xCondIs64), 5443, 5457,
+	/*5443*/ uint16(x86_xCondDataSize), 5447, 5452, 0,
+	/*5447*/ uint16(x86_xSetOp), uint16(x86_JP),
+	/*5449*/ uint16(x86_xReadCw),
+	/*5450*/ uint16(x86_xArgRel16),
+	/*5451*/ uint16(x86_xMatch),
+	/*5452*/ uint16(x86_xSetOp), uint16(x86_JP),
+	/*5454*/ uint16(x86_xReadCd),
+	/*5455*/ uint16(x86_xArgRel32),
+	/*5456*/ uint16(x86_xMatch),
+	/*5457*/ uint16(x86_xCondDataSize), 5461, 5452, 5466,
+	/*5461*/ uint16(x86_xSetOp), uint16(x86_JP),
+	/*5463*/ uint16(x86_xReadCd),
+	/*5464*/ uint16(x86_xArgRel32),
+	/*5465*/ uint16(x86_xMatch),
+	/*5466*/ uint16(x86_xSetOp), uint16(x86_JP),
+	/*5468*/ uint16(x86_xReadCd),
+	/*5469*/ uint16(x86_xArgRel32),
+	/*5470*/ uint16(x86_xMatch),
+	/*5471*/ uint16(x86_xCondIs64), 5474, 5488,
+	/*5474*/ uint16(x86_xCondDataSize), 5478, 5483, 0,
+	/*5478*/ uint16(x86_xSetOp), uint16(x86_JNP),
+	/*5480*/ uint16(x86_xReadCw),
+	/*5481*/ uint16(x86_xArgRel16),
+	/*5482*/ uint16(x86_xMatch),
+	/*5483*/ uint16(x86_xSetOp), uint16(x86_JNP),
+	/*5485*/ uint16(x86_xReadCd),
+	/*5486*/ uint16(x86_xArgRel32),
+	/*5487*/ uint16(x86_xMatch),
+	/*5488*/ uint16(x86_xCondDataSize), 5492, 5483, 5497,
+	/*5492*/ uint16(x86_xSetOp), uint16(x86_JNP),
+	/*5494*/ uint16(x86_xReadCd),
+	/*5495*/ uint16(x86_xArgRel32),
+	/*5496*/ uint16(x86_xMatch),
+	/*5497*/ uint16(x86_xSetOp), uint16(x86_JNP),
+	/*5499*/ uint16(x86_xReadCd),
+	/*5500*/ uint16(x86_xArgRel32),
+	/*5501*/ uint16(x86_xMatch),
+	/*5502*/ uint16(x86_xCondIs64), 5505, 5519,
+	/*5505*/ uint16(x86_xCondDataSize), 5509, 5514, 0,
+	/*5509*/ uint16(x86_xSetOp), uint16(x86_JL),
+	/*5511*/ uint16(x86_xReadCw),
+	/*5512*/ uint16(x86_xArgRel16),
+	/*5513*/ uint16(x86_xMatch),
+	/*5514*/ uint16(x86_xSetOp), uint16(x86_JL),
+	/*5516*/ uint16(x86_xReadCd),
+	/*5517*/ uint16(x86_xArgRel32),
+	/*5518*/ uint16(x86_xMatch),
+	/*5519*/ uint16(x86_xCondDataSize), 5523, 5514, 5528,
+	/*5523*/ uint16(x86_xSetOp), uint16(x86_JL),
+	/*5525*/ uint16(x86_xReadCd),
+	/*5526*/ uint16(x86_xArgRel32),
+	/*5527*/ uint16(x86_xMatch),
+	/*5528*/ uint16(x86_xSetOp), uint16(x86_JL),
+	/*5530*/ uint16(x86_xReadCd),
+	/*5531*/ uint16(x86_xArgRel32),
+	/*5532*/ uint16(x86_xMatch),
+	/*5533*/ uint16(x86_xCondIs64), 5536, 5550,
+	/*5536*/ uint16(x86_xCondDataSize), 5540, 5545, 0,
+	/*5540*/ uint16(x86_xSetOp), uint16(x86_JGE),
+	/*5542*/ uint16(x86_xReadCw),
+	/*5543*/ uint16(x86_xArgRel16),
+	/*5544*/ uint16(x86_xMatch),
+	/*5545*/ uint16(x86_xSetOp), uint16(x86_JGE),
+	/*5547*/ uint16(x86_xReadCd),
+	/*5548*/ uint16(x86_xArgRel32),
+	/*5549*/ uint16(x86_xMatch),
+	/*5550*/ uint16(x86_xCondDataSize), 5554, 5545, 5559,
+	/*5554*/ uint16(x86_xSetOp), uint16(x86_JGE),
+	/*5556*/ uint16(x86_xReadCd),
+	/*5557*/ uint16(x86_xArgRel32),
+	/*5558*/ uint16(x86_xMatch),
+	/*5559*/ uint16(x86_xSetOp), uint16(x86_JGE),
+	/*5561*/ uint16(x86_xReadCd),
+	/*5562*/ uint16(x86_xArgRel32),
+	/*5563*/ uint16(x86_xMatch),
+	/*5564*/ uint16(x86_xCondIs64), 5567, 5581,
+	/*5567*/ uint16(x86_xCondDataSize), 5571, 5576, 0,
+	/*5571*/ uint16(x86_xSetOp), uint16(x86_JLE),
+	/*5573*/ uint16(x86_xReadCw),
+	/*5574*/ uint16(x86_xArgRel16),
+	/*5575*/ uint16(x86_xMatch),
+	/*5576*/ uint16(x86_xSetOp), uint16(x86_JLE),
+	/*5578*/ uint16(x86_xReadCd),
+	/*5579*/ uint16(x86_xArgRel32),
+	/*5580*/ uint16(x86_xMatch),
+	/*5581*/ uint16(x86_xCondDataSize), 5585, 5576, 5590,
+	/*5585*/ uint16(x86_xSetOp), uint16(x86_JLE),
+	/*5587*/ uint16(x86_xReadCd),
+	/*5588*/ uint16(x86_xArgRel32),
+	/*5589*/ uint16(x86_xMatch),
+	/*5590*/ uint16(x86_xSetOp), uint16(x86_JLE),
+	/*5592*/ uint16(x86_xReadCd),
+	/*5593*/ uint16(x86_xArgRel32),
+	/*5594*/ uint16(x86_xMatch),
+	/*5595*/ uint16(x86_xCondIs64), 5598, 5612,
+	/*5598*/ uint16(x86_xCondDataSize), 5602, 5607, 0,
+	/*5602*/ uint16(x86_xSetOp), uint16(x86_JG),
+	/*5604*/ uint16(x86_xReadCw),
+	/*5605*/ uint16(x86_xArgRel16),
+	/*5606*/ uint16(x86_xMatch),
+	/*5607*/ uint16(x86_xSetOp), uint16(x86_JG),
+	/*5609*/ uint16(x86_xReadCd),
+	/*5610*/ uint16(x86_xArgRel32),
+	/*5611*/ uint16(x86_xMatch),
+	/*5612*/ uint16(x86_xCondDataSize), 5616, 5607, 5621,
+	/*5616*/ uint16(x86_xSetOp), uint16(x86_JG),
+	/*5618*/ uint16(x86_xReadCd),
+	/*5619*/ uint16(x86_xArgRel32),
+	/*5620*/ uint16(x86_xMatch),
+	/*5621*/ uint16(x86_xSetOp), uint16(x86_JG),
+	/*5623*/ uint16(x86_xReadCd),
+	/*5624*/ uint16(x86_xArgRel32),
+	/*5625*/ uint16(x86_xMatch),
+	/*5626*/ uint16(x86_xSetOp), uint16(x86_SETO),
+	/*5628*/ uint16(x86_xReadSlashR),
+	/*5629*/ uint16(x86_xArgRM8),
+	/*5630*/ uint16(x86_xMatch),
+	/*5631*/ uint16(x86_xSetOp), uint16(x86_SETNO),
+	/*5633*/ uint16(x86_xReadSlashR),
+	/*5634*/ uint16(x86_xArgRM8),
+	/*5635*/ uint16(x86_xMatch),
+	/*5636*/ uint16(x86_xSetOp), uint16(x86_SETB),
+	/*5638*/ uint16(x86_xReadSlashR),
+	/*5639*/ uint16(x86_xArgRM8),
+	/*5640*/ uint16(x86_xMatch),
+	/*5641*/ uint16(x86_xSetOp), uint16(x86_SETAE),
+	/*5643*/ uint16(x86_xReadSlashR),
+	/*5644*/ uint16(x86_xArgRM8),
+	/*5645*/ uint16(x86_xMatch),
+	/*5646*/ uint16(x86_xSetOp), uint16(x86_SETE),
+	/*5648*/ uint16(x86_xReadSlashR),
+	/*5649*/ uint16(x86_xArgRM8),
+	/*5650*/ uint16(x86_xMatch),
+	/*5651*/ uint16(x86_xSetOp), uint16(x86_SETNE),
+	/*5653*/ uint16(x86_xReadSlashR),
+	/*5654*/ uint16(x86_xArgRM8),
+	/*5655*/ uint16(x86_xMatch),
+	/*5656*/ uint16(x86_xSetOp), uint16(x86_SETBE),
+	/*5658*/ uint16(x86_xReadSlashR),
+	/*5659*/ uint16(x86_xArgRM8),
+	/*5660*/ uint16(x86_xMatch),
+	/*5661*/ uint16(x86_xSetOp), uint16(x86_SETA),
+	/*5663*/ uint16(x86_xReadSlashR),
+	/*5664*/ uint16(x86_xArgRM8),
+	/*5665*/ uint16(x86_xMatch),
+	/*5666*/ uint16(x86_xSetOp), uint16(x86_SETS),
+	/*5668*/ uint16(x86_xReadSlashR),
+	/*5669*/ uint16(x86_xArgRM8),
+	/*5670*/ uint16(x86_xMatch),
+	/*5671*/ uint16(x86_xSetOp), uint16(x86_SETNS),
+	/*5673*/ uint16(x86_xReadSlashR),
+	/*5674*/ uint16(x86_xArgRM8),
+	/*5675*/ uint16(x86_xMatch),
+	/*5676*/ uint16(x86_xSetOp), uint16(x86_SETP),
+	/*5678*/ uint16(x86_xReadSlashR),
+	/*5679*/ uint16(x86_xArgRM8),
+	/*5680*/ uint16(x86_xMatch),
+	/*5681*/ uint16(x86_xSetOp), uint16(x86_SETNP),
+	/*5683*/ uint16(x86_xReadSlashR),
+	/*5684*/ uint16(x86_xArgRM8),
+	/*5685*/ uint16(x86_xMatch),
+	/*5686*/ uint16(x86_xSetOp), uint16(x86_SETL),
+	/*5688*/ uint16(x86_xReadSlashR),
+	/*5689*/ uint16(x86_xArgRM8),
+	/*5690*/ uint16(x86_xMatch),
+	/*5691*/ uint16(x86_xSetOp), uint16(x86_SETGE),
+	/*5693*/ uint16(x86_xReadSlashR),
+	/*5694*/ uint16(x86_xArgRM8),
+	/*5695*/ uint16(x86_xMatch),
+	/*5696*/ uint16(x86_xSetOp), uint16(x86_SETLE),
+	/*5698*/ uint16(x86_xReadSlashR),
+	/*5699*/ uint16(x86_xArgRM8),
+	/*5700*/ uint16(x86_xMatch),
+	/*5701*/ uint16(x86_xSetOp), uint16(x86_SETG),
+	/*5703*/ uint16(x86_xReadSlashR),
+	/*5704*/ uint16(x86_xArgRM8),
+	/*5705*/ uint16(x86_xMatch),
+	/*5706*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+	/*5708*/ uint16(x86_xArgFS),
+	/*5709*/ uint16(x86_xMatch),
+	/*5710*/ uint16(x86_xCondIs64), 5713, 5725,
+	/*5713*/ uint16(x86_xCondDataSize), 5717, 5721, 0,
+	/*5717*/ uint16(x86_xSetOp), uint16(x86_POP),
+	/*5719*/ uint16(x86_xArgFS),
+	/*5720*/ uint16(x86_xMatch),
+	/*5721*/ uint16(x86_xSetOp), uint16(x86_POP),
+	/*5723*/ uint16(x86_xArgFS),
+	/*5724*/ uint16(x86_xMatch),
+	/*5725*/ uint16(x86_xCondDataSize), 5717, 5729, 5733,
+	/*5729*/ uint16(x86_xSetOp), uint16(x86_POP),
+	/*5731*/ uint16(x86_xArgFS),
+	/*5732*/ uint16(x86_xMatch),
+	/*5733*/ uint16(x86_xSetOp), uint16(x86_POP),
+	/*5735*/ uint16(x86_xArgFS),
+	/*5736*/ uint16(x86_xMatch),
+	/*5737*/ uint16(x86_xSetOp), uint16(x86_CPUID),
+	/*5739*/ uint16(x86_xMatch),
+	/*5740*/ uint16(x86_xCondIs64), 5743, 5759,
+	/*5743*/ uint16(x86_xCondDataSize), 5747, 5753, 0,
+	/*5747*/ uint16(x86_xSetOp), uint16(x86_BT),
+	/*5749*/ uint16(x86_xReadSlashR),
+	/*5750*/ uint16(x86_xArgRM16),
+	/*5751*/ uint16(x86_xArgR16),
+	/*5752*/ uint16(x86_xMatch),
+	/*5753*/ uint16(x86_xSetOp), uint16(x86_BT),
+	/*5755*/ uint16(x86_xReadSlashR),
+	/*5756*/ uint16(x86_xArgRM32),
+	/*5757*/ uint16(x86_xArgR32),
+	/*5758*/ uint16(x86_xMatch),
+	/*5759*/ uint16(x86_xCondDataSize), 5747, 5753, 5763,
+	/*5763*/ uint16(x86_xSetOp), uint16(x86_BT),
+	/*5765*/ uint16(x86_xReadSlashR),
+	/*5766*/ uint16(x86_xArgRM64),
+	/*5767*/ uint16(x86_xArgR64),
+	/*5768*/ uint16(x86_xMatch),
+	/*5769*/ uint16(x86_xCondIs64), 5772, 5792,
+	/*5772*/ uint16(x86_xCondDataSize), 5776, 5784, 0,
+	/*5776*/ uint16(x86_xSetOp), uint16(x86_SHLD),
+	/*5778*/ uint16(x86_xReadSlashR),
+	/*5779*/ uint16(x86_xReadIb),
+	/*5780*/ uint16(x86_xArgRM16),
+	/*5781*/ uint16(x86_xArgR16),
+	/*5782*/ uint16(x86_xArgImm8u),
+	/*5783*/ uint16(x86_xMatch),
+	/*5784*/ uint16(x86_xSetOp), uint16(x86_SHLD),
+	/*5786*/ uint16(x86_xReadSlashR),
+	/*5787*/ uint16(x86_xReadIb),
+	/*5788*/ uint16(x86_xArgRM32),
+	/*5789*/ uint16(x86_xArgR32),
+	/*5790*/ uint16(x86_xArgImm8u),
+	/*5791*/ uint16(x86_xMatch),
+	/*5792*/ uint16(x86_xCondDataSize), 5776, 5784, 5796,
+	/*5796*/ uint16(x86_xSetOp), uint16(x86_SHLD),
+	/*5798*/ uint16(x86_xReadSlashR),
+	/*5799*/ uint16(x86_xReadIb),
+	/*5800*/ uint16(x86_xArgRM64),
+	/*5801*/ uint16(x86_xArgR64),
+	/*5802*/ uint16(x86_xArgImm8u),
+	/*5803*/ uint16(x86_xMatch),
+	/*5804*/ uint16(x86_xCondIs64), 5807, 5825,
+	/*5807*/ uint16(x86_xCondDataSize), 5811, 5818, 0,
+	/*5811*/ uint16(x86_xSetOp), uint16(x86_SHLD),
+	/*5813*/ uint16(x86_xReadSlashR),
+	/*5814*/ uint16(x86_xArgRM16),
+	/*5815*/ uint16(x86_xArgR16),
+	/*5816*/ uint16(x86_xArgCL),
+	/*5817*/ uint16(x86_xMatch),
+	/*5818*/ uint16(x86_xSetOp), uint16(x86_SHLD),
+	/*5820*/ uint16(x86_xReadSlashR),
+	/*5821*/ uint16(x86_xArgRM32),
+	/*5822*/ uint16(x86_xArgR32),
+	/*5823*/ uint16(x86_xArgCL),
+	/*5824*/ uint16(x86_xMatch),
+	/*5825*/ uint16(x86_xCondDataSize), 5811, 5818, 5829,
+	/*5829*/ uint16(x86_xSetOp), uint16(x86_SHLD),
+	/*5831*/ uint16(x86_xReadSlashR),
+	/*5832*/ uint16(x86_xArgRM64),
+	/*5833*/ uint16(x86_xArgR64),
+	/*5834*/ uint16(x86_xArgCL),
+	/*5835*/ uint16(x86_xMatch),
+	/*5836*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+	/*5838*/ uint16(x86_xArgGS),
+	/*5839*/ uint16(x86_xMatch),
+	/*5840*/ uint16(x86_xCondIs64), 5843, 5855,
+	/*5843*/ uint16(x86_xCondDataSize), 5847, 5851, 0,
+	/*5847*/ uint16(x86_xSetOp), uint16(x86_POP),
+	/*5849*/ uint16(x86_xArgGS),
+	/*5850*/ uint16(x86_xMatch),
+	/*5851*/ uint16(x86_xSetOp), uint16(x86_POP),
+	/*5853*/ uint16(x86_xArgGS),
+	/*5854*/ uint16(x86_xMatch),
+	/*5855*/ uint16(x86_xCondDataSize), 5847, 5859, 5863,
+	/*5859*/ uint16(x86_xSetOp), uint16(x86_POP),
+	/*5861*/ uint16(x86_xArgGS),
+	/*5862*/ uint16(x86_xMatch),
+	/*5863*/ uint16(x86_xSetOp), uint16(x86_POP),
+	/*5865*/ uint16(x86_xArgGS),
+	/*5866*/ uint16(x86_xMatch),
+	/*5867*/ uint16(x86_xSetOp), uint16(x86_RSM),
+	/*5869*/ uint16(x86_xMatch),
+	/*5870*/ uint16(x86_xCondIs64), 5873, 5889,
+	/*5873*/ uint16(x86_xCondDataSize), 5877, 5883, 0,
+	/*5877*/ uint16(x86_xSetOp), uint16(x86_BTS),
+	/*5879*/ uint16(x86_xReadSlashR),
+	/*5880*/ uint16(x86_xArgRM16),
+	/*5881*/ uint16(x86_xArgR16),
+	/*5882*/ uint16(x86_xMatch),
+	/*5883*/ uint16(x86_xSetOp), uint16(x86_BTS),
+	/*5885*/ uint16(x86_xReadSlashR),
+	/*5886*/ uint16(x86_xArgRM32),
+	/*5887*/ uint16(x86_xArgR32),
+	/*5888*/ uint16(x86_xMatch),
+	/*5889*/ uint16(x86_xCondDataSize), 5877, 5883, 5893,
+	/*5893*/ uint16(x86_xSetOp), uint16(x86_BTS),
+	/*5895*/ uint16(x86_xReadSlashR),
+	/*5896*/ uint16(x86_xArgRM64),
+	/*5897*/ uint16(x86_xArgR64),
+	/*5898*/ uint16(x86_xMatch),
+	/*5899*/ uint16(x86_xCondIs64), 5902, 5922,
+	/*5902*/ uint16(x86_xCondDataSize), 5906, 5914, 0,
+	/*5906*/ uint16(x86_xSetOp), uint16(x86_SHRD),
+	/*5908*/ uint16(x86_xReadSlashR),
+	/*5909*/ uint16(x86_xReadIb),
+	/*5910*/ uint16(x86_xArgRM16),
+	/*5911*/ uint16(x86_xArgR16),
+	/*5912*/ uint16(x86_xArgImm8u),
+	/*5913*/ uint16(x86_xMatch),
+	/*5914*/ uint16(x86_xSetOp), uint16(x86_SHRD),
+	/*5916*/ uint16(x86_xReadSlashR),
+	/*5917*/ uint16(x86_xReadIb),
+	/*5918*/ uint16(x86_xArgRM32),
+	/*5919*/ uint16(x86_xArgR32),
+	/*5920*/ uint16(x86_xArgImm8u),
+	/*5921*/ uint16(x86_xMatch),
+	/*5922*/ uint16(x86_xCondDataSize), 5906, 5914, 5926,
+	/*5926*/ uint16(x86_xSetOp), uint16(x86_SHRD),
+	/*5928*/ uint16(x86_xReadSlashR),
+	/*5929*/ uint16(x86_xReadIb),
+	/*5930*/ uint16(x86_xArgRM64),
+	/*5931*/ uint16(x86_xArgR64),
+	/*5932*/ uint16(x86_xArgImm8u),
+	/*5933*/ uint16(x86_xMatch),
+	/*5934*/ uint16(x86_xCondIs64), 5937, 5955,
+	/*5937*/ uint16(x86_xCondDataSize), 5941, 5948, 0,
+	/*5941*/ uint16(x86_xSetOp), uint16(x86_SHRD),
+	/*5943*/ uint16(x86_xReadSlashR),
+	/*5944*/ uint16(x86_xArgRM16),
+	/*5945*/ uint16(x86_xArgR16),
+	/*5946*/ uint16(x86_xArgCL),
+	/*5947*/ uint16(x86_xMatch),
+	/*5948*/ uint16(x86_xSetOp), uint16(x86_SHRD),
+	/*5950*/ uint16(x86_xReadSlashR),
+	/*5951*/ uint16(x86_xArgRM32),
+	/*5952*/ uint16(x86_xArgR32),
+	/*5953*/ uint16(x86_xArgCL),
+	/*5954*/ uint16(x86_xMatch),
+	/*5955*/ uint16(x86_xCondDataSize), 5941, 5948, 5959,
+	/*5959*/ uint16(x86_xSetOp), uint16(x86_SHRD),
+	/*5961*/ uint16(x86_xReadSlashR),
+	/*5962*/ uint16(x86_xArgRM64),
+	/*5963*/ uint16(x86_xArgR64),
+	/*5964*/ uint16(x86_xArgCL),
+	/*5965*/ uint16(x86_xMatch),
+	/*5966*/ uint16(x86_xCondByte), 3,
+	0xE8, 6215,
+	0xF0, 6218,
+	0xF8, 6221,
+	/*5974*/ uint16(x86_xCondSlashR),
+	5983, // 0
+	6037, // 1
+	6091, // 2
+	6120, // 3
+	6149, // 4
+	6172, // 5
+	6195, // 6
+	6211, // 7
+	/*5983*/ uint16(x86_xCondIs64), 5986, 5998,
+	/*5986*/ uint16(x86_xCondDataSize), 5990, 5994, 0,
+	/*5990*/ uint16(x86_xSetOp), uint16(x86_FXSAVE),
+	/*5992*/ uint16(x86_xArgM512byte),
+	/*5993*/ uint16(x86_xMatch),
+	/*5994*/ uint16(x86_xSetOp), uint16(x86_FXSAVE),
+	/*5996*/ uint16(x86_xArgM512byte),
+	/*5997*/ uint16(x86_xMatch),
+	/*5998*/ uint16(x86_xCondPrefix), 2,
+	0xF3, 6012,
+	0x0, 6004,
+	/*6004*/ uint16(x86_xCondDataSize), 5990, 5994, 6008,
+	/*6008*/ uint16(x86_xSetOp), uint16(x86_FXSAVE64),
+	/*6010*/ uint16(x86_xArgM512byte),
+	/*6011*/ uint16(x86_xMatch),
+	/*6012*/ uint16(x86_xCondDataSize), 6016, 6023, 6030,
+	/*6016*/ uint16(x86_xCondIsMem), 6019, 0,
+	/*6019*/ uint16(x86_xSetOp), uint16(x86_RDFSBASE),
+	/*6021*/ uint16(x86_xArgRM32),
+	/*6022*/ uint16(x86_xMatch),
+	/*6023*/ uint16(x86_xCondIsMem), 6026, 0,
+	/*6026*/ uint16(x86_xSetOp), uint16(x86_RDFSBASE),
+	/*6028*/ uint16(x86_xArgRM32),
+	/*6029*/ uint16(x86_xMatch),
+	/*6030*/ uint16(x86_xCondIsMem), 6033, 0,
+	/*6033*/ uint16(x86_xSetOp), uint16(x86_RDFSBASE),
+	/*6035*/ uint16(x86_xArgRM64),
+	/*6036*/ uint16(x86_xMatch),
+	/*6037*/ uint16(x86_xCondIs64), 6040, 6052,
+	/*6040*/ uint16(x86_xCondDataSize), 6044, 6048, 0,
+	/*6044*/ uint16(x86_xSetOp), uint16(x86_FXRSTOR),
+	/*6046*/ uint16(x86_xArgM512byte),
+	/*6047*/ uint16(x86_xMatch),
+	/*6048*/ uint16(x86_xSetOp), uint16(x86_FXRSTOR),
+	/*6050*/ uint16(x86_xArgM512byte),
+	/*6051*/ uint16(x86_xMatch),
+	/*6052*/ uint16(x86_xCondPrefix), 2,
+	0xF3, 6066,
+	0x0, 6058,
+	/*6058*/ uint16(x86_xCondDataSize), 6044, 6048, 6062,
+	/*6062*/ uint16(x86_xSetOp), uint16(x86_FXRSTOR64),
+	/*6064*/ uint16(x86_xArgM512byte),
+	/*6065*/ uint16(x86_xMatch),
+	/*6066*/ uint16(x86_xCondDataSize), 6070, 6077, 6084,
+	/*6070*/ uint16(x86_xCondIsMem), 6073, 0,
+	/*6073*/ uint16(x86_xSetOp), uint16(x86_RDGSBASE),
+	/*6075*/ uint16(x86_xArgRM32),
+	/*6076*/ uint16(x86_xMatch),
+	/*6077*/ uint16(x86_xCondIsMem), 6080, 0,
+	/*6080*/ uint16(x86_xSetOp), uint16(x86_RDGSBASE),
+	/*6082*/ uint16(x86_xArgRM32),
+	/*6083*/ uint16(x86_xMatch),
+	/*6084*/ uint16(x86_xCondIsMem), 6087, 0,
+	/*6087*/ uint16(x86_xSetOp), uint16(x86_RDGSBASE),
+	/*6089*/ uint16(x86_xArgRM64),
+	/*6090*/ uint16(x86_xMatch),
+	/*6091*/ uint16(x86_xCondIs64), 6094, 6098,
+	/*6094*/ uint16(x86_xSetOp), uint16(x86_LDMXCSR),
+	/*6096*/ uint16(x86_xArgM32),
+	/*6097*/ uint16(x86_xMatch),
+	/*6098*/ uint16(x86_xCondPrefix), 2,
+	0xF3, 6104,
+	0x0, 6094,
+	/*6104*/ uint16(x86_xCondDataSize), 6108, 6112, 6116,
+	/*6108*/ uint16(x86_xSetOp), uint16(x86_WRFSBASE),
+	/*6110*/ uint16(x86_xArgRM32),
+	/*6111*/ uint16(x86_xMatch),
+	/*6112*/ uint16(x86_xSetOp), uint16(x86_WRFSBASE),
+	/*6114*/ uint16(x86_xArgRM32),
+	/*6115*/ uint16(x86_xMatch),
+	/*6116*/ uint16(x86_xSetOp), uint16(x86_WRFSBASE),
+	/*6118*/ uint16(x86_xArgRM64),
+	/*6119*/ uint16(x86_xMatch),
+	/*6120*/ uint16(x86_xCondIs64), 6123, 6127,
+	/*6123*/ uint16(x86_xSetOp), uint16(x86_STMXCSR),
+	/*6125*/ uint16(x86_xArgM32),
+	/*6126*/ uint16(x86_xMatch),
+	/*6127*/ uint16(x86_xCondPrefix), 2,
+	0xF3, 6133,
+	0x0, 6123,
+	/*6133*/ uint16(x86_xCondDataSize), 6137, 6141, 6145,
+	/*6137*/ uint16(x86_xSetOp), uint16(x86_WRGSBASE),
+	/*6139*/ uint16(x86_xArgRM32),
+	/*6140*/ uint16(x86_xMatch),
+	/*6141*/ uint16(x86_xSetOp), uint16(x86_WRGSBASE),
+	/*6143*/ uint16(x86_xArgRM32),
+	/*6144*/ uint16(x86_xMatch),
+	/*6145*/ uint16(x86_xSetOp), uint16(x86_WRGSBASE),
+	/*6147*/ uint16(x86_xArgRM64),
+	/*6148*/ uint16(x86_xMatch),
+	/*6149*/ uint16(x86_xCondIs64), 6152, 6164,
+	/*6152*/ uint16(x86_xCondDataSize), 6156, 6160, 0,
+	/*6156*/ uint16(x86_xSetOp), uint16(x86_XSAVE),
+	/*6158*/ uint16(x86_xArgMem),
+	/*6159*/ uint16(x86_xMatch),
+	/*6160*/ uint16(x86_xSetOp), uint16(x86_XSAVE),
+	/*6162*/ uint16(x86_xArgMem),
+	/*6163*/ uint16(x86_xMatch),
+	/*6164*/ uint16(x86_xCondDataSize), 6156, 6160, 6168,
+	/*6168*/ uint16(x86_xSetOp), uint16(x86_XSAVE64),
+	/*6170*/ uint16(x86_xArgMem),
+	/*6171*/ uint16(x86_xMatch),
+	/*6172*/ uint16(x86_xCondIs64), 6175, 6187,
+	/*6175*/ uint16(x86_xCondDataSize), 6179, 6183, 0,
+	/*6179*/ uint16(x86_xSetOp), uint16(x86_XRSTOR),
+	/*6181*/ uint16(x86_xArgMem),
+	/*6182*/ uint16(x86_xMatch),
+	/*6183*/ uint16(x86_xSetOp), uint16(x86_XRSTOR),
+	/*6185*/ uint16(x86_xArgMem),
+	/*6186*/ uint16(x86_xMatch),
+	/*6187*/ uint16(x86_xCondDataSize), 6179, 6183, 6191,
+	/*6191*/ uint16(x86_xSetOp), uint16(x86_XRSTOR64),
+	/*6193*/ uint16(x86_xArgMem),
+	/*6194*/ uint16(x86_xMatch),
+	/*6195*/ uint16(x86_xCondDataSize), 6199, 6203, 6207,
+	/*6199*/ uint16(x86_xSetOp), uint16(x86_XSAVEOPT),
+	/*6201*/ uint16(x86_xArgMem),
+	/*6202*/ uint16(x86_xMatch),
+	/*6203*/ uint16(x86_xSetOp), uint16(x86_XSAVEOPT),
+	/*6205*/ uint16(x86_xArgMem),
+	/*6206*/ uint16(x86_xMatch),
+	/*6207*/ uint16(x86_xSetOp), uint16(x86_XSAVEOPT64),
+	/*6209*/ uint16(x86_xArgMem),
+	/*6210*/ uint16(x86_xMatch),
+	/*6211*/ uint16(x86_xSetOp), uint16(x86_CLFLUSH),
+	/*6213*/ uint16(x86_xArgM8),
+	/*6214*/ uint16(x86_xMatch),
+	/*6215*/ uint16(x86_xSetOp), uint16(x86_LFENCE),
+	/*6217*/ uint16(x86_xMatch),
+	/*6218*/ uint16(x86_xSetOp), uint16(x86_MFENCE),
+	/*6220*/ uint16(x86_xMatch),
+	/*6221*/ uint16(x86_xSetOp), uint16(x86_SFENCE),
+	/*6223*/ uint16(x86_xMatch),
+	/*6224*/ uint16(x86_xCondIs64), 6227, 6243,
+	/*6227*/ uint16(x86_xCondDataSize), 6231, 6237, 0,
+	/*6231*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+	/*6233*/ uint16(x86_xReadSlashR),
+	/*6234*/ uint16(x86_xArgR16),
+	/*6235*/ uint16(x86_xArgRM16),
+	/*6236*/ uint16(x86_xMatch),
+	/*6237*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+	/*6239*/ uint16(x86_xReadSlashR),
+	/*6240*/ uint16(x86_xArgR32),
+	/*6241*/ uint16(x86_xArgRM32),
+	/*6242*/ uint16(x86_xMatch),
+	/*6243*/ uint16(x86_xCondDataSize), 6231, 6237, 6247,
+	/*6247*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+	/*6249*/ uint16(x86_xReadSlashR),
+	/*6250*/ uint16(x86_xArgR64),
+	/*6251*/ uint16(x86_xArgRM64),
+	/*6252*/ uint16(x86_xMatch),
+	/*6253*/ uint16(x86_xSetOp), uint16(x86_CMPXCHG),
+	/*6255*/ uint16(x86_xReadSlashR),
+	/*6256*/ uint16(x86_xArgRM8),
+	/*6257*/ uint16(x86_xArgR8),
+	/*6258*/ uint16(x86_xMatch),
+	/*6259*/ uint16(x86_xCondIs64), 6262, 6278,
+	/*6262*/ uint16(x86_xCondDataSize), 6266, 6272, 0,
+	/*6266*/ uint16(x86_xSetOp), uint16(x86_CMPXCHG),
+	/*6268*/ uint16(x86_xReadSlashR),
+	/*6269*/ uint16(x86_xArgRM16),
+	/*6270*/ uint16(x86_xArgR16),
+	/*6271*/ uint16(x86_xMatch),
+	/*6272*/ uint16(x86_xSetOp), uint16(x86_CMPXCHG),
+	/*6274*/ uint16(x86_xReadSlashR),
+	/*6275*/ uint16(x86_xArgRM32),
+	/*6276*/ uint16(x86_xArgR32),
+	/*6277*/ uint16(x86_xMatch),
+	/*6278*/ uint16(x86_xCondDataSize), 6266, 6272, 6282,
+	/*6282*/ uint16(x86_xSetOp), uint16(x86_CMPXCHG),
+	/*6284*/ uint16(x86_xReadSlashR),
+	/*6285*/ uint16(x86_xArgRM64),
+	/*6286*/ uint16(x86_xArgR64),
+	/*6287*/ uint16(x86_xMatch),
+	/*6288*/ uint16(x86_xCondIs64), 6291, 6307,
+	/*6291*/ uint16(x86_xCondDataSize), 6295, 6301, 0,
+	/*6295*/ uint16(x86_xSetOp), uint16(x86_LSS),
+	/*6297*/ uint16(x86_xReadSlashR),
+	/*6298*/ uint16(x86_xArgR16),
+	/*6299*/ uint16(x86_xArgM16colon16),
+	/*6300*/ uint16(x86_xMatch),
+	/*6301*/ uint16(x86_xSetOp), uint16(x86_LSS),
+	/*6303*/ uint16(x86_xReadSlashR),
+	/*6304*/ uint16(x86_xArgR32),
+	/*6305*/ uint16(x86_xArgM16colon32),
+	/*6306*/ uint16(x86_xMatch),
+	/*6307*/ uint16(x86_xCondDataSize), 6295, 6301, 6311,
+	/*6311*/ uint16(x86_xSetOp), uint16(x86_LSS),
+	/*6313*/ uint16(x86_xReadSlashR),
+	/*6314*/ uint16(x86_xArgR64),
+	/*6315*/ uint16(x86_xArgM16colon64),
+	/*6316*/ uint16(x86_xMatch),
+	/*6317*/ uint16(x86_xCondIs64), 6320, 6336,
+	/*6320*/ uint16(x86_xCondDataSize), 6324, 6330, 0,
+	/*6324*/ uint16(x86_xSetOp), uint16(x86_BTR),
+	/*6326*/ uint16(x86_xReadSlashR),
+	/*6327*/ uint16(x86_xArgRM16),
+	/*6328*/ uint16(x86_xArgR16),
+	/*6329*/ uint16(x86_xMatch),
+	/*6330*/ uint16(x86_xSetOp), uint16(x86_BTR),
+	/*6332*/ uint16(x86_xReadSlashR),
+	/*6333*/ uint16(x86_xArgRM32),
+	/*6334*/ uint16(x86_xArgR32),
+	/*6335*/ uint16(x86_xMatch),
+	/*6336*/ uint16(x86_xCondDataSize), 6324, 6330, 6340,
+	/*6340*/ uint16(x86_xSetOp), uint16(x86_BTR),
+	/*6342*/ uint16(x86_xReadSlashR),
+	/*6343*/ uint16(x86_xArgRM64),
+	/*6344*/ uint16(x86_xArgR64),
+	/*6345*/ uint16(x86_xMatch),
+	/*6346*/ uint16(x86_xCondIs64), 6349, 6365,
+	/*6349*/ uint16(x86_xCondDataSize), 6353, 6359, 0,
+	/*6353*/ uint16(x86_xSetOp), uint16(x86_LFS),
+	/*6355*/ uint16(x86_xReadSlashR),
+	/*6356*/ uint16(x86_xArgR16),
+	/*6357*/ uint16(x86_xArgM16colon16),
+	/*6358*/ uint16(x86_xMatch),
+	/*6359*/ uint16(x86_xSetOp), uint16(x86_LFS),
+	/*6361*/ uint16(x86_xReadSlashR),
+	/*6362*/ uint16(x86_xArgR32),
+	/*6363*/ uint16(x86_xArgM16colon32),
+	/*6364*/ uint16(x86_xMatch),
+	/*6365*/ uint16(x86_xCondDataSize), 6353, 6359, 6369,
+	/*6369*/ uint16(x86_xSetOp), uint16(x86_LFS),
+	/*6371*/ uint16(x86_xReadSlashR),
+	/*6372*/ uint16(x86_xArgR64),
+	/*6373*/ uint16(x86_xArgM16colon64),
+	/*6374*/ uint16(x86_xMatch),
+	/*6375*/ uint16(x86_xCondIs64), 6378, 6394,
+	/*6378*/ uint16(x86_xCondDataSize), 6382, 6388, 0,
+	/*6382*/ uint16(x86_xSetOp), uint16(x86_LGS),
+	/*6384*/ uint16(x86_xReadSlashR),
+	/*6385*/ uint16(x86_xArgR16),
+	/*6386*/ uint16(x86_xArgM16colon16),
+	/*6387*/ uint16(x86_xMatch),
+	/*6388*/ uint16(x86_xSetOp), uint16(x86_LGS),
+	/*6390*/ uint16(x86_xReadSlashR),
+	/*6391*/ uint16(x86_xArgR32),
+	/*6392*/ uint16(x86_xArgM16colon32),
+	/*6393*/ uint16(x86_xMatch),
+	/*6394*/ uint16(x86_xCondDataSize), 6382, 6388, 6398,
+	/*6398*/ uint16(x86_xSetOp), uint16(x86_LGS),
+	/*6400*/ uint16(x86_xReadSlashR),
+	/*6401*/ uint16(x86_xArgR64),
+	/*6402*/ uint16(x86_xArgM16colon64),
+	/*6403*/ uint16(x86_xMatch),
+	/*6404*/ uint16(x86_xCondIs64), 6407, 6423,
+	/*6407*/ uint16(x86_xCondDataSize), 6411, 6417, 0,
+	/*6411*/ uint16(x86_xSetOp), uint16(x86_MOVZX),
+	/*6413*/ uint16(x86_xReadSlashR),
+	/*6414*/ uint16(x86_xArgR16),
+	/*6415*/ uint16(x86_xArgRM8),
+	/*6416*/ uint16(x86_xMatch),
+	/*6417*/ uint16(x86_xSetOp), uint16(x86_MOVZX),
+	/*6419*/ uint16(x86_xReadSlashR),
+	/*6420*/ uint16(x86_xArgR32),
+	/*6421*/ uint16(x86_xArgRM8),
+	/*6422*/ uint16(x86_xMatch),
+	/*6423*/ uint16(x86_xCondDataSize), 6411, 6417, 6427,
+	/*6427*/ uint16(x86_xSetOp), uint16(x86_MOVZX),
+	/*6429*/ uint16(x86_xReadSlashR),
+	/*6430*/ uint16(x86_xArgR64),
+	/*6431*/ uint16(x86_xArgRM8),
+	/*6432*/ uint16(x86_xMatch),
+	/*6433*/ uint16(x86_xCondIs64), 6436, 6452,
+	/*6436*/ uint16(x86_xCondDataSize), 6440, 6446, 0,
+	/*6440*/ uint16(x86_xSetOp), uint16(x86_MOVZX),
+	/*6442*/ uint16(x86_xReadSlashR),
+	/*6443*/ uint16(x86_xArgR16),
+	/*6444*/ uint16(x86_xArgRM16),
+	/*6445*/ uint16(x86_xMatch),
+	/*6446*/ uint16(x86_xSetOp), uint16(x86_MOVZX),
+	/*6448*/ uint16(x86_xReadSlashR),
+	/*6449*/ uint16(x86_xArgR32),
+	/*6450*/ uint16(x86_xArgRM16),
+	/*6451*/ uint16(x86_xMatch),
+	/*6452*/ uint16(x86_xCondDataSize), 6440, 6446, 6456,
+	/*6456*/ uint16(x86_xSetOp), uint16(x86_MOVZX),
+	/*6458*/ uint16(x86_xReadSlashR),
+	/*6459*/ uint16(x86_xArgR64),
+	/*6460*/ uint16(x86_xArgRM16),
+	/*6461*/ uint16(x86_xMatch),
+	/*6462*/ uint16(x86_xCondIs64), 6465, 6485,
+	/*6465*/ uint16(x86_xCondPrefix), 1,
+	0xF3, 6469,
+	/*6469*/ uint16(x86_xCondDataSize), 6473, 6479, 0,
+	/*6473*/ uint16(x86_xSetOp), uint16(x86_POPCNT),
+	/*6475*/ uint16(x86_xReadSlashR),
+	/*6476*/ uint16(x86_xArgR16),
+	/*6477*/ uint16(x86_xArgRM16),
+	/*6478*/ uint16(x86_xMatch),
+	/*6479*/ uint16(x86_xSetOp), uint16(x86_POPCNT),
+	/*6481*/ uint16(x86_xReadSlashR),
+	/*6482*/ uint16(x86_xArgR32),
+	/*6483*/ uint16(x86_xArgRM32),
+	/*6484*/ uint16(x86_xMatch),
+	/*6485*/ uint16(x86_xCondPrefix), 1,
+	0xF3, 6489,
+	/*6489*/ uint16(x86_xCondDataSize), 6473, 6479, 6493,
+	/*6493*/ uint16(x86_xSetOp), uint16(x86_POPCNT),
+	/*6495*/ uint16(x86_xReadSlashR),
+	/*6496*/ uint16(x86_xArgR64),
+	/*6497*/ uint16(x86_xArgRM64),
+	/*6498*/ uint16(x86_xMatch),
+	/*6499*/ uint16(x86_xSetOp), uint16(x86_UD1),
+	/*6501*/ uint16(x86_xMatch),
+	/*6502*/ uint16(x86_xCondSlashR),
+	0,    // 0
+	0,    // 1
+	0,    // 2
+	0,    // 3
+	6511, // 4
+	6540, // 5
+	6569, // 6
+	6598, // 7
+	/*6511*/ uint16(x86_xCondIs64), 6514, 6530,
+	/*6514*/ uint16(x86_xCondDataSize), 6518, 6524, 0,
+	/*6518*/ uint16(x86_xSetOp), uint16(x86_BT),
+	/*6520*/ uint16(x86_xReadIb),
+	/*6521*/ uint16(x86_xArgRM16),
+	/*6522*/ uint16(x86_xArgImm8u),
+	/*6523*/ uint16(x86_xMatch),
+	/*6524*/ uint16(x86_xSetOp), uint16(x86_BT),
+	/*6526*/ uint16(x86_xReadIb),
+	/*6527*/ uint16(x86_xArgRM32),
+	/*6528*/ uint16(x86_xArgImm8u),
+	/*6529*/ uint16(x86_xMatch),
+	/*6530*/ uint16(x86_xCondDataSize), 6518, 6524, 6534,
+	/*6534*/ uint16(x86_xSetOp), uint16(x86_BT),
+	/*6536*/ uint16(x86_xReadIb),
+	/*6537*/ uint16(x86_xArgRM64),
+	/*6538*/ uint16(x86_xArgImm8u),
+	/*6539*/ uint16(x86_xMatch),
+	/*6540*/ uint16(x86_xCondIs64), 6543, 6559,
+	/*6543*/ uint16(x86_xCondDataSize), 6547, 6553, 0,
+	/*6547*/ uint16(x86_xSetOp), uint16(x86_BTS),
+	/*6549*/ uint16(x86_xReadIb),
+	/*6550*/ uint16(x86_xArgRM16),
+	/*6551*/ uint16(x86_xArgImm8u),
+	/*6552*/ uint16(x86_xMatch),
+	/*6553*/ uint16(x86_xSetOp), uint16(x86_BTS),
+	/*6555*/ uint16(x86_xReadIb),
+	/*6556*/ uint16(x86_xArgRM32),
+	/*6557*/ uint16(x86_xArgImm8u),
+	/*6558*/ uint16(x86_xMatch),
+	/*6559*/ uint16(x86_xCondDataSize), 6547, 6553, 6563,
+	/*6563*/ uint16(x86_xSetOp), uint16(x86_BTS),
+	/*6565*/ uint16(x86_xReadIb),
+	/*6566*/ uint16(x86_xArgRM64),
+	/*6567*/ uint16(x86_xArgImm8u),
+	/*6568*/ uint16(x86_xMatch),
+	/*6569*/ uint16(x86_xCondIs64), 6572, 6588,
+	/*6572*/ uint16(x86_xCondDataSize), 6576, 6582, 0,
+	/*6576*/ uint16(x86_xSetOp), uint16(x86_BTR),
+	/*6578*/ uint16(x86_xReadIb),
+	/*6579*/ uint16(x86_xArgRM16),
+	/*6580*/ uint16(x86_xArgImm8u),
+	/*6581*/ uint16(x86_xMatch),
+	/*6582*/ uint16(x86_xSetOp), uint16(x86_BTR),
+	/*6584*/ uint16(x86_xReadIb),
+	/*6585*/ uint16(x86_xArgRM32),
+	/*6586*/ uint16(x86_xArgImm8u),
+	/*6587*/ uint16(x86_xMatch),
+	/*6588*/ uint16(x86_xCondDataSize), 6576, 6582, 6592,
+	/*6592*/ uint16(x86_xSetOp), uint16(x86_BTR),
+	/*6594*/ uint16(x86_xReadIb),
+	/*6595*/ uint16(x86_xArgRM64),
+	/*6596*/ uint16(x86_xArgImm8u),
+	/*6597*/ uint16(x86_xMatch),
+	/*6598*/ uint16(x86_xCondIs64), 6601, 6617,
+	/*6601*/ uint16(x86_xCondDataSize), 6605, 6611, 0,
+	/*6605*/ uint16(x86_xSetOp), uint16(x86_BTC),
+	/*6607*/ uint16(x86_xReadIb),
+	/*6608*/ uint16(x86_xArgRM16),
+	/*6609*/ uint16(x86_xArgImm8u),
+	/*6610*/ uint16(x86_xMatch),
+	/*6611*/ uint16(x86_xSetOp), uint16(x86_BTC),
+	/*6613*/ uint16(x86_xReadIb),
+	/*6614*/ uint16(x86_xArgRM32),
+	/*6615*/ uint16(x86_xArgImm8u),
+	/*6616*/ uint16(x86_xMatch),
+	/*6617*/ uint16(x86_xCondDataSize), 6605, 6611, 6621,
+	/*6621*/ uint16(x86_xSetOp), uint16(x86_BTC),
+	/*6623*/ uint16(x86_xReadIb),
+	/*6624*/ uint16(x86_xArgRM64),
+	/*6625*/ uint16(x86_xArgImm8u),
+	/*6626*/ uint16(x86_xMatch),
+	/*6627*/ uint16(x86_xCondIs64), 6630, 6646,
+	/*6630*/ uint16(x86_xCondDataSize), 6634, 6640, 0,
+	/*6634*/ uint16(x86_xSetOp), uint16(x86_BTC),
+	/*6636*/ uint16(x86_xReadSlashR),
+	/*6637*/ uint16(x86_xArgRM16),
+	/*6638*/ uint16(x86_xArgR16),
+	/*6639*/ uint16(x86_xMatch),
+	/*6640*/ uint16(x86_xSetOp), uint16(x86_BTC),
+	/*6642*/ uint16(x86_xReadSlashR),
+	/*6643*/ uint16(x86_xArgRM32),
+	/*6644*/ uint16(x86_xArgR32),
+	/*6645*/ uint16(x86_xMatch),
+	/*6646*/ uint16(x86_xCondDataSize), 6634, 6640, 6650,
+	/*6650*/ uint16(x86_xSetOp), uint16(x86_BTC),
+	/*6652*/ uint16(x86_xReadSlashR),
+	/*6653*/ uint16(x86_xArgRM64),
+	/*6654*/ uint16(x86_xArgR64),
+	/*6655*/ uint16(x86_xMatch),
+	/*6656*/ uint16(x86_xCondIs64), 6659, 6697,
+	/*6659*/ uint16(x86_xCondPrefix), 2,
+	0xF3, 6681,
+	0x0, 6665,
+	/*6665*/ uint16(x86_xCondDataSize), 6669, 6675, 0,
+	/*6669*/ uint16(x86_xSetOp), uint16(x86_BSF),
+	/*6671*/ uint16(x86_xReadSlashR),
+	/*6672*/ uint16(x86_xArgR16),
+	/*6673*/ uint16(x86_xArgRM16),
+	/*6674*/ uint16(x86_xMatch),
+	/*6675*/ uint16(x86_xSetOp), uint16(x86_BSF),
+	/*6677*/ uint16(x86_xReadSlashR),
+	/*6678*/ uint16(x86_xArgR32),
+	/*6679*/ uint16(x86_xArgRM32),
+	/*6680*/ uint16(x86_xMatch),
+	/*6681*/ uint16(x86_xCondDataSize), 6685, 6691, 0,
+	/*6685*/ uint16(x86_xSetOp), uint16(x86_TZCNT),
+	/*6687*/ uint16(x86_xReadSlashR),
+	/*6688*/ uint16(x86_xArgR16),
+	/*6689*/ uint16(x86_xArgRM16),
+	/*6690*/ uint16(x86_xMatch),
+	/*6691*/ uint16(x86_xSetOp), uint16(x86_TZCNT),
+	/*6693*/ uint16(x86_xReadSlashR),
+	/*6694*/ uint16(x86_xArgR32),
+	/*6695*/ uint16(x86_xArgRM32),
+	/*6696*/ uint16(x86_xMatch),
+	/*6697*/ uint16(x86_xCondPrefix), 2,
+	0xF3, 6713,
+	0x0, 6703,
+	/*6703*/ uint16(x86_xCondDataSize), 6669, 6675, 6707,
+	/*6707*/ uint16(x86_xSetOp), uint16(x86_BSF),
+	/*6709*/ uint16(x86_xReadSlashR),
+	/*6710*/ uint16(x86_xArgR64),
+	/*6711*/ uint16(x86_xArgRM64),
+	/*6712*/ uint16(x86_xMatch),
+	/*6713*/ uint16(x86_xCondDataSize), 6685, 6691, 6717,
+	/*6717*/ uint16(x86_xSetOp), uint16(x86_TZCNT),
+	/*6719*/ uint16(x86_xReadSlashR),
+	/*6720*/ uint16(x86_xArgR64),
+	/*6721*/ uint16(x86_xArgRM64),
+	/*6722*/ uint16(x86_xMatch),
+	/*6723*/ uint16(x86_xCondIs64), 6726, 6764,
+	/*6726*/ uint16(x86_xCondPrefix), 2,
+	0xF3, 6748,
+	0x0, 6732,
+	/*6732*/ uint16(x86_xCondDataSize), 6736, 6742, 0,
+	/*6736*/ uint16(x86_xSetOp), uint16(x86_BSR),
+	/*6738*/ uint16(x86_xReadSlashR),
+	/*6739*/ uint16(x86_xArgR16),
+	/*6740*/ uint16(x86_xArgRM16),
+	/*6741*/ uint16(x86_xMatch),
+	/*6742*/ uint16(x86_xSetOp), uint16(x86_BSR),
+	/*6744*/ uint16(x86_xReadSlashR),
+	/*6745*/ uint16(x86_xArgR32),
+	/*6746*/ uint16(x86_xArgRM32),
+	/*6747*/ uint16(x86_xMatch),
+	/*6748*/ uint16(x86_xCondDataSize), 6752, 6758, 0,
+	/*6752*/ uint16(x86_xSetOp), uint16(x86_LZCNT),
+	/*6754*/ uint16(x86_xReadSlashR),
+	/*6755*/ uint16(x86_xArgR16),
+	/*6756*/ uint16(x86_xArgRM16),
+	/*6757*/ uint16(x86_xMatch),
+	/*6758*/ uint16(x86_xSetOp), uint16(x86_LZCNT),
+	/*6760*/ uint16(x86_xReadSlashR),
+	/*6761*/ uint16(x86_xArgR32),
+	/*6762*/ uint16(x86_xArgRM32),
+	/*6763*/ uint16(x86_xMatch),
+	/*6764*/ uint16(x86_xCondPrefix), 2,
+	0xF3, 6780,
+	0x0, 6770,
+	/*6770*/ uint16(x86_xCondDataSize), 6736, 6742, 6774,
+	/*6774*/ uint16(x86_xSetOp), uint16(x86_BSR),
+	/*6776*/ uint16(x86_xReadSlashR),
+	/*6777*/ uint16(x86_xArgR64),
+	/*6778*/ uint16(x86_xArgRM64),
+	/*6779*/ uint16(x86_xMatch),
+	/*6780*/ uint16(x86_xCondDataSize), 6752, 6758, 6784,
+	/*6784*/ uint16(x86_xSetOp), uint16(x86_LZCNT),
+	/*6786*/ uint16(x86_xReadSlashR),
+	/*6787*/ uint16(x86_xArgR64),
+	/*6788*/ uint16(x86_xArgRM64),
+	/*6789*/ uint16(x86_xMatch),
+	/*6790*/ uint16(x86_xCondIs64), 6793, 6809,
+	/*6793*/ uint16(x86_xCondDataSize), 6797, 6803, 0,
+	/*6797*/ uint16(x86_xSetOp), uint16(x86_MOVSX),
+	/*6799*/ uint16(x86_xReadSlashR),
+	/*6800*/ uint16(x86_xArgR16),
+	/*6801*/ uint16(x86_xArgRM8),
+	/*6802*/ uint16(x86_xMatch),
+	/*6803*/ uint16(x86_xSetOp), uint16(x86_MOVSX),
+	/*6805*/ uint16(x86_xReadSlashR),
+	/*6806*/ uint16(x86_xArgR32),
+	/*6807*/ uint16(x86_xArgRM8),
+	/*6808*/ uint16(x86_xMatch),
+	/*6809*/ uint16(x86_xCondDataSize), 6797, 6803, 6813,
+	/*6813*/ uint16(x86_xSetOp), uint16(x86_MOVSX),
+	/*6815*/ uint16(x86_xReadSlashR),
+	/*6816*/ uint16(x86_xArgR64),
+	/*6817*/ uint16(x86_xArgRM8),
+	/*6818*/ uint16(x86_xMatch),
+	/*6819*/ uint16(x86_xCondIs64), 6822, 6838,
+	/*6822*/ uint16(x86_xCondDataSize), 6826, 6832, 0,
+	/*6826*/ uint16(x86_xSetOp), uint16(x86_MOVSX),
+	/*6828*/ uint16(x86_xReadSlashR),
+	/*6829*/ uint16(x86_xArgR16),
+	/*6830*/ uint16(x86_xArgRM16),
+	/*6831*/ uint16(x86_xMatch),
+	/*6832*/ uint16(x86_xSetOp), uint16(x86_MOVSX),
+	/*6834*/ uint16(x86_xReadSlashR),
+	/*6835*/ uint16(x86_xArgR32),
+	/*6836*/ uint16(x86_xArgRM16),
+	/*6837*/ uint16(x86_xMatch),
+	/*6838*/ uint16(x86_xCondDataSize), 6826, 6832, 6842,
+	/*6842*/ uint16(x86_xSetOp), uint16(x86_MOVSX),
+	/*6844*/ uint16(x86_xReadSlashR),
+	/*6845*/ uint16(x86_xArgR64),
+	/*6846*/ uint16(x86_xArgRM16),
+	/*6847*/ uint16(x86_xMatch),
+	/*6848*/ uint16(x86_xSetOp), uint16(x86_XADD),
+	/*6850*/ uint16(x86_xReadSlashR),
+	/*6851*/ uint16(x86_xArgRM8),
+	/*6852*/ uint16(x86_xArgR8),
+	/*6853*/ uint16(x86_xMatch),
+	/*6854*/ uint16(x86_xCondIs64), 6857, 6873,
+	/*6857*/ uint16(x86_xCondDataSize), 6861, 6867, 0,
+	/*6861*/ uint16(x86_xSetOp), uint16(x86_XADD),
+	/*6863*/ uint16(x86_xReadSlashR),
+	/*6864*/ uint16(x86_xArgRM16),
+	/*6865*/ uint16(x86_xArgR16),
+	/*6866*/ uint16(x86_xMatch),
+	/*6867*/ uint16(x86_xSetOp), uint16(x86_XADD),
+	/*6869*/ uint16(x86_xReadSlashR),
+	/*6870*/ uint16(x86_xArgRM32),
+	/*6871*/ uint16(x86_xArgR32),
+	/*6872*/ uint16(x86_xMatch),
+	/*6873*/ uint16(x86_xCondDataSize), 6861, 6867, 6877,
+	/*6877*/ uint16(x86_xSetOp), uint16(x86_XADD),
+	/*6879*/ uint16(x86_xReadSlashR),
+	/*6880*/ uint16(x86_xArgRM64),
+	/*6881*/ uint16(x86_xArgR64),
+	/*6882*/ uint16(x86_xMatch),
+	/*6883*/ uint16(x86_xCondPrefix), 4,
+	0xF3, 6917,
+	0xF2, 6909,
+	0x66, 6901,
+	0x0, 6893,
+	/*6893*/ uint16(x86_xSetOp), uint16(x86_CMPPS),
+	/*6895*/ uint16(x86_xReadSlashR),
+	/*6896*/ uint16(x86_xReadIb),
+	/*6897*/ uint16(x86_xArgXmm1),
+	/*6898*/ uint16(x86_xArgXmm2M128),
+	/*6899*/ uint16(x86_xArgImm8u),
+	/*6900*/ uint16(x86_xMatch),
+	/*6901*/ uint16(x86_xSetOp), uint16(x86_CMPPD),
+	/*6903*/ uint16(x86_xReadSlashR),
+	/*6904*/ uint16(x86_xReadIb),
+	/*6905*/ uint16(x86_xArgXmm1),
+	/*6906*/ uint16(x86_xArgXmm2M128),
+	/*6907*/ uint16(x86_xArgImm8u),
+	/*6908*/ uint16(x86_xMatch),
+	/*6909*/ uint16(x86_xSetOp), uint16(x86_CMPSD_XMM),
+	/*6911*/ uint16(x86_xReadSlashR),
+	/*6912*/ uint16(x86_xReadIb),
+	/*6913*/ uint16(x86_xArgXmm1),
+	/*6914*/ uint16(x86_xArgXmm2M64),
+	/*6915*/ uint16(x86_xArgImm8u),
+	/*6916*/ uint16(x86_xMatch),
+	/*6917*/ uint16(x86_xSetOp), uint16(x86_CMPSS),
+	/*6919*/ uint16(x86_xReadSlashR),
+	/*6920*/ uint16(x86_xReadIb),
+	/*6921*/ uint16(x86_xArgXmm1),
+	/*6922*/ uint16(x86_xArgXmm2M32),
+	/*6923*/ uint16(x86_xArgImm8u),
+	/*6924*/ uint16(x86_xMatch),
+	/*6925*/ uint16(x86_xCondIs64), 6928, 6944,
+	/*6928*/ uint16(x86_xCondDataSize), 6932, 6938, 0,
+	/*6932*/ uint16(x86_xSetOp), uint16(x86_MOVNTI),
+	/*6934*/ uint16(x86_xReadSlashR),
+	/*6935*/ uint16(x86_xArgM32),
+	/*6936*/ uint16(x86_xArgR32),
+	/*6937*/ uint16(x86_xMatch),
+	/*6938*/ uint16(x86_xSetOp), uint16(x86_MOVNTI),
+	/*6940*/ uint16(x86_xReadSlashR),
+	/*6941*/ uint16(x86_xArgM32),
+	/*6942*/ uint16(x86_xArgR32),
+	/*6943*/ uint16(x86_xMatch),
+	/*6944*/ uint16(x86_xCondDataSize), 6932, 6938, 6948,
+	/*6948*/ uint16(x86_xSetOp), uint16(x86_MOVNTI),
+	/*6950*/ uint16(x86_xReadSlashR),
+	/*6951*/ uint16(x86_xArgM64),
+	/*6952*/ uint16(x86_xArgR64),
+	/*6953*/ uint16(x86_xMatch),
+	/*6954*/ uint16(x86_xCondPrefix), 2,
+	0x66, 6968,
+	0x0, 6960,
+	/*6960*/ uint16(x86_xSetOp), uint16(x86_PINSRW),
+	/*6962*/ uint16(x86_xReadSlashR),
+	/*6963*/ uint16(x86_xReadIb),
+	/*6964*/ uint16(x86_xArgMm),
+	/*6965*/ uint16(x86_xArgR32M16),
+	/*6966*/ uint16(x86_xArgImm8u),
+	/*6967*/ uint16(x86_xMatch),
+	/*6968*/ uint16(x86_xSetOp), uint16(x86_PINSRW),
+	/*6970*/ uint16(x86_xReadSlashR),
+	/*6971*/ uint16(x86_xReadIb),
+	/*6972*/ uint16(x86_xArgXmm),
+	/*6973*/ uint16(x86_xArgR32M16),
+	/*6974*/ uint16(x86_xArgImm8u),
+	/*6975*/ uint16(x86_xMatch),
+	/*6976*/ uint16(x86_xCondPrefix), 2,
+	0x66, 6990,
+	0x0, 6982,
+	/*6982*/ uint16(x86_xSetOp), uint16(x86_PEXTRW),
+	/*6984*/ uint16(x86_xReadSlashR),
+	/*6985*/ uint16(x86_xReadIb),
+	/*6986*/ uint16(x86_xArgR32),
+	/*6987*/ uint16(x86_xArgMm2),
+	/*6988*/ uint16(x86_xArgImm8u),
+	/*6989*/ uint16(x86_xMatch),
+	/*6990*/ uint16(x86_xSetOp), uint16(x86_PEXTRW),
+	/*6992*/ uint16(x86_xReadSlashR),
+	/*6993*/ uint16(x86_xReadIb),
+	/*6994*/ uint16(x86_xArgR32),
+	/*6995*/ uint16(x86_xArgXmm2),
+	/*6996*/ uint16(x86_xArgImm8u),
+	/*6997*/ uint16(x86_xMatch),
+	/*6998*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7012,
+	0x0, 7004,
+	/*7004*/ uint16(x86_xSetOp), uint16(x86_SHUFPS),
+	/*7006*/ uint16(x86_xReadSlashR),
+	/*7007*/ uint16(x86_xReadIb),
+	/*7008*/ uint16(x86_xArgXmm1),
+	/*7009*/ uint16(x86_xArgXmm2M128),
+	/*7010*/ uint16(x86_xArgImm8u),
+	/*7011*/ uint16(x86_xMatch),
+	/*7012*/ uint16(x86_xSetOp), uint16(x86_SHUFPD),
+	/*7014*/ uint16(x86_xReadSlashR),
+	/*7015*/ uint16(x86_xReadIb),
+	/*7016*/ uint16(x86_xArgXmm1),
+	/*7017*/ uint16(x86_xArgXmm2M128),
+	/*7018*/ uint16(x86_xArgImm8u),
+	/*7019*/ uint16(x86_xMatch),
+	/*7020*/ uint16(x86_xCondSlashR),
+	0,    // 0
+	7029, // 1
+	0,    // 2
+	7052, // 3
+	7075, // 4
+	7098, // 5
+	7121, // 6
+	0,    // 7
+	/*7029*/ uint16(x86_xCondIs64), 7032, 7044,
+	/*7032*/ uint16(x86_xCondDataSize), 7036, 7040, 0,
+	/*7036*/ uint16(x86_xSetOp), uint16(x86_CMPXCHG8B),
+	/*7038*/ uint16(x86_xArgM64),
+	/*7039*/ uint16(x86_xMatch),
+	/*7040*/ uint16(x86_xSetOp), uint16(x86_CMPXCHG8B),
+	/*7042*/ uint16(x86_xArgM64),
+	/*7043*/ uint16(x86_xMatch),
+	/*7044*/ uint16(x86_xCondDataSize), 7036, 7040, 7048,
+	/*7048*/ uint16(x86_xSetOp), uint16(x86_CMPXCHG16B),
+	/*7050*/ uint16(x86_xArgM128),
+	/*7051*/ uint16(x86_xMatch),
+	/*7052*/ uint16(x86_xCondIs64), 7055, 7067,
+	/*7055*/ uint16(x86_xCondDataSize), 7059, 7063, 0,
+	/*7059*/ uint16(x86_xSetOp), uint16(x86_XRSTORS),
+	/*7061*/ uint16(x86_xArgMem),
+	/*7062*/ uint16(x86_xMatch),
+	/*7063*/ uint16(x86_xSetOp), uint16(x86_XRSTORS),
+	/*7065*/ uint16(x86_xArgMem),
+	/*7066*/ uint16(x86_xMatch),
+	/*7067*/ uint16(x86_xCondDataSize), 7059, 7063, 7071,
+	/*7071*/ uint16(x86_xSetOp), uint16(x86_XRSTORS64),
+	/*7073*/ uint16(x86_xArgMem),
+	/*7074*/ uint16(x86_xMatch),
+	/*7075*/ uint16(x86_xCondIs64), 7078, 7090,
+	/*7078*/ uint16(x86_xCondDataSize), 7082, 7086, 0,
+	/*7082*/ uint16(x86_xSetOp), uint16(x86_XSAVEC),
+	/*7084*/ uint16(x86_xArgMem),
+	/*7085*/ uint16(x86_xMatch),
+	/*7086*/ uint16(x86_xSetOp), uint16(x86_XSAVEC),
+	/*7088*/ uint16(x86_xArgMem),
+	/*7089*/ uint16(x86_xMatch),
+	/*7090*/ uint16(x86_xCondDataSize), 7082, 7086, 7094,
+	/*7094*/ uint16(x86_xSetOp), uint16(x86_XSAVEC64),
+	/*7096*/ uint16(x86_xArgMem),
+	/*7097*/ uint16(x86_xMatch),
+	/*7098*/ uint16(x86_xCondIs64), 7101, 7113,
+	/*7101*/ uint16(x86_xCondDataSize), 7105, 7109, 0,
+	/*7105*/ uint16(x86_xSetOp), uint16(x86_XSAVES),
+	/*7107*/ uint16(x86_xArgMem),
+	/*7108*/ uint16(x86_xMatch),
+	/*7109*/ uint16(x86_xSetOp), uint16(x86_XSAVES),
+	/*7111*/ uint16(x86_xArgMem),
+	/*7112*/ uint16(x86_xMatch),
+	/*7113*/ uint16(x86_xCondDataSize), 7105, 7109, 7117,
+	/*7117*/ uint16(x86_xSetOp), uint16(x86_XSAVES64),
+	/*7119*/ uint16(x86_xArgMem),
+	/*7120*/ uint16(x86_xMatch),
+	/*7121*/ uint16(x86_xCondIs64), 7124, 7142,
+	/*7124*/ uint16(x86_xCondDataSize), 7128, 7135, 0,
+	/*7128*/ uint16(x86_xCondIsMem), 7131, 0,
+	/*7131*/ uint16(x86_xSetOp), uint16(x86_RDRAND),
+	/*7133*/ uint16(x86_xArgRmf16),
+	/*7134*/ uint16(x86_xMatch),
+	/*7135*/ uint16(x86_xCondIsMem), 7138, 0,
+	/*7138*/ uint16(x86_xSetOp), uint16(x86_RDRAND),
+	/*7140*/ uint16(x86_xArgRmf32),
+	/*7141*/ uint16(x86_xMatch),
+	/*7142*/ uint16(x86_xCondDataSize), 7128, 7135, 7146,
+	/*7146*/ uint16(x86_xSetOp), uint16(x86_RDRAND),
+	/*7148*/ uint16(x86_xMatch),
+	/*7149*/ uint16(x86_xCondIs64), 7152, 7164,
+	/*7152*/ uint16(x86_xCondDataSize), 7156, 7160, 0,
+	/*7156*/ uint16(x86_xSetOp), uint16(x86_BSWAP),
+	/*7158*/ uint16(x86_xArgR16op),
+	/*7159*/ uint16(x86_xMatch),
+	/*7160*/ uint16(x86_xSetOp), uint16(x86_BSWAP),
+	/*7162*/ uint16(x86_xArgR32op),
+	/*7163*/ uint16(x86_xMatch),
+	/*7164*/ uint16(x86_xCondDataSize), 7156, 7160, 7168,
+	/*7168*/ uint16(x86_xSetOp), uint16(x86_BSWAP),
+	/*7170*/ uint16(x86_xArgR64op),
+	/*7171*/ uint16(x86_xMatch),
+	/*7172*/ uint16(x86_xCondPrefix), 2,
+	0xF2, 7184,
+	0x66, 7178,
+	/*7178*/ uint16(x86_xSetOp), uint16(x86_ADDSUBPD),
+	/*7180*/ uint16(x86_xReadSlashR),
+	/*7181*/ uint16(x86_xArgXmm1),
+	/*7182*/ uint16(x86_xArgXmm2M128),
+	/*7183*/ uint16(x86_xMatch),
+	/*7184*/ uint16(x86_xSetOp), uint16(x86_ADDSUBPS),
+	/*7186*/ uint16(x86_xReadSlashR),
+	/*7187*/ uint16(x86_xArgXmm1),
+	/*7188*/ uint16(x86_xArgXmm2M128),
+	/*7189*/ uint16(x86_xMatch),
+	/*7190*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7202,
+	0x0, 7196,
+	/*7196*/ uint16(x86_xSetOp), uint16(x86_PSRLW),
+	/*7198*/ uint16(x86_xReadSlashR),
+	/*7199*/ uint16(x86_xArgMm),
+	/*7200*/ uint16(x86_xArgMmM64),
+	/*7201*/ uint16(x86_xMatch),
+	/*7202*/ uint16(x86_xSetOp), uint16(x86_PSRLW),
+	/*7204*/ uint16(x86_xReadSlashR),
+	/*7205*/ uint16(x86_xArgXmm1),
+	/*7206*/ uint16(x86_xArgXmm2M128),
+	/*7207*/ uint16(x86_xMatch),
+	/*7208*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7220,
+	0x0, 7214,
+	/*7214*/ uint16(x86_xSetOp), uint16(x86_PSRLD),
+	/*7216*/ uint16(x86_xReadSlashR),
+	/*7217*/ uint16(x86_xArgMm),
+	/*7218*/ uint16(x86_xArgMmM64),
+	/*7219*/ uint16(x86_xMatch),
+	/*7220*/ uint16(x86_xSetOp), uint16(x86_PSRLD),
+	/*7222*/ uint16(x86_xReadSlashR),
+	/*7223*/ uint16(x86_xArgXmm1),
+	/*7224*/ uint16(x86_xArgXmm2M128),
+	/*7225*/ uint16(x86_xMatch),
+	/*7226*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7238,
+	0x0, 7232,
+	/*7232*/ uint16(x86_xSetOp), uint16(x86_PSRLQ),
+	/*7234*/ uint16(x86_xReadSlashR),
+	/*7235*/ uint16(x86_xArgMm),
+	/*7236*/ uint16(x86_xArgMmM64),
+	/*7237*/ uint16(x86_xMatch),
+	/*7238*/ uint16(x86_xSetOp), uint16(x86_PSRLQ),
+	/*7240*/ uint16(x86_xReadSlashR),
+	/*7241*/ uint16(x86_xArgXmm1),
+	/*7242*/ uint16(x86_xArgXmm2M128),
+	/*7243*/ uint16(x86_xMatch),
+	/*7244*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7256,
+	0x0, 7250,
+	/*7250*/ uint16(x86_xSetOp), uint16(x86_PADDQ),
+	/*7252*/ uint16(x86_xReadSlashR),
+	/*7253*/ uint16(x86_xArgMm1),
+	/*7254*/ uint16(x86_xArgMm2M64),
+	/*7255*/ uint16(x86_xMatch),
+	/*7256*/ uint16(x86_xSetOp), uint16(x86_PADDQ),
+	/*7258*/ uint16(x86_xReadSlashR),
+	/*7259*/ uint16(x86_xArgXmm1),
+	/*7260*/ uint16(x86_xArgXmm2M128),
+	/*7261*/ uint16(x86_xMatch),
+	/*7262*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7274,
+	0x0, 7268,
+	/*7268*/ uint16(x86_xSetOp), uint16(x86_PMULLW),
+	/*7270*/ uint16(x86_xReadSlashR),
+	/*7271*/ uint16(x86_xArgMm),
+	/*7272*/ uint16(x86_xArgMmM64),
+	/*7273*/ uint16(x86_xMatch),
+	/*7274*/ uint16(x86_xSetOp), uint16(x86_PMULLW),
+	/*7276*/ uint16(x86_xReadSlashR),
+	/*7277*/ uint16(x86_xArgXmm1),
+	/*7278*/ uint16(x86_xArgXmm2M128),
+	/*7279*/ uint16(x86_xMatch),
+	/*7280*/ uint16(x86_xCondPrefix), 3,
+	0xF3, 7300,
+	0xF2, 7294,
+	0x66, 7288,
+	/*7288*/ uint16(x86_xSetOp), uint16(x86_MOVQ),
+	/*7290*/ uint16(x86_xReadSlashR),
+	/*7291*/ uint16(x86_xArgXmm2M64),
+	/*7292*/ uint16(x86_xArgXmm1),
+	/*7293*/ uint16(x86_xMatch),
+	/*7294*/ uint16(x86_xSetOp), uint16(x86_MOVDQ2Q),
+	/*7296*/ uint16(x86_xReadSlashR),
+	/*7297*/ uint16(x86_xArgMm),
+	/*7298*/ uint16(x86_xArgXmm2),
+	/*7299*/ uint16(x86_xMatch),
+	/*7300*/ uint16(x86_xSetOp), uint16(x86_MOVQ2DQ),
+	/*7302*/ uint16(x86_xReadSlashR),
+	/*7303*/ uint16(x86_xArgXmm1),
+	/*7304*/ uint16(x86_xArgMm2),
+	/*7305*/ uint16(x86_xMatch),
+	/*7306*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7318,
+	0x0, 7312,
+	/*7312*/ uint16(x86_xSetOp), uint16(x86_PMOVMSKB),
+	/*7314*/ uint16(x86_xReadSlashR),
+	/*7315*/ uint16(x86_xArgR32),
+	/*7316*/ uint16(x86_xArgMm2),
+	/*7317*/ uint16(x86_xMatch),
+	/*7318*/ uint16(x86_xSetOp), uint16(x86_PMOVMSKB),
+	/*7320*/ uint16(x86_xReadSlashR),
+	/*7321*/ uint16(x86_xArgR32),
+	/*7322*/ uint16(x86_xArgXmm2),
+	/*7323*/ uint16(x86_xMatch),
+	/*7324*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7336,
+	0x0, 7330,
+	/*7330*/ uint16(x86_xSetOp), uint16(x86_PSUBUSB),
+	/*7332*/ uint16(x86_xReadSlashR),
+	/*7333*/ uint16(x86_xArgMm),
+	/*7334*/ uint16(x86_xArgMmM64),
+	/*7335*/ uint16(x86_xMatch),
+	/*7336*/ uint16(x86_xSetOp), uint16(x86_PSUBUSB),
+	/*7338*/ uint16(x86_xReadSlashR),
+	/*7339*/ uint16(x86_xArgXmm1),
+	/*7340*/ uint16(x86_xArgXmm2M128),
+	/*7341*/ uint16(x86_xMatch),
+	/*7342*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7354,
+	0x0, 7348,
+	/*7348*/ uint16(x86_xSetOp), uint16(x86_PSUBUSW),
+	/*7350*/ uint16(x86_xReadSlashR),
+	/*7351*/ uint16(x86_xArgMm),
+	/*7352*/ uint16(x86_xArgMmM64),
+	/*7353*/ uint16(x86_xMatch),
+	/*7354*/ uint16(x86_xSetOp), uint16(x86_PSUBUSW),
+	/*7356*/ uint16(x86_xReadSlashR),
+	/*7357*/ uint16(x86_xArgXmm1),
+	/*7358*/ uint16(x86_xArgXmm2M128),
+	/*7359*/ uint16(x86_xMatch),
+	/*7360*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7372,
+	0x0, 7366,
+	/*7366*/ uint16(x86_xSetOp), uint16(x86_PMINUB),
+	/*7368*/ uint16(x86_xReadSlashR),
+	/*7369*/ uint16(x86_xArgMm1),
+	/*7370*/ uint16(x86_xArgMm2M64),
+	/*7371*/ uint16(x86_xMatch),
+	/*7372*/ uint16(x86_xSetOp), uint16(x86_PMINUB),
+	/*7374*/ uint16(x86_xReadSlashR),
+	/*7375*/ uint16(x86_xArgXmm1),
+	/*7376*/ uint16(x86_xArgXmm2M128),
+	/*7377*/ uint16(x86_xMatch),
+	/*7378*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7390,
+	0x0, 7384,
+	/*7384*/ uint16(x86_xSetOp), uint16(x86_PAND),
+	/*7386*/ uint16(x86_xReadSlashR),
+	/*7387*/ uint16(x86_xArgMm),
+	/*7388*/ uint16(x86_xArgMmM64),
+	/*7389*/ uint16(x86_xMatch),
+	/*7390*/ uint16(x86_xSetOp), uint16(x86_PAND),
+	/*7392*/ uint16(x86_xReadSlashR),
+	/*7393*/ uint16(x86_xArgXmm1),
+	/*7394*/ uint16(x86_xArgXmm2M128),
+	/*7395*/ uint16(x86_xMatch),
+	/*7396*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7408,
+	0x0, 7402,
+	/*7402*/ uint16(x86_xSetOp), uint16(x86_PADDUSB),
+	/*7404*/ uint16(x86_xReadSlashR),
+	/*7405*/ uint16(x86_xArgMm),
+	/*7406*/ uint16(x86_xArgMmM64),
+	/*7407*/ uint16(x86_xMatch),
+	/*7408*/ uint16(x86_xSetOp), uint16(x86_PADDUSB),
+	/*7410*/ uint16(x86_xReadSlashR),
+	/*7411*/ uint16(x86_xArgXmm1),
+	/*7412*/ uint16(x86_xArgXmm2M128),
+	/*7413*/ uint16(x86_xMatch),
+	/*7414*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7426,
+	0x0, 7420,
+	/*7420*/ uint16(x86_xSetOp), uint16(x86_PADDUSW),
+	/*7422*/ uint16(x86_xReadSlashR),
+	/*7423*/ uint16(x86_xArgMm),
+	/*7424*/ uint16(x86_xArgMmM64),
+	/*7425*/ uint16(x86_xMatch),
+	/*7426*/ uint16(x86_xSetOp), uint16(x86_PADDUSW),
+	/*7428*/ uint16(x86_xReadSlashR),
+	/*7429*/ uint16(x86_xArgXmm1),
+	/*7430*/ uint16(x86_xArgXmm2M128),
+	/*7431*/ uint16(x86_xMatch),
+	/*7432*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7444,
+	0x0, 7438,
+	/*7438*/ uint16(x86_xSetOp), uint16(x86_PMAXUB),
+	/*7440*/ uint16(x86_xReadSlashR),
+	/*7441*/ uint16(x86_xArgMm1),
+	/*7442*/ uint16(x86_xArgMm2M64),
+	/*7443*/ uint16(x86_xMatch),
+	/*7444*/ uint16(x86_xSetOp), uint16(x86_PMAXUB),
+	/*7446*/ uint16(x86_xReadSlashR),
+	/*7447*/ uint16(x86_xArgXmm1),
+	/*7448*/ uint16(x86_xArgXmm2M128),
+	/*7449*/ uint16(x86_xMatch),
+	/*7450*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7462,
+	0x0, 7456,
+	/*7456*/ uint16(x86_xSetOp), uint16(x86_PANDN),
+	/*7458*/ uint16(x86_xReadSlashR),
+	/*7459*/ uint16(x86_xArgMm),
+	/*7460*/ uint16(x86_xArgMmM64),
+	/*7461*/ uint16(x86_xMatch),
+	/*7462*/ uint16(x86_xSetOp), uint16(x86_PANDN),
+	/*7464*/ uint16(x86_xReadSlashR),
+	/*7465*/ uint16(x86_xArgXmm1),
+	/*7466*/ uint16(x86_xArgXmm2M128),
+	/*7467*/ uint16(x86_xMatch),
+	/*7468*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7480,
+	0x0, 7474,
+	/*7474*/ uint16(x86_xSetOp), uint16(x86_PAVGB),
+	/*7476*/ uint16(x86_xReadSlashR),
+	/*7477*/ uint16(x86_xArgMm1),
+	/*7478*/ uint16(x86_xArgMm2M64),
+	/*7479*/ uint16(x86_xMatch),
+	/*7480*/ uint16(x86_xSetOp), uint16(x86_PAVGB),
+	/*7482*/ uint16(x86_xReadSlashR),
+	/*7483*/ uint16(x86_xArgXmm1),
+	/*7484*/ uint16(x86_xArgXmm2M128),
+	/*7485*/ uint16(x86_xMatch),
+	/*7486*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7498,
+	0x0, 7492,
+	/*7492*/ uint16(x86_xSetOp), uint16(x86_PSRAW),
+	/*7494*/ uint16(x86_xReadSlashR),
+	/*7495*/ uint16(x86_xArgMm),
+	/*7496*/ uint16(x86_xArgMmM64),
+	/*7497*/ uint16(x86_xMatch),
+	/*7498*/ uint16(x86_xSetOp), uint16(x86_PSRAW),
+	/*7500*/ uint16(x86_xReadSlashR),
+	/*7501*/ uint16(x86_xArgXmm1),
+	/*7502*/ uint16(x86_xArgXmm2M128),
+	/*7503*/ uint16(x86_xMatch),
+	/*7504*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7516,
+	0x0, 7510,
+	/*7510*/ uint16(x86_xSetOp), uint16(x86_PSRAD),
+	/*7512*/ uint16(x86_xReadSlashR),
+	/*7513*/ uint16(x86_xArgMm),
+	/*7514*/ uint16(x86_xArgMmM64),
+	/*7515*/ uint16(x86_xMatch),
+	/*7516*/ uint16(x86_xSetOp), uint16(x86_PSRAD),
+	/*7518*/ uint16(x86_xReadSlashR),
+	/*7519*/ uint16(x86_xArgXmm1),
+	/*7520*/ uint16(x86_xArgXmm2M128),
+	/*7521*/ uint16(x86_xMatch),
+	/*7522*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7534,
+	0x0, 7528,
+	/*7528*/ uint16(x86_xSetOp), uint16(x86_PAVGW),
+	/*7530*/ uint16(x86_xReadSlashR),
+	/*7531*/ uint16(x86_xArgMm1),
+	/*7532*/ uint16(x86_xArgMm2M64),
+	/*7533*/ uint16(x86_xMatch),
+	/*7534*/ uint16(x86_xSetOp), uint16(x86_PAVGW),
+	/*7536*/ uint16(x86_xReadSlashR),
+	/*7537*/ uint16(x86_xArgXmm1),
+	/*7538*/ uint16(x86_xArgXmm2M128),
+	/*7539*/ uint16(x86_xMatch),
+	/*7540*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7552,
+	0x0, 7546,
+	/*7546*/ uint16(x86_xSetOp), uint16(x86_PMULHUW),
+	/*7548*/ uint16(x86_xReadSlashR),
+	/*7549*/ uint16(x86_xArgMm1),
+	/*7550*/ uint16(x86_xArgMm2M64),
+	/*7551*/ uint16(x86_xMatch),
+	/*7552*/ uint16(x86_xSetOp), uint16(x86_PMULHUW),
+	/*7554*/ uint16(x86_xReadSlashR),
+	/*7555*/ uint16(x86_xArgXmm1),
+	/*7556*/ uint16(x86_xArgXmm2M128),
+	/*7557*/ uint16(x86_xMatch),
+	/*7558*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7570,
+	0x0, 7564,
+	/*7564*/ uint16(x86_xSetOp), uint16(x86_PMULHW),
+	/*7566*/ uint16(x86_xReadSlashR),
+	/*7567*/ uint16(x86_xArgMm),
+	/*7568*/ uint16(x86_xArgMmM64),
+	/*7569*/ uint16(x86_xMatch),
+	/*7570*/ uint16(x86_xSetOp), uint16(x86_PMULHW),
+	/*7572*/ uint16(x86_xReadSlashR),
+	/*7573*/ uint16(x86_xArgXmm1),
+	/*7574*/ uint16(x86_xArgXmm2M128),
+	/*7575*/ uint16(x86_xMatch),
+	/*7576*/ uint16(x86_xCondPrefix), 3,
+	0xF3, 7596,
+	0xF2, 7590,
+	0x66, 7584,
+	/*7584*/ uint16(x86_xSetOp), uint16(x86_CVTTPD2DQ),
+	/*7586*/ uint16(x86_xReadSlashR),
+	/*7587*/ uint16(x86_xArgXmm1),
+	/*7588*/ uint16(x86_xArgXmm2M128),
+	/*7589*/ uint16(x86_xMatch),
+	/*7590*/ uint16(x86_xSetOp), uint16(x86_CVTPD2DQ),
+	/*7592*/ uint16(x86_xReadSlashR),
+	/*7593*/ uint16(x86_xArgXmm1),
+	/*7594*/ uint16(x86_xArgXmm2M128),
+	/*7595*/ uint16(x86_xMatch),
+	/*7596*/ uint16(x86_xSetOp), uint16(x86_CVTDQ2PD),
+	/*7598*/ uint16(x86_xReadSlashR),
+	/*7599*/ uint16(x86_xArgXmm1),
+	/*7600*/ uint16(x86_xArgXmm2M64),
+	/*7601*/ uint16(x86_xMatch),
+	/*7602*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7614,
+	0x0, 7608,
+	/*7608*/ uint16(x86_xSetOp), uint16(x86_MOVNTQ),
+	/*7610*/ uint16(x86_xReadSlashR),
+	/*7611*/ uint16(x86_xArgM64),
+	/*7612*/ uint16(x86_xArgMm),
+	/*7613*/ uint16(x86_xMatch),
+	/*7614*/ uint16(x86_xSetOp), uint16(x86_MOVNTDQ),
+	/*7616*/ uint16(x86_xReadSlashR),
+	/*7617*/ uint16(x86_xArgM128),
+	/*7618*/ uint16(x86_xArgXmm),
+	/*7619*/ uint16(x86_xMatch),
+	/*7620*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7632,
+	0x0, 7626,
+	/*7626*/ uint16(x86_xSetOp), uint16(x86_PSUBSB),
+	/*7628*/ uint16(x86_xReadSlashR),
+	/*7629*/ uint16(x86_xArgMm),
+	/*7630*/ uint16(x86_xArgMmM64),
+	/*7631*/ uint16(x86_xMatch),
+	/*7632*/ uint16(x86_xSetOp), uint16(x86_PSUBSB),
+	/*7634*/ uint16(x86_xReadSlashR),
+	/*7635*/ uint16(x86_xArgXmm1),
+	/*7636*/ uint16(x86_xArgXmm2M128),
+	/*7637*/ uint16(x86_xMatch),
+	/*7638*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7650,
+	0x0, 7644,
+	/*7644*/ uint16(x86_xSetOp), uint16(x86_PSUBSW),
+	/*7646*/ uint16(x86_xReadSlashR),
+	/*7647*/ uint16(x86_xArgMm),
+	/*7648*/ uint16(x86_xArgMmM64),
+	/*7649*/ uint16(x86_xMatch),
+	/*7650*/ uint16(x86_xSetOp), uint16(x86_PSUBSW),
+	/*7652*/ uint16(x86_xReadSlashR),
+	/*7653*/ uint16(x86_xArgXmm1),
+	/*7654*/ uint16(x86_xArgXmm2M128),
+	/*7655*/ uint16(x86_xMatch),
+	/*7656*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7668,
+	0x0, 7662,
+	/*7662*/ uint16(x86_xSetOp), uint16(x86_PMINSW),
+	/*7664*/ uint16(x86_xReadSlashR),
+	/*7665*/ uint16(x86_xArgMm1),
+	/*7666*/ uint16(x86_xArgMm2M64),
+	/*7667*/ uint16(x86_xMatch),
+	/*7668*/ uint16(x86_xSetOp), uint16(x86_PMINSW),
+	/*7670*/ uint16(x86_xReadSlashR),
+	/*7671*/ uint16(x86_xArgXmm1),
+	/*7672*/ uint16(x86_xArgXmm2M128),
+	/*7673*/ uint16(x86_xMatch),
+	/*7674*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7686,
+	0x0, 7680,
+	/*7680*/ uint16(x86_xSetOp), uint16(x86_POR),
+	/*7682*/ uint16(x86_xReadSlashR),
+	/*7683*/ uint16(x86_xArgMm),
+	/*7684*/ uint16(x86_xArgMmM64),
+	/*7685*/ uint16(x86_xMatch),
+	/*7686*/ uint16(x86_xSetOp), uint16(x86_POR),
+	/*7688*/ uint16(x86_xReadSlashR),
+	/*7689*/ uint16(x86_xArgXmm1),
+	/*7690*/ uint16(x86_xArgXmm2M128),
+	/*7691*/ uint16(x86_xMatch),
+	/*7692*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7704,
+	0x0, 7698,
+	/*7698*/ uint16(x86_xSetOp), uint16(x86_PADDSB),
+	/*7700*/ uint16(x86_xReadSlashR),
+	/*7701*/ uint16(x86_xArgMm),
+	/*7702*/ uint16(x86_xArgMmM64),
+	/*7703*/ uint16(x86_xMatch),
+	/*7704*/ uint16(x86_xSetOp), uint16(x86_PADDSB),
+	/*7706*/ uint16(x86_xReadSlashR),
+	/*7707*/ uint16(x86_xArgXmm1),
+	/*7708*/ uint16(x86_xArgXmm2M128),
+	/*7709*/ uint16(x86_xMatch),
+	/*7710*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7722,
+	0x0, 7716,
+	/*7716*/ uint16(x86_xSetOp), uint16(x86_PADDSW),
+	/*7718*/ uint16(x86_xReadSlashR),
+	/*7719*/ uint16(x86_xArgMm),
+	/*7720*/ uint16(x86_xArgMmM64),
+	/*7721*/ uint16(x86_xMatch),
+	/*7722*/ uint16(x86_xSetOp), uint16(x86_PADDSW),
+	/*7724*/ uint16(x86_xReadSlashR),
+	/*7725*/ uint16(x86_xArgXmm1),
+	/*7726*/ uint16(x86_xArgXmm2M128),
+	/*7727*/ uint16(x86_xMatch),
+	/*7728*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7740,
+	0x0, 7734,
+	/*7734*/ uint16(x86_xSetOp), uint16(x86_PMAXSW),
+	/*7736*/ uint16(x86_xReadSlashR),
+	/*7737*/ uint16(x86_xArgMm1),
+	/*7738*/ uint16(x86_xArgMm2M64),
+	/*7739*/ uint16(x86_xMatch),
+	/*7740*/ uint16(x86_xSetOp), uint16(x86_PMAXSW),
+	/*7742*/ uint16(x86_xReadSlashR),
+	/*7743*/ uint16(x86_xArgXmm1),
+	/*7744*/ uint16(x86_xArgXmm2M128),
+	/*7745*/ uint16(x86_xMatch),
+	/*7746*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7758,
+	0x0, 7752,
+	/*7752*/ uint16(x86_xSetOp), uint16(x86_PXOR),
+	/*7754*/ uint16(x86_xReadSlashR),
+	/*7755*/ uint16(x86_xArgMm),
+	/*7756*/ uint16(x86_xArgMmM64),
+	/*7757*/ uint16(x86_xMatch),
+	/*7758*/ uint16(x86_xSetOp), uint16(x86_PXOR),
+	/*7760*/ uint16(x86_xReadSlashR),
+	/*7761*/ uint16(x86_xArgXmm1),
+	/*7762*/ uint16(x86_xArgXmm2M128),
+	/*7763*/ uint16(x86_xMatch),
+	/*7764*/ uint16(x86_xCondPrefix), 1,
+	0xF2, 7768,
+	/*7768*/ uint16(x86_xSetOp), uint16(x86_LDDQU),
+	/*7770*/ uint16(x86_xReadSlashR),
+	/*7771*/ uint16(x86_xArgXmm1),
+	/*7772*/ uint16(x86_xArgM128),
+	/*7773*/ uint16(x86_xMatch),
+	/*7774*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7786,
+	0x0, 7780,
+	/*7780*/ uint16(x86_xSetOp), uint16(x86_PSLLW),
+	/*7782*/ uint16(x86_xReadSlashR),
+	/*7783*/ uint16(x86_xArgMm),
+	/*7784*/ uint16(x86_xArgMmM64),
+	/*7785*/ uint16(x86_xMatch),
+	/*7786*/ uint16(x86_xSetOp), uint16(x86_PSLLW),
+	/*7788*/ uint16(x86_xReadSlashR),
+	/*7789*/ uint16(x86_xArgXmm1),
+	/*7790*/ uint16(x86_xArgXmm2M128),
+	/*7791*/ uint16(x86_xMatch),
+	/*7792*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7804,
+	0x0, 7798,
+	/*7798*/ uint16(x86_xSetOp), uint16(x86_PSLLD),
+	/*7800*/ uint16(x86_xReadSlashR),
+	/*7801*/ uint16(x86_xArgMm),
+	/*7802*/ uint16(x86_xArgMmM64),
+	/*7803*/ uint16(x86_xMatch),
+	/*7804*/ uint16(x86_xSetOp), uint16(x86_PSLLD),
+	/*7806*/ uint16(x86_xReadSlashR),
+	/*7807*/ uint16(x86_xArgXmm1),
+	/*7808*/ uint16(x86_xArgXmm2M128),
+	/*7809*/ uint16(x86_xMatch),
+	/*7810*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7822,
+	0x0, 7816,
+	/*7816*/ uint16(x86_xSetOp), uint16(x86_PSLLQ),
+	/*7818*/ uint16(x86_xReadSlashR),
+	/*7819*/ uint16(x86_xArgMm),
+	/*7820*/ uint16(x86_xArgMmM64),
+	/*7821*/ uint16(x86_xMatch),
+	/*7822*/ uint16(x86_xSetOp), uint16(x86_PSLLQ),
+	/*7824*/ uint16(x86_xReadSlashR),
+	/*7825*/ uint16(x86_xArgXmm1),
+	/*7826*/ uint16(x86_xArgXmm2M128),
+	/*7827*/ uint16(x86_xMatch),
+	/*7828*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7840,
+	0x0, 7834,
+	/*7834*/ uint16(x86_xSetOp), uint16(x86_PMULUDQ),
+	/*7836*/ uint16(x86_xReadSlashR),
+	/*7837*/ uint16(x86_xArgMm1),
+	/*7838*/ uint16(x86_xArgMm2M64),
+	/*7839*/ uint16(x86_xMatch),
+	/*7840*/ uint16(x86_xSetOp), uint16(x86_PMULUDQ),
+	/*7842*/ uint16(x86_xReadSlashR),
+	/*7843*/ uint16(x86_xArgXmm1),
+	/*7844*/ uint16(x86_xArgXmm2M128),
+	/*7845*/ uint16(x86_xMatch),
+	/*7846*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7858,
+	0x0, 7852,
+	/*7852*/ uint16(x86_xSetOp), uint16(x86_PMADDWD),
+	/*7854*/ uint16(x86_xReadSlashR),
+	/*7855*/ uint16(x86_xArgMm),
+	/*7856*/ uint16(x86_xArgMmM64),
+	/*7857*/ uint16(x86_xMatch),
+	/*7858*/ uint16(x86_xSetOp), uint16(x86_PMADDWD),
+	/*7860*/ uint16(x86_xReadSlashR),
+	/*7861*/ uint16(x86_xArgXmm1),
+	/*7862*/ uint16(x86_xArgXmm2M128),
+	/*7863*/ uint16(x86_xMatch),
+	/*7864*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7876,
+	0x0, 7870,
+	/*7870*/ uint16(x86_xSetOp), uint16(x86_PSADBW),
+	/*7872*/ uint16(x86_xReadSlashR),
+	/*7873*/ uint16(x86_xArgMm1),
+	/*7874*/ uint16(x86_xArgMm2M64),
+	/*7875*/ uint16(x86_xMatch),
+	/*7876*/ uint16(x86_xSetOp), uint16(x86_PSADBW),
+	/*7878*/ uint16(x86_xReadSlashR),
+	/*7879*/ uint16(x86_xArgXmm1),
+	/*7880*/ uint16(x86_xArgXmm2M128),
+	/*7881*/ uint16(x86_xMatch),
+	/*7882*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7894,
+	0x0, 7888,
+	/*7888*/ uint16(x86_xSetOp), uint16(x86_MASKMOVQ),
+	/*7890*/ uint16(x86_xReadSlashR),
+	/*7891*/ uint16(x86_xArgMm1),
+	/*7892*/ uint16(x86_xArgMm2),
+	/*7893*/ uint16(x86_xMatch),
+	/*7894*/ uint16(x86_xSetOp), uint16(x86_MASKMOVDQU),
+	/*7896*/ uint16(x86_xReadSlashR),
+	/*7897*/ uint16(x86_xArgXmm1),
+	/*7898*/ uint16(x86_xArgXmm2),
+	/*7899*/ uint16(x86_xMatch),
+	/*7900*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7912,
+	0x0, 7906,
+	/*7906*/ uint16(x86_xSetOp), uint16(x86_PSUBB),
+	/*7908*/ uint16(x86_xReadSlashR),
+	/*7909*/ uint16(x86_xArgMm),
+	/*7910*/ uint16(x86_xArgMmM64),
+	/*7911*/ uint16(x86_xMatch),
+	/*7912*/ uint16(x86_xSetOp), uint16(x86_PSUBB),
+	/*7914*/ uint16(x86_xReadSlashR),
+	/*7915*/ uint16(x86_xArgXmm1),
+	/*7916*/ uint16(x86_xArgXmm2M128),
+	/*7917*/ uint16(x86_xMatch),
+	/*7918*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7930,
+	0x0, 7924,
+	/*7924*/ uint16(x86_xSetOp), uint16(x86_PSUBW),
+	/*7926*/ uint16(x86_xReadSlashR),
+	/*7927*/ uint16(x86_xArgMm),
+	/*7928*/ uint16(x86_xArgMmM64),
+	/*7929*/ uint16(x86_xMatch),
+	/*7930*/ uint16(x86_xSetOp), uint16(x86_PSUBW),
+	/*7932*/ uint16(x86_xReadSlashR),
+	/*7933*/ uint16(x86_xArgXmm1),
+	/*7934*/ uint16(x86_xArgXmm2M128),
+	/*7935*/ uint16(x86_xMatch),
+	/*7936*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7948,
+	0x0, 7942,
+	/*7942*/ uint16(x86_xSetOp), uint16(x86_PSUBD),
+	/*7944*/ uint16(x86_xReadSlashR),
+	/*7945*/ uint16(x86_xArgMm),
+	/*7946*/ uint16(x86_xArgMmM64),
+	/*7947*/ uint16(x86_xMatch),
+	/*7948*/ uint16(x86_xSetOp), uint16(x86_PSUBD),
+	/*7950*/ uint16(x86_xReadSlashR),
+	/*7951*/ uint16(x86_xArgXmm1),
+	/*7952*/ uint16(x86_xArgXmm2M128),
+	/*7953*/ uint16(x86_xMatch),
+	/*7954*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7966,
+	0x0, 7960,
+	/*7960*/ uint16(x86_xSetOp), uint16(x86_PSUBQ),
+	/*7962*/ uint16(x86_xReadSlashR),
+	/*7963*/ uint16(x86_xArgMm1),
+	/*7964*/ uint16(x86_xArgMm2M64),
+	/*7965*/ uint16(x86_xMatch),
+	/*7966*/ uint16(x86_xSetOp), uint16(x86_PSUBQ),
+	/*7968*/ uint16(x86_xReadSlashR),
+	/*7969*/ uint16(x86_xArgXmm1),
+	/*7970*/ uint16(x86_xArgXmm2M128),
+	/*7971*/ uint16(x86_xMatch),
+	/*7972*/ uint16(x86_xCondPrefix), 2,
+	0x66, 7984,
+	0x0, 7978,
+	/*7978*/ uint16(x86_xSetOp), uint16(x86_PADDB),
+	/*7980*/ uint16(x86_xReadSlashR),
+	/*7981*/ uint16(x86_xArgMm),
+	/*7982*/ uint16(x86_xArgMmM64),
+	/*7983*/ uint16(x86_xMatch),
+	/*7984*/ uint16(x86_xSetOp), uint16(x86_PADDB),
+	/*7986*/ uint16(x86_xReadSlashR),
+	/*7987*/ uint16(x86_xArgXmm1),
+	/*7988*/ uint16(x86_xArgXmm2M128),
+	/*7989*/ uint16(x86_xMatch),
+	/*7990*/ uint16(x86_xCondPrefix), 2,
+	0x66, 8002,
+	0x0, 7996,
+	/*7996*/ uint16(x86_xSetOp), uint16(x86_PADDW),
+	/*7998*/ uint16(x86_xReadSlashR),
+	/*7999*/ uint16(x86_xArgMm),
+	/*8000*/ uint16(x86_xArgMmM64),
+	/*8001*/ uint16(x86_xMatch),
+	/*8002*/ uint16(x86_xSetOp), uint16(x86_PADDW),
+	/*8004*/ uint16(x86_xReadSlashR),
+	/*8005*/ uint16(x86_xArgXmm1),
+	/*8006*/ uint16(x86_xArgXmm2M128),
+	/*8007*/ uint16(x86_xMatch),
+	/*8008*/ uint16(x86_xCondPrefix), 2,
+	0x66, 8020,
+	0x0, 8014,
+	/*8014*/ uint16(x86_xSetOp), uint16(x86_PADDD),
+	/*8016*/ uint16(x86_xReadSlashR),
+	/*8017*/ uint16(x86_xArgMm),
+	/*8018*/ uint16(x86_xArgMmM64),
+	/*8019*/ uint16(x86_xMatch),
+	/*8020*/ uint16(x86_xSetOp), uint16(x86_PADDD),
+	/*8022*/ uint16(x86_xReadSlashR),
+	/*8023*/ uint16(x86_xArgXmm1),
+	/*8024*/ uint16(x86_xArgXmm2M128),
+	/*8025*/ uint16(x86_xMatch),
+	/*8026*/ uint16(x86_xSetOp), uint16(x86_ADC),
+	/*8028*/ uint16(x86_xReadSlashR),
+	/*8029*/ uint16(x86_xArgRM8),
+	/*8030*/ uint16(x86_xArgR8),
+	/*8031*/ uint16(x86_xMatch),
+	/*8032*/ uint16(x86_xCondIs64), 8035, 8051,
+	/*8035*/ uint16(x86_xCondDataSize), 8039, 8045, 0,
+	/*8039*/ uint16(x86_xSetOp), uint16(x86_ADC),
+	/*8041*/ uint16(x86_xReadSlashR),
+	/*8042*/ uint16(x86_xArgRM16),
+	/*8043*/ uint16(x86_xArgR16),
+	/*8044*/ uint16(x86_xMatch),
+	/*8045*/ uint16(x86_xSetOp), uint16(x86_ADC),
+	/*8047*/ uint16(x86_xReadSlashR),
+	/*8048*/ uint16(x86_xArgRM32),
+	/*8049*/ uint16(x86_xArgR32),
+	/*8050*/ uint16(x86_xMatch),
+	/*8051*/ uint16(x86_xCondDataSize), 8039, 8045, 8055,
+	/*8055*/ uint16(x86_xSetOp), uint16(x86_ADC),
+	/*8057*/ uint16(x86_xReadSlashR),
+	/*8058*/ uint16(x86_xArgRM64),
+	/*8059*/ uint16(x86_xArgR64),
+	/*8060*/ uint16(x86_xMatch),
+	/*8061*/ uint16(x86_xSetOp), uint16(x86_ADC),
+	/*8063*/ uint16(x86_xReadSlashR),
+	/*8064*/ uint16(x86_xArgR8),
+	/*8065*/ uint16(x86_xArgRM8),
+	/*8066*/ uint16(x86_xMatch),
+	/*8067*/ uint16(x86_xCondIs64), 8070, 8086,
+	/*8070*/ uint16(x86_xCondDataSize), 8074, 8080, 0,
+	/*8074*/ uint16(x86_xSetOp), uint16(x86_ADC),
+	/*8076*/ uint16(x86_xReadSlashR),
+	/*8077*/ uint16(x86_xArgR16),
+	/*8078*/ uint16(x86_xArgRM16),
+	/*8079*/ uint16(x86_xMatch),
+	/*8080*/ uint16(x86_xSetOp), uint16(x86_ADC),
+	/*8082*/ uint16(x86_xReadSlashR),
+	/*8083*/ uint16(x86_xArgR32),
+	/*8084*/ uint16(x86_xArgRM32),
+	/*8085*/ uint16(x86_xMatch),
+	/*8086*/ uint16(x86_xCondDataSize), 8074, 8080, 8090,
+	/*8090*/ uint16(x86_xSetOp), uint16(x86_ADC),
+	/*8092*/ uint16(x86_xReadSlashR),
+	/*8093*/ uint16(x86_xArgR64),
+	/*8094*/ uint16(x86_xArgRM64),
+	/*8095*/ uint16(x86_xMatch),
+	/*8096*/ uint16(x86_xSetOp), uint16(x86_ADC),
+	/*8098*/ uint16(x86_xReadIb),
+	/*8099*/ uint16(x86_xArgAL),
+	/*8100*/ uint16(x86_xArgImm8u),
+	/*8101*/ uint16(x86_xMatch),
+	/*8102*/ uint16(x86_xCondIs64), 8105, 8121,
+	/*8105*/ uint16(x86_xCondDataSize), 8109, 8115, 0,
+	/*8109*/ uint16(x86_xSetOp), uint16(x86_ADC),
+	/*8111*/ uint16(x86_xReadIw),
+	/*8112*/ uint16(x86_xArgAX),
+	/*8113*/ uint16(x86_xArgImm16),
+	/*8114*/ uint16(x86_xMatch),
+	/*8115*/ uint16(x86_xSetOp), uint16(x86_ADC),
+	/*8117*/ uint16(x86_xReadId),
+	/*8118*/ uint16(x86_xArgEAX),
+	/*8119*/ uint16(x86_xArgImm32),
+	/*8120*/ uint16(x86_xMatch),
+	/*8121*/ uint16(x86_xCondDataSize), 8109, 8115, 8125,
+	/*8125*/ uint16(x86_xSetOp), uint16(x86_ADC),
+	/*8127*/ uint16(x86_xReadId),
+	/*8128*/ uint16(x86_xArgRAX),
+	/*8129*/ uint16(x86_xArgImm32),
+	/*8130*/ uint16(x86_xMatch),
+	/*8131*/ uint16(x86_xCondIs64), 8134, 0,
+	/*8134*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+	/*8136*/ uint16(x86_xArgSS),
+	/*8137*/ uint16(x86_xMatch),
+	/*8138*/ uint16(x86_xCondIs64), 8141, 0,
+	/*8141*/ uint16(x86_xSetOp), uint16(x86_POP),
+	/*8143*/ uint16(x86_xArgSS),
+	/*8144*/ uint16(x86_xMatch),
+	/*8145*/ uint16(x86_xSetOp), uint16(x86_SBB),
+	/*8147*/ uint16(x86_xReadSlashR),
+	/*8148*/ uint16(x86_xArgRM8),
+	/*8149*/ uint16(x86_xArgR8),
+	/*8150*/ uint16(x86_xMatch),
+	/*8151*/ uint16(x86_xCondIs64), 8154, 8170,
+	/*8154*/ uint16(x86_xCondDataSize), 8158, 8164, 0,
+	/*8158*/ uint16(x86_xSetOp), uint16(x86_SBB),
+	/*8160*/ uint16(x86_xReadSlashR),
+	/*8161*/ uint16(x86_xArgRM16),
+	/*8162*/ uint16(x86_xArgR16),
+	/*8163*/ uint16(x86_xMatch),
+	/*8164*/ uint16(x86_xSetOp), uint16(x86_SBB),
+	/*8166*/ uint16(x86_xReadSlashR),
+	/*8167*/ uint16(x86_xArgRM32),
+	/*8168*/ uint16(x86_xArgR32),
+	/*8169*/ uint16(x86_xMatch),
+	/*8170*/ uint16(x86_xCondDataSize), 8158, 8164, 8174,
+	/*8174*/ uint16(x86_xSetOp), uint16(x86_SBB),
+	/*8176*/ uint16(x86_xReadSlashR),
+	/*8177*/ uint16(x86_xArgRM64),
+	/*8178*/ uint16(x86_xArgR64),
+	/*8179*/ uint16(x86_xMatch),
+	/*8180*/ uint16(x86_xSetOp), uint16(x86_SBB),
+	/*8182*/ uint16(x86_xReadSlashR),
+	/*8183*/ uint16(x86_xArgR8),
+	/*8184*/ uint16(x86_xArgRM8),
+	/*8185*/ uint16(x86_xMatch),
+	/*8186*/ uint16(x86_xCondIs64), 8189, 8205,
+	/*8189*/ uint16(x86_xCondDataSize), 8193, 8199, 0,
+	/*8193*/ uint16(x86_xSetOp), uint16(x86_SBB),
+	/*8195*/ uint16(x86_xReadSlashR),
+	/*8196*/ uint16(x86_xArgR16),
+	/*8197*/ uint16(x86_xArgRM16),
+	/*8198*/ uint16(x86_xMatch),
+	/*8199*/ uint16(x86_xSetOp), uint16(x86_SBB),
+	/*8201*/ uint16(x86_xReadSlashR),
+	/*8202*/ uint16(x86_xArgR32),
+	/*8203*/ uint16(x86_xArgRM32),
+	/*8204*/ uint16(x86_xMatch),
+	/*8205*/ uint16(x86_xCondDataSize), 8193, 8199, 8209,
+	/*8209*/ uint16(x86_xSetOp), uint16(x86_SBB),
+	/*8211*/ uint16(x86_xReadSlashR),
+	/*8212*/ uint16(x86_xArgR64),
+	/*8213*/ uint16(x86_xArgRM64),
+	/*8214*/ uint16(x86_xMatch),
+	/*8215*/ uint16(x86_xSetOp), uint16(x86_SBB),
+	/*8217*/ uint16(x86_xReadIb),
+	/*8218*/ uint16(x86_xArgAL),
+	/*8219*/ uint16(x86_xArgImm8u),
+	/*8220*/ uint16(x86_xMatch),
+	/*8221*/ uint16(x86_xCondIs64), 8224, 8240,
+	/*8224*/ uint16(x86_xCondDataSize), 8228, 8234, 0,
+	/*8228*/ uint16(x86_xSetOp), uint16(x86_SBB),
+	/*8230*/ uint16(x86_xReadIw),
+	/*8231*/ uint16(x86_xArgAX),
+	/*8232*/ uint16(x86_xArgImm16),
+	/*8233*/ uint16(x86_xMatch),
+	/*8234*/ uint16(x86_xSetOp), uint16(x86_SBB),
+	/*8236*/ uint16(x86_xReadId),
+	/*8237*/ uint16(x86_xArgEAX),
+	/*8238*/ uint16(x86_xArgImm32),
+	/*8239*/ uint16(x86_xMatch),
+	/*8240*/ uint16(x86_xCondDataSize), 8228, 8234, 8244,
+	/*8244*/ uint16(x86_xSetOp), uint16(x86_SBB),
+	/*8246*/ uint16(x86_xReadId),
+	/*8247*/ uint16(x86_xArgRAX),
+	/*8248*/ uint16(x86_xArgImm32),
+	/*8249*/ uint16(x86_xMatch),
+	/*8250*/ uint16(x86_xCondIs64), 8253, 0,
+	/*8253*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+	/*8255*/ uint16(x86_xArgDS),
+	/*8256*/ uint16(x86_xMatch),
+	/*8257*/ uint16(x86_xCondIs64), 8260, 0,
+	/*8260*/ uint16(x86_xSetOp), uint16(x86_POP),
+	/*8262*/ uint16(x86_xArgDS),
+	/*8263*/ uint16(x86_xMatch),
+	/*8264*/ uint16(x86_xSetOp), uint16(x86_AND),
+	/*8266*/ uint16(x86_xReadSlashR),
+	/*8267*/ uint16(x86_xArgRM8),
+	/*8268*/ uint16(x86_xArgR8),
+	/*8269*/ uint16(x86_xMatch),
+	/*8270*/ uint16(x86_xCondIs64), 8273, 8289,
+	/*8273*/ uint16(x86_xCondDataSize), 8277, 8283, 0,
+	/*8277*/ uint16(x86_xSetOp), uint16(x86_AND),
+	/*8279*/ uint16(x86_xReadSlashR),
+	/*8280*/ uint16(x86_xArgRM16),
+	/*8281*/ uint16(x86_xArgR16),
+	/*8282*/ uint16(x86_xMatch),
+	/*8283*/ uint16(x86_xSetOp), uint16(x86_AND),
+	/*8285*/ uint16(x86_xReadSlashR),
+	/*8286*/ uint16(x86_xArgRM32),
+	/*8287*/ uint16(x86_xArgR32),
+	/*8288*/ uint16(x86_xMatch),
+	/*8289*/ uint16(x86_xCondDataSize), 8277, 8283, 8293,
+	/*8293*/ uint16(x86_xSetOp), uint16(x86_AND),
+	/*8295*/ uint16(x86_xReadSlashR),
+	/*8296*/ uint16(x86_xArgRM64),
+	/*8297*/ uint16(x86_xArgR64),
+	/*8298*/ uint16(x86_xMatch),
+	/*8299*/ uint16(x86_xSetOp), uint16(x86_AND),
+	/*8301*/ uint16(x86_xReadSlashR),
+	/*8302*/ uint16(x86_xArgR8),
+	/*8303*/ uint16(x86_xArgRM8),
+	/*8304*/ uint16(x86_xMatch),
+	/*8305*/ uint16(x86_xCondIs64), 8308, 8324,
+	/*8308*/ uint16(x86_xCondDataSize), 8312, 8318, 0,
+	/*8312*/ uint16(x86_xSetOp), uint16(x86_AND),
+	/*8314*/ uint16(x86_xReadSlashR),
+	/*8315*/ uint16(x86_xArgR16),
+	/*8316*/ uint16(x86_xArgRM16),
+	/*8317*/ uint16(x86_xMatch),
+	/*8318*/ uint16(x86_xSetOp), uint16(x86_AND),
+	/*8320*/ uint16(x86_xReadSlashR),
+	/*8321*/ uint16(x86_xArgR32),
+	/*8322*/ uint16(x86_xArgRM32),
+	/*8323*/ uint16(x86_xMatch),
+	/*8324*/ uint16(x86_xCondDataSize), 8312, 8318, 8328,
+	/*8328*/ uint16(x86_xSetOp), uint16(x86_AND),
+	/*8330*/ uint16(x86_xReadSlashR),
+	/*8331*/ uint16(x86_xArgR64),
+	/*8332*/ uint16(x86_xArgRM64),
+	/*8333*/ uint16(x86_xMatch),
+	/*8334*/ uint16(x86_xSetOp), uint16(x86_AND),
+	/*8336*/ uint16(x86_xReadIb),
+	/*8337*/ uint16(x86_xArgAL),
+	/*8338*/ uint16(x86_xArgImm8u),
+	/*8339*/ uint16(x86_xMatch),
+	/*8340*/ uint16(x86_xCondIs64), 8343, 8359,
+	/*8343*/ uint16(x86_xCondDataSize), 8347, 8353, 0,
+	/*8347*/ uint16(x86_xSetOp), uint16(x86_AND),
+	/*8349*/ uint16(x86_xReadIw),
+	/*8350*/ uint16(x86_xArgAX),
+	/*8351*/ uint16(x86_xArgImm16),
+	/*8352*/ uint16(x86_xMatch),
+	/*8353*/ uint16(x86_xSetOp), uint16(x86_AND),
+	/*8355*/ uint16(x86_xReadId),
+	/*8356*/ uint16(x86_xArgEAX),
+	/*8357*/ uint16(x86_xArgImm32),
+	/*8358*/ uint16(x86_xMatch),
+	/*8359*/ uint16(x86_xCondDataSize), 8347, 8353, 8363,
+	/*8363*/ uint16(x86_xSetOp), uint16(x86_AND),
+	/*8365*/ uint16(x86_xReadId),
+	/*8366*/ uint16(x86_xArgRAX),
+	/*8367*/ uint16(x86_xArgImm32),
+	/*8368*/ uint16(x86_xMatch),
+	/*8369*/ uint16(x86_xCondIs64), 8372, 0,
+	/*8372*/ uint16(x86_xSetOp), uint16(x86_DAA),
+	/*8374*/ uint16(x86_xMatch),
+	/*8375*/ uint16(x86_xSetOp), uint16(x86_SUB),
+	/*8377*/ uint16(x86_xReadSlashR),
+	/*8378*/ uint16(x86_xArgRM8),
+	/*8379*/ uint16(x86_xArgR8),
+	/*8380*/ uint16(x86_xMatch),
+	/*8381*/ uint16(x86_xCondIs64), 8384, 8400,
+	/*8384*/ uint16(x86_xCondDataSize), 8388, 8394, 0,
+	/*8388*/ uint16(x86_xSetOp), uint16(x86_SUB),
+	/*8390*/ uint16(x86_xReadSlashR),
+	/*8391*/ uint16(x86_xArgRM16),
+	/*8392*/ uint16(x86_xArgR16),
+	/*8393*/ uint16(x86_xMatch),
+	/*8394*/ uint16(x86_xSetOp), uint16(x86_SUB),
+	/*8396*/ uint16(x86_xReadSlashR),
+	/*8397*/ uint16(x86_xArgRM32),
+	/*8398*/ uint16(x86_xArgR32),
+	/*8399*/ uint16(x86_xMatch),
+	/*8400*/ uint16(x86_xCondDataSize), 8388, 8394, 8404,
+	/*8404*/ uint16(x86_xSetOp), uint16(x86_SUB),
+	/*8406*/ uint16(x86_xReadSlashR),
+	/*8407*/ uint16(x86_xArgRM64),
+	/*8408*/ uint16(x86_xArgR64),
+	/*8409*/ uint16(x86_xMatch),
+	/*8410*/ uint16(x86_xSetOp), uint16(x86_SUB),
+	/*8412*/ uint16(x86_xReadSlashR),
+	/*8413*/ uint16(x86_xArgR8),
+	/*8414*/ uint16(x86_xArgRM8),
+	/*8415*/ uint16(x86_xMatch),
+	/*8416*/ uint16(x86_xCondIs64), 8419, 8435,
+	/*8419*/ uint16(x86_xCondDataSize), 8423, 8429, 0,
+	/*8423*/ uint16(x86_xSetOp), uint16(x86_SUB),
+	/*8425*/ uint16(x86_xReadSlashR),
+	/*8426*/ uint16(x86_xArgR16),
+	/*8427*/ uint16(x86_xArgRM16),
+	/*8428*/ uint16(x86_xMatch),
+	/*8429*/ uint16(x86_xSetOp), uint16(x86_SUB),
+	/*8431*/ uint16(x86_xReadSlashR),
+	/*8432*/ uint16(x86_xArgR32),
+	/*8433*/ uint16(x86_xArgRM32),
+	/*8434*/ uint16(x86_xMatch),
+	/*8435*/ uint16(x86_xCondDataSize), 8423, 8429, 8439,
+	/*8439*/ uint16(x86_xSetOp), uint16(x86_SUB),
+	/*8441*/ uint16(x86_xReadSlashR),
+	/*8442*/ uint16(x86_xArgR64),
+	/*8443*/ uint16(x86_xArgRM64),
+	/*8444*/ uint16(x86_xMatch),
+	/*8445*/ uint16(x86_xSetOp), uint16(x86_SUB),
+	/*8447*/ uint16(x86_xReadIb),
+	/*8448*/ uint16(x86_xArgAL),
+	/*8449*/ uint16(x86_xArgImm8u),
+	/*8450*/ uint16(x86_xMatch),
+	/*8451*/ uint16(x86_xCondIs64), 8454, 8470,
+	/*8454*/ uint16(x86_xCondDataSize), 8458, 8464, 0,
+	/*8458*/ uint16(x86_xSetOp), uint16(x86_SUB),
+	/*8460*/ uint16(x86_xReadIw),
+	/*8461*/ uint16(x86_xArgAX),
+	/*8462*/ uint16(x86_xArgImm16),
+	/*8463*/ uint16(x86_xMatch),
+	/*8464*/ uint16(x86_xSetOp), uint16(x86_SUB),
+	/*8466*/ uint16(x86_xReadId),
+	/*8467*/ uint16(x86_xArgEAX),
+	/*8468*/ uint16(x86_xArgImm32),
+	/*8469*/ uint16(x86_xMatch),
+	/*8470*/ uint16(x86_xCondDataSize), 8458, 8464, 8474,
+	/*8474*/ uint16(x86_xSetOp), uint16(x86_SUB),
+	/*8476*/ uint16(x86_xReadId),
+	/*8477*/ uint16(x86_xArgRAX),
+	/*8478*/ uint16(x86_xArgImm32),
+	/*8479*/ uint16(x86_xMatch),
+	/*8480*/ uint16(x86_xCondIs64), 8483, 0,
+	/*8483*/ uint16(x86_xSetOp), uint16(x86_DAS),
+	/*8485*/ uint16(x86_xMatch),
+	/*8486*/ uint16(x86_xSetOp), uint16(x86_XOR),
+	/*8488*/ uint16(x86_xReadSlashR),
+	/*8489*/ uint16(x86_xArgRM8),
+	/*8490*/ uint16(x86_xArgR8),
+	/*8491*/ uint16(x86_xMatch),
+	/*8492*/ uint16(x86_xCondIs64), 8495, 8511,
+	/*8495*/ uint16(x86_xCondDataSize), 8499, 8505, 0,
+	/*8499*/ uint16(x86_xSetOp), uint16(x86_XOR),
+	/*8501*/ uint16(x86_xReadSlashR),
+	/*8502*/ uint16(x86_xArgRM16),
+	/*8503*/ uint16(x86_xArgR16),
+	/*8504*/ uint16(x86_xMatch),
+	/*8505*/ uint16(x86_xSetOp), uint16(x86_XOR),
+	/*8507*/ uint16(x86_xReadSlashR),
+	/*8508*/ uint16(x86_xArgRM32),
+	/*8509*/ uint16(x86_xArgR32),
+	/*8510*/ uint16(x86_xMatch),
+	/*8511*/ uint16(x86_xCondDataSize), 8499, 8505, 8515,
+	/*8515*/ uint16(x86_xSetOp), uint16(x86_XOR),
+	/*8517*/ uint16(x86_xReadSlashR),
+	/*8518*/ uint16(x86_xArgRM64),
+	/*8519*/ uint16(x86_xArgR64),
+	/*8520*/ uint16(x86_xMatch),
+	/*8521*/ uint16(x86_xSetOp), uint16(x86_XOR),
+	/*8523*/ uint16(x86_xReadSlashR),
+	/*8524*/ uint16(x86_xArgR8),
+	/*8525*/ uint16(x86_xArgRM8),
+	/*8526*/ uint16(x86_xMatch),
+	/*8527*/ uint16(x86_xCondIs64), 8530, 8546,
+	/*8530*/ uint16(x86_xCondDataSize), 8534, 8540, 0,
+	/*8534*/ uint16(x86_xSetOp), uint16(x86_XOR),
+	/*8536*/ uint16(x86_xReadSlashR),
+	/*8537*/ uint16(x86_xArgR16),
+	/*8538*/ uint16(x86_xArgRM16),
+	/*8539*/ uint16(x86_xMatch),
+	/*8540*/ uint16(x86_xSetOp), uint16(x86_XOR),
+	/*8542*/ uint16(x86_xReadSlashR),
+	/*8543*/ uint16(x86_xArgR32),
+	/*8544*/ uint16(x86_xArgRM32),
+	/*8545*/ uint16(x86_xMatch),
+	/*8546*/ uint16(x86_xCondDataSize), 8534, 8540, 8550,
+	/*8550*/ uint16(x86_xSetOp), uint16(x86_XOR),
+	/*8552*/ uint16(x86_xReadSlashR),
+	/*8553*/ uint16(x86_xArgR64),
+	/*8554*/ uint16(x86_xArgRM64),
+	/*8555*/ uint16(x86_xMatch),
+	/*8556*/ uint16(x86_xSetOp), uint16(x86_XOR),
+	/*8558*/ uint16(x86_xReadIb),
+	/*8559*/ uint16(x86_xArgAL),
+	/*8560*/ uint16(x86_xArgImm8u),
+	/*8561*/ uint16(x86_xMatch),
+	/*8562*/ uint16(x86_xCondIs64), 8565, 8581,
+	/*8565*/ uint16(x86_xCondDataSize), 8569, 8575, 0,
+	/*8569*/ uint16(x86_xSetOp), uint16(x86_XOR),
+	/*8571*/ uint16(x86_xReadIw),
+	/*8572*/ uint16(x86_xArgAX),
+	/*8573*/ uint16(x86_xArgImm16),
+	/*8574*/ uint16(x86_xMatch),
+	/*8575*/ uint16(x86_xSetOp), uint16(x86_XOR),
+	/*8577*/ uint16(x86_xReadId),
+	/*8578*/ uint16(x86_xArgEAX),
+	/*8579*/ uint16(x86_xArgImm32),
+	/*8580*/ uint16(x86_xMatch),
+	/*8581*/ uint16(x86_xCondDataSize), 8569, 8575, 8585,
+	/*8585*/ uint16(x86_xSetOp), uint16(x86_XOR),
+	/*8587*/ uint16(x86_xReadId),
+	/*8588*/ uint16(x86_xArgRAX),
+	/*8589*/ uint16(x86_xArgImm32),
+	/*8590*/ uint16(x86_xMatch),
+	/*8591*/ uint16(x86_xCondIs64), 8594, 0,
+	/*8594*/ uint16(x86_xSetOp), uint16(x86_AAA),
+	/*8596*/ uint16(x86_xMatch),
+	/*8597*/ uint16(x86_xSetOp), uint16(x86_CMP),
+	/*8599*/ uint16(x86_xReadSlashR),
+	/*8600*/ uint16(x86_xArgRM8),
+	/*8601*/ uint16(x86_xArgR8),
+	/*8602*/ uint16(x86_xMatch),
+	/*8603*/ uint16(x86_xCondIs64), 8606, 8622,
+	/*8606*/ uint16(x86_xCondDataSize), 8610, 8616, 0,
+	/*8610*/ uint16(x86_xSetOp), uint16(x86_CMP),
+	/*8612*/ uint16(x86_xReadSlashR),
+	/*8613*/ uint16(x86_xArgRM16),
+	/*8614*/ uint16(x86_xArgR16),
+	/*8615*/ uint16(x86_xMatch),
+	/*8616*/ uint16(x86_xSetOp), uint16(x86_CMP),
+	/*8618*/ uint16(x86_xReadSlashR),
+	/*8619*/ uint16(x86_xArgRM32),
+	/*8620*/ uint16(x86_xArgR32),
+	/*8621*/ uint16(x86_xMatch),
+	/*8622*/ uint16(x86_xCondDataSize), 8610, 8616, 8626,
+	/*8626*/ uint16(x86_xSetOp), uint16(x86_CMP),
+	/*8628*/ uint16(x86_xReadSlashR),
+	/*8629*/ uint16(x86_xArgRM64),
+	/*8630*/ uint16(x86_xArgR64),
+	/*8631*/ uint16(x86_xMatch),
+	/*8632*/ uint16(x86_xSetOp), uint16(x86_CMP),
+	/*8634*/ uint16(x86_xReadSlashR),
+	/*8635*/ uint16(x86_xArgR8),
+	/*8636*/ uint16(x86_xArgRM8),
+	/*8637*/ uint16(x86_xMatch),
+	/*8638*/ uint16(x86_xCondIs64), 8641, 8657,
+	/*8641*/ uint16(x86_xCondDataSize), 8645, 8651, 0,
+	/*8645*/ uint16(x86_xSetOp), uint16(x86_CMP),
+	/*8647*/ uint16(x86_xReadSlashR),
+	/*8648*/ uint16(x86_xArgR16),
+	/*8649*/ uint16(x86_xArgRM16),
+	/*8650*/ uint16(x86_xMatch),
+	/*8651*/ uint16(x86_xSetOp), uint16(x86_CMP),
+	/*8653*/ uint16(x86_xReadSlashR),
+	/*8654*/ uint16(x86_xArgR32),
+	/*8655*/ uint16(x86_xArgRM32),
+	/*8656*/ uint16(x86_xMatch),
+	/*8657*/ uint16(x86_xCondDataSize), 8645, 8651, 8661,
+	/*8661*/ uint16(x86_xSetOp), uint16(x86_CMP),
+	/*8663*/ uint16(x86_xReadSlashR),
+	/*8664*/ uint16(x86_xArgR64),
+	/*8665*/ uint16(x86_xArgRM64),
+	/*8666*/ uint16(x86_xMatch),
+	/*8667*/ uint16(x86_xSetOp), uint16(x86_CMP),
+	/*8669*/ uint16(x86_xReadIb),
+	/*8670*/ uint16(x86_xArgAL),
+	/*8671*/ uint16(x86_xArgImm8u),
+	/*8672*/ uint16(x86_xMatch),
+	/*8673*/ uint16(x86_xCondIs64), 8676, 8692,
+	/*8676*/ uint16(x86_xCondDataSize), 8680, 8686, 0,
+	/*8680*/ uint16(x86_xSetOp), uint16(x86_CMP),
+	/*8682*/ uint16(x86_xReadIw),
+	/*8683*/ uint16(x86_xArgAX),
+	/*8684*/ uint16(x86_xArgImm16),
+	/*8685*/ uint16(x86_xMatch),
+	/*8686*/ uint16(x86_xSetOp), uint16(x86_CMP),
+	/*8688*/ uint16(x86_xReadId),
+	/*8689*/ uint16(x86_xArgEAX),
+	/*8690*/ uint16(x86_xArgImm32),
+	/*8691*/ uint16(x86_xMatch),
+	/*8692*/ uint16(x86_xCondDataSize), 8680, 8686, 8696,
+	/*8696*/ uint16(x86_xSetOp), uint16(x86_CMP),
+	/*8698*/ uint16(x86_xReadId),
+	/*8699*/ uint16(x86_xArgRAX),
+	/*8700*/ uint16(x86_xArgImm32),
+	/*8701*/ uint16(x86_xMatch),
+	/*8702*/ uint16(x86_xCondIs64), 8705, 0,
+	/*8705*/ uint16(x86_xSetOp), uint16(x86_AAS),
+	/*8707*/ uint16(x86_xMatch),
+	/*8708*/ uint16(x86_xCondIs64), 8711, 0,
+	/*8711*/ uint16(x86_xCondDataSize), 8715, 8719, 0,
+	/*8715*/ uint16(x86_xSetOp), uint16(x86_INC),
+	/*8717*/ uint16(x86_xArgR16op),
+	/*8718*/ uint16(x86_xMatch),
+	/*8719*/ uint16(x86_xSetOp), uint16(x86_INC),
+	/*8721*/ uint16(x86_xArgR32op),
+	/*8722*/ uint16(x86_xMatch),
+	/*8723*/ uint16(x86_xCondIs64), 8726, 0,
+	/*8726*/ uint16(x86_xCondDataSize), 8730, 8734, 0,
+	/*8730*/ uint16(x86_xSetOp), uint16(x86_DEC),
+	/*8732*/ uint16(x86_xArgR16op),
+	/*8733*/ uint16(x86_xMatch),
+	/*8734*/ uint16(x86_xSetOp), uint16(x86_DEC),
+	/*8736*/ uint16(x86_xArgR32op),
+	/*8737*/ uint16(x86_xMatch),
+	/*8738*/ uint16(x86_xCondIs64), 8741, 8753,
+	/*8741*/ uint16(x86_xCondDataSize), 8745, 8749, 0,
+	/*8745*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+	/*8747*/ uint16(x86_xArgR16op),
+	/*8748*/ uint16(x86_xMatch),
+	/*8749*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+	/*8751*/ uint16(x86_xArgR32op),
+	/*8752*/ uint16(x86_xMatch),
+	/*8753*/ uint16(x86_xCondDataSize), 8745, 8757, 8761,
+	/*8757*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+	/*8759*/ uint16(x86_xArgR64op),
+	/*8760*/ uint16(x86_xMatch),
+	/*8761*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+	/*8763*/ uint16(x86_xArgR64op),
+	/*8764*/ uint16(x86_xMatch),
+	/*8765*/ uint16(x86_xCondIs64), 8768, 8780,
+	/*8768*/ uint16(x86_xCondDataSize), 8772, 8776, 0,
+	/*8772*/ uint16(x86_xSetOp), uint16(x86_POP),
+	/*8774*/ uint16(x86_xArgR16op),
+	/*8775*/ uint16(x86_xMatch),
+	/*8776*/ uint16(x86_xSetOp), uint16(x86_POP),
+	/*8778*/ uint16(x86_xArgR32op),
+	/*8779*/ uint16(x86_xMatch),
+	/*8780*/ uint16(x86_xCondDataSize), 8772, 8784, 8788,
+	/*8784*/ uint16(x86_xSetOp), uint16(x86_POP),
+	/*8786*/ uint16(x86_xArgR64op),
+	/*8787*/ uint16(x86_xMatch),
+	/*8788*/ uint16(x86_xSetOp), uint16(x86_POP),
+	/*8790*/ uint16(x86_xArgR64op),
+	/*8791*/ uint16(x86_xMatch),
+	/*8792*/ uint16(x86_xCondIs64), 8795, 0,
+	/*8795*/ uint16(x86_xCondDataSize), 8799, 8802, 0,
+	/*8799*/ uint16(x86_xSetOp), uint16(x86_PUSHA),
+	/*8801*/ uint16(x86_xMatch),
+	/*8802*/ uint16(x86_xSetOp), uint16(x86_PUSHAD),
+	/*8804*/ uint16(x86_xMatch),
+	/*8805*/ uint16(x86_xCondIs64), 8808, 0,
+	/*8808*/ uint16(x86_xCondDataSize), 8812, 8815, 0,
+	/*8812*/ uint16(x86_xSetOp), uint16(x86_POPA),
+	/*8814*/ uint16(x86_xMatch),
+	/*8815*/ uint16(x86_xSetOp), uint16(x86_POPAD),
+	/*8817*/ uint16(x86_xMatch),
+	/*8818*/ uint16(x86_xCondIs64), 8821, 0,
+	/*8821*/ uint16(x86_xCondDataSize), 8825, 8831, 0,
+	/*8825*/ uint16(x86_xSetOp), uint16(x86_BOUND),
+	/*8827*/ uint16(x86_xReadSlashR),
+	/*8828*/ uint16(x86_xArgR16),
+	/*8829*/ uint16(x86_xArgM16and16),
+	/*8830*/ uint16(x86_xMatch),
+	/*8831*/ uint16(x86_xSetOp), uint16(x86_BOUND),
+	/*8833*/ uint16(x86_xReadSlashR),
+	/*8834*/ uint16(x86_xArgR32),
+	/*8835*/ uint16(x86_xArgM32and32),
+	/*8836*/ uint16(x86_xMatch),
+	/*8837*/ uint16(x86_xCondIs64), 8840, 8846,
+	/*8840*/ uint16(x86_xSetOp), uint16(x86_ARPL),
+	/*8842*/ uint16(x86_xReadSlashR),
+	/*8843*/ uint16(x86_xArgRM16),
+	/*8844*/ uint16(x86_xArgR16),
+	/*8845*/ uint16(x86_xMatch),
+	/*8846*/ uint16(x86_xCondDataSize), 8850, 8856, 8862,
+	/*8850*/ uint16(x86_xSetOp), uint16(x86_MOVSXD),
+	/*8852*/ uint16(x86_xReadSlashR),
+	/*8853*/ uint16(x86_xArgR16),
+	/*8854*/ uint16(x86_xArgRM32),
+	/*8855*/ uint16(x86_xMatch),
+	/*8856*/ uint16(x86_xSetOp), uint16(x86_MOVSXD),
+	/*8858*/ uint16(x86_xReadSlashR),
+	/*8859*/ uint16(x86_xArgR32),
+	/*8860*/ uint16(x86_xArgRM32),
+	/*8861*/ uint16(x86_xMatch),
+	/*8862*/ uint16(x86_xSetOp), uint16(x86_MOVSXD),
+	/*8864*/ uint16(x86_xReadSlashR),
+	/*8865*/ uint16(x86_xArgR64),
+	/*8866*/ uint16(x86_xArgRM32),
+	/*8867*/ uint16(x86_xMatch),
+	/*8868*/ uint16(x86_xCondDataSize), 8872, 8877, 8882,
+	/*8872*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+	/*8874*/ uint16(x86_xReadIw),
+	/*8875*/ uint16(x86_xArgImm16),
+	/*8876*/ uint16(x86_xMatch),
+	/*8877*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+	/*8879*/ uint16(x86_xReadId),
+	/*8880*/ uint16(x86_xArgImm32),
+	/*8881*/ uint16(x86_xMatch),
+	/*8882*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+	/*8884*/ uint16(x86_xReadId),
+	/*8885*/ uint16(x86_xArgImm32),
+	/*8886*/ uint16(x86_xMatch),
+	/*8887*/ uint16(x86_xCondIs64), 8890, 8910,
+	/*8890*/ uint16(x86_xCondDataSize), 8894, 8902, 0,
+	/*8894*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+	/*8896*/ uint16(x86_xReadSlashR),
+	/*8897*/ uint16(x86_xReadIw),
+	/*8898*/ uint16(x86_xArgR16),
+	/*8899*/ uint16(x86_xArgRM16),
+	/*8900*/ uint16(x86_xArgImm16),
+	/*8901*/ uint16(x86_xMatch),
+	/*8902*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+	/*8904*/ uint16(x86_xReadSlashR),
+	/*8905*/ uint16(x86_xReadId),
+	/*8906*/ uint16(x86_xArgR32),
+	/*8907*/ uint16(x86_xArgRM32),
+	/*8908*/ uint16(x86_xArgImm32),
+	/*8909*/ uint16(x86_xMatch),
+	/*8910*/ uint16(x86_xCondDataSize), 8894, 8902, 8914,
+	/*8914*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+	/*8916*/ uint16(x86_xReadSlashR),
+	/*8917*/ uint16(x86_xReadId),
+	/*8918*/ uint16(x86_xArgR64),
+	/*8919*/ uint16(x86_xArgRM64),
+	/*8920*/ uint16(x86_xArgImm32),
+	/*8921*/ uint16(x86_xMatch),
+	/*8922*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+	/*8924*/ uint16(x86_xReadIb),
+	/*8925*/ uint16(x86_xArgImm8),
+	/*8926*/ uint16(x86_xMatch),
+	/*8927*/ uint16(x86_xCondIs64), 8930, 8950,
+	/*8930*/ uint16(x86_xCondDataSize), 8934, 8942, 0,
+	/*8934*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+	/*8936*/ uint16(x86_xReadSlashR),
+	/*8937*/ uint16(x86_xReadIb),
+	/*8938*/ uint16(x86_xArgR16),
+	/*8939*/ uint16(x86_xArgRM16),
+	/*8940*/ uint16(x86_xArgImm8),
+	/*8941*/ uint16(x86_xMatch),
+	/*8942*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+	/*8944*/ uint16(x86_xReadSlashR),
+	/*8945*/ uint16(x86_xReadIb),
+	/*8946*/ uint16(x86_xArgR32),
+	/*8947*/ uint16(x86_xArgRM32),
+	/*8948*/ uint16(x86_xArgImm8),
+	/*8949*/ uint16(x86_xMatch),
+	/*8950*/ uint16(x86_xCondDataSize), 8934, 8942, 8954,
+	/*8954*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+	/*8956*/ uint16(x86_xReadSlashR),
+	/*8957*/ uint16(x86_xReadIb),
+	/*8958*/ uint16(x86_xArgR64),
+	/*8959*/ uint16(x86_xArgRM64),
+	/*8960*/ uint16(x86_xArgImm8),
+	/*8961*/ uint16(x86_xMatch),
+	/*8962*/ uint16(x86_xSetOp), uint16(x86_INSB),
+	/*8964*/ uint16(x86_xMatch),
+	/*8965*/ uint16(x86_xCondDataSize), 8969, 8972, 8975,
+	/*8969*/ uint16(x86_xSetOp), uint16(x86_INSW),
+	/*8971*/ uint16(x86_xMatch),
+	/*8972*/ uint16(x86_xSetOp), uint16(x86_INSD),
+	/*8974*/ uint16(x86_xMatch),
+	/*8975*/ uint16(x86_xSetOp), uint16(x86_INSD),
+	/*8977*/ uint16(x86_xMatch),
+	/*8978*/ uint16(x86_xSetOp), uint16(x86_OUTSB),
+	/*8980*/ uint16(x86_xMatch),
+	/*8981*/ uint16(x86_xCondDataSize), 8985, 8988, 8991,
+	/*8985*/ uint16(x86_xSetOp), uint16(x86_OUTSW),
+	/*8987*/ uint16(x86_xMatch),
+	/*8988*/ uint16(x86_xSetOp), uint16(x86_OUTSD),
+	/*8990*/ uint16(x86_xMatch),
+	/*8991*/ uint16(x86_xSetOp), uint16(x86_OUTSD),
+	/*8993*/ uint16(x86_xMatch),
+	/*8994*/ uint16(x86_xSetOp), uint16(x86_JO),
+	/*8996*/ uint16(x86_xReadCb),
+	/*8997*/ uint16(x86_xArgRel8),
+	/*8998*/ uint16(x86_xMatch),
+	/*8999*/ uint16(x86_xSetOp), uint16(x86_JNO),
+	/*9001*/ uint16(x86_xReadCb),
+	/*9002*/ uint16(x86_xArgRel8),
+	/*9003*/ uint16(x86_xMatch),
+	/*9004*/ uint16(x86_xSetOp), uint16(x86_JB),
+	/*9006*/ uint16(x86_xReadCb),
+	/*9007*/ uint16(x86_xArgRel8),
+	/*9008*/ uint16(x86_xMatch),
+	/*9009*/ uint16(x86_xSetOp), uint16(x86_JAE),
+	/*9011*/ uint16(x86_xReadCb),
+	/*9012*/ uint16(x86_xArgRel8),
+	/*9013*/ uint16(x86_xMatch),
+	/*9014*/ uint16(x86_xSetOp), uint16(x86_JE),
+	/*9016*/ uint16(x86_xReadCb),
+	/*9017*/ uint16(x86_xArgRel8),
+	/*9018*/ uint16(x86_xMatch),
+	/*9019*/ uint16(x86_xSetOp), uint16(x86_JNE),
+	/*9021*/ uint16(x86_xReadCb),
+	/*9022*/ uint16(x86_xArgRel8),
+	/*9023*/ uint16(x86_xMatch),
+	/*9024*/ uint16(x86_xSetOp), uint16(x86_JBE),
+	/*9026*/ uint16(x86_xReadCb),
+	/*9027*/ uint16(x86_xArgRel8),
+	/*9028*/ uint16(x86_xMatch),
+	/*9029*/ uint16(x86_xSetOp), uint16(x86_JA),
+	/*9031*/ uint16(x86_xReadCb),
+	/*9032*/ uint16(x86_xArgRel8),
+	/*9033*/ uint16(x86_xMatch),
+	/*9034*/ uint16(x86_xSetOp), uint16(x86_JS),
+	/*9036*/ uint16(x86_xReadCb),
+	/*9037*/ uint16(x86_xArgRel8),
+	/*9038*/ uint16(x86_xMatch),
+	/*9039*/ uint16(x86_xSetOp), uint16(x86_JNS),
+	/*9041*/ uint16(x86_xReadCb),
+	/*9042*/ uint16(x86_xArgRel8),
+	/*9043*/ uint16(x86_xMatch),
+	/*9044*/ uint16(x86_xSetOp), uint16(x86_JP),
+	/*9046*/ uint16(x86_xReadCb),
+	/*9047*/ uint16(x86_xArgRel8),
+	/*9048*/ uint16(x86_xMatch),
+	/*9049*/ uint16(x86_xSetOp), uint16(x86_JNP),
+	/*9051*/ uint16(x86_xReadCb),
+	/*9052*/ uint16(x86_xArgRel8),
+	/*9053*/ uint16(x86_xMatch),
+	/*9054*/ uint16(x86_xSetOp), uint16(x86_JL),
+	/*9056*/ uint16(x86_xReadCb),
+	/*9057*/ uint16(x86_xArgRel8),
+	/*9058*/ uint16(x86_xMatch),
+	/*9059*/ uint16(x86_xSetOp), uint16(x86_JGE),
+	/*9061*/ uint16(x86_xReadCb),
+	/*9062*/ uint16(x86_xArgRel8),
+	/*9063*/ uint16(x86_xMatch),
+	/*9064*/ uint16(x86_xSetOp), uint16(x86_JLE),
+	/*9066*/ uint16(x86_xReadCb),
+	/*9067*/ uint16(x86_xArgRel8),
+	/*9068*/ uint16(x86_xMatch),
+	/*9069*/ uint16(x86_xSetOp), uint16(x86_JG),
+	/*9071*/ uint16(x86_xReadCb),
+	/*9072*/ uint16(x86_xArgRel8),
+	/*9073*/ uint16(x86_xMatch),
+	/*9074*/ uint16(x86_xCondSlashR),
+	9083, // 0
+	9089, // 1
+	9095, // 2
+	9101, // 3
+	9107, // 4
+	9113, // 5
+	9119, // 6
+	9125, // 7
+	/*9083*/ uint16(x86_xSetOp), uint16(x86_ADD),
+	/*9085*/ uint16(x86_xReadIb),
+	/*9086*/ uint16(x86_xArgRM8),
+	/*9087*/ uint16(x86_xArgImm8u),
+	/*9088*/ uint16(x86_xMatch),
+	/*9089*/ uint16(x86_xSetOp), uint16(x86_OR),
+	/*9091*/ uint16(x86_xReadIb),
+	/*9092*/ uint16(x86_xArgRM8),
+	/*9093*/ uint16(x86_xArgImm8u),
+	/*9094*/ uint16(x86_xMatch),
+	/*9095*/ uint16(x86_xSetOp), uint16(x86_ADC),
+	/*9097*/ uint16(x86_xReadIb),
+	/*9098*/ uint16(x86_xArgRM8),
+	/*9099*/ uint16(x86_xArgImm8u),
+	/*9100*/ uint16(x86_xMatch),
+	/*9101*/ uint16(x86_xSetOp), uint16(x86_SBB),
+	/*9103*/ uint16(x86_xReadIb),
+	/*9104*/ uint16(x86_xArgRM8),
+	/*9105*/ uint16(x86_xArgImm8u),
+	/*9106*/ uint16(x86_xMatch),
+	/*9107*/ uint16(x86_xSetOp), uint16(x86_AND),
+	/*9109*/ uint16(x86_xReadIb),
+	/*9110*/ uint16(x86_xArgRM8),
+	/*9111*/ uint16(x86_xArgImm8u),
+	/*9112*/ uint16(x86_xMatch),
+	/*9113*/ uint16(x86_xSetOp), uint16(x86_SUB),
+	/*9115*/ uint16(x86_xReadIb),
+	/*9116*/ uint16(x86_xArgRM8),
+	/*9117*/ uint16(x86_xArgImm8u),
+	/*9118*/ uint16(x86_xMatch),
+	/*9119*/ uint16(x86_xSetOp), uint16(x86_XOR),
+	/*9121*/ uint16(x86_xReadIb),
+	/*9122*/ uint16(x86_xArgRM8),
+	/*9123*/ uint16(x86_xArgImm8u),
+	/*9124*/ uint16(x86_xMatch),
+	/*9125*/ uint16(x86_xSetOp), uint16(x86_CMP),
+	/*9127*/ uint16(x86_xReadIb),
+	/*9128*/ uint16(x86_xArgRM8),
+	/*9129*/ uint16(x86_xArgImm8u),
+	/*9130*/ uint16(x86_xMatch),
+	/*9131*/ uint16(x86_xCondSlashR),
+	9140, // 0
+	9169, // 1
+	9198, // 2
+	9227, // 3
+	9256, // 4
+	9285, // 5
+	9314, // 6
+	9343, // 7
+	/*9140*/ uint16(x86_xCondIs64), 9143, 9159,
+	/*9143*/ uint16(x86_xCondDataSize), 9147, 9153, 0,
+	/*9147*/ uint16(x86_xSetOp), uint16(x86_ADD),
+	/*9149*/ uint16(x86_xReadIw),
+	/*9150*/ uint16(x86_xArgRM16),
+	/*9151*/ uint16(x86_xArgImm16),
+	/*9152*/ uint16(x86_xMatch),
+	/*9153*/ uint16(x86_xSetOp), uint16(x86_ADD),
+	/*9155*/ uint16(x86_xReadId),
+	/*9156*/ uint16(x86_xArgRM32),
+	/*9157*/ uint16(x86_xArgImm32),
+	/*9158*/ uint16(x86_xMatch),
+	/*9159*/ uint16(x86_xCondDataSize), 9147, 9153, 9163,
+	/*9163*/ uint16(x86_xSetOp), uint16(x86_ADD),
+	/*9165*/ uint16(x86_xReadId),
+	/*9166*/ uint16(x86_xArgRM64),
+	/*9167*/ uint16(x86_xArgImm32),
+	/*9168*/ uint16(x86_xMatch),
+	/*9169*/ uint16(x86_xCondIs64), 9172, 9188,
+	/*9172*/ uint16(x86_xCondDataSize), 9176, 9182, 0,
+	/*9176*/ uint16(x86_xSetOp), uint16(x86_OR),
+	/*9178*/ uint16(x86_xReadIw),
+	/*9179*/ uint16(x86_xArgRM16),
+	/*9180*/ uint16(x86_xArgImm16),
+	/*9181*/ uint16(x86_xMatch),
+	/*9182*/ uint16(x86_xSetOp), uint16(x86_OR),
+	/*9184*/ uint16(x86_xReadId),
+	/*9185*/ uint16(x86_xArgRM32),
+	/*9186*/ uint16(x86_xArgImm32),
+	/*9187*/ uint16(x86_xMatch),
+	/*9188*/ uint16(x86_xCondDataSize), 9176, 9182, 9192,
+	/*9192*/ uint16(x86_xSetOp), uint16(x86_OR),
+	/*9194*/ uint16(x86_xReadId),
+	/*9195*/ uint16(x86_xArgRM64),
+	/*9196*/ uint16(x86_xArgImm32),
+	/*9197*/ uint16(x86_xMatch),
+	/*9198*/ uint16(x86_xCondIs64), 9201, 9217,
+	/*9201*/ uint16(x86_xCondDataSize), 9205, 9211, 0,
+	/*9205*/ uint16(x86_xSetOp), uint16(x86_ADC),
+	/*9207*/ uint16(x86_xReadIw),
+	/*9208*/ uint16(x86_xArgRM16),
+	/*9209*/ uint16(x86_xArgImm16),
+	/*9210*/ uint16(x86_xMatch),
+	/*9211*/ uint16(x86_xSetOp), uint16(x86_ADC),
+	/*9213*/ uint16(x86_xReadId),
+	/*9214*/ uint16(x86_xArgRM32),
+	/*9215*/ uint16(x86_xArgImm32),
+	/*9216*/ uint16(x86_xMatch),
+	/*9217*/ uint16(x86_xCondDataSize), 9205, 9211, 9221,
+	/*9221*/ uint16(x86_xSetOp), uint16(x86_ADC),
+	/*9223*/ uint16(x86_xReadId),
+	/*9224*/ uint16(x86_xArgRM64),
+	/*9225*/ uint16(x86_xArgImm32),
+	/*9226*/ uint16(x86_xMatch),
+	/*9227*/ uint16(x86_xCondIs64), 9230, 9246,
+	/*9230*/ uint16(x86_xCondDataSize), 9234, 9240, 0,
+	/*9234*/ uint16(x86_xSetOp), uint16(x86_SBB),
+	/*9236*/ uint16(x86_xReadIw),
+	/*9237*/ uint16(x86_xArgRM16),
+	/*9238*/ uint16(x86_xArgImm16),
+	/*9239*/ uint16(x86_xMatch),
+	/*9240*/ uint16(x86_xSetOp), uint16(x86_SBB),
+	/*9242*/ uint16(x86_xReadId),
+	/*9243*/ uint16(x86_xArgRM32),
+	/*9244*/ uint16(x86_xArgImm32),
+	/*9245*/ uint16(x86_xMatch),
+	/*9246*/ uint16(x86_xCondDataSize), 9234, 9240, 9250,
+	/*9250*/ uint16(x86_xSetOp), uint16(x86_SBB),
+	/*9252*/ uint16(x86_xReadId),
+	/*9253*/ uint16(x86_xArgRM64),
+	/*9254*/ uint16(x86_xArgImm32),
+	/*9255*/ uint16(x86_xMatch),
+	/*9256*/ uint16(x86_xCondIs64), 9259, 9275,
+	/*9259*/ uint16(x86_xCondDataSize), 9263, 9269, 0,
+	/*9263*/ uint16(x86_xSetOp), uint16(x86_AND),
+	/*9265*/ uint16(x86_xReadIw),
+	/*9266*/ uint16(x86_xArgRM16),
+	/*9267*/ uint16(x86_xArgImm16),
+	/*9268*/ uint16(x86_xMatch),
+	/*9269*/ uint16(x86_xSetOp), uint16(x86_AND),
+	/*9271*/ uint16(x86_xReadId),
+	/*9272*/ uint16(x86_xArgRM32),
+	/*9273*/ uint16(x86_xArgImm32),
+	/*9274*/ uint16(x86_xMatch),
+	/*9275*/ uint16(x86_xCondDataSize), 9263, 9269, 9279,
+	/*9279*/ uint16(x86_xSetOp), uint16(x86_AND),
+	/*9281*/ uint16(x86_xReadId),
+	/*9282*/ uint16(x86_xArgRM64),
+	/*9283*/ uint16(x86_xArgImm32),
+	/*9284*/ uint16(x86_xMatch),
+	/*9285*/ uint16(x86_xCondIs64), 9288, 9304,
+	/*9288*/ uint16(x86_xCondDataSize), 9292, 9298, 0,
+	/*9292*/ uint16(x86_xSetOp), uint16(x86_SUB),
+	/*9294*/ uint16(x86_xReadIw),
+	/*9295*/ uint16(x86_xArgRM16),
+	/*9296*/ uint16(x86_xArgImm16),
+	/*9297*/ uint16(x86_xMatch),
+	/*9298*/ uint16(x86_xSetOp), uint16(x86_SUB),
+	/*9300*/ uint16(x86_xReadId),
+	/*9301*/ uint16(x86_xArgRM32),
+	/*9302*/ uint16(x86_xArgImm32),
+	/*9303*/ uint16(x86_xMatch),
+	/*9304*/ uint16(x86_xCondDataSize), 9292, 9298, 9308,
+	/*9308*/ uint16(x86_xSetOp), uint16(x86_SUB),
+	/*9310*/ uint16(x86_xReadId),
+	/*9311*/ uint16(x86_xArgRM64),
+	/*9312*/ uint16(x86_xArgImm32),
+	/*9313*/ uint16(x86_xMatch),
+	/*9314*/ uint16(x86_xCondIs64), 9317, 9333,
+	/*9317*/ uint16(x86_xCondDataSize), 9321, 9327, 0,
+	/*9321*/ uint16(x86_xSetOp), uint16(x86_XOR),
+	/*9323*/ uint16(x86_xReadIw),
+	/*9324*/ uint16(x86_xArgRM16),
+	/*9325*/ uint16(x86_xArgImm16),
+	/*9326*/ uint16(x86_xMatch),
+	/*9327*/ uint16(x86_xSetOp), uint16(x86_XOR),
+	/*9329*/ uint16(x86_xReadId),
+	/*9330*/ uint16(x86_xArgRM32),
+	/*9331*/ uint16(x86_xArgImm32),
+	/*9332*/ uint16(x86_xMatch),
+	/*9333*/ uint16(x86_xCondDataSize), 9321, 9327, 9337,
+	/*9337*/ uint16(x86_xSetOp), uint16(x86_XOR),
+	/*9339*/ uint16(x86_xReadId),
+	/*9340*/ uint16(x86_xArgRM64),
+	/*9341*/ uint16(x86_xArgImm32),
+	/*9342*/ uint16(x86_xMatch),
+	/*9343*/ uint16(x86_xCondIs64), 9346, 9362,
+	/*9346*/ uint16(x86_xCondDataSize), 9350, 9356, 0,
+	/*9350*/ uint16(x86_xSetOp), uint16(x86_CMP),
+	/*9352*/ uint16(x86_xReadIw),
+	/*9353*/ uint16(x86_xArgRM16),
+	/*9354*/ uint16(x86_xArgImm16),
+	/*9355*/ uint16(x86_xMatch),
+	/*9356*/ uint16(x86_xSetOp), uint16(x86_CMP),
+	/*9358*/ uint16(x86_xReadId),
+	/*9359*/ uint16(x86_xArgRM32),
+	/*9360*/ uint16(x86_xArgImm32),
+	/*9361*/ uint16(x86_xMatch),
+	/*9362*/ uint16(x86_xCondDataSize), 9350, 9356, 9366,
+	/*9366*/ uint16(x86_xSetOp), uint16(x86_CMP),
+	/*9368*/ uint16(x86_xReadId),
+	/*9369*/ uint16(x86_xArgRM64),
+	/*9370*/ uint16(x86_xArgImm32),
+	/*9371*/ uint16(x86_xMatch),
+	/*9372*/ uint16(x86_xCondSlashR),
+	9381, // 0
+	9410, // 1
+	9439, // 2
+	9468, // 3
+	9497, // 4
+	9526, // 5
+	9555, // 6
+	9584, // 7
+	/*9381*/ uint16(x86_xCondIs64), 9384, 9400,
+	/*9384*/ uint16(x86_xCondDataSize), 9388, 9394, 0,
+	/*9388*/ uint16(x86_xSetOp), uint16(x86_ADD),
+	/*9390*/ uint16(x86_xReadIb),
+	/*9391*/ uint16(x86_xArgRM16),
+	/*9392*/ uint16(x86_xArgImm8),
+	/*9393*/ uint16(x86_xMatch),
+	/*9394*/ uint16(x86_xSetOp), uint16(x86_ADD),
+	/*9396*/ uint16(x86_xReadIb),
+	/*9397*/ uint16(x86_xArgRM32),
+	/*9398*/ uint16(x86_xArgImm8),
+	/*9399*/ uint16(x86_xMatch),
+	/*9400*/ uint16(x86_xCondDataSize), 9388, 9394, 9404,
+	/*9404*/ uint16(x86_xSetOp), uint16(x86_ADD),
+	/*9406*/ uint16(x86_xReadIb),
+	/*9407*/ uint16(x86_xArgRM64),
+	/*9408*/ uint16(x86_xArgImm8),
+	/*9409*/ uint16(x86_xMatch),
+	/*9410*/ uint16(x86_xCondIs64), 9413, 9429,
+	/*9413*/ uint16(x86_xCondDataSize), 9417, 9423, 0,
+	/*9417*/ uint16(x86_xSetOp), uint16(x86_OR),
+	/*9419*/ uint16(x86_xReadIb),
+	/*9420*/ uint16(x86_xArgRM16),
+	/*9421*/ uint16(x86_xArgImm8),
+	/*9422*/ uint16(x86_xMatch),
+	/*9423*/ uint16(x86_xSetOp), uint16(x86_OR),
+	/*9425*/ uint16(x86_xReadIb),
+	/*9426*/ uint16(x86_xArgRM32),
+	/*9427*/ uint16(x86_xArgImm8),
+	/*9428*/ uint16(x86_xMatch),
+	/*9429*/ uint16(x86_xCondDataSize), 9417, 9423, 9433,
+	/*9433*/ uint16(x86_xSetOp), uint16(x86_OR),
+	/*9435*/ uint16(x86_xReadIb),
+	/*9436*/ uint16(x86_xArgRM64),
+	/*9437*/ uint16(x86_xArgImm8),
+	/*9438*/ uint16(x86_xMatch),
+	/*9439*/ uint16(x86_xCondIs64), 9442, 9458,
+	/*9442*/ uint16(x86_xCondDataSize), 9446, 9452, 0,
+	/*9446*/ uint16(x86_xSetOp), uint16(x86_ADC),
+	/*9448*/ uint16(x86_xReadIb),
+	/*9449*/ uint16(x86_xArgRM16),
+	/*9450*/ uint16(x86_xArgImm8),
+	/*9451*/ uint16(x86_xMatch),
+	/*9452*/ uint16(x86_xSetOp), uint16(x86_ADC),
+	/*9454*/ uint16(x86_xReadIb),
+	/*9455*/ uint16(x86_xArgRM32),
+	/*9456*/ uint16(x86_xArgImm8),
+	/*9457*/ uint16(x86_xMatch),
+	/*9458*/ uint16(x86_xCondDataSize), 9446, 9452, 9462,
+	/*9462*/ uint16(x86_xSetOp), uint16(x86_ADC),
+	/*9464*/ uint16(x86_xReadIb),
+	/*9465*/ uint16(x86_xArgRM64),
+	/*9466*/ uint16(x86_xArgImm8),
+	/*9467*/ uint16(x86_xMatch),
+	/*9468*/ uint16(x86_xCondIs64), 9471, 9487,
+	/*9471*/ uint16(x86_xCondDataSize), 9475, 9481, 0,
+	/*9475*/ uint16(x86_xSetOp), uint16(x86_SBB),
+	/*9477*/ uint16(x86_xReadIb),
+	/*9478*/ uint16(x86_xArgRM16),
+	/*9479*/ uint16(x86_xArgImm8),
+	/*9480*/ uint16(x86_xMatch),
+	/*9481*/ uint16(x86_xSetOp), uint16(x86_SBB),
+	/*9483*/ uint16(x86_xReadIb),
+	/*9484*/ uint16(x86_xArgRM32),
+	/*9485*/ uint16(x86_xArgImm8),
+	/*9486*/ uint16(x86_xMatch),
+	/*9487*/ uint16(x86_xCondDataSize), 9475, 9481, 9491,
+	/*9491*/ uint16(x86_xSetOp), uint16(x86_SBB),
+	/*9493*/ uint16(x86_xReadIb),
+	/*9494*/ uint16(x86_xArgRM64),
+	/*9495*/ uint16(x86_xArgImm8),
+	/*9496*/ uint16(x86_xMatch),
+	/*9497*/ uint16(x86_xCondIs64), 9500, 9516,
+	/*9500*/ uint16(x86_xCondDataSize), 9504, 9510, 0,
+	/*9504*/ uint16(x86_xSetOp), uint16(x86_AND),
+	/*9506*/ uint16(x86_xReadIb),
+	/*9507*/ uint16(x86_xArgRM16),
+	/*9508*/ uint16(x86_xArgImm8),
+	/*9509*/ uint16(x86_xMatch),
+	/*9510*/ uint16(x86_xSetOp), uint16(x86_AND),
+	/*9512*/ uint16(x86_xReadIb),
+	/*9513*/ uint16(x86_xArgRM32),
+	/*9514*/ uint16(x86_xArgImm8),
+	/*9515*/ uint16(x86_xMatch),
+	/*9516*/ uint16(x86_xCondDataSize), 9504, 9510, 9520,
+	/*9520*/ uint16(x86_xSetOp), uint16(x86_AND),
+	/*9522*/ uint16(x86_xReadIb),
+	/*9523*/ uint16(x86_xArgRM64),
+	/*9524*/ uint16(x86_xArgImm8),
+	/*9525*/ uint16(x86_xMatch),
+	/*9526*/ uint16(x86_xCondIs64), 9529, 9545,
+	/*9529*/ uint16(x86_xCondDataSize), 9533, 9539, 0,
+	/*9533*/ uint16(x86_xSetOp), uint16(x86_SUB),
+	/*9535*/ uint16(x86_xReadIb),
+	/*9536*/ uint16(x86_xArgRM16),
+	/*9537*/ uint16(x86_xArgImm8),
+	/*9538*/ uint16(x86_xMatch),
+	/*9539*/ uint16(x86_xSetOp), uint16(x86_SUB),
+	/*9541*/ uint16(x86_xReadIb),
+	/*9542*/ uint16(x86_xArgRM32),
+	/*9543*/ uint16(x86_xArgImm8),
+	/*9544*/ uint16(x86_xMatch),
+	/*9545*/ uint16(x86_xCondDataSize), 9533, 9539, 9549,
+	/*9549*/ uint16(x86_xSetOp), uint16(x86_SUB),
+	/*9551*/ uint16(x86_xReadIb),
+	/*9552*/ uint16(x86_xArgRM64),
+	/*9553*/ uint16(x86_xArgImm8),
+	/*9554*/ uint16(x86_xMatch),
+	/*9555*/ uint16(x86_xCondIs64), 9558, 9574,
+	/*9558*/ uint16(x86_xCondDataSize), 9562, 9568, 0,
+	/*9562*/ uint16(x86_xSetOp), uint16(x86_XOR),
+	/*9564*/ uint16(x86_xReadIb),
+	/*9565*/ uint16(x86_xArgRM16),
+	/*9566*/ uint16(x86_xArgImm8),
+	/*9567*/ uint16(x86_xMatch),
+	/*9568*/ uint16(x86_xSetOp), uint16(x86_XOR),
+	/*9570*/ uint16(x86_xReadIb),
+	/*9571*/ uint16(x86_xArgRM32),
+	/*9572*/ uint16(x86_xArgImm8),
+	/*9573*/ uint16(x86_xMatch),
+	/*9574*/ uint16(x86_xCondDataSize), 9562, 9568, 9578,
+	/*9578*/ uint16(x86_xSetOp), uint16(x86_XOR),
+	/*9580*/ uint16(x86_xReadIb),
+	/*9581*/ uint16(x86_xArgRM64),
+	/*9582*/ uint16(x86_xArgImm8),
+	/*9583*/ uint16(x86_xMatch),
+	/*9584*/ uint16(x86_xCondIs64), 9587, 9603,
+	/*9587*/ uint16(x86_xCondDataSize), 9591, 9597, 0,
+	/*9591*/ uint16(x86_xSetOp), uint16(x86_CMP),
+	/*9593*/ uint16(x86_xReadIb),
+	/*9594*/ uint16(x86_xArgRM16),
+	/*9595*/ uint16(x86_xArgImm8),
+	/*9596*/ uint16(x86_xMatch),
+	/*9597*/ uint16(x86_xSetOp), uint16(x86_CMP),
+	/*9599*/ uint16(x86_xReadIb),
+	/*9600*/ uint16(x86_xArgRM32),
+	/*9601*/ uint16(x86_xArgImm8),
+	/*9602*/ uint16(x86_xMatch),
+	/*9603*/ uint16(x86_xCondDataSize), 9591, 9597, 9607,
+	/*9607*/ uint16(x86_xSetOp), uint16(x86_CMP),
+	/*9609*/ uint16(x86_xReadIb),
+	/*9610*/ uint16(x86_xArgRM64),
+	/*9611*/ uint16(x86_xArgImm8),
+	/*9612*/ uint16(x86_xMatch),
+	/*9613*/ uint16(x86_xSetOp), uint16(x86_TEST),
+	/*9615*/ uint16(x86_xReadSlashR),
+	/*9616*/ uint16(x86_xArgRM8),
+	/*9617*/ uint16(x86_xArgR8),
+	/*9618*/ uint16(x86_xMatch),
+	/*9619*/ uint16(x86_xCondIs64), 9622, 9638,
+	/*9622*/ uint16(x86_xCondDataSize), 9626, 9632, 0,
+	/*9626*/ uint16(x86_xSetOp), uint16(x86_TEST),
+	/*9628*/ uint16(x86_xReadSlashR),
+	/*9629*/ uint16(x86_xArgRM16),
+	/*9630*/ uint16(x86_xArgR16),
+	/*9631*/ uint16(x86_xMatch),
+	/*9632*/ uint16(x86_xSetOp), uint16(x86_TEST),
+	/*9634*/ uint16(x86_xReadSlashR),
+	/*9635*/ uint16(x86_xArgRM32),
+	/*9636*/ uint16(x86_xArgR32),
+	/*9637*/ uint16(x86_xMatch),
+	/*9638*/ uint16(x86_xCondDataSize), 9626, 9632, 9642,
+	/*9642*/ uint16(x86_xSetOp), uint16(x86_TEST),
+	/*9644*/ uint16(x86_xReadSlashR),
+	/*9645*/ uint16(x86_xArgRM64),
+	/*9646*/ uint16(x86_xArgR64),
+	/*9647*/ uint16(x86_xMatch),
+	/*9648*/ uint16(x86_xSetOp), uint16(x86_XCHG),
+	/*9650*/ uint16(x86_xReadSlashR),
+	/*9651*/ uint16(x86_xArgRM8),
+	/*9652*/ uint16(x86_xArgR8),
+	/*9653*/ uint16(x86_xMatch),
+	/*9654*/ uint16(x86_xCondIs64), 9657, 9673,
+	/*9657*/ uint16(x86_xCondDataSize), 9661, 9667, 0,
+	/*9661*/ uint16(x86_xSetOp), uint16(x86_XCHG),
+	/*9663*/ uint16(x86_xReadSlashR),
+	/*9664*/ uint16(x86_xArgRM16),
+	/*9665*/ uint16(x86_xArgR16),
+	/*9666*/ uint16(x86_xMatch),
+	/*9667*/ uint16(x86_xSetOp), uint16(x86_XCHG),
+	/*9669*/ uint16(x86_xReadSlashR),
+	/*9670*/ uint16(x86_xArgRM32),
+	/*9671*/ uint16(x86_xArgR32),
+	/*9672*/ uint16(x86_xMatch),
+	/*9673*/ uint16(x86_xCondDataSize), 9661, 9667, 9677,
+	/*9677*/ uint16(x86_xSetOp), uint16(x86_XCHG),
+	/*9679*/ uint16(x86_xReadSlashR),
+	/*9680*/ uint16(x86_xArgRM64),
+	/*9681*/ uint16(x86_xArgR64),
+	/*9682*/ uint16(x86_xMatch),
+	/*9683*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*9685*/ uint16(x86_xReadSlashR),
+	/*9686*/ uint16(x86_xArgRM8),
+	/*9687*/ uint16(x86_xArgR8),
+	/*9688*/ uint16(x86_xMatch),
+	/*9689*/ uint16(x86_xCondDataSize), 9693, 9699, 9705,
+	/*9693*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*9695*/ uint16(x86_xReadSlashR),
+	/*9696*/ uint16(x86_xArgRM16),
+	/*9697*/ uint16(x86_xArgR16),
+	/*9698*/ uint16(x86_xMatch),
+	/*9699*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*9701*/ uint16(x86_xReadSlashR),
+	/*9702*/ uint16(x86_xArgRM32),
+	/*9703*/ uint16(x86_xArgR32),
+	/*9704*/ uint16(x86_xMatch),
+	/*9705*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*9707*/ uint16(x86_xReadSlashR),
+	/*9708*/ uint16(x86_xArgRM64),
+	/*9709*/ uint16(x86_xArgR64),
+	/*9710*/ uint16(x86_xMatch),
+	/*9711*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*9713*/ uint16(x86_xReadSlashR),
+	/*9714*/ uint16(x86_xArgR8),
+	/*9715*/ uint16(x86_xArgRM8),
+	/*9716*/ uint16(x86_xMatch),
+	/*9717*/ uint16(x86_xCondDataSize), 9721, 9727, 9733,
+	/*9721*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*9723*/ uint16(x86_xReadSlashR),
+	/*9724*/ uint16(x86_xArgR16),
+	/*9725*/ uint16(x86_xArgRM16),
+	/*9726*/ uint16(x86_xMatch),
+	/*9727*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*9729*/ uint16(x86_xReadSlashR),
+	/*9730*/ uint16(x86_xArgR32),
+	/*9731*/ uint16(x86_xArgRM32),
+	/*9732*/ uint16(x86_xMatch),
+	/*9733*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*9735*/ uint16(x86_xReadSlashR),
+	/*9736*/ uint16(x86_xArgR64),
+	/*9737*/ uint16(x86_xArgRM64),
+	/*9738*/ uint16(x86_xMatch),
+	/*9739*/ uint16(x86_xCondIs64), 9742, 9758,
+	/*9742*/ uint16(x86_xCondDataSize), 9746, 9752, 0,
+	/*9746*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*9748*/ uint16(x86_xReadSlashR),
+	/*9749*/ uint16(x86_xArgRM16),
+	/*9750*/ uint16(x86_xArgSreg),
+	/*9751*/ uint16(x86_xMatch),
+	/*9752*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*9754*/ uint16(x86_xReadSlashR),
+	/*9755*/ uint16(x86_xArgR32M16),
+	/*9756*/ uint16(x86_xArgSreg),
+	/*9757*/ uint16(x86_xMatch),
+	/*9758*/ uint16(x86_xCondDataSize), 9746, 9752, 9762,
+	/*9762*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*9764*/ uint16(x86_xReadSlashR),
+	/*9765*/ uint16(x86_xArgR64M16),
+	/*9766*/ uint16(x86_xArgSreg),
+	/*9767*/ uint16(x86_xMatch),
+	/*9768*/ uint16(x86_xCondIs64), 9771, 9787,
+	/*9771*/ uint16(x86_xCondDataSize), 9775, 9781, 0,
+	/*9775*/ uint16(x86_xSetOp), uint16(x86_LEA),
+	/*9777*/ uint16(x86_xReadSlashR),
+	/*9778*/ uint16(x86_xArgR16),
+	/*9779*/ uint16(x86_xArgM),
+	/*9780*/ uint16(x86_xMatch),
+	/*9781*/ uint16(x86_xSetOp), uint16(x86_LEA),
+	/*9783*/ uint16(x86_xReadSlashR),
+	/*9784*/ uint16(x86_xArgR32),
+	/*9785*/ uint16(x86_xArgM),
+	/*9786*/ uint16(x86_xMatch),
+	/*9787*/ uint16(x86_xCondDataSize), 9775, 9781, 9791,
+	/*9791*/ uint16(x86_xSetOp), uint16(x86_LEA),
+	/*9793*/ uint16(x86_xReadSlashR),
+	/*9794*/ uint16(x86_xArgR64),
+	/*9795*/ uint16(x86_xArgM),
+	/*9796*/ uint16(x86_xMatch),
+	/*9797*/ uint16(x86_xCondIs64), 9800, 9816,
+	/*9800*/ uint16(x86_xCondDataSize), 9804, 9810, 0,
+	/*9804*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*9806*/ uint16(x86_xReadSlashR),
+	/*9807*/ uint16(x86_xArgSreg),
+	/*9808*/ uint16(x86_xArgRM16),
+	/*9809*/ uint16(x86_xMatch),
+	/*9810*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*9812*/ uint16(x86_xReadSlashR),
+	/*9813*/ uint16(x86_xArgSreg),
+	/*9814*/ uint16(x86_xArgR32M16),
+	/*9815*/ uint16(x86_xMatch),
+	/*9816*/ uint16(x86_xCondDataSize), 9804, 9810, 9820,
+	/*9820*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*9822*/ uint16(x86_xReadSlashR),
+	/*9823*/ uint16(x86_xArgSreg),
+	/*9824*/ uint16(x86_xArgR64M16),
+	/*9825*/ uint16(x86_xMatch),
+	/*9826*/ uint16(x86_xCondSlashR),
+	9835, // 0
+	0,    // 1
+	0,    // 2
+	0,    // 3
+	0,    // 4
+	0,    // 5
+	0,    // 6
+	0,    // 7
+	/*9835*/ uint16(x86_xCondIs64), 9838, 9850,
+	/*9838*/ uint16(x86_xCondDataSize), 9842, 9846, 0,
+	/*9842*/ uint16(x86_xSetOp), uint16(x86_POP),
+	/*9844*/ uint16(x86_xArgRM16),
+	/*9845*/ uint16(x86_xMatch),
+	/*9846*/ uint16(x86_xSetOp), uint16(x86_POP),
+	/*9848*/ uint16(x86_xArgRM32),
+	/*9849*/ uint16(x86_xMatch),
+	/*9850*/ uint16(x86_xCondDataSize), 9842, 9854, 9858,
+	/*9854*/ uint16(x86_xSetOp), uint16(x86_POP),
+	/*9856*/ uint16(x86_xArgRM64),
+	/*9857*/ uint16(x86_xMatch),
+	/*9858*/ uint16(x86_xSetOp), uint16(x86_POP),
+	/*9860*/ uint16(x86_xArgRM64),
+	/*9861*/ uint16(x86_xMatch),
+	/*9862*/ uint16(x86_xCondIs64), 9865, 9879,
+	/*9865*/ uint16(x86_xCondDataSize), 9869, 9874, 0,
+	/*9869*/ uint16(x86_xSetOp), uint16(x86_XCHG),
+	/*9871*/ uint16(x86_xArgR16op),
+	/*9872*/ uint16(x86_xArgAX),
+	/*9873*/ uint16(x86_xMatch),
+	/*9874*/ uint16(x86_xSetOp), uint16(x86_XCHG),
+	/*9876*/ uint16(x86_xArgR32op),
+	/*9877*/ uint16(x86_xArgEAX),
+	/*9878*/ uint16(x86_xMatch),
+	/*9879*/ uint16(x86_xCondDataSize), 9869, 9874, 9883,
+	/*9883*/ uint16(x86_xSetOp), uint16(x86_XCHG),
+	/*9885*/ uint16(x86_xArgR64op),
+	/*9886*/ uint16(x86_xArgRAX),
+	/*9887*/ uint16(x86_xMatch),
+	/*9888*/ uint16(x86_xCondIs64), 9891, 9901,
+	/*9891*/ uint16(x86_xCondDataSize), 9895, 9898, 0,
+	/*9895*/ uint16(x86_xSetOp), uint16(x86_CBW),
+	/*9897*/ uint16(x86_xMatch),
+	/*9898*/ uint16(x86_xSetOp), uint16(x86_CWDE),
+	/*9900*/ uint16(x86_xMatch),
+	/*9901*/ uint16(x86_xCondDataSize), 9895, 9898, 9905,
+	/*9905*/ uint16(x86_xSetOp), uint16(x86_CDQE),
+	/*9907*/ uint16(x86_xMatch),
+	/*9908*/ uint16(x86_xCondIs64), 9911, 9921,
+	/*9911*/ uint16(x86_xCondDataSize), 9915, 9918, 0,
+	/*9915*/ uint16(x86_xSetOp), uint16(x86_CWD),
+	/*9917*/ uint16(x86_xMatch),
+	/*9918*/ uint16(x86_xSetOp), uint16(x86_CDQ),
+	/*9920*/ uint16(x86_xMatch),
+	/*9921*/ uint16(x86_xCondDataSize), 9915, 9918, 9925,
+	/*9925*/ uint16(x86_xSetOp), uint16(x86_CQO),
+	/*9927*/ uint16(x86_xMatch),
+	/*9928*/ uint16(x86_xCondIs64), 9931, 0,
+	/*9931*/ uint16(x86_xCondDataSize), 9935, 9940, 0,
+	/*9935*/ uint16(x86_xSetOp), uint16(x86_LCALL),
+	/*9937*/ uint16(x86_xReadCd),
+	/*9938*/ uint16(x86_xArgPtr16colon16),
+	/*9939*/ uint16(x86_xMatch),
+	/*9940*/ uint16(x86_xSetOp), uint16(x86_LCALL),
+	/*9942*/ uint16(x86_xReadCp),
+	/*9943*/ uint16(x86_xArgPtr16colon32),
+	/*9944*/ uint16(x86_xMatch),
+	/*9945*/ uint16(x86_xSetOp), uint16(x86_FWAIT),
+	/*9947*/ uint16(x86_xMatch),
+	/*9948*/ uint16(x86_xCondIs64), 9951, 9961,
+	/*9951*/ uint16(x86_xCondDataSize), 9955, 9958, 0,
+	/*9955*/ uint16(x86_xSetOp), uint16(x86_PUSHF),
+	/*9957*/ uint16(x86_xMatch),
+	/*9958*/ uint16(x86_xSetOp), uint16(x86_PUSHFD),
+	/*9960*/ uint16(x86_xMatch),
+	/*9961*/ uint16(x86_xCondDataSize), 9955, 9965, 9968,
+	/*9965*/ uint16(x86_xSetOp), uint16(x86_PUSHFQ),
+	/*9967*/ uint16(x86_xMatch),
+	/*9968*/ uint16(x86_xSetOp), uint16(x86_PUSHFQ),
+	/*9970*/ uint16(x86_xMatch),
+	/*9971*/ uint16(x86_xCondIs64), 9974, 9984,
+	/*9974*/ uint16(x86_xCondDataSize), 9978, 9981, 0,
+	/*9978*/ uint16(x86_xSetOp), uint16(x86_POPF),
+	/*9980*/ uint16(x86_xMatch),
+	/*9981*/ uint16(x86_xSetOp), uint16(x86_POPFD),
+	/*9983*/ uint16(x86_xMatch),
+	/*9984*/ uint16(x86_xCondDataSize), 9978, 9988, 9991,
+	/*9988*/ uint16(x86_xSetOp), uint16(x86_POPFQ),
+	/*9990*/ uint16(x86_xMatch),
+	/*9991*/ uint16(x86_xSetOp), uint16(x86_POPFQ),
+	/*9993*/ uint16(x86_xMatch),
+	/*9994*/ uint16(x86_xSetOp), uint16(x86_SAHF),
+	/*9996*/ uint16(x86_xMatch),
+	/*9997*/ uint16(x86_xSetOp), uint16(x86_LAHF),
+	/*9999*/ uint16(x86_xMatch),
+	/*10000*/ uint16(x86_xCondIs64), 10003, 10009,
+	/*10003*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*10005*/ uint16(x86_xReadCm),
+	/*10006*/ uint16(x86_xArgAL),
+	/*10007*/ uint16(x86_xArgMoffs8),
+	/*10008*/ uint16(x86_xMatch),
+	/*10009*/ uint16(x86_xCondDataSize), 10003, 10003, 10013,
+	/*10013*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*10015*/ uint16(x86_xReadCm),
+	/*10016*/ uint16(x86_xArgAL),
+	/*10017*/ uint16(x86_xArgMoffs8),
+	/*10018*/ uint16(x86_xMatch),
+	/*10019*/ uint16(x86_xCondDataSize), 10023, 10029, 10035,
+	/*10023*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*10025*/ uint16(x86_xReadCm),
+	/*10026*/ uint16(x86_xArgAX),
+	/*10027*/ uint16(x86_xArgMoffs16),
+	/*10028*/ uint16(x86_xMatch),
+	/*10029*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*10031*/ uint16(x86_xReadCm),
+	/*10032*/ uint16(x86_xArgEAX),
+	/*10033*/ uint16(x86_xArgMoffs32),
+	/*10034*/ uint16(x86_xMatch),
+	/*10035*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*10037*/ uint16(x86_xReadCm),
+	/*10038*/ uint16(x86_xArgRAX),
+	/*10039*/ uint16(x86_xArgMoffs64),
+	/*10040*/ uint16(x86_xMatch),
+	/*10041*/ uint16(x86_xCondIs64), 10044, 10050,
+	/*10044*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*10046*/ uint16(x86_xReadCm),
+	/*10047*/ uint16(x86_xArgMoffs8),
+	/*10048*/ uint16(x86_xArgAL),
+	/*10049*/ uint16(x86_xMatch),
+	/*10050*/ uint16(x86_xCondDataSize), 10044, 10044, 10054,
+	/*10054*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*10056*/ uint16(x86_xReadCm),
+	/*10057*/ uint16(x86_xArgMoffs8),
+	/*10058*/ uint16(x86_xArgAL),
+	/*10059*/ uint16(x86_xMatch),
+	/*10060*/ uint16(x86_xCondDataSize), 10064, 10070, 10076,
+	/*10064*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*10066*/ uint16(x86_xReadCm),
+	/*10067*/ uint16(x86_xArgMoffs16),
+	/*10068*/ uint16(x86_xArgAX),
+	/*10069*/ uint16(x86_xMatch),
+	/*10070*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*10072*/ uint16(x86_xReadCm),
+	/*10073*/ uint16(x86_xArgMoffs32),
+	/*10074*/ uint16(x86_xArgEAX),
+	/*10075*/ uint16(x86_xMatch),
+	/*10076*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*10078*/ uint16(x86_xReadCm),
+	/*10079*/ uint16(x86_xArgMoffs64),
+	/*10080*/ uint16(x86_xArgRAX),
+	/*10081*/ uint16(x86_xMatch),
+	/*10082*/ uint16(x86_xSetOp), uint16(x86_MOVSB),
+	/*10084*/ uint16(x86_xMatch),
+	/*10085*/ uint16(x86_xCondIs64), 10088, 10098,
+	/*10088*/ uint16(x86_xCondDataSize), 10092, 10095, 0,
+	/*10092*/ uint16(x86_xSetOp), uint16(x86_MOVSW),
+	/*10094*/ uint16(x86_xMatch),
+	/*10095*/ uint16(x86_xSetOp), uint16(x86_MOVSD),
+	/*10097*/ uint16(x86_xMatch),
+	/*10098*/ uint16(x86_xCondDataSize), 10092, 10095, 10102,
+	/*10102*/ uint16(x86_xSetOp), uint16(x86_MOVSQ),
+	/*10104*/ uint16(x86_xMatch),
+	/*10105*/ uint16(x86_xSetOp), uint16(x86_CMPSB),
+	/*10107*/ uint16(x86_xMatch),
+	/*10108*/ uint16(x86_xCondIs64), 10111, 10121,
+	/*10111*/ uint16(x86_xCondDataSize), 10115, 10118, 0,
+	/*10115*/ uint16(x86_xSetOp), uint16(x86_CMPSW),
+	/*10117*/ uint16(x86_xMatch),
+	/*10118*/ uint16(x86_xSetOp), uint16(x86_CMPSD),
+	/*10120*/ uint16(x86_xMatch),
+	/*10121*/ uint16(x86_xCondDataSize), 10115, 10118, 10125,
+	/*10125*/ uint16(x86_xSetOp), uint16(x86_CMPSQ),
+	/*10127*/ uint16(x86_xMatch),
+	/*10128*/ uint16(x86_xSetOp), uint16(x86_TEST),
+	/*10130*/ uint16(x86_xReadIb),
+	/*10131*/ uint16(x86_xArgAL),
+	/*10132*/ uint16(x86_xArgImm8u),
+	/*10133*/ uint16(x86_xMatch),
+	/*10134*/ uint16(x86_xCondIs64), 10137, 10153,
+	/*10137*/ uint16(x86_xCondDataSize), 10141, 10147, 0,
+	/*10141*/ uint16(x86_xSetOp), uint16(x86_TEST),
+	/*10143*/ uint16(x86_xReadIw),
+	/*10144*/ uint16(x86_xArgAX),
+	/*10145*/ uint16(x86_xArgImm16),
+	/*10146*/ uint16(x86_xMatch),
+	/*10147*/ uint16(x86_xSetOp), uint16(x86_TEST),
+	/*10149*/ uint16(x86_xReadId),
+	/*10150*/ uint16(x86_xArgEAX),
+	/*10151*/ uint16(x86_xArgImm32),
+	/*10152*/ uint16(x86_xMatch),
+	/*10153*/ uint16(x86_xCondDataSize), 10141, 10147, 10157,
+	/*10157*/ uint16(x86_xSetOp), uint16(x86_TEST),
+	/*10159*/ uint16(x86_xReadId),
+	/*10160*/ uint16(x86_xArgRAX),
+	/*10161*/ uint16(x86_xArgImm32),
+	/*10162*/ uint16(x86_xMatch),
+	/*10163*/ uint16(x86_xSetOp), uint16(x86_STOSB),
+	/*10165*/ uint16(x86_xMatch),
+	/*10166*/ uint16(x86_xCondIs64), 10169, 10179,
+	/*10169*/ uint16(x86_xCondDataSize), 10173, 10176, 0,
+	/*10173*/ uint16(x86_xSetOp), uint16(x86_STOSW),
+	/*10175*/ uint16(x86_xMatch),
+	/*10176*/ uint16(x86_xSetOp), uint16(x86_STOSD),
+	/*10178*/ uint16(x86_xMatch),
+	/*10179*/ uint16(x86_xCondDataSize), 10173, 10176, 10183,
+	/*10183*/ uint16(x86_xSetOp), uint16(x86_STOSQ),
+	/*10185*/ uint16(x86_xMatch),
+	/*10186*/ uint16(x86_xSetOp), uint16(x86_LODSB),
+	/*10188*/ uint16(x86_xMatch),
+	/*10189*/ uint16(x86_xCondIs64), 10192, 10202,
+	/*10192*/ uint16(x86_xCondDataSize), 10196, 10199, 0,
+	/*10196*/ uint16(x86_xSetOp), uint16(x86_LODSW),
+	/*10198*/ uint16(x86_xMatch),
+	/*10199*/ uint16(x86_xSetOp), uint16(x86_LODSD),
+	/*10201*/ uint16(x86_xMatch),
+	/*10202*/ uint16(x86_xCondDataSize), 10196, 10199, 10206,
+	/*10206*/ uint16(x86_xSetOp), uint16(x86_LODSQ),
+	/*10208*/ uint16(x86_xMatch),
+	/*10209*/ uint16(x86_xSetOp), uint16(x86_SCASB),
+	/*10211*/ uint16(x86_xMatch),
+	/*10212*/ uint16(x86_xCondIs64), 10215, 10225,
+	/*10215*/ uint16(x86_xCondDataSize), 10219, 10222, 0,
+	/*10219*/ uint16(x86_xSetOp), uint16(x86_SCASW),
+	/*10221*/ uint16(x86_xMatch),
+	/*10222*/ uint16(x86_xSetOp), uint16(x86_SCASD),
+	/*10224*/ uint16(x86_xMatch),
+	/*10225*/ uint16(x86_xCondDataSize), 10219, 10222, 10229,
+	/*10229*/ uint16(x86_xSetOp), uint16(x86_SCASQ),
+	/*10231*/ uint16(x86_xMatch),
+	/*10232*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*10234*/ uint16(x86_xReadIb),
+	/*10235*/ uint16(x86_xArgR8op),
+	/*10236*/ uint16(x86_xArgImm8u),
+	/*10237*/ uint16(x86_xMatch),
+	/*10238*/ uint16(x86_xCondIs64), 10241, 10257,
+	/*10241*/ uint16(x86_xCondDataSize), 10245, 10251, 0,
+	/*10245*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*10247*/ uint16(x86_xReadIw),
+	/*10248*/ uint16(x86_xArgR16op),
+	/*10249*/ uint16(x86_xArgImm16),
+	/*10250*/ uint16(x86_xMatch),
+	/*10251*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*10253*/ uint16(x86_xReadId),
+	/*10254*/ uint16(x86_xArgR32op),
+	/*10255*/ uint16(x86_xArgImm32),
+	/*10256*/ uint16(x86_xMatch),
+	/*10257*/ uint16(x86_xCondDataSize), 10245, 10251, 10261,
+	/*10261*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*10263*/ uint16(x86_xReadIo),
+	/*10264*/ uint16(x86_xArgR64op),
+	/*10265*/ uint16(x86_xArgImm64),
+	/*10266*/ uint16(x86_xMatch),
+	/*10267*/ uint16(x86_xCondSlashR),
+	10276, // 0
+	10282, // 1
+	10288, // 2
+	10294, // 3
+	10300, // 4
+	10306, // 5
+	0,     // 6
+	10312, // 7
+	/*10276*/ uint16(x86_xSetOp), uint16(x86_ROL),
+	/*10278*/ uint16(x86_xReadIb),
+	/*10279*/ uint16(x86_xArgRM8),
+	/*10280*/ uint16(x86_xArgImm8u),
+	/*10281*/ uint16(x86_xMatch),
+	/*10282*/ uint16(x86_xSetOp), uint16(x86_ROR),
+	/*10284*/ uint16(x86_xReadIb),
+	/*10285*/ uint16(x86_xArgRM8),
+	/*10286*/ uint16(x86_xArgImm8u),
+	/*10287*/ uint16(x86_xMatch),
+	/*10288*/ uint16(x86_xSetOp), uint16(x86_RCL),
+	/*10290*/ uint16(x86_xReadIb),
+	/*10291*/ uint16(x86_xArgRM8),
+	/*10292*/ uint16(x86_xArgImm8u),
+	/*10293*/ uint16(x86_xMatch),
+	/*10294*/ uint16(x86_xSetOp), uint16(x86_RCR),
+	/*10296*/ uint16(x86_xReadIb),
+	/*10297*/ uint16(x86_xArgRM8),
+	/*10298*/ uint16(x86_xArgImm8u),
+	/*10299*/ uint16(x86_xMatch),
+	/*10300*/ uint16(x86_xSetOp), uint16(x86_SHL),
+	/*10302*/ uint16(x86_xReadIb),
+	/*10303*/ uint16(x86_xArgRM8),
+	/*10304*/ uint16(x86_xArgImm8u),
+	/*10305*/ uint16(x86_xMatch),
+	/*10306*/ uint16(x86_xSetOp), uint16(x86_SHR),
+	/*10308*/ uint16(x86_xReadIb),
+	/*10309*/ uint16(x86_xArgRM8),
+	/*10310*/ uint16(x86_xArgImm8u),
+	/*10311*/ uint16(x86_xMatch),
+	/*10312*/ uint16(x86_xSetOp), uint16(x86_SAR),
+	/*10314*/ uint16(x86_xReadIb),
+	/*10315*/ uint16(x86_xArgRM8),
+	/*10316*/ uint16(x86_xArgImm8u),
+	/*10317*/ uint16(x86_xMatch),
+	/*10318*/ uint16(x86_xCondSlashR),
+	10327, // 0
+	10349, // 1
+	10371, // 2
+	10400, // 3
+	10429, // 4
+	10458, // 5
+	0,     // 6
+	10487, // 7
+	/*10327*/ uint16(x86_xCondDataSize), 10331, 10337, 10343,
+	/*10331*/ uint16(x86_xSetOp), uint16(x86_ROL),
+	/*10333*/ uint16(x86_xReadIb),
+	/*10334*/ uint16(x86_xArgRM16),
+	/*10335*/ uint16(x86_xArgImm8u),
+	/*10336*/ uint16(x86_xMatch),
+	/*10337*/ uint16(x86_xSetOp), uint16(x86_ROL),
+	/*10339*/ uint16(x86_xReadIb),
+	/*10340*/ uint16(x86_xArgRM32),
+	/*10341*/ uint16(x86_xArgImm8u),
+	/*10342*/ uint16(x86_xMatch),
+	/*10343*/ uint16(x86_xSetOp), uint16(x86_ROL),
+	/*10345*/ uint16(x86_xReadIb),
+	/*10346*/ uint16(x86_xArgRM64),
+	/*10347*/ uint16(x86_xArgImm8u),
+	/*10348*/ uint16(x86_xMatch),
+	/*10349*/ uint16(x86_xCondDataSize), 10353, 10359, 10365,
+	/*10353*/ uint16(x86_xSetOp), uint16(x86_ROR),
+	/*10355*/ uint16(x86_xReadIb),
+	/*10356*/ uint16(x86_xArgRM16),
+	/*10357*/ uint16(x86_xArgImm8u),
+	/*10358*/ uint16(x86_xMatch),
+	/*10359*/ uint16(x86_xSetOp), uint16(x86_ROR),
+	/*10361*/ uint16(x86_xReadIb),
+	/*10362*/ uint16(x86_xArgRM32),
+	/*10363*/ uint16(x86_xArgImm8u),
+	/*10364*/ uint16(x86_xMatch),
+	/*10365*/ uint16(x86_xSetOp), uint16(x86_ROR),
+	/*10367*/ uint16(x86_xReadIb),
+	/*10368*/ uint16(x86_xArgRM64),
+	/*10369*/ uint16(x86_xArgImm8u),
+	/*10370*/ uint16(x86_xMatch),
+	/*10371*/ uint16(x86_xCondIs64), 10374, 10390,
+	/*10374*/ uint16(x86_xCondDataSize), 10378, 10384, 0,
+	/*10378*/ uint16(x86_xSetOp), uint16(x86_RCL),
+	/*10380*/ uint16(x86_xReadIb),
+	/*10381*/ uint16(x86_xArgRM16),
+	/*10382*/ uint16(x86_xArgImm8u),
+	/*10383*/ uint16(x86_xMatch),
+	/*10384*/ uint16(x86_xSetOp), uint16(x86_RCL),
+	/*10386*/ uint16(x86_xReadIb),
+	/*10387*/ uint16(x86_xArgRM32),
+	/*10388*/ uint16(x86_xArgImm8u),
+	/*10389*/ uint16(x86_xMatch),
+	/*10390*/ uint16(x86_xCondDataSize), 10378, 10384, 10394,
+	/*10394*/ uint16(x86_xSetOp), uint16(x86_RCL),
+	/*10396*/ uint16(x86_xReadIb),
+	/*10397*/ uint16(x86_xArgRM64),
+	/*10398*/ uint16(x86_xArgImm8u),
+	/*10399*/ uint16(x86_xMatch),
+	/*10400*/ uint16(x86_xCondIs64), 10403, 10419,
+	/*10403*/ uint16(x86_xCondDataSize), 10407, 10413, 0,
+	/*10407*/ uint16(x86_xSetOp), uint16(x86_RCR),
+	/*10409*/ uint16(x86_xReadIb),
+	/*10410*/ uint16(x86_xArgRM16),
+	/*10411*/ uint16(x86_xArgImm8u),
+	/*10412*/ uint16(x86_xMatch),
+	/*10413*/ uint16(x86_xSetOp), uint16(x86_RCR),
+	/*10415*/ uint16(x86_xReadIb),
+	/*10416*/ uint16(x86_xArgRM32),
+	/*10417*/ uint16(x86_xArgImm8u),
+	/*10418*/ uint16(x86_xMatch),
+	/*10419*/ uint16(x86_xCondDataSize), 10407, 10413, 10423,
+	/*10423*/ uint16(x86_xSetOp), uint16(x86_RCR),
+	/*10425*/ uint16(x86_xReadIb),
+	/*10426*/ uint16(x86_xArgRM64),
+	/*10427*/ uint16(x86_xArgImm8u),
+	/*10428*/ uint16(x86_xMatch),
+	/*10429*/ uint16(x86_xCondIs64), 10432, 10448,
+	/*10432*/ uint16(x86_xCondDataSize), 10436, 10442, 0,
+	/*10436*/ uint16(x86_xSetOp), uint16(x86_SHL),
+	/*10438*/ uint16(x86_xReadIb),
+	/*10439*/ uint16(x86_xArgRM16),
+	/*10440*/ uint16(x86_xArgImm8u),
+	/*10441*/ uint16(x86_xMatch),
+	/*10442*/ uint16(x86_xSetOp), uint16(x86_SHL),
+	/*10444*/ uint16(x86_xReadIb),
+	/*10445*/ uint16(x86_xArgRM32),
+	/*10446*/ uint16(x86_xArgImm8u),
+	/*10447*/ uint16(x86_xMatch),
+	/*10448*/ uint16(x86_xCondDataSize), 10436, 10442, 10452,
+	/*10452*/ uint16(x86_xSetOp), uint16(x86_SHL),
+	/*10454*/ uint16(x86_xReadIb),
+	/*10455*/ uint16(x86_xArgRM64),
+	/*10456*/ uint16(x86_xArgImm8u),
+	/*10457*/ uint16(x86_xMatch),
+	/*10458*/ uint16(x86_xCondIs64), 10461, 10477,
+	/*10461*/ uint16(x86_xCondDataSize), 10465, 10471, 0,
+	/*10465*/ uint16(x86_xSetOp), uint16(x86_SHR),
+	/*10467*/ uint16(x86_xReadIb),
+	/*10468*/ uint16(x86_xArgRM16),
+	/*10469*/ uint16(x86_xArgImm8u),
+	/*10470*/ uint16(x86_xMatch),
+	/*10471*/ uint16(x86_xSetOp), uint16(x86_SHR),
+	/*10473*/ uint16(x86_xReadIb),
+	/*10474*/ uint16(x86_xArgRM32),
+	/*10475*/ uint16(x86_xArgImm8u),
+	/*10476*/ uint16(x86_xMatch),
+	/*10477*/ uint16(x86_xCondDataSize), 10465, 10471, 10481,
+	/*10481*/ uint16(x86_xSetOp), uint16(x86_SHR),
+	/*10483*/ uint16(x86_xReadIb),
+	/*10484*/ uint16(x86_xArgRM64),
+	/*10485*/ uint16(x86_xArgImm8u),
+	/*10486*/ uint16(x86_xMatch),
+	/*10487*/ uint16(x86_xCondIs64), 10490, 10506,
+	/*10490*/ uint16(x86_xCondDataSize), 10494, 10500, 0,
+	/*10494*/ uint16(x86_xSetOp), uint16(x86_SAR),
+	/*10496*/ uint16(x86_xReadIb),
+	/*10497*/ uint16(x86_xArgRM16),
+	/*10498*/ uint16(x86_xArgImm8u),
+	/*10499*/ uint16(x86_xMatch),
+	/*10500*/ uint16(x86_xSetOp), uint16(x86_SAR),
+	/*10502*/ uint16(x86_xReadIb),
+	/*10503*/ uint16(x86_xArgRM32),
+	/*10504*/ uint16(x86_xArgImm8u),
+	/*10505*/ uint16(x86_xMatch),
+	/*10506*/ uint16(x86_xCondDataSize), 10494, 10500, 10510,
+	/*10510*/ uint16(x86_xSetOp), uint16(x86_SAR),
+	/*10512*/ uint16(x86_xReadIb),
+	/*10513*/ uint16(x86_xArgRM64),
+	/*10514*/ uint16(x86_xArgImm8u),
+	/*10515*/ uint16(x86_xMatch),
+	/*10516*/ uint16(x86_xSetOp), uint16(x86_RET),
+	/*10518*/ uint16(x86_xReadIw),
+	/*10519*/ uint16(x86_xArgImm16u),
+	/*10520*/ uint16(x86_xMatch),
+	/*10521*/ uint16(x86_xSetOp), uint16(x86_RET),
+	/*10523*/ uint16(x86_xMatch),
+	/*10524*/ uint16(x86_xCondIs64), 10527, 0,
+	/*10527*/ uint16(x86_xCondDataSize), 10531, 10537, 0,
+	/*10531*/ uint16(x86_xSetOp), uint16(x86_LES),
+	/*10533*/ uint16(x86_xReadSlashR),
+	/*10534*/ uint16(x86_xArgR16),
+	/*10535*/ uint16(x86_xArgM16colon16),
+	/*10536*/ uint16(x86_xMatch),
+	/*10537*/ uint16(x86_xSetOp), uint16(x86_LES),
+	/*10539*/ uint16(x86_xReadSlashR),
+	/*10540*/ uint16(x86_xArgR32),
+	/*10541*/ uint16(x86_xArgM16colon32),
+	/*10542*/ uint16(x86_xMatch),
+	/*10543*/ uint16(x86_xCondIs64), 10546, 0,
+	/*10546*/ uint16(x86_xCondDataSize), 10550, 10556, 0,
+	/*10550*/ uint16(x86_xSetOp), uint16(x86_LDS),
+	/*10552*/ uint16(x86_xReadSlashR),
+	/*10553*/ uint16(x86_xArgR16),
+	/*10554*/ uint16(x86_xArgM16colon16),
+	/*10555*/ uint16(x86_xMatch),
+	/*10556*/ uint16(x86_xSetOp), uint16(x86_LDS),
+	/*10558*/ uint16(x86_xReadSlashR),
+	/*10559*/ uint16(x86_xArgR32),
+	/*10560*/ uint16(x86_xArgM16colon32),
+	/*10561*/ uint16(x86_xMatch),
+	/*10562*/ uint16(x86_xCondByte), 1,
+	0xF8, 10581,
+	/*10566*/ uint16(x86_xCondSlashR),
+	10575, // 0
+	0,     // 1
+	0,     // 2
+	0,     // 3
+	0,     // 4
+	0,     // 5
+	0,     // 6
+	0,     // 7
+	/*10575*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*10577*/ uint16(x86_xReadIb),
+	/*10578*/ uint16(x86_xArgRM8),
+	/*10579*/ uint16(x86_xArgImm8u),
+	/*10580*/ uint16(x86_xMatch),
+	/*10581*/ uint16(x86_xSetOp), uint16(x86_XABORT),
+	/*10583*/ uint16(x86_xReadIb),
+	/*10584*/ uint16(x86_xArgImm8u),
+	/*10585*/ uint16(x86_xMatch),
+	/*10586*/ uint16(x86_xCondByte), 1,
+	0xF8, 10628,
+	/*10590*/ uint16(x86_xCondSlashR),
+	10599, // 0
+	0,     // 1
+	0,     // 2
+	0,     // 3
+	0,     // 4
+	0,     // 5
+	0,     // 6
+	0,     // 7
+	/*10599*/ uint16(x86_xCondIs64), 10602, 10618,
+	/*10602*/ uint16(x86_xCondDataSize), 10606, 10612, 0,
+	/*10606*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*10608*/ uint16(x86_xReadIw),
+	/*10609*/ uint16(x86_xArgRM16),
+	/*10610*/ uint16(x86_xArgImm16),
+	/*10611*/ uint16(x86_xMatch),
+	/*10612*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*10614*/ uint16(x86_xReadId),
+	/*10615*/ uint16(x86_xArgRM32),
+	/*10616*/ uint16(x86_xArgImm32),
+	/*10617*/ uint16(x86_xMatch),
+	/*10618*/ uint16(x86_xCondDataSize), 10606, 10612, 10622,
+	/*10622*/ uint16(x86_xSetOp), uint16(x86_MOV),
+	/*10624*/ uint16(x86_xReadId),
+	/*10625*/ uint16(x86_xArgRM64),
+	/*10626*/ uint16(x86_xArgImm32),
+	/*10627*/ uint16(x86_xMatch),
+	/*10628*/ uint16(x86_xCondDataSize), 10632, 10637, 10642,
+	/*10632*/ uint16(x86_xSetOp), uint16(x86_XBEGIN),
+	/*10634*/ uint16(x86_xReadCw),
+	/*10635*/ uint16(x86_xArgRel16),
+	/*10636*/ uint16(x86_xMatch),
+	/*10637*/ uint16(x86_xSetOp), uint16(x86_XBEGIN),
+	/*10639*/ uint16(x86_xReadCd),
+	/*10640*/ uint16(x86_xArgRel32),
+	/*10641*/ uint16(x86_xMatch),
+	/*10642*/ uint16(x86_xSetOp), uint16(x86_XBEGIN),
+	/*10644*/ uint16(x86_xReadCd),
+	/*10645*/ uint16(x86_xArgRel32),
+	/*10646*/ uint16(x86_xMatch),
+	/*10647*/ uint16(x86_xSetOp), uint16(x86_ENTER),
+	/*10649*/ uint16(x86_xReadIw),
+	/*10650*/ uint16(x86_xReadIb),
+	/*10651*/ uint16(x86_xArgImm16u),
+	/*10652*/ uint16(x86_xArgImm8u),
+	/*10653*/ uint16(x86_xMatch),
+	/*10654*/ uint16(x86_xCondIs64), 10657, 10667,
+	/*10657*/ uint16(x86_xCondDataSize), 10661, 10664, 0,
+	/*10661*/ uint16(x86_xSetOp), uint16(x86_LEAVE),
+	/*10663*/ uint16(x86_xMatch),
+	/*10664*/ uint16(x86_xSetOp), uint16(x86_LEAVE),
+	/*10666*/ uint16(x86_xMatch),
+	/*10667*/ uint16(x86_xCondDataSize), 10661, 10671, 10674,
+	/*10671*/ uint16(x86_xSetOp), uint16(x86_LEAVE),
+	/*10673*/ uint16(x86_xMatch),
+	/*10674*/ uint16(x86_xSetOp), uint16(x86_LEAVE),
+	/*10676*/ uint16(x86_xMatch),
+	/*10677*/ uint16(x86_xSetOp), uint16(x86_LRET),
+	/*10679*/ uint16(x86_xReadIw),
+	/*10680*/ uint16(x86_xArgImm16u),
+	/*10681*/ uint16(x86_xMatch),
+	/*10682*/ uint16(x86_xSetOp), uint16(x86_LRET),
+	/*10684*/ uint16(x86_xMatch),
+	/*10685*/ uint16(x86_xSetOp), uint16(x86_INT),
+	/*10687*/ uint16(x86_xArg3),
+	/*10688*/ uint16(x86_xMatch),
+	/*10689*/ uint16(x86_xSetOp), uint16(x86_INT),
+	/*10691*/ uint16(x86_xReadIb),
+	/*10692*/ uint16(x86_xArgImm8u),
+	/*10693*/ uint16(x86_xMatch),
+	/*10694*/ uint16(x86_xCondIs64), 10697, 0,
+	/*10697*/ uint16(x86_xSetOp), uint16(x86_INTO),
+	/*10699*/ uint16(x86_xMatch),
+	/*10700*/ uint16(x86_xCondIs64), 10703, 10713,
+	/*10703*/ uint16(x86_xCondDataSize), 10707, 10710, 0,
+	/*10707*/ uint16(x86_xSetOp), uint16(x86_IRET),
+	/*10709*/ uint16(x86_xMatch),
+	/*10710*/ uint16(x86_xSetOp), uint16(x86_IRETD),
+	/*10712*/ uint16(x86_xMatch),
+	/*10713*/ uint16(x86_xCondDataSize), 10707, 10710, 10717,
+	/*10717*/ uint16(x86_xSetOp), uint16(x86_IRETQ),
+	/*10719*/ uint16(x86_xMatch),
+	/*10720*/ uint16(x86_xCondSlashR),
+	10729, // 0
+	10734, // 1
+	10739, // 2
+	10744, // 3
+	10749, // 4
+	10754, // 5
+	0,     // 6
+	10759, // 7
+	/*10729*/ uint16(x86_xSetOp), uint16(x86_ROL),
+	/*10731*/ uint16(x86_xArgRM8),
+	/*10732*/ uint16(x86_xArg1),
+	/*10733*/ uint16(x86_xMatch),
+	/*10734*/ uint16(x86_xSetOp), uint16(x86_ROR),
+	/*10736*/ uint16(x86_xArgRM8),
+	/*10737*/ uint16(x86_xArg1),
+	/*10738*/ uint16(x86_xMatch),
+	/*10739*/ uint16(x86_xSetOp), uint16(x86_RCL),
+	/*10741*/ uint16(x86_xArgRM8),
+	/*10742*/ uint16(x86_xArg1),
+	/*10743*/ uint16(x86_xMatch),
+	/*10744*/ uint16(x86_xSetOp), uint16(x86_RCR),
+	/*10746*/ uint16(x86_xArgRM8),
+	/*10747*/ uint16(x86_xArg1),
+	/*10748*/ uint16(x86_xMatch),
+	/*10749*/ uint16(x86_xSetOp), uint16(x86_SHL),
+	/*10751*/ uint16(x86_xArgRM8),
+	/*10752*/ uint16(x86_xArg1),
+	/*10753*/ uint16(x86_xMatch),
+	/*10754*/ uint16(x86_xSetOp), uint16(x86_SHR),
+	/*10756*/ uint16(x86_xArgRM8),
+	/*10757*/ uint16(x86_xArg1),
+	/*10758*/ uint16(x86_xMatch),
+	/*10759*/ uint16(x86_xSetOp), uint16(x86_SAR),
+	/*10761*/ uint16(x86_xArgRM8),
+	/*10762*/ uint16(x86_xArg1),
+	/*10763*/ uint16(x86_xMatch),
+	/*10764*/ uint16(x86_xCondSlashR),
+	10773, // 0
+	10799, // 1
+	10825, // 2
+	10851, // 3
+	10877, // 4
+	10903, // 5
+	0,     // 6
+	10929, // 7
+	/*10773*/ uint16(x86_xCondIs64), 10776, 10790,
+	/*10776*/ uint16(x86_xCondDataSize), 10780, 10785, 0,
+	/*10780*/ uint16(x86_xSetOp), uint16(x86_ROL),
+	/*10782*/ uint16(x86_xArgRM16),
+	/*10783*/ uint16(x86_xArg1),
+	/*10784*/ uint16(x86_xMatch),
+	/*10785*/ uint16(x86_xSetOp), uint16(x86_ROL),
+	/*10787*/ uint16(x86_xArgRM32),
+	/*10788*/ uint16(x86_xArg1),
+	/*10789*/ uint16(x86_xMatch),
+	/*10790*/ uint16(x86_xCondDataSize), 10780, 10785, 10794,
+	/*10794*/ uint16(x86_xSetOp), uint16(x86_ROL),
+	/*10796*/ uint16(x86_xArgRM64),
+	/*10797*/ uint16(x86_xArg1),
+	/*10798*/ uint16(x86_xMatch),
+	/*10799*/ uint16(x86_xCondIs64), 10802, 10816,
+	/*10802*/ uint16(x86_xCondDataSize), 10806, 10811, 0,
+	/*10806*/ uint16(x86_xSetOp), uint16(x86_ROR),
+	/*10808*/ uint16(x86_xArgRM16),
+	/*10809*/ uint16(x86_xArg1),
+	/*10810*/ uint16(x86_xMatch),
+	/*10811*/ uint16(x86_xSetOp), uint16(x86_ROR),
+	/*10813*/ uint16(x86_xArgRM32),
+	/*10814*/ uint16(x86_xArg1),
+	/*10815*/ uint16(x86_xMatch),
+	/*10816*/ uint16(x86_xCondDataSize), 10806, 10811, 10820,
+	/*10820*/ uint16(x86_xSetOp), uint16(x86_ROR),
+	/*10822*/ uint16(x86_xArgRM64),
+	/*10823*/ uint16(x86_xArg1),
+	/*10824*/ uint16(x86_xMatch),
+	/*10825*/ uint16(x86_xCondIs64), 10828, 10842,
+	/*10828*/ uint16(x86_xCondDataSize), 10832, 10837, 0,
+	/*10832*/ uint16(x86_xSetOp), uint16(x86_RCL),
+	/*10834*/ uint16(x86_xArgRM16),
+	/*10835*/ uint16(x86_xArg1),
+	/*10836*/ uint16(x86_xMatch),
+	/*10837*/ uint16(x86_xSetOp), uint16(x86_RCL),
+	/*10839*/ uint16(x86_xArgRM32),
+	/*10840*/ uint16(x86_xArg1),
+	/*10841*/ uint16(x86_xMatch),
+	/*10842*/ uint16(x86_xCondDataSize), 10832, 10837, 10846,
+	/*10846*/ uint16(x86_xSetOp), uint16(x86_RCL),
+	/*10848*/ uint16(x86_xArgRM64),
+	/*10849*/ uint16(x86_xArg1),
+	/*10850*/ uint16(x86_xMatch),
+	/*10851*/ uint16(x86_xCondIs64), 10854, 10868,
+	/*10854*/ uint16(x86_xCondDataSize), 10858, 10863, 0,
+	/*10858*/ uint16(x86_xSetOp), uint16(x86_RCR),
+	/*10860*/ uint16(x86_xArgRM16),
+	/*10861*/ uint16(x86_xArg1),
+	/*10862*/ uint16(x86_xMatch),
+	/*10863*/ uint16(x86_xSetOp), uint16(x86_RCR),
+	/*10865*/ uint16(x86_xArgRM32),
+	/*10866*/ uint16(x86_xArg1),
+	/*10867*/ uint16(x86_xMatch),
+	/*10868*/ uint16(x86_xCondDataSize), 10858, 10863, 10872,
+	/*10872*/ uint16(x86_xSetOp), uint16(x86_RCR),
+	/*10874*/ uint16(x86_xArgRM64),
+	/*10875*/ uint16(x86_xArg1),
+	/*10876*/ uint16(x86_xMatch),
+	/*10877*/ uint16(x86_xCondIs64), 10880, 10894,
+	/*10880*/ uint16(x86_xCondDataSize), 10884, 10889, 0,
+	/*10884*/ uint16(x86_xSetOp), uint16(x86_SHL),
+	/*10886*/ uint16(x86_xArgRM16),
+	/*10887*/ uint16(x86_xArg1),
+	/*10888*/ uint16(x86_xMatch),
+	/*10889*/ uint16(x86_xSetOp), uint16(x86_SHL),
+	/*10891*/ uint16(x86_xArgRM32),
+	/*10892*/ uint16(x86_xArg1),
+	/*10893*/ uint16(x86_xMatch),
+	/*10894*/ uint16(x86_xCondDataSize), 10884, 10889, 10898,
+	/*10898*/ uint16(x86_xSetOp), uint16(x86_SHL),
+	/*10900*/ uint16(x86_xArgRM64),
+	/*10901*/ uint16(x86_xArg1),
+	/*10902*/ uint16(x86_xMatch),
+	/*10903*/ uint16(x86_xCondIs64), 10906, 10920,
+	/*10906*/ uint16(x86_xCondDataSize), 10910, 10915, 0,
+	/*10910*/ uint16(x86_xSetOp), uint16(x86_SHR),
+	/*10912*/ uint16(x86_xArgRM16),
+	/*10913*/ uint16(x86_xArg1),
+	/*10914*/ uint16(x86_xMatch),
+	/*10915*/ uint16(x86_xSetOp), uint16(x86_SHR),
+	/*10917*/ uint16(x86_xArgRM32),
+	/*10918*/ uint16(x86_xArg1),
+	/*10919*/ uint16(x86_xMatch),
+	/*10920*/ uint16(x86_xCondDataSize), 10910, 10915, 10924,
+	/*10924*/ uint16(x86_xSetOp), uint16(x86_SHR),
+	/*10926*/ uint16(x86_xArgRM64),
+	/*10927*/ uint16(x86_xArg1),
+	/*10928*/ uint16(x86_xMatch),
+	/*10929*/ uint16(x86_xCondIs64), 10932, 10946,
+	/*10932*/ uint16(x86_xCondDataSize), 10936, 10941, 0,
+	/*10936*/ uint16(x86_xSetOp), uint16(x86_SAR),
+	/*10938*/ uint16(x86_xArgRM16),
+	/*10939*/ uint16(x86_xArg1),
+	/*10940*/ uint16(x86_xMatch),
+	/*10941*/ uint16(x86_xSetOp), uint16(x86_SAR),
+	/*10943*/ uint16(x86_xArgRM32),
+	/*10944*/ uint16(x86_xArg1),
+	/*10945*/ uint16(x86_xMatch),
+	/*10946*/ uint16(x86_xCondDataSize), 10936, 10941, 10950,
+	/*10950*/ uint16(x86_xSetOp), uint16(x86_SAR),
+	/*10952*/ uint16(x86_xArgRM64),
+	/*10953*/ uint16(x86_xArg1),
+	/*10954*/ uint16(x86_xMatch),
+	/*10955*/ uint16(x86_xCondSlashR),
+	10964, // 0
+	10969, // 1
+	10974, // 2
+	10979, // 3
+	10984, // 4
+	10989, // 5
+	0,     // 6
+	10994, // 7
+	/*10964*/ uint16(x86_xSetOp), uint16(x86_ROL),
+	/*10966*/ uint16(x86_xArgRM8),
+	/*10967*/ uint16(x86_xArgCL),
+	/*10968*/ uint16(x86_xMatch),
+	/*10969*/ uint16(x86_xSetOp), uint16(x86_ROR),
+	/*10971*/ uint16(x86_xArgRM8),
+	/*10972*/ uint16(x86_xArgCL),
+	/*10973*/ uint16(x86_xMatch),
+	/*10974*/ uint16(x86_xSetOp), uint16(x86_RCL),
+	/*10976*/ uint16(x86_xArgRM8),
+	/*10977*/ uint16(x86_xArgCL),
+	/*10978*/ uint16(x86_xMatch),
+	/*10979*/ uint16(x86_xSetOp), uint16(x86_RCR),
+	/*10981*/ uint16(x86_xArgRM8),
+	/*10982*/ uint16(x86_xArgCL),
+	/*10983*/ uint16(x86_xMatch),
+	/*10984*/ uint16(x86_xSetOp), uint16(x86_SHL),
+	/*10986*/ uint16(x86_xArgRM8),
+	/*10987*/ uint16(x86_xArgCL),
+	/*10988*/ uint16(x86_xMatch),
+	/*10989*/ uint16(x86_xSetOp), uint16(x86_SHR),
+	/*10991*/ uint16(x86_xArgRM8),
+	/*10992*/ uint16(x86_xArgCL),
+	/*10993*/ uint16(x86_xMatch),
+	/*10994*/ uint16(x86_xSetOp), uint16(x86_SAR),
+	/*10996*/ uint16(x86_xArgRM8),
+	/*10997*/ uint16(x86_xArgCL),
+	/*10998*/ uint16(x86_xMatch),
+	/*10999*/ uint16(x86_xCondSlashR),
+	11008, // 0
+	11034, // 1
+	11060, // 2
+	11086, // 3
+	11112, // 4
+	11138, // 5
+	0,     // 6
+	11164, // 7
+	/*11008*/ uint16(x86_xCondIs64), 11011, 11025,
+	/*11011*/ uint16(x86_xCondDataSize), 11015, 11020, 0,
+	/*11015*/ uint16(x86_xSetOp), uint16(x86_ROL),
+	/*11017*/ uint16(x86_xArgRM16),
+	/*11018*/ uint16(x86_xArgCL),
+	/*11019*/ uint16(x86_xMatch),
+	/*11020*/ uint16(x86_xSetOp), uint16(x86_ROL),
+	/*11022*/ uint16(x86_xArgRM32),
+	/*11023*/ uint16(x86_xArgCL),
+	/*11024*/ uint16(x86_xMatch),
+	/*11025*/ uint16(x86_xCondDataSize), 11015, 11020, 11029,
+	/*11029*/ uint16(x86_xSetOp), uint16(x86_ROL),
+	/*11031*/ uint16(x86_xArgRM64),
+	/*11032*/ uint16(x86_xArgCL),
+	/*11033*/ uint16(x86_xMatch),
+	/*11034*/ uint16(x86_xCondIs64), 11037, 11051,
+	/*11037*/ uint16(x86_xCondDataSize), 11041, 11046, 0,
+	/*11041*/ uint16(x86_xSetOp), uint16(x86_ROR),
+	/*11043*/ uint16(x86_xArgRM16),
+	/*11044*/ uint16(x86_xArgCL),
+	/*11045*/ uint16(x86_xMatch),
+	/*11046*/ uint16(x86_xSetOp), uint16(x86_ROR),
+	/*11048*/ uint16(x86_xArgRM32),
+	/*11049*/ uint16(x86_xArgCL),
+	/*11050*/ uint16(x86_xMatch),
+	/*11051*/ uint16(x86_xCondDataSize), 11041, 11046, 11055,
+	/*11055*/ uint16(x86_xSetOp), uint16(x86_ROR),
+	/*11057*/ uint16(x86_xArgRM64),
+	/*11058*/ uint16(x86_xArgCL),
+	/*11059*/ uint16(x86_xMatch),
+	/*11060*/ uint16(x86_xCondIs64), 11063, 11077,
+	/*11063*/ uint16(x86_xCondDataSize), 11067, 11072, 0,
+	/*11067*/ uint16(x86_xSetOp), uint16(x86_RCL),
+	/*11069*/ uint16(x86_xArgRM16),
+	/*11070*/ uint16(x86_xArgCL),
+	/*11071*/ uint16(x86_xMatch),
+	/*11072*/ uint16(x86_xSetOp), uint16(x86_RCL),
+	/*11074*/ uint16(x86_xArgRM32),
+	/*11075*/ uint16(x86_xArgCL),
+	/*11076*/ uint16(x86_xMatch),
+	/*11077*/ uint16(x86_xCondDataSize), 11067, 11072, 11081,
+	/*11081*/ uint16(x86_xSetOp), uint16(x86_RCL),
+	/*11083*/ uint16(x86_xArgRM64),
+	/*11084*/ uint16(x86_xArgCL),
+	/*11085*/ uint16(x86_xMatch),
+	/*11086*/ uint16(x86_xCondIs64), 11089, 11103,
+	/*11089*/ uint16(x86_xCondDataSize), 11093, 11098, 0,
+	/*11093*/ uint16(x86_xSetOp), uint16(x86_RCR),
+	/*11095*/ uint16(x86_xArgRM16),
+	/*11096*/ uint16(x86_xArgCL),
+	/*11097*/ uint16(x86_xMatch),
+	/*11098*/ uint16(x86_xSetOp), uint16(x86_RCR),
+	/*11100*/ uint16(x86_xArgRM32),
+	/*11101*/ uint16(x86_xArgCL),
+	/*11102*/ uint16(x86_xMatch),
+	/*11103*/ uint16(x86_xCondDataSize), 11093, 11098, 11107,
+	/*11107*/ uint16(x86_xSetOp), uint16(x86_RCR),
+	/*11109*/ uint16(x86_xArgRM64),
+	/*11110*/ uint16(x86_xArgCL),
+	/*11111*/ uint16(x86_xMatch),
+	/*11112*/ uint16(x86_xCondIs64), 11115, 11129,
+	/*11115*/ uint16(x86_xCondDataSize), 11119, 11124, 0,
+	/*11119*/ uint16(x86_xSetOp), uint16(x86_SHL),
+	/*11121*/ uint16(x86_xArgRM16),
+	/*11122*/ uint16(x86_xArgCL),
+	/*11123*/ uint16(x86_xMatch),
+	/*11124*/ uint16(x86_xSetOp), uint16(x86_SHL),
+	/*11126*/ uint16(x86_xArgRM32),
+	/*11127*/ uint16(x86_xArgCL),
+	/*11128*/ uint16(x86_xMatch),
+	/*11129*/ uint16(x86_xCondDataSize), 11119, 11124, 11133,
+	/*11133*/ uint16(x86_xSetOp), uint16(x86_SHL),
+	/*11135*/ uint16(x86_xArgRM64),
+	/*11136*/ uint16(x86_xArgCL),
+	/*11137*/ uint16(x86_xMatch),
+	/*11138*/ uint16(x86_xCondIs64), 11141, 11155,
+	/*11141*/ uint16(x86_xCondDataSize), 11145, 11150, 0,
+	/*11145*/ uint16(x86_xSetOp), uint16(x86_SHR),
+	/*11147*/ uint16(x86_xArgRM16),
+	/*11148*/ uint16(x86_xArgCL),
+	/*11149*/ uint16(x86_xMatch),
+	/*11150*/ uint16(x86_xSetOp), uint16(x86_SHR),
+	/*11152*/ uint16(x86_xArgRM32),
+	/*11153*/ uint16(x86_xArgCL),
+	/*11154*/ uint16(x86_xMatch),
+	/*11155*/ uint16(x86_xCondDataSize), 11145, 11150, 11159,
+	/*11159*/ uint16(x86_xSetOp), uint16(x86_SHR),
+	/*11161*/ uint16(x86_xArgRM64),
+	/*11162*/ uint16(x86_xArgCL),
+	/*11163*/ uint16(x86_xMatch),
+	/*11164*/ uint16(x86_xCondIs64), 11167, 11181,
+	/*11167*/ uint16(x86_xCondDataSize), 11171, 11176, 0,
+	/*11171*/ uint16(x86_xSetOp), uint16(x86_SAR),
+	/*11173*/ uint16(x86_xArgRM16),
+	/*11174*/ uint16(x86_xArgCL),
+	/*11175*/ uint16(x86_xMatch),
+	/*11176*/ uint16(x86_xSetOp), uint16(x86_SAR),
+	/*11178*/ uint16(x86_xArgRM32),
+	/*11179*/ uint16(x86_xArgCL),
+	/*11180*/ uint16(x86_xMatch),
+	/*11181*/ uint16(x86_xCondDataSize), 11171, 11176, 11185,
+	/*11185*/ uint16(x86_xSetOp), uint16(x86_SAR),
+	/*11187*/ uint16(x86_xArgRM64),
+	/*11188*/ uint16(x86_xArgCL),
+	/*11189*/ uint16(x86_xMatch),
+	/*11190*/ uint16(x86_xCondIs64), 11193, 0,
+	/*11193*/ uint16(x86_xSetOp), uint16(x86_AAM),
+	/*11195*/ uint16(x86_xReadIb),
+	/*11196*/ uint16(x86_xArgImm8u),
+	/*11197*/ uint16(x86_xMatch),
+	/*11198*/ uint16(x86_xCondIs64), 11201, 0,
+	/*11201*/ uint16(x86_xSetOp), uint16(x86_AAD),
+	/*11203*/ uint16(x86_xReadIb),
+	/*11204*/ uint16(x86_xArgImm8u),
+	/*11205*/ uint16(x86_xMatch),
+	/*11206*/ uint16(x86_xCondIs64), 11209, 11212,
+	/*11209*/ uint16(x86_xSetOp), uint16(x86_XLATB),
+	/*11211*/ uint16(x86_xMatch),
+	/*11212*/ uint16(x86_xCondDataSize), 11209, 11209, 11216,
+	/*11216*/ uint16(x86_xSetOp), uint16(x86_XLATB),
+	/*11218*/ uint16(x86_xMatch),
+	/*11219*/ uint16(x86_xCondByte), 64,
+	0xc0, 11390,
+	0xc1, 11390,
+	0xc2, 11390,
+	0xc3, 11390,
+	0xc4, 11390,
+	0xc5, 11390,
+	0xc6, 11390,
+	0xc7, 11390,
+	0xc8, 11395,
+	0xc9, 11395,
+	0xca, 11395,
+	0xcb, 11395,
+	0xcc, 11395,
+	0xcd, 11395,
+	0xce, 11395,
+	0xcf, 11395,
+	0xd0, 11400,
+	0xd1, 11400,
+	0xd2, 11400,
+	0xd3, 11400,
+	0xd4, 11400,
+	0xd5, 11400,
+	0xd6, 11400,
+	0xd7, 11400,
+	0xd8, 11404,
+	0xd9, 11404,
+	0xda, 11404,
+	0xdb, 11404,
+	0xdc, 11404,
+	0xdd, 11404,
+	0xde, 11404,
+	0xdf, 11404,
+	0xe0, 11408,
+	0xe1, 11408,
+	0xe2, 11408,
+	0xe3, 11408,
+	0xe4, 11408,
+	0xe5, 11408,
+	0xe6, 11408,
+	0xe7, 11408,
+	0xe8, 11413,
+	0xe9, 11413,
+	0xea, 11413,
+	0xeb, 11413,
+	0xec, 11413,
+	0xed, 11413,
+	0xee, 11413,
+	0xef, 11413,
+	0xf0, 11418,
+	0xf1, 11418,
+	0xf2, 11418,
+	0xf3, 11418,
+	0xf4, 11418,
+	0xf5, 11418,
+	0xf6, 11418,
+	0xf7, 11418,
+	0xf8, 11423,
+	0xf9, 11423,
+	0xfa, 11423,
+	0xfb, 11423,
+	0xfc, 11423,
+	0xfd, 11423,
+	0xfe, 11423,
+	0xff, 11423,
+	/*11349*/ uint16(x86_xCondSlashR),
+	11358, // 0
+	11362, // 1
+	11366, // 2
+	11370, // 3
+	11374, // 4
+	11378, // 5
+	11382, // 6
+	11386, // 7
+	/*11358*/ uint16(x86_xSetOp), uint16(x86_FADD),
+	/*11360*/ uint16(x86_xArgM32fp),
+	/*11361*/ uint16(x86_xMatch),
+	/*11362*/ uint16(x86_xSetOp), uint16(x86_FMUL),
+	/*11364*/ uint16(x86_xArgM32fp),
+	/*11365*/ uint16(x86_xMatch),
+	/*11366*/ uint16(x86_xSetOp), uint16(x86_FCOM),
+	/*11368*/ uint16(x86_xArgM32fp),
+	/*11369*/ uint16(x86_xMatch),
+	/*11370*/ uint16(x86_xSetOp), uint16(x86_FCOMP),
+	/*11372*/ uint16(x86_xArgM32fp),
+	/*11373*/ uint16(x86_xMatch),
+	/*11374*/ uint16(x86_xSetOp), uint16(x86_FSUB),
+	/*11376*/ uint16(x86_xArgM32fp),
+	/*11377*/ uint16(x86_xMatch),
+	/*11378*/ uint16(x86_xSetOp), uint16(x86_FSUBR),
+	/*11380*/ uint16(x86_xArgM32fp),
+	/*11381*/ uint16(x86_xMatch),
+	/*11382*/ uint16(x86_xSetOp), uint16(x86_FDIV),
+	/*11384*/ uint16(x86_xArgM32fp),
+	/*11385*/ uint16(x86_xMatch),
+	/*11386*/ uint16(x86_xSetOp), uint16(x86_FDIVR),
+	/*11388*/ uint16(x86_xArgM32fp),
+	/*11389*/ uint16(x86_xMatch),
+	/*11390*/ uint16(x86_xSetOp), uint16(x86_FADD),
+	/*11392*/ uint16(x86_xArgST),
+	/*11393*/ uint16(x86_xArgSTi),
+	/*11394*/ uint16(x86_xMatch),
+	/*11395*/ uint16(x86_xSetOp), uint16(x86_FMUL),
+	/*11397*/ uint16(x86_xArgST),
+	/*11398*/ uint16(x86_xArgSTi),
+	/*11399*/ uint16(x86_xMatch),
+	/*11400*/ uint16(x86_xSetOp), uint16(x86_FCOM),
+	/*11402*/ uint16(x86_xArgSTi),
+	/*11403*/ uint16(x86_xMatch),
+	/*11404*/ uint16(x86_xSetOp), uint16(x86_FCOMP),
+	/*11406*/ uint16(x86_xArgSTi),
+	/*11407*/ uint16(x86_xMatch),
+	/*11408*/ uint16(x86_xSetOp), uint16(x86_FSUB),
+	/*11410*/ uint16(x86_xArgST),
+	/*11411*/ uint16(x86_xArgSTi),
+	/*11412*/ uint16(x86_xMatch),
+	/*11413*/ uint16(x86_xSetOp), uint16(x86_FSUBR),
+	/*11415*/ uint16(x86_xArgST),
+	/*11416*/ uint16(x86_xArgSTi),
+	/*11417*/ uint16(x86_xMatch),
+	/*11418*/ uint16(x86_xSetOp), uint16(x86_FDIV),
+	/*11420*/ uint16(x86_xArgST),
+	/*11421*/ uint16(x86_xArgSTi),
+	/*11422*/ uint16(x86_xMatch),
+	/*11423*/ uint16(x86_xSetOp), uint16(x86_FDIVR),
+	/*11425*/ uint16(x86_xArgST),
+	/*11426*/ uint16(x86_xArgSTi),
+	/*11427*/ uint16(x86_xMatch),
+	/*11428*/ uint16(x86_xCondByte), 42,
+	0xc0, 11551,
+	0xc1, 11551,
+	0xc2, 11551,
+	0xc3, 11551,
+	0xc4, 11551,
+	0xc5, 11551,
+	0xc6, 11551,
+	0xc7, 11551,
+	0xc8, 11555,
+	0xc9, 11555,
+	0xca, 11555,
+	0xcb, 11555,
+	0xcc, 11555,
+	0xcd, 11555,
+	0xce, 11555,
+	0xcf, 11555,
+	0xD0, 11559,
+	0xE0, 11562,
+	0xE1, 11565,
+	0xE4, 11568,
+	0xE5, 11571,
+	0xE8, 11574,
+	0xE9, 11577,
+	0xEA, 11580,
+	0xEB, 11583,
+	0xEC, 11586,
+	0xF0, 11589,
+	0xF1, 11592,
+	0xF2, 11595,
+	0xF3, 11598,
+	0xF4, 11601,
+	0xF5, 11604,
+	0xF6, 11607,
+	0xF7, 11610,
+	0xF8, 11613,
+	0xF9, 11616,
+	0xFA, 11619,
+	0xFB, 11622,
+	0xFC, 11625,
+	0xFD, 11628,
+	0xFE, 11631,
+	0xFF, 11634,
+	/*11514*/ uint16(x86_xCondSlashR),
+	11523, // 0
+	0,     // 1
+	11527, // 2
+	11531, // 3
+	11535, // 4
+	11539, // 5
+	11543, // 6
+	11547, // 7
+	/*11523*/ uint16(x86_xSetOp), uint16(x86_FLD),
+	/*11525*/ uint16(x86_xArgM32fp),
+	/*11526*/ uint16(x86_xMatch),
+	/*11527*/ uint16(x86_xSetOp), uint16(x86_FST),
+	/*11529*/ uint16(x86_xArgM32fp),
+	/*11530*/ uint16(x86_xMatch),
+	/*11531*/ uint16(x86_xSetOp), uint16(x86_FSTP),
+	/*11533*/ uint16(x86_xArgM32fp),
+	/*11534*/ uint16(x86_xMatch),
+	/*11535*/ uint16(x86_xSetOp), uint16(x86_FLDENV),
+	/*11537*/ uint16(x86_xArgM1428byte),
+	/*11538*/ uint16(x86_xMatch),
+	/*11539*/ uint16(x86_xSetOp), uint16(x86_FLDCW),
+	/*11541*/ uint16(x86_xArgM2byte),
+	/*11542*/ uint16(x86_xMatch),
+	/*11543*/ uint16(x86_xSetOp), uint16(x86_FNSTENV),
+	/*11545*/ uint16(x86_xArgM1428byte),
+	/*11546*/ uint16(x86_xMatch),
+	/*11547*/ uint16(x86_xSetOp), uint16(x86_FNSTCW),
+	/*11549*/ uint16(x86_xArgM2byte),
+	/*11550*/ uint16(x86_xMatch),
+	/*11551*/ uint16(x86_xSetOp), uint16(x86_FLD),
+	/*11553*/ uint16(x86_xArgSTi),
+	/*11554*/ uint16(x86_xMatch),
+	/*11555*/ uint16(x86_xSetOp), uint16(x86_FXCH),
+	/*11557*/ uint16(x86_xArgSTi),
+	/*11558*/ uint16(x86_xMatch),
+	/*11559*/ uint16(x86_xSetOp), uint16(x86_FNOP),
+	/*11561*/ uint16(x86_xMatch),
+	/*11562*/ uint16(x86_xSetOp), uint16(x86_FCHS),
+	/*11564*/ uint16(x86_xMatch),
+	/*11565*/ uint16(x86_xSetOp), uint16(x86_FABS),
+	/*11567*/ uint16(x86_xMatch),
+	/*11568*/ uint16(x86_xSetOp), uint16(x86_FTST),
+	/*11570*/ uint16(x86_xMatch),
+	/*11571*/ uint16(x86_xSetOp), uint16(x86_FXAM),
+	/*11573*/ uint16(x86_xMatch),
+	/*11574*/ uint16(x86_xSetOp), uint16(x86_FLD1),
+	/*11576*/ uint16(x86_xMatch),
+	/*11577*/ uint16(x86_xSetOp), uint16(x86_FLDL2T),
+	/*11579*/ uint16(x86_xMatch),
+	/*11580*/ uint16(x86_xSetOp), uint16(x86_FLDL2E),
+	/*11582*/ uint16(x86_xMatch),
+	/*11583*/ uint16(x86_xSetOp), uint16(x86_FLDPI),
+	/*11585*/ uint16(x86_xMatch),
+	/*11586*/ uint16(x86_xSetOp), uint16(x86_FLDLG2),
+	/*11588*/ uint16(x86_xMatch),
+	/*11589*/ uint16(x86_xSetOp), uint16(x86_F2XM1),
+	/*11591*/ uint16(x86_xMatch),
+	/*11592*/ uint16(x86_xSetOp), uint16(x86_FYL2X),
+	/*11594*/ uint16(x86_xMatch),
+	/*11595*/ uint16(x86_xSetOp), uint16(x86_FPTAN),
+	/*11597*/ uint16(x86_xMatch),
+	/*11598*/ uint16(x86_xSetOp), uint16(x86_FPATAN),
+	/*11600*/ uint16(x86_xMatch),
+	/*11601*/ uint16(x86_xSetOp), uint16(x86_FXTRACT),
+	/*11603*/ uint16(x86_xMatch),
+	/*11604*/ uint16(x86_xSetOp), uint16(x86_FPREM1),
+	/*11606*/ uint16(x86_xMatch),
+	/*11607*/ uint16(x86_xSetOp), uint16(x86_FDECSTP),
+	/*11609*/ uint16(x86_xMatch),
+	/*11610*/ uint16(x86_xSetOp), uint16(x86_FINCSTP),
+	/*11612*/ uint16(x86_xMatch),
+	/*11613*/ uint16(x86_xSetOp), uint16(x86_FPREM),
+	/*11615*/ uint16(x86_xMatch),
+	/*11616*/ uint16(x86_xSetOp), uint16(x86_FYL2XP1),
+	/*11618*/ uint16(x86_xMatch),
+	/*11619*/ uint16(x86_xSetOp), uint16(x86_FSQRT),
+	/*11621*/ uint16(x86_xMatch),
+	/*11622*/ uint16(x86_xSetOp), uint16(x86_FSINCOS),
+	/*11624*/ uint16(x86_xMatch),
+	/*11625*/ uint16(x86_xSetOp), uint16(x86_FRNDINT),
+	/*11627*/ uint16(x86_xMatch),
+	/*11628*/ uint16(x86_xSetOp), uint16(x86_FSCALE),
+	/*11630*/ uint16(x86_xMatch),
+	/*11631*/ uint16(x86_xSetOp), uint16(x86_FSIN),
+	/*11633*/ uint16(x86_xMatch),
+	/*11634*/ uint16(x86_xSetOp), uint16(x86_FCOS),
+	/*11636*/ uint16(x86_xMatch),
+	/*11637*/ uint16(x86_xCondByte), 33,
+	0xc0, 11746,
+	0xc1, 11746,
+	0xc2, 11746,
+	0xc3, 11746,
+	0xc4, 11746,
+	0xc5, 11746,
+	0xc6, 11746,
+	0xc7, 11746,
+	0xc8, 11751,
+	0xc9, 11751,
+	0xca, 11751,
+	0xcb, 11751,
+	0xcc, 11751,
+	0xcd, 11751,
+	0xce, 11751,
+	0xcf, 11751,
+	0xd0, 11756,
+	0xd1, 11756,
+	0xd2, 11756,
+	0xd3, 11756,
+	0xd4, 11756,
+	0xd5, 11756,
+	0xd6, 11756,
+	0xd7, 11756,
+	0xd8, 11761,
+	0xd9, 11761,
+	0xda, 11761,
+	0xdb, 11761,
+	0xdc, 11761,
+	0xdd, 11761,
+	0xde, 11761,
+	0xdf, 11761,
+	0xE9, 11766,
+	/*11705*/ uint16(x86_xCondSlashR),
+	11714, // 0
+	11718, // 1
+	11722, // 2
+	11726, // 3
+	11730, // 4
+	11734, // 5
+	11738, // 6
+	11742, // 7
+	/*11714*/ uint16(x86_xSetOp), uint16(x86_FIADD),
+	/*11716*/ uint16(x86_xArgM32int),
+	/*11717*/ uint16(x86_xMatch),
+	/*11718*/ uint16(x86_xSetOp), uint16(x86_FIMUL),
+	/*11720*/ uint16(x86_xArgM32int),
+	/*11721*/ uint16(x86_xMatch),
+	/*11722*/ uint16(x86_xSetOp), uint16(x86_FICOM),
+	/*11724*/ uint16(x86_xArgM32int),
+	/*11725*/ uint16(x86_xMatch),
+	/*11726*/ uint16(x86_xSetOp), uint16(x86_FICOMP),
+	/*11728*/ uint16(x86_xArgM32int),
+	/*11729*/ uint16(x86_xMatch),
+	/*11730*/ uint16(x86_xSetOp), uint16(x86_FISUB),
+	/*11732*/ uint16(x86_xArgM32int),
+	/*11733*/ uint16(x86_xMatch),
+	/*11734*/ uint16(x86_xSetOp), uint16(x86_FISUBR),
+	/*11736*/ uint16(x86_xArgM32int),
+	/*11737*/ uint16(x86_xMatch),
+	/*11738*/ uint16(x86_xSetOp), uint16(x86_FIDIV),
+	/*11740*/ uint16(x86_xArgM32int),
+	/*11741*/ uint16(x86_xMatch),
+	/*11742*/ uint16(x86_xSetOp), uint16(x86_FIDIVR),
+	/*11744*/ uint16(x86_xArgM32int),
+	/*11745*/ uint16(x86_xMatch),
+	/*11746*/ uint16(x86_xSetOp), uint16(x86_FCMOVB),
+	/*11748*/ uint16(x86_xArgST),
+	/*11749*/ uint16(x86_xArgSTi),
+	/*11750*/ uint16(x86_xMatch),
+	/*11751*/ uint16(x86_xSetOp), uint16(x86_FCMOVE),
+	/*11753*/ uint16(x86_xArgST),
+	/*11754*/ uint16(x86_xArgSTi),
+	/*11755*/ uint16(x86_xMatch),
+	/*11756*/ uint16(x86_xSetOp), uint16(x86_FCMOVBE),
+	/*11758*/ uint16(x86_xArgST),
+	/*11759*/ uint16(x86_xArgSTi),
+	/*11760*/ uint16(x86_xMatch),
+	/*11761*/ uint16(x86_xSetOp), uint16(x86_FCMOVU),
+	/*11763*/ uint16(x86_xArgST),
+	/*11764*/ uint16(x86_xArgSTi),
+	/*11765*/ uint16(x86_xMatch),
+	/*11766*/ uint16(x86_xSetOp), uint16(x86_FUCOMPP),
+	/*11768*/ uint16(x86_xMatch),
+	/*11769*/ uint16(x86_xCondByte), 50,
+	0xc0, 11904,
+	0xc1, 11904,
+	0xc2, 11904,
+	0xc3, 11904,
+	0xc4, 11904,
+	0xc5, 11904,
+	0xc6, 11904,
+	0xc7, 11904,
+	0xc8, 11909,
+	0xc9, 11909,
+	0xca, 11909,
+	0xcb, 11909,
+	0xcc, 11909,
+	0xcd, 11909,
+	0xce, 11909,
+	0xcf, 11909,
+	0xd0, 11914,
+	0xd1, 11914,
+	0xd2, 11914,
+	0xd3, 11914,
+	0xd4, 11914,
+	0xd5, 11914,
+	0xd6, 11914,
+	0xd7, 11914,
+	0xd8, 11919,
+	0xd9, 11919,
+	0xda, 11919,
+	0xdb, 11919,
+	0xdc, 11919,
+	0xdd, 11919,
+	0xde, 11919,
+	0xdf, 11919,
+	0xE2, 11924,
+	0xE3, 11927,
+	0xe8, 11930,
+	0xe9, 11930,
+	0xea, 11930,
+	0xeb, 11930,
+	0xec, 11930,
+	0xed, 11930,
+	0xee, 11930,
+	0xef, 11930,
+	0xf0, 11935,
+	0xf1, 11935,
+	0xf2, 11935,
+	0xf3, 11935,
+	0xf4, 11935,
+	0xf5, 11935,
+	0xf6, 11935,
+	0xf7, 11935,
+	/*11871*/ uint16(x86_xCondSlashR),
+	11880, // 0
+	11884, // 1
+	11888, // 2
+	11892, // 3
+	0,     // 4
+	11896, // 5
+	0,     // 6
+	11900, // 7
+	/*11880*/ uint16(x86_xSetOp), uint16(x86_FILD),
+	/*11882*/ uint16(x86_xArgM32int),
+	/*11883*/ uint16(x86_xMatch),
+	/*11884*/ uint16(x86_xSetOp), uint16(x86_FISTTP),
+	/*11886*/ uint16(x86_xArgM32int),
+	/*11887*/ uint16(x86_xMatch),
+	/*11888*/ uint16(x86_xSetOp), uint16(x86_FIST),
+	/*11890*/ uint16(x86_xArgM32int),
+	/*11891*/ uint16(x86_xMatch),
+	/*11892*/ uint16(x86_xSetOp), uint16(x86_FISTP),
+	/*11894*/ uint16(x86_xArgM32int),
+	/*11895*/ uint16(x86_xMatch),
+	/*11896*/ uint16(x86_xSetOp), uint16(x86_FLD),
+	/*11898*/ uint16(x86_xArgM80fp),
+	/*11899*/ uint16(x86_xMatch),
+	/*11900*/ uint16(x86_xSetOp), uint16(x86_FSTP),
+	/*11902*/ uint16(x86_xArgM80fp),
+	/*11903*/ uint16(x86_xMatch),
+	/*11904*/ uint16(x86_xSetOp), uint16(x86_FCMOVNB),
+	/*11906*/ uint16(x86_xArgST),
+	/*11907*/ uint16(x86_xArgSTi),
+	/*11908*/ uint16(x86_xMatch),
+	/*11909*/ uint16(x86_xSetOp), uint16(x86_FCMOVNE),
+	/*11911*/ uint16(x86_xArgST),
+	/*11912*/ uint16(x86_xArgSTi),
+	/*11913*/ uint16(x86_xMatch),
+	/*11914*/ uint16(x86_xSetOp), uint16(x86_FCMOVNBE),
+	/*11916*/ uint16(x86_xArgST),
+	/*11917*/ uint16(x86_xArgSTi),
+	/*11918*/ uint16(x86_xMatch),
+	/*11919*/ uint16(x86_xSetOp), uint16(x86_FCMOVNU),
+	/*11921*/ uint16(x86_xArgST),
+	/*11922*/ uint16(x86_xArgSTi),
+	/*11923*/ uint16(x86_xMatch),
+	/*11924*/ uint16(x86_xSetOp), uint16(x86_FNCLEX),
+	/*11926*/ uint16(x86_xMatch),
+	/*11927*/ uint16(x86_xSetOp), uint16(x86_FNINIT),
+	/*11929*/ uint16(x86_xMatch),
+	/*11930*/ uint16(x86_xSetOp), uint16(x86_FUCOMI),
+	/*11932*/ uint16(x86_xArgST),
+	/*11933*/ uint16(x86_xArgSTi),
+	/*11934*/ uint16(x86_xMatch),
+	/*11935*/ uint16(x86_xSetOp), uint16(x86_FCOMI),
+	/*11937*/ uint16(x86_xArgST),
+	/*11938*/ uint16(x86_xArgSTi),
+	/*11939*/ uint16(x86_xMatch),
+	/*11940*/ uint16(x86_xCondByte), 48,
+	0xc0, 12079,
+	0xc1, 12079,
+	0xc2, 12079,
+	0xc3, 12079,
+	0xc4, 12079,
+	0xc5, 12079,
+	0xc6, 12079,
+	0xc7, 12079,
+	0xc8, 12084,
+	0xc9, 12084,
+	0xca, 12084,
+	0xcb, 12084,
+	0xcc, 12084,
+	0xcd, 12084,
+	0xce, 12084,
+	0xcf, 12084,
+	0xe0, 12089,
+	0xe1, 12089,
+	0xe2, 12089,
+	0xe3, 12089,
+	0xe4, 12089,
+	0xe5, 12089,
+	0xe6, 12089,
+	0xe7, 12089,
+	0xe8, 12094,
+	0xe9, 12094,
+	0xea, 12094,
+	0xeb, 12094,
+	0xec, 12094,
+	0xed, 12094,
+	0xee, 12094,
+	0xef, 12094,
+	0xf0, 12099,
+	0xf1, 12099,
+	0xf2, 12099,
+	0xf3, 12099,
+	0xf4, 12099,
+	0xf5, 12099,
+	0xf6, 12099,
+	0xf7, 12099,
+	0xf8, 12104,
+	0xf9, 12104,
+	0xfa, 12104,
+	0xfb, 12104,
+	0xfc, 12104,
+	0xfd, 12104,
+	0xfe, 12104,
+	0xff, 12104,
+	/*12038*/ uint16(x86_xCondSlashR),
+	12047, // 0
+	12051, // 1
+	12055, // 2
+	12059, // 3
+	12063, // 4
+	12067, // 5
+	12071, // 6
+	12075, // 7
+	/*12047*/ uint16(x86_xSetOp), uint16(x86_FADD),
+	/*12049*/ uint16(x86_xArgM64fp),
+	/*12050*/ uint16(x86_xMatch),
+	/*12051*/ uint16(x86_xSetOp), uint16(x86_FMUL),
+	/*12053*/ uint16(x86_xArgM64fp),
+	/*12054*/ uint16(x86_xMatch),
+	/*12055*/ uint16(x86_xSetOp), uint16(x86_FCOM),
+	/*12057*/ uint16(x86_xArgM64fp),
+	/*12058*/ uint16(x86_xMatch),
+	/*12059*/ uint16(x86_xSetOp), uint16(x86_FCOMP),
+	/*12061*/ uint16(x86_xArgM64fp),
+	/*12062*/ uint16(x86_xMatch),
+	/*12063*/ uint16(x86_xSetOp), uint16(x86_FSUB),
+	/*12065*/ uint16(x86_xArgM64fp),
+	/*12066*/ uint16(x86_xMatch),
+	/*12067*/ uint16(x86_xSetOp), uint16(x86_FSUBR),
+	/*12069*/ uint16(x86_xArgM64fp),
+	/*12070*/ uint16(x86_xMatch),
+	/*12071*/ uint16(x86_xSetOp), uint16(x86_FDIV),
+	/*12073*/ uint16(x86_xArgM64fp),
+	/*12074*/ uint16(x86_xMatch),
+	/*12075*/ uint16(x86_xSetOp), uint16(x86_FDIVR),
+	/*12077*/ uint16(x86_xArgM64fp),
+	/*12078*/ uint16(x86_xMatch),
+	/*12079*/ uint16(x86_xSetOp), uint16(x86_FADD),
+	/*12081*/ uint16(x86_xArgSTi),
+	/*12082*/ uint16(x86_xArgST),
+	/*12083*/ uint16(x86_xMatch),
+	/*12084*/ uint16(x86_xSetOp), uint16(x86_FMUL),
+	/*12086*/ uint16(x86_xArgSTi),
+	/*12087*/ uint16(x86_xArgST),
+	/*12088*/ uint16(x86_xMatch),
+	/*12089*/ uint16(x86_xSetOp), uint16(x86_FSUBR),
+	/*12091*/ uint16(x86_xArgSTi),
+	/*12092*/ uint16(x86_xArgST),
+	/*12093*/ uint16(x86_xMatch),
+	/*12094*/ uint16(x86_xSetOp), uint16(x86_FSUB),
+	/*12096*/ uint16(x86_xArgSTi),
+	/*12097*/ uint16(x86_xArgST),
+	/*12098*/ uint16(x86_xMatch),
+	/*12099*/ uint16(x86_xSetOp), uint16(x86_FDIVR),
+	/*12101*/ uint16(x86_xArgSTi),
+	/*12102*/ uint16(x86_xArgST),
+	/*12103*/ uint16(x86_xMatch),
+	/*12104*/ uint16(x86_xSetOp), uint16(x86_FDIV),
+	/*12106*/ uint16(x86_xArgSTi),
+	/*12107*/ uint16(x86_xArgST),
+	/*12108*/ uint16(x86_xMatch),
+	/*12109*/ uint16(x86_xCondByte), 40,
+	0xc0, 12228,
+	0xc1, 12228,
+	0xc2, 12228,
+	0xc3, 12228,
+	0xc4, 12228,
+	0xc5, 12228,
+	0xc6, 12228,
+	0xc7, 12228,
+	0xd0, 12232,
+	0xd1, 12232,
+	0xd2, 12232,
+	0xd3, 12232,
+	0xd4, 12232,
+	0xd5, 12232,
+	0xd6, 12232,
+	0xd7, 12232,
+	0xd8, 12236,
+	0xd9, 12236,
+	0xda, 12236,
+	0xdb, 12236,
+	0xdc, 12236,
+	0xdd, 12236,
+	0xde, 12236,
+	0xdf, 12236,
+	0xe0, 12240,
+	0xe1, 12240,
+	0xe2, 12240,
+	0xe3, 12240,
+	0xe4, 12240,
+	0xe5, 12240,
+	0xe6, 12240,
+	0xe7, 12240,
+	0xe8, 12244,
+	0xe9, 12244,
+	0xea, 12244,
+	0xeb, 12244,
+	0xec, 12244,
+	0xed, 12244,
+	0xee, 12244,
+	0xef, 12244,
+	/*12191*/ uint16(x86_xCondSlashR),
+	12200, // 0
+	12204, // 1
+	12208, // 2
+	12212, // 3
+	12216, // 4
+	0,     // 5
+	12220, // 6
+	12224, // 7
+	/*12200*/ uint16(x86_xSetOp), uint16(x86_FLD),
+	/*12202*/ uint16(x86_xArgM64fp),
+	/*12203*/ uint16(x86_xMatch),
+	/*12204*/ uint16(x86_xSetOp), uint16(x86_FISTTP),
+	/*12206*/ uint16(x86_xArgM64int),
+	/*12207*/ uint16(x86_xMatch),
+	/*12208*/ uint16(x86_xSetOp), uint16(x86_FST),
+	/*12210*/ uint16(x86_xArgM64fp),
+	/*12211*/ uint16(x86_xMatch),
+	/*12212*/ uint16(x86_xSetOp), uint16(x86_FSTP),
+	/*12214*/ uint16(x86_xArgM64fp),
+	/*12215*/ uint16(x86_xMatch),
+	/*12216*/ uint16(x86_xSetOp), uint16(x86_FRSTOR),
+	/*12218*/ uint16(x86_xArgM94108byte),
+	/*12219*/ uint16(x86_xMatch),
+	/*12220*/ uint16(x86_xSetOp), uint16(x86_FNSAVE),
+	/*12222*/ uint16(x86_xArgM94108byte),
+	/*12223*/ uint16(x86_xMatch),
+	/*12224*/ uint16(x86_xSetOp), uint16(x86_FNSTSW),
+	/*12226*/ uint16(x86_xArgM2byte),
+	/*12227*/ uint16(x86_xMatch),
+	/*12228*/ uint16(x86_xSetOp), uint16(x86_FFREE),
+	/*12230*/ uint16(x86_xArgSTi),
+	/*12231*/ uint16(x86_xMatch),
+	/*12232*/ uint16(x86_xSetOp), uint16(x86_FST),
+	/*12234*/ uint16(x86_xArgSTi),
+	/*12235*/ uint16(x86_xMatch),
+	/*12236*/ uint16(x86_xSetOp), uint16(x86_FSTP),
+	/*12238*/ uint16(x86_xArgSTi),
+	/*12239*/ uint16(x86_xMatch),
+	/*12240*/ uint16(x86_xSetOp), uint16(x86_FUCOM),
+	/*12242*/ uint16(x86_xArgSTi),
+	/*12243*/ uint16(x86_xMatch),
+	/*12244*/ uint16(x86_xSetOp), uint16(x86_FUCOMP),
+	/*12246*/ uint16(x86_xArgSTi),
+	/*12247*/ uint16(x86_xMatch),
+	/*12248*/ uint16(x86_xCondByte), 49,
+	0xc0, 12389,
+	0xc1, 12389,
+	0xc2, 12389,
+	0xc3, 12389,
+	0xc4, 12389,
+	0xc5, 12389,
+	0xc6, 12389,
+	0xc7, 12389,
+	0xc8, 12394,
+	0xc9, 12394,
+	0xca, 12394,
+	0xcb, 12394,
+	0xcc, 12394,
+	0xcd, 12394,
+	0xce, 12394,
+	0xcf, 12394,
+	0xD9, 12399,
+	0xe0, 12402,
+	0xe1, 12402,
+	0xe2, 12402,
+	0xe3, 12402,
+	0xe4, 12402,
+	0xe5, 12402,
+	0xe6, 12402,
+	0xe7, 12402,
+	0xe8, 12407,
+	0xe9, 12407,
+	0xea, 12407,
+	0xeb, 12407,
+	0xec, 12407,
+	0xed, 12407,
+	0xee, 12407,
+	0xef, 12407,
+	0xf0, 12412,
+	0xf1, 12412,
+	0xf2, 12412,
+	0xf3, 12412,
+	0xf4, 12412,
+	0xf5, 12412,
+	0xf6, 12412,
+	0xf7, 12412,
+	0xf8, 12417,
+	0xf9, 12417,
+	0xfa, 12417,
+	0xfb, 12417,
+	0xfc, 12417,
+	0xfd, 12417,
+	0xfe, 12417,
+	0xff, 12417,
+	/*12348*/ uint16(x86_xCondSlashR),
+	12357, // 0
+	12361, // 1
+	12365, // 2
+	12369, // 3
+	12373, // 4
+	12377, // 5
+	12381, // 6
+	12385, // 7
+	/*12357*/ uint16(x86_xSetOp), uint16(x86_FIADD),
+	/*12359*/ uint16(x86_xArgM16int),
+	/*12360*/ uint16(x86_xMatch),
+	/*12361*/ uint16(x86_xSetOp), uint16(x86_FIMUL),
+	/*12363*/ uint16(x86_xArgM16int),
+	/*12364*/ uint16(x86_xMatch),
+	/*12365*/ uint16(x86_xSetOp), uint16(x86_FICOM),
+	/*12367*/ uint16(x86_xArgM16int),
+	/*12368*/ uint16(x86_xMatch),
+	/*12369*/ uint16(x86_xSetOp), uint16(x86_FICOMP),
+	/*12371*/ uint16(x86_xArgM16int),
+	/*12372*/ uint16(x86_xMatch),
+	/*12373*/ uint16(x86_xSetOp), uint16(x86_FISUB),
+	/*12375*/ uint16(x86_xArgM16int),
+	/*12376*/ uint16(x86_xMatch),
+	/*12377*/ uint16(x86_xSetOp), uint16(x86_FISUBR),
+	/*12379*/ uint16(x86_xArgM16int),
+	/*12380*/ uint16(x86_xMatch),
+	/*12381*/ uint16(x86_xSetOp), uint16(x86_FIDIV),
+	/*12383*/ uint16(x86_xArgM16int),
+	/*12384*/ uint16(x86_xMatch),
+	/*12385*/ uint16(x86_xSetOp), uint16(x86_FIDIVR),
+	/*12387*/ uint16(x86_xArgM16int),
+	/*12388*/ uint16(x86_xMatch),
+	/*12389*/ uint16(x86_xSetOp), uint16(x86_FADDP),
+	/*12391*/ uint16(x86_xArgSTi),
+	/*12392*/ uint16(x86_xArgST),
+	/*12393*/ uint16(x86_xMatch),
+	/*12394*/ uint16(x86_xSetOp), uint16(x86_FMULP),
+	/*12396*/ uint16(x86_xArgSTi),
+	/*12397*/ uint16(x86_xArgST),
+	/*12398*/ uint16(x86_xMatch),
+	/*12399*/ uint16(x86_xSetOp), uint16(x86_FCOMPP),
+	/*12401*/ uint16(x86_xMatch),
+	/*12402*/ uint16(x86_xSetOp), uint16(x86_FSUBRP),
+	/*12404*/ uint16(x86_xArgSTi),
+	/*12405*/ uint16(x86_xArgST),
+	/*12406*/ uint16(x86_xMatch),
+	/*12407*/ uint16(x86_xSetOp), uint16(x86_FSUBP),
+	/*12409*/ uint16(x86_xArgSTi),
+	/*12410*/ uint16(x86_xArgST),
+	/*12411*/ uint16(x86_xMatch),
+	/*12412*/ uint16(x86_xSetOp), uint16(x86_FDIVRP),
+	/*12414*/ uint16(x86_xArgSTi),
+	/*12415*/ uint16(x86_xArgST),
+	/*12416*/ uint16(x86_xMatch),
+	/*12417*/ uint16(x86_xSetOp), uint16(x86_FDIVP),
+	/*12419*/ uint16(x86_xArgSTi),
+	/*12420*/ uint16(x86_xArgST),
+	/*12421*/ uint16(x86_xMatch),
+	/*12422*/ uint16(x86_xCondByte), 25,
+	0xc0, 12515,
+	0xc1, 12515,
+	0xc2, 12515,
+	0xc3, 12515,
+	0xc4, 12515,
+	0xc5, 12515,
+	0xc6, 12515,
+	0xc7, 12515,
+	0xE0, 12519,
+	0xe8, 12523,
+	0xe9, 12523,
+	0xea, 12523,
+	0xeb, 12523,
+	0xec, 12523,
+	0xed, 12523,
+	0xee, 12523,
+	0xef, 12523,
+	0xf0, 12528,
+	0xf1, 12528,
+	0xf2, 12528,
+	0xf3, 12528,
+	0xf4, 12528,
+	0xf5, 12528,
+	0xf6, 12528,
+	0xf7, 12528,
+	/*12474*/ uint16(x86_xCondSlashR),
+	12483, // 0
+	12487, // 1
+	12491, // 2
+	12495, // 3
+	12499, // 4
+	12503, // 5
+	12507, // 6
+	12511, // 7
+	/*12483*/ uint16(x86_xSetOp), uint16(x86_FILD),
+	/*12485*/ uint16(x86_xArgM16int),
+	/*12486*/ uint16(x86_xMatch),
+	/*12487*/ uint16(x86_xSetOp), uint16(x86_FISTTP),
+	/*12489*/ uint16(x86_xArgM16int),
+	/*12490*/ uint16(x86_xMatch),
+	/*12491*/ uint16(x86_xSetOp), uint16(x86_FIST),
+	/*12493*/ uint16(x86_xArgM16int),
+	/*12494*/ uint16(x86_xMatch),
+	/*12495*/ uint16(x86_xSetOp), uint16(x86_FISTP),
+	/*12497*/ uint16(x86_xArgM16int),
+	/*12498*/ uint16(x86_xMatch),
+	/*12499*/ uint16(x86_xSetOp), uint16(x86_FBLD),
+	/*12501*/ uint16(x86_xArgM80dec),
+	/*12502*/ uint16(x86_xMatch),
+	/*12503*/ uint16(x86_xSetOp), uint16(x86_FILD),
+	/*12505*/ uint16(x86_xArgM64int),
+	/*12506*/ uint16(x86_xMatch),
+	/*12507*/ uint16(x86_xSetOp), uint16(x86_FBSTP),
+	/*12509*/ uint16(x86_xArgM80bcd),
+	/*12510*/ uint16(x86_xMatch),
+	/*12511*/ uint16(x86_xSetOp), uint16(x86_FISTP),
+	/*12513*/ uint16(x86_xArgM64int),
+	/*12514*/ uint16(x86_xMatch),
+	/*12515*/ uint16(x86_xSetOp), uint16(x86_FFREEP),
+	/*12517*/ uint16(x86_xArgSTi),
+	/*12518*/ uint16(x86_xMatch),
+	/*12519*/ uint16(x86_xSetOp), uint16(x86_FNSTSW),
+	/*12521*/ uint16(x86_xArgAX),
+	/*12522*/ uint16(x86_xMatch),
+	/*12523*/ uint16(x86_xSetOp), uint16(x86_FUCOMIP),
+	/*12525*/ uint16(x86_xArgST),
+	/*12526*/ uint16(x86_xArgSTi),
+	/*12527*/ uint16(x86_xMatch),
+	/*12528*/ uint16(x86_xSetOp), uint16(x86_FCOMIP),
+	/*12530*/ uint16(x86_xArgST),
+	/*12531*/ uint16(x86_xArgSTi),
+	/*12532*/ uint16(x86_xMatch),
+	/*12533*/ uint16(x86_xSetOp), uint16(x86_LOOPNE),
+	/*12535*/ uint16(x86_xReadCb),
+	/*12536*/ uint16(x86_xArgRel8),
+	/*12537*/ uint16(x86_xMatch),
+	/*12538*/ uint16(x86_xSetOp), uint16(x86_LOOPE),
+	/*12540*/ uint16(x86_xReadCb),
+	/*12541*/ uint16(x86_xArgRel8),
+	/*12542*/ uint16(x86_xMatch),
+	/*12543*/ uint16(x86_xSetOp), uint16(x86_LOOP),
+	/*12545*/ uint16(x86_xReadCb),
+	/*12546*/ uint16(x86_xArgRel8),
+	/*12547*/ uint16(x86_xMatch),
+	/*12548*/ uint16(x86_xCondIs64), 12551, 12565,
+	/*12551*/ uint16(x86_xCondAddrSize), 12555, 12560, 0,
+	/*12555*/ uint16(x86_xSetOp), uint16(x86_JCXZ),
+	/*12557*/ uint16(x86_xReadCb),
+	/*12558*/ uint16(x86_xArgRel8),
+	/*12559*/ uint16(x86_xMatch),
+	/*12560*/ uint16(x86_xSetOp), uint16(x86_JECXZ),
+	/*12562*/ uint16(x86_xReadCb),
+	/*12563*/ uint16(x86_xArgRel8),
+	/*12564*/ uint16(x86_xMatch),
+	/*12565*/ uint16(x86_xCondAddrSize), 0, 12560, 12569,
+	/*12569*/ uint16(x86_xSetOp), uint16(x86_JRCXZ),
+	/*12571*/ uint16(x86_xReadCb),
+	/*12572*/ uint16(x86_xArgRel8),
+	/*12573*/ uint16(x86_xMatch),
+	/*12574*/ uint16(x86_xSetOp), uint16(x86_IN),
+	/*12576*/ uint16(x86_xReadIb),
+	/*12577*/ uint16(x86_xArgAL),
+	/*12578*/ uint16(x86_xArgImm8u),
+	/*12579*/ uint16(x86_xMatch),
+	/*12580*/ uint16(x86_xCondDataSize), 12584, 12590, 12596,
+	/*12584*/ uint16(x86_xSetOp), uint16(x86_IN),
+	/*12586*/ uint16(x86_xReadIb),
+	/*12587*/ uint16(x86_xArgAX),
+	/*12588*/ uint16(x86_xArgImm8u),
+	/*12589*/ uint16(x86_xMatch),
+	/*12590*/ uint16(x86_xSetOp), uint16(x86_IN),
+	/*12592*/ uint16(x86_xReadIb),
+	/*12593*/ uint16(x86_xArgEAX),
+	/*12594*/ uint16(x86_xArgImm8u),
+	/*12595*/ uint16(x86_xMatch),
+	/*12596*/ uint16(x86_xSetOp), uint16(x86_IN),
+	/*12598*/ uint16(x86_xReadIb),
+	/*12599*/ uint16(x86_xArgEAX),
+	/*12600*/ uint16(x86_xArgImm8u),
+	/*12601*/ uint16(x86_xMatch),
+	/*12602*/ uint16(x86_xSetOp), uint16(x86_OUT),
+	/*12604*/ uint16(x86_xReadIb),
+	/*12605*/ uint16(x86_xArgImm8u),
+	/*12606*/ uint16(x86_xArgAL),
+	/*12607*/ uint16(x86_xMatch),
+	/*12608*/ uint16(x86_xCondDataSize), 12612, 12618, 12624,
+	/*12612*/ uint16(x86_xSetOp), uint16(x86_OUT),
+	/*12614*/ uint16(x86_xReadIb),
+	/*12615*/ uint16(x86_xArgImm8u),
+	/*12616*/ uint16(x86_xArgAX),
+	/*12617*/ uint16(x86_xMatch),
+	/*12618*/ uint16(x86_xSetOp), uint16(x86_OUT),
+	/*12620*/ uint16(x86_xReadIb),
+	/*12621*/ uint16(x86_xArgImm8u),
+	/*12622*/ uint16(x86_xArgEAX),
+	/*12623*/ uint16(x86_xMatch),
+	/*12624*/ uint16(x86_xSetOp), uint16(x86_OUT),
+	/*12626*/ uint16(x86_xReadIb),
+	/*12627*/ uint16(x86_xArgImm8u),
+	/*12628*/ uint16(x86_xArgEAX),
+	/*12629*/ uint16(x86_xMatch),
+	/*12630*/ uint16(x86_xCondIs64), 12633, 12647,
+	/*12633*/ uint16(x86_xCondDataSize), 12637, 12642, 0,
+	/*12637*/ uint16(x86_xSetOp), uint16(x86_CALL),
+	/*12639*/ uint16(x86_xReadCw),
+	/*12640*/ uint16(x86_xArgRel16),
+	/*12641*/ uint16(x86_xMatch),
+	/*12642*/ uint16(x86_xSetOp), uint16(x86_CALL),
+	/*12644*/ uint16(x86_xReadCd),
+	/*12645*/ uint16(x86_xArgRel32),
+	/*12646*/ uint16(x86_xMatch),
+	/*12647*/ uint16(x86_xCondDataSize), 12651, 12642, 12656,
+	/*12651*/ uint16(x86_xSetOp), uint16(x86_CALL),
+	/*12653*/ uint16(x86_xReadCd),
+	/*12654*/ uint16(x86_xArgRel32),
+	/*12655*/ uint16(x86_xMatch),
+	/*12656*/ uint16(x86_xSetOp), uint16(x86_CALL),
+	/*12658*/ uint16(x86_xReadCd),
+	/*12659*/ uint16(x86_xArgRel32),
+	/*12660*/ uint16(x86_xMatch),
+	/*12661*/ uint16(x86_xCondIs64), 12664, 12678,
+	/*12664*/ uint16(x86_xCondDataSize), 12668, 12673, 0,
+	/*12668*/ uint16(x86_xSetOp), uint16(x86_JMP),
+	/*12670*/ uint16(x86_xReadCw),
+	/*12671*/ uint16(x86_xArgRel16),
+	/*12672*/ uint16(x86_xMatch),
+	/*12673*/ uint16(x86_xSetOp), uint16(x86_JMP),
+	/*12675*/ uint16(x86_xReadCd),
+	/*12676*/ uint16(x86_xArgRel32),
+	/*12677*/ uint16(x86_xMatch),
+	/*12678*/ uint16(x86_xCondDataSize), 12682, 12673, 12687,
+	/*12682*/ uint16(x86_xSetOp), uint16(x86_JMP),
+	/*12684*/ uint16(x86_xReadCd),
+	/*12685*/ uint16(x86_xArgRel32),
+	/*12686*/ uint16(x86_xMatch),
+	/*12687*/ uint16(x86_xSetOp), uint16(x86_JMP),
+	/*12689*/ uint16(x86_xReadCd),
+	/*12690*/ uint16(x86_xArgRel32),
+	/*12691*/ uint16(x86_xMatch),
+	/*12692*/ uint16(x86_xCondIs64), 12695, 0,
+	/*12695*/ uint16(x86_xCondDataSize), 12699, 12704, 0,
+	/*12699*/ uint16(x86_xSetOp), uint16(x86_LJMP),
+	/*12701*/ uint16(x86_xReadCd),
+	/*12702*/ uint16(x86_xArgPtr16colon16),
+	/*12703*/ uint16(x86_xMatch),
+	/*12704*/ uint16(x86_xSetOp), uint16(x86_LJMP),
+	/*12706*/ uint16(x86_xReadCp),
+	/*12707*/ uint16(x86_xArgPtr16colon32),
+	/*12708*/ uint16(x86_xMatch),
+	/*12709*/ uint16(x86_xSetOp), uint16(x86_JMP),
+	/*12711*/ uint16(x86_xReadCb),
+	/*12712*/ uint16(x86_xArgRel8),
+	/*12713*/ uint16(x86_xMatch),
+	/*12714*/ uint16(x86_xSetOp), uint16(x86_IN),
+	/*12716*/ uint16(x86_xArgAL),
+	/*12717*/ uint16(x86_xArgDX),
+	/*12718*/ uint16(x86_xMatch),
+	/*12719*/ uint16(x86_xCondDataSize), 12723, 12728, 12733,
+	/*12723*/ uint16(x86_xSetOp), uint16(x86_IN),
+	/*12725*/ uint16(x86_xArgAX),
+	/*12726*/ uint16(x86_xArgDX),
+	/*12727*/ uint16(x86_xMatch),
+	/*12728*/ uint16(x86_xSetOp), uint16(x86_IN),
+	/*12730*/ uint16(x86_xArgEAX),
+	/*12731*/ uint16(x86_xArgDX),
+	/*12732*/ uint16(x86_xMatch),
+	/*12733*/ uint16(x86_xSetOp), uint16(x86_IN),
+	/*12735*/ uint16(x86_xArgEAX),
+	/*12736*/ uint16(x86_xArgDX),
+	/*12737*/ uint16(x86_xMatch),
+	/*12738*/ uint16(x86_xSetOp), uint16(x86_OUT),
+	/*12740*/ uint16(x86_xArgDX),
+	/*12741*/ uint16(x86_xArgAL),
+	/*12742*/ uint16(x86_xMatch),
+	/*12743*/ uint16(x86_xCondDataSize), 12747, 12752, 12757,
+	/*12747*/ uint16(x86_xSetOp), uint16(x86_OUT),
+	/*12749*/ uint16(x86_xArgDX),
+	/*12750*/ uint16(x86_xArgAX),
+	/*12751*/ uint16(x86_xMatch),
+	/*12752*/ uint16(x86_xSetOp), uint16(x86_OUT),
+	/*12754*/ uint16(x86_xArgDX),
+	/*12755*/ uint16(x86_xArgEAX),
+	/*12756*/ uint16(x86_xMatch),
+	/*12757*/ uint16(x86_xSetOp), uint16(x86_OUT),
+	/*12759*/ uint16(x86_xArgDX),
+	/*12760*/ uint16(x86_xArgEAX),
+	/*12761*/ uint16(x86_xMatch),
+	/*12762*/ uint16(x86_xSetOp), uint16(x86_ICEBP),
+	/*12764*/ uint16(x86_xMatch),
+	/*12765*/ uint16(x86_xSetOp), uint16(x86_HLT),
+	/*12767*/ uint16(x86_xMatch),
+	/*12768*/ uint16(x86_xSetOp), uint16(x86_CMC),
+	/*12770*/ uint16(x86_xMatch),
+	/*12771*/ uint16(x86_xCondSlashR),
+	12780, // 0
+	0,     // 1
+	12786, // 2
+	12790, // 3
+	12794, // 4
+	12798, // 5
+	12802, // 6
+	12806, // 7
+	/*12780*/ uint16(x86_xSetOp), uint16(x86_TEST),
+	/*12782*/ uint16(x86_xReadIb),
+	/*12783*/ uint16(x86_xArgRM8),
+	/*12784*/ uint16(x86_xArgImm8u),
+	/*12785*/ uint16(x86_xMatch),
+	/*12786*/ uint16(x86_xSetOp), uint16(x86_NOT),
+	/*12788*/ uint16(x86_xArgRM8),
+	/*12789*/ uint16(x86_xMatch),
+	/*12790*/ uint16(x86_xSetOp), uint16(x86_NEG),
+	/*12792*/ uint16(x86_xArgRM8),
+	/*12793*/ uint16(x86_xMatch),
+	/*12794*/ uint16(x86_xSetOp), uint16(x86_MUL),
+	/*12796*/ uint16(x86_xArgRM8),
+	/*12797*/ uint16(x86_xMatch),
+	/*12798*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+	/*12800*/ uint16(x86_xArgRM8),
+	/*12801*/ uint16(x86_xMatch),
+	/*12802*/ uint16(x86_xSetOp), uint16(x86_DIV),
+	/*12804*/ uint16(x86_xArgRM8),
+	/*12805*/ uint16(x86_xMatch),
+	/*12806*/ uint16(x86_xSetOp), uint16(x86_IDIV),
+	/*12808*/ uint16(x86_xArgRM8),
+	/*12809*/ uint16(x86_xMatch),
+	/*12810*/ uint16(x86_xCondSlashR),
+	12819, // 0
+	0,     // 1
+	12848, // 2
+	12871, // 3
+	12894, // 4
+	12917, // 5
+	12940, // 6
+	12963, // 7
+	/*12819*/ uint16(x86_xCondIs64), 12822, 12838,
+	/*12822*/ uint16(x86_xCondDataSize), 12826, 12832, 0,
+	/*12826*/ uint16(x86_xSetOp), uint16(x86_TEST),
+	/*12828*/ uint16(x86_xReadIw),
+	/*12829*/ uint16(x86_xArgRM16),
+	/*12830*/ uint16(x86_xArgImm16),
+	/*12831*/ uint16(x86_xMatch),
+	/*12832*/ uint16(x86_xSetOp), uint16(x86_TEST),
+	/*12834*/ uint16(x86_xReadId),
+	/*12835*/ uint16(x86_xArgRM32),
+	/*12836*/ uint16(x86_xArgImm32),
+	/*12837*/ uint16(x86_xMatch),
+	/*12838*/ uint16(x86_xCondDataSize), 12826, 12832, 12842,
+	/*12842*/ uint16(x86_xSetOp), uint16(x86_TEST),
+	/*12844*/ uint16(x86_xReadId),
+	/*12845*/ uint16(x86_xArgRM64),
+	/*12846*/ uint16(x86_xArgImm32),
+	/*12847*/ uint16(x86_xMatch),
+	/*12848*/ uint16(x86_xCondIs64), 12851, 12863,
+	/*12851*/ uint16(x86_xCondDataSize), 12855, 12859, 0,
+	/*12855*/ uint16(x86_xSetOp), uint16(x86_NOT),
+	/*12857*/ uint16(x86_xArgRM16),
+	/*12858*/ uint16(x86_xMatch),
+	/*12859*/ uint16(x86_xSetOp), uint16(x86_NOT),
+	/*12861*/ uint16(x86_xArgRM32),
+	/*12862*/ uint16(x86_xMatch),
+	/*12863*/ uint16(x86_xCondDataSize), 12855, 12859, 12867,
+	/*12867*/ uint16(x86_xSetOp), uint16(x86_NOT),
+	/*12869*/ uint16(x86_xArgRM64),
+	/*12870*/ uint16(x86_xMatch),
+	/*12871*/ uint16(x86_xCondIs64), 12874, 12886,
+	/*12874*/ uint16(x86_xCondDataSize), 12878, 12882, 0,
+	/*12878*/ uint16(x86_xSetOp), uint16(x86_NEG),
+	/*12880*/ uint16(x86_xArgRM16),
+	/*12881*/ uint16(x86_xMatch),
+	/*12882*/ uint16(x86_xSetOp), uint16(x86_NEG),
+	/*12884*/ uint16(x86_xArgRM32),
+	/*12885*/ uint16(x86_xMatch),
+	/*12886*/ uint16(x86_xCondDataSize), 12878, 12882, 12890,
+	/*12890*/ uint16(x86_xSetOp), uint16(x86_NEG),
+	/*12892*/ uint16(x86_xArgRM64),
+	/*12893*/ uint16(x86_xMatch),
+	/*12894*/ uint16(x86_xCondIs64), 12897, 12909,
+	/*12897*/ uint16(x86_xCondDataSize), 12901, 12905, 0,
+	/*12901*/ uint16(x86_xSetOp), uint16(x86_MUL),
+	/*12903*/ uint16(x86_xArgRM16),
+	/*12904*/ uint16(x86_xMatch),
+	/*12905*/ uint16(x86_xSetOp), uint16(x86_MUL),
+	/*12907*/ uint16(x86_xArgRM32),
+	/*12908*/ uint16(x86_xMatch),
+	/*12909*/ uint16(x86_xCondDataSize), 12901, 12905, 12913,
+	/*12913*/ uint16(x86_xSetOp), uint16(x86_MUL),
+	/*12915*/ uint16(x86_xArgRM64),
+	/*12916*/ uint16(x86_xMatch),
+	/*12917*/ uint16(x86_xCondIs64), 12920, 12932,
+	/*12920*/ uint16(x86_xCondDataSize), 12924, 12928, 0,
+	/*12924*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+	/*12926*/ uint16(x86_xArgRM16),
+	/*12927*/ uint16(x86_xMatch),
+	/*12928*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+	/*12930*/ uint16(x86_xArgRM32),
+	/*12931*/ uint16(x86_xMatch),
+	/*12932*/ uint16(x86_xCondDataSize), 12924, 12928, 12936,
+	/*12936*/ uint16(x86_xSetOp), uint16(x86_IMUL),
+	/*12938*/ uint16(x86_xArgRM64),
+	/*12939*/ uint16(x86_xMatch),
+	/*12940*/ uint16(x86_xCondIs64), 12943, 12955,
+	/*12943*/ uint16(x86_xCondDataSize), 12947, 12951, 0,
+	/*12947*/ uint16(x86_xSetOp), uint16(x86_DIV),
+	/*12949*/ uint16(x86_xArgRM16),
+	/*12950*/ uint16(x86_xMatch),
+	/*12951*/ uint16(x86_xSetOp), uint16(x86_DIV),
+	/*12953*/ uint16(x86_xArgRM32),
+	/*12954*/ uint16(x86_xMatch),
+	/*12955*/ uint16(x86_xCondDataSize), 12947, 12951, 12959,
+	/*12959*/ uint16(x86_xSetOp), uint16(x86_DIV),
+	/*12961*/ uint16(x86_xArgRM64),
+	/*12962*/ uint16(x86_xMatch),
+	/*12963*/ uint16(x86_xCondIs64), 12966, 12978,
+	/*12966*/ uint16(x86_xCondDataSize), 12970, 12974, 0,
+	/*12970*/ uint16(x86_xSetOp), uint16(x86_IDIV),
+	/*12972*/ uint16(x86_xArgRM16),
+	/*12973*/ uint16(x86_xMatch),
+	/*12974*/ uint16(x86_xSetOp), uint16(x86_IDIV),
+	/*12976*/ uint16(x86_xArgRM32),
+	/*12977*/ uint16(x86_xMatch),
+	/*12978*/ uint16(x86_xCondDataSize), 12970, 12974, 12982,
+	/*12982*/ uint16(x86_xSetOp), uint16(x86_IDIV),
+	/*12984*/ uint16(x86_xArgRM64),
+	/*12985*/ uint16(x86_xMatch),
+	/*12986*/ uint16(x86_xSetOp), uint16(x86_CLC),
+	/*12988*/ uint16(x86_xMatch),
+	/*12989*/ uint16(x86_xSetOp), uint16(x86_STC),
+	/*12991*/ uint16(x86_xMatch),
+	/*12992*/ uint16(x86_xSetOp), uint16(x86_CLI),
+	/*12994*/ uint16(x86_xMatch),
+	/*12995*/ uint16(x86_xSetOp), uint16(x86_STI),
+	/*12997*/ uint16(x86_xMatch),
+	/*12998*/ uint16(x86_xSetOp), uint16(x86_CLD),
+	/*13000*/ uint16(x86_xMatch),
+	/*13001*/ uint16(x86_xSetOp), uint16(x86_STD),
+	/*13003*/ uint16(x86_xMatch),
+	/*13004*/ uint16(x86_xCondSlashR),
+	13013, // 0
+	13017, // 1
+	0,     // 2
+	0,     // 3
+	0,     // 4
+	0,     // 5
+	0,     // 6
+	0,     // 7
+	/*13013*/ uint16(x86_xSetOp), uint16(x86_INC),
+	/*13015*/ uint16(x86_xArgRM8),
+	/*13016*/ uint16(x86_xMatch),
+	/*13017*/ uint16(x86_xSetOp), uint16(x86_DEC),
+	/*13019*/ uint16(x86_xArgRM8),
+	/*13020*/ uint16(x86_xMatch),
+	/*13021*/ uint16(x86_xCondSlashR),
+	13030, // 0
+	13053, // 1
+	13076, // 2
+	13095, // 3
+	13118, // 4
+	13137, // 5
+	13160, // 6
+	0,     // 7
+	/*13030*/ uint16(x86_xCondIs64), 13033, 13045,
+	/*13033*/ uint16(x86_xCondDataSize), 13037, 13041, 0,
+	/*13037*/ uint16(x86_xSetOp), uint16(x86_INC),
+	/*13039*/ uint16(x86_xArgRM16),
+	/*13040*/ uint16(x86_xMatch),
+	/*13041*/ uint16(x86_xSetOp), uint16(x86_INC),
+	/*13043*/ uint16(x86_xArgRM32),
+	/*13044*/ uint16(x86_xMatch),
+	/*13045*/ uint16(x86_xCondDataSize), 13037, 13041, 13049,
+	/*13049*/ uint16(x86_xSetOp), uint16(x86_INC),
+	/*13051*/ uint16(x86_xArgRM64),
+	/*13052*/ uint16(x86_xMatch),
+	/*13053*/ uint16(x86_xCondIs64), 13056, 13068,
+	/*13056*/ uint16(x86_xCondDataSize), 13060, 13064, 0,
+	/*13060*/ uint16(x86_xSetOp), uint16(x86_DEC),
+	/*13062*/ uint16(x86_xArgRM16),
+	/*13063*/ uint16(x86_xMatch),
+	/*13064*/ uint16(x86_xSetOp), uint16(x86_DEC),
+	/*13066*/ uint16(x86_xArgRM32),
+	/*13067*/ uint16(x86_xMatch),
+	/*13068*/ uint16(x86_xCondDataSize), 13060, 13064, 13072,
+	/*13072*/ uint16(x86_xSetOp), uint16(x86_DEC),
+	/*13074*/ uint16(x86_xArgRM64),
+	/*13075*/ uint16(x86_xMatch),
+	/*13076*/ uint16(x86_xCondIs64), 13079, 13091,
+	/*13079*/ uint16(x86_xCondDataSize), 13083, 13087, 0,
+	/*13083*/ uint16(x86_xSetOp), uint16(x86_CALL),
+	/*13085*/ uint16(x86_xArgRM16),
+	/*13086*/ uint16(x86_xMatch),
+	/*13087*/ uint16(x86_xSetOp), uint16(x86_CALL),
+	/*13089*/ uint16(x86_xArgRM32),
+	/*13090*/ uint16(x86_xMatch),
+	/*13091*/ uint16(x86_xSetOp), uint16(x86_CALL),
+	/*13093*/ uint16(x86_xArgRM64),
+	/*13094*/ uint16(x86_xMatch),
+	/*13095*/ uint16(x86_xCondIs64), 13098, 13110,
+	/*13098*/ uint16(x86_xCondDataSize), 13102, 13106, 0,
+	/*13102*/ uint16(x86_xSetOp), uint16(x86_LCALL),
+	/*13104*/ uint16(x86_xArgM16colon16),
+	/*13105*/ uint16(x86_xMatch),
+	/*13106*/ uint16(x86_xSetOp), uint16(x86_LCALL),
+	/*13108*/ uint16(x86_xArgM16colon32),
+	/*13109*/ uint16(x86_xMatch),
+	/*13110*/ uint16(x86_xCondDataSize), 13102, 13106, 13114,
+	/*13114*/ uint16(x86_xSetOp), uint16(x86_LCALL),
+	/*13116*/ uint16(x86_xArgM16colon64),
+	/*13117*/ uint16(x86_xMatch),
+	/*13118*/ uint16(x86_xCondIs64), 13121, 13133,
+	/*13121*/ uint16(x86_xCondDataSize), 13125, 13129, 0,
+	/*13125*/ uint16(x86_xSetOp), uint16(x86_JMP),
+	/*13127*/ uint16(x86_xArgRM16),
+	/*13128*/ uint16(x86_xMatch),
+	/*13129*/ uint16(x86_xSetOp), uint16(x86_JMP),
+	/*13131*/ uint16(x86_xArgRM32),
+	/*13132*/ uint16(x86_xMatch),
+	/*13133*/ uint16(x86_xSetOp), uint16(x86_JMP),
+	/*13135*/ uint16(x86_xArgRM64),
+	/*13136*/ uint16(x86_xMatch),
+	/*13137*/ uint16(x86_xCondIs64), 13140, 13152,
+	/*13140*/ uint16(x86_xCondDataSize), 13144, 13148, 0,
+	/*13144*/ uint16(x86_xSetOp), uint16(x86_LJMP),
+	/*13146*/ uint16(x86_xArgM16colon16),
+	/*13147*/ uint16(x86_xMatch),
+	/*13148*/ uint16(x86_xSetOp), uint16(x86_LJMP),
+	/*13150*/ uint16(x86_xArgM16colon32),
+	/*13151*/ uint16(x86_xMatch),
+	/*13152*/ uint16(x86_xCondDataSize), 13144, 13148, 13156,
+	/*13156*/ uint16(x86_xSetOp), uint16(x86_LJMP),
+	/*13158*/ uint16(x86_xArgM16colon64),
+	/*13159*/ uint16(x86_xMatch),
+	/*13160*/ uint16(x86_xCondIs64), 13163, 13175,
+	/*13163*/ uint16(x86_xCondDataSize), 13167, 13171, 0,
+	/*13167*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+	/*13169*/ uint16(x86_xArgRM16),
+	/*13170*/ uint16(x86_xMatch),
+	/*13171*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+	/*13173*/ uint16(x86_xArgRM32),
+	/*13174*/ uint16(x86_xMatch),
+	/*13175*/ uint16(x86_xCondDataSize), 13167, 13179, 13183,
+	/*13179*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+	/*13181*/ uint16(x86_xArgRM64),
+	/*13182*/ uint16(x86_xMatch),
+	/*13183*/ uint16(x86_xSetOp), uint16(x86_PUSH),
+	/*13185*/ uint16(x86_xArgRM64),
+	/*13186*/ uint16(x86_xMatch),
+}
+
+const (
+	_ x86_Op = iota
+
+	x86_AAA
+	x86_AAD
+	x86_AAM
+	x86_AAS
+	x86_ADC
+	x86_ADD
+	x86_ADDPD
+	x86_ADDPS
+	x86_ADDSD
+	x86_ADDSS
+	x86_ADDSUBPD
+	x86_ADDSUBPS
+	x86_AESDEC
+	x86_AESDECLAST
+	x86_AESENC
+	x86_AESENCLAST
+	x86_AESIMC
+	x86_AESKEYGENASSIST
+	x86_AND
+	x86_ANDNPD
+	x86_ANDNPS
+	x86_ANDPD
+	x86_ANDPS
+	x86_ARPL
+	x86_BLENDPD
+	x86_BLENDPS
+	x86_BLENDVPD
+	x86_BLENDVPS
+	x86_BOUND
+	x86_BSF
+	x86_BSR
+	x86_BSWAP
+	x86_BT
+	x86_BTC
+	x86_BTR
+	x86_BTS
+	x86_CALL
+	x86_CBW
+	x86_CDQ
+	x86_CDQE
+	x86_CLC
+	x86_CLD
+	x86_CLFLUSH
+	x86_CLI
+	x86_CLTS
+	x86_CMC
+	x86_CMOVA
+	x86_CMOVAE
+	x86_CMOVB
+	x86_CMOVBE
+	x86_CMOVE
+	x86_CMOVG
+	x86_CMOVGE
+	x86_CMOVL
+	x86_CMOVLE
+	x86_CMOVNE
+	x86_CMOVNO
+	x86_CMOVNP
+	x86_CMOVNS
+	x86_CMOVO
+	x86_CMOVP
+	x86_CMOVS
+	x86_CMP
+	x86_CMPPD
+	x86_CMPPS
+	x86_CMPSB
+	x86_CMPSD
+	x86_CMPSD_XMM
+	x86_CMPSQ
+	x86_CMPSS
+	x86_CMPSW
+	x86_CMPXCHG
+	x86_CMPXCHG16B
+	x86_CMPXCHG8B
+	x86_COMISD
+	x86_COMISS
+	x86_CPUID
+	x86_CQO
+	x86_CRC32
+	x86_CVTDQ2PD
+	x86_CVTDQ2PS
+	x86_CVTPD2DQ
+	x86_CVTPD2PI
+	x86_CVTPD2PS
+	x86_CVTPI2PD
+	x86_CVTPI2PS
+	x86_CVTPS2DQ
+	x86_CVTPS2PD
+	x86_CVTPS2PI
+	x86_CVTSD2SI
+	x86_CVTSD2SS
+	x86_CVTSI2SD
+	x86_CVTSI2SS
+	x86_CVTSS2SD
+	x86_CVTSS2SI
+	x86_CVTTPD2DQ
+	x86_CVTTPD2PI
+	x86_CVTTPS2DQ
+	x86_CVTTPS2PI
+	x86_CVTTSD2SI
+	x86_CVTTSS2SI
+	x86_CWD
+	x86_CWDE
+	x86_DAA
+	x86_DAS
+	x86_DEC
+	x86_DIV
+	x86_DIVPD
+	x86_DIVPS
+	x86_DIVSD
+	x86_DIVSS
+	x86_DPPD
+	x86_DPPS
+	x86_EMMS
+	x86_ENTER
+	x86_EXTRACTPS
+	x86_F2XM1
+	x86_FABS
+	x86_FADD
+	x86_FADDP
+	x86_FBLD
+	x86_FBSTP
+	x86_FCHS
+	x86_FCMOVB
+	x86_FCMOVBE
+	x86_FCMOVE
+	x86_FCMOVNB
+	x86_FCMOVNBE
+	x86_FCMOVNE
+	x86_FCMOVNU
+	x86_FCMOVU
+	x86_FCOM
+	x86_FCOMI
+	x86_FCOMIP
+	x86_FCOMP
+	x86_FCOMPP
+	x86_FCOS
+	x86_FDECSTP
+	x86_FDIV
+	x86_FDIVP
+	x86_FDIVR
+	x86_FDIVRP
+	x86_FFREE
+	x86_FFREEP
+	x86_FIADD
+	x86_FICOM
+	x86_FICOMP
+	x86_FIDIV
+	x86_FIDIVR
+	x86_FILD
+	x86_FIMUL
+	x86_FINCSTP
+	x86_FIST
+	x86_FISTP
+	x86_FISTTP
+	x86_FISUB
+	x86_FISUBR
+	x86_FLD
+	x86_FLD1
+	x86_FLDCW
+	x86_FLDENV
+	x86_FLDL2E
+	x86_FLDL2T
+	x86_FLDLG2
+	x86_FLDPI
+	x86_FMUL
+	x86_FMULP
+	x86_FNCLEX
+	x86_FNINIT
+	x86_FNOP
+	x86_FNSAVE
+	x86_FNSTCW
+	x86_FNSTENV
+	x86_FNSTSW
+	x86_FPATAN
+	x86_FPREM
+	x86_FPREM1
+	x86_FPTAN
+	x86_FRNDINT
+	x86_FRSTOR
+	x86_FSCALE
+	x86_FSIN
+	x86_FSINCOS
+	x86_FSQRT
+	x86_FST
+	x86_FSTP
+	x86_FSUB
+	x86_FSUBP
+	x86_FSUBR
+	x86_FSUBRP
+	x86_FTST
+	x86_FUCOM
+	x86_FUCOMI
+	x86_FUCOMIP
+	x86_FUCOMP
+	x86_FUCOMPP
+	x86_FWAIT
+	x86_FXAM
+	x86_FXCH
+	x86_FXRSTOR
+	x86_FXRSTOR64
+	x86_FXSAVE
+	x86_FXSAVE64
+	x86_FXTRACT
+	x86_FYL2X
+	x86_FYL2XP1
+	x86_HADDPD
+	x86_HADDPS
+	x86_HLT
+	x86_HSUBPD
+	x86_HSUBPS
+	x86_ICEBP
+	x86_IDIV
+	x86_IMUL
+	x86_IN
+	x86_INC
+	x86_INSB
+	x86_INSD
+	x86_INSERTPS
+	x86_INSW
+	x86_INT
+	x86_INTO
+	x86_INVD
+	x86_INVLPG
+	x86_INVPCID
+	x86_IRET
+	x86_IRETD
+	x86_IRETQ
+	x86_JA
+	x86_JAE
+	x86_JB
+	x86_JBE
+	x86_JCXZ
+	x86_JE
+	x86_JECXZ
+	x86_JG
+	x86_JGE
+	x86_JL
+	x86_JLE
+	x86_JMP
+	x86_JNE
+	x86_JNO
+	x86_JNP
+	x86_JNS
+	x86_JO
+	x86_JP
+	x86_JRCXZ
+	x86_JS
+	x86_LAHF
+	x86_LAR
+	x86_LCALL
+	x86_LDDQU
+	x86_LDMXCSR
+	x86_LDS
+	x86_LEA
+	x86_LEAVE
+	x86_LES
+	x86_LFENCE
+	x86_LFS
+	x86_LGDT
+	x86_LGS
+	x86_LIDT
+	x86_LJMP
+	x86_LLDT
+	x86_LMSW
+	x86_LODSB
+	x86_LODSD
+	x86_LODSQ
+	x86_LODSW
+	x86_LOOP
+	x86_LOOPE
+	x86_LOOPNE
+	x86_LRET
+	x86_LSL
+	x86_LSS
+	x86_LTR
+	x86_LZCNT
+	x86_MASKMOVDQU
+	x86_MASKMOVQ
+	x86_MAXPD
+	x86_MAXPS
+	x86_MAXSD
+	x86_MAXSS
+	x86_MFENCE
+	x86_MINPD
+	x86_MINPS
+	x86_MINSD
+	x86_MINSS
+	x86_MONITOR
+	x86_MOV
+	x86_MOVAPD
+	x86_MOVAPS
+	x86_MOVBE
+	x86_MOVD
+	x86_MOVDDUP
+	x86_MOVDQ2Q
+	x86_MOVDQA
+	x86_MOVDQU
+	x86_MOVHLPS
+	x86_MOVHPD
+	x86_MOVHPS
+	x86_MOVLHPS
+	x86_MOVLPD
+	x86_MOVLPS
+	x86_MOVMSKPD
+	x86_MOVMSKPS
+	x86_MOVNTDQ
+	x86_MOVNTDQA
+	x86_MOVNTI
+	x86_MOVNTPD
+	x86_MOVNTPS
+	x86_MOVNTQ
+	x86_MOVNTSD
+	x86_MOVNTSS
+	x86_MOVQ
+	x86_MOVQ2DQ
+	x86_MOVSB
+	x86_MOVSD
+	x86_MOVSD_XMM
+	x86_MOVSHDUP
+	x86_MOVSLDUP
+	x86_MOVSQ
+	x86_MOVSS
+	x86_MOVSW
+	x86_MOVSX
+	x86_MOVSXD
+	x86_MOVUPD
+	x86_MOVUPS
+	x86_MOVZX
+	x86_MPSADBW
+	x86_MUL
+	x86_MULPD
+	x86_MULPS
+	x86_MULSD
+	x86_MULSS
+	x86_MWAIT
+	x86_NEG
+	x86_NOP
+	x86_NOT
+	x86_OR
+	x86_ORPD
+	x86_ORPS
+	x86_OUT
+	x86_OUTSB
+	x86_OUTSD
+	x86_OUTSW
+	x86_PABSB
+	x86_PABSD
+	x86_PABSW
+	x86_PACKSSDW
+	x86_PACKSSWB
+	x86_PACKUSDW
+	x86_PACKUSWB
+	x86_PADDB
+	x86_PADDD
+	x86_PADDQ
+	x86_PADDSB
+	x86_PADDSW
+	x86_PADDUSB
+	x86_PADDUSW
+	x86_PADDW
+	x86_PALIGNR
+	x86_PAND
+	x86_PANDN
+	x86_PAUSE
+	x86_PAVGB
+	x86_PAVGW
+	x86_PBLENDVB
+	x86_PBLENDW
+	x86_PCLMULQDQ
+	x86_PCMPEQB
+	x86_PCMPEQD
+	x86_PCMPEQQ
+	x86_PCMPEQW
+	x86_PCMPESTRI
+	x86_PCMPESTRM
+	x86_PCMPGTB
+	x86_PCMPGTD
+	x86_PCMPGTQ
+	x86_PCMPGTW
+	x86_PCMPISTRI
+	x86_PCMPISTRM
+	x86_PEXTRB
+	x86_PEXTRD
+	x86_PEXTRQ
+	x86_PEXTRW
+	x86_PHADDD
+	x86_PHADDSW
+	x86_PHADDW
+	x86_PHMINPOSUW
+	x86_PHSUBD
+	x86_PHSUBSW
+	x86_PHSUBW
+	x86_PINSRB
+	x86_PINSRD
+	x86_PINSRQ
+	x86_PINSRW
+	x86_PMADDUBSW
+	x86_PMADDWD
+	x86_PMAXSB
+	x86_PMAXSD
+	x86_PMAXSW
+	x86_PMAXUB
+	x86_PMAXUD
+	x86_PMAXUW
+	x86_PMINSB
+	x86_PMINSD
+	x86_PMINSW
+	x86_PMINUB
+	x86_PMINUD
+	x86_PMINUW
+	x86_PMOVMSKB
+	x86_PMOVSXBD
+	x86_PMOVSXBQ
+	x86_PMOVSXBW
+	x86_PMOVSXDQ
+	x86_PMOVSXWD
+	x86_PMOVSXWQ
+	x86_PMOVZXBD
+	x86_PMOVZXBQ
+	x86_PMOVZXBW
+	x86_PMOVZXDQ
+	x86_PMOVZXWD
+	x86_PMOVZXWQ
+	x86_PMULDQ
+	x86_PMULHRSW
+	x86_PMULHUW
+	x86_PMULHW
+	x86_PMULLD
+	x86_PMULLW
+	x86_PMULUDQ
+	x86_POP
+	x86_POPA
+	x86_POPAD
+	x86_POPCNT
+	x86_POPF
+	x86_POPFD
+	x86_POPFQ
+	x86_POR
+	x86_PREFETCHNTA
+	x86_PREFETCHT0
+	x86_PREFETCHT1
+	x86_PREFETCHT2
+	x86_PREFETCHW
+	x86_PSADBW
+	x86_PSHUFB
+	x86_PSHUFD
+	x86_PSHUFHW
+	x86_PSHUFLW
+	x86_PSHUFW
+	x86_PSIGNB
+	x86_PSIGND
+	x86_PSIGNW
+	x86_PSLLD
+	x86_PSLLDQ
+	x86_PSLLQ
+	x86_PSLLW
+	x86_PSRAD
+	x86_PSRAW
+	x86_PSRLD
+	x86_PSRLDQ
+	x86_PSRLQ
+	x86_PSRLW
+	x86_PSUBB
+	x86_PSUBD
+	x86_PSUBQ
+	x86_PSUBSB
+	x86_PSUBSW
+	x86_PSUBUSB
+	x86_PSUBUSW
+	x86_PSUBW
+	x86_PTEST
+	x86_PUNPCKHBW
+	x86_PUNPCKHDQ
+	x86_PUNPCKHQDQ
+	x86_PUNPCKHWD
+	x86_PUNPCKLBW
+	x86_PUNPCKLDQ
+	x86_PUNPCKLQDQ
+	x86_PUNPCKLWD
+	x86_PUSH
+	x86_PUSHA
+	x86_PUSHAD
+	x86_PUSHF
+	x86_PUSHFD
+	x86_PUSHFQ
+	x86_PXOR
+	x86_RCL
+	x86_RCPPS
+	x86_RCPSS
+	x86_RCR
+	x86_RDFSBASE
+	x86_RDGSBASE
+	x86_RDMSR
+	x86_RDPMC
+	x86_RDRAND
+	x86_RDTSC
+	x86_RDTSCP
+	x86_RET
+	x86_ROL
+	x86_ROR
+	x86_ROUNDPD
+	x86_ROUNDPS
+	x86_ROUNDSD
+	x86_ROUNDSS
+	x86_RSM
+	x86_RSQRTPS
+	x86_RSQRTSS
+	x86_SAHF
+	x86_SAR
+	x86_SBB
+	x86_SCASB
+	x86_SCASD
+	x86_SCASQ
+	x86_SCASW
+	x86_SETA
+	x86_SETAE
+	x86_SETB
+	x86_SETBE
+	x86_SETE
+	x86_SETG
+	x86_SETGE
+	x86_SETL
+	x86_SETLE
+	x86_SETNE
+	x86_SETNO
+	x86_SETNP
+	x86_SETNS
+	x86_SETO
+	x86_SETP
+	x86_SETS
+	x86_SFENCE
+	x86_SGDT
+	x86_SHL
+	x86_SHLD
+	x86_SHR
+	x86_SHRD
+	x86_SHUFPD
+	x86_SHUFPS
+	x86_SIDT
+	x86_SLDT
+	x86_SMSW
+	x86_SQRTPD
+	x86_SQRTPS
+	x86_SQRTSD
+	x86_SQRTSS
+	x86_STC
+	x86_STD
+	x86_STI
+	x86_STMXCSR
+	x86_STOSB
+	x86_STOSD
+	x86_STOSQ
+	x86_STOSW
+	x86_STR
+	x86_SUB
+	x86_SUBPD
+	x86_SUBPS
+	x86_SUBSD
+	x86_SUBSS
+	x86_SWAPGS
+	x86_SYSCALL
+	x86_SYSENTER
+	x86_SYSEXIT
+	x86_SYSRET
+	x86_TEST
+	x86_TZCNT
+	x86_UCOMISD
+	x86_UCOMISS
+	x86_UD1
+	x86_UD2
+	x86_UNPCKHPD
+	x86_UNPCKHPS
+	x86_UNPCKLPD
+	x86_UNPCKLPS
+	x86_VERR
+	x86_VERW
+	x86_WBINVD
+	x86_WRFSBASE
+	x86_WRGSBASE
+	x86_WRMSR
+	x86_XABORT
+	x86_XADD
+	x86_XBEGIN
+	x86_XCHG
+	x86_XEND
+	x86_XGETBV
+	x86_XLATB
+	x86_XOR
+	x86_XORPD
+	x86_XORPS
+	x86_XRSTOR
+	x86_XRSTOR64
+	x86_XRSTORS
+	x86_XRSTORS64
+	x86_XSAVE
+	x86_XSAVE64
+	x86_XSAVEC
+	x86_XSAVEC64
+	x86_XSAVEOPT
+	x86_XSAVEOPT64
+	x86_XSAVES
+	x86_XSAVES64
+	x86_XSETBV
+	x86_XTEST
+)
+
+const x86_maxOp = x86_XTEST
+
+var x86_opNames = [...]string{
+	x86_AAA:             "AAA",
+	x86_AAD:             "AAD",
+	x86_AAM:             "AAM",
+	x86_AAS:             "AAS",
+	x86_ADC:             "ADC",
+	x86_ADD:             "ADD",
+	x86_ADDPD:           "ADDPD",
+	x86_ADDPS:           "ADDPS",
+	x86_ADDSD:           "ADDSD",
+	x86_ADDSS:           "ADDSS",
+	x86_ADDSUBPD:        "ADDSUBPD",
+	x86_ADDSUBPS:        "ADDSUBPS",
+	x86_AESDEC:          "AESDEC",
+	x86_AESDECLAST:      "AESDECLAST",
+	x86_AESENC:          "AESENC",
+	x86_AESENCLAST:      "AESENCLAST",
+	x86_AESIMC:          "AESIMC",
+	x86_AESKEYGENASSIST: "AESKEYGENASSIST",
+	x86_AND:             "AND",
+	x86_ANDNPD:          "ANDNPD",
+	x86_ANDNPS:          "ANDNPS",
+	x86_ANDPD:           "ANDPD",
+	x86_ANDPS:           "ANDPS",
+	x86_ARPL:            "ARPL",
+	x86_BLENDPD:         "BLENDPD",
+	x86_BLENDPS:         "BLENDPS",
+	x86_BLENDVPD:        "BLENDVPD",
+	x86_BLENDVPS:        "BLENDVPS",
+	x86_BOUND:           "BOUND",
+	x86_BSF:             "BSF",
+	x86_BSR:             "BSR",
+	x86_BSWAP:           "BSWAP",
+	x86_BT:              "BT",
+	x86_BTC:             "BTC",
+	x86_BTR:             "BTR",
+	x86_BTS:             "BTS",
+	x86_CALL:            "CALL",
+	x86_CBW:             "CBW",
+	x86_CDQ:             "CDQ",
+	x86_CDQE:            "CDQE",
+	x86_CLC:             "CLC",
+	x86_CLD:             "CLD",
+	x86_CLFLUSH:         "CLFLUSH",
+	x86_CLI:             "CLI",
+	x86_CLTS:            "CLTS",
+	x86_CMC:             "CMC",
+	x86_CMOVA:           "CMOVA",
+	x86_CMOVAE:          "CMOVAE",
+	x86_CMOVB:           "CMOVB",
+	x86_CMOVBE:          "CMOVBE",
+	x86_CMOVE:           "CMOVE",
+	x86_CMOVG:           "CMOVG",
+	x86_CMOVGE:          "CMOVGE",
+	x86_CMOVL:           "CMOVL",
+	x86_CMOVLE:          "CMOVLE",
+	x86_CMOVNE:          "CMOVNE",
+	x86_CMOVNO:          "CMOVNO",
+	x86_CMOVNP:          "CMOVNP",
+	x86_CMOVNS:          "CMOVNS",
+	x86_CMOVO:           "CMOVO",
+	x86_CMOVP:           "CMOVP",
+	x86_CMOVS:           "CMOVS",
+	x86_CMP:             "CMP",
+	x86_CMPPD:           "CMPPD",
+	x86_CMPPS:           "CMPPS",
+	x86_CMPSB:           "CMPSB",
+	x86_CMPSD:           "CMPSD",
+	x86_CMPSD_XMM:       "CMPSD_XMM",
+	x86_CMPSQ:           "CMPSQ",
+	x86_CMPSS:           "CMPSS",
+	x86_CMPSW:           "CMPSW",
+	x86_CMPXCHG:         "CMPXCHG",
+	x86_CMPXCHG16B:      "CMPXCHG16B",
+	x86_CMPXCHG8B:       "CMPXCHG8B",
+	x86_COMISD:          "COMISD",
+	x86_COMISS:          "COMISS",
+	x86_CPUID:           "CPUID",
+	x86_CQO:             "CQO",
+	x86_CRC32:           "CRC32",
+	x86_CVTDQ2PD:        "CVTDQ2PD",
+	x86_CVTDQ2PS:        "CVTDQ2PS",
+	x86_CVTPD2DQ:        "CVTPD2DQ",
+	x86_CVTPD2PI:        "CVTPD2PI",
+	x86_CVTPD2PS:        "CVTPD2PS",
+	x86_CVTPI2PD:        "CVTPI2PD",
+	x86_CVTPI2PS:        "CVTPI2PS",
+	x86_CVTPS2DQ:        "CVTPS2DQ",
+	x86_CVTPS2PD:        "CVTPS2PD",
+	x86_CVTPS2PI:        "CVTPS2PI",
+	x86_CVTSD2SI:        "CVTSD2SI",
+	x86_CVTSD2SS:        "CVTSD2SS",
+	x86_CVTSI2SD:        "CVTSI2SD",
+	x86_CVTSI2SS:        "CVTSI2SS",
+	x86_CVTSS2SD:        "CVTSS2SD",
+	x86_CVTSS2SI:        "CVTSS2SI",
+	x86_CVTTPD2DQ:       "CVTTPD2DQ",
+	x86_CVTTPD2PI:       "CVTTPD2PI",
+	x86_CVTTPS2DQ:       "CVTTPS2DQ",
+	x86_CVTTPS2PI:       "CVTTPS2PI",
+	x86_CVTTSD2SI:       "CVTTSD2SI",
+	x86_CVTTSS2SI:       "CVTTSS2SI",
+	x86_CWD:             "CWD",
+	x86_CWDE:            "CWDE",
+	x86_DAA:             "DAA",
+	x86_DAS:             "DAS",
+	x86_DEC:             "DEC",
+	x86_DIV:             "DIV",
+	x86_DIVPD:           "DIVPD",
+	x86_DIVPS:           "DIVPS",
+	x86_DIVSD:           "DIVSD",
+	x86_DIVSS:           "DIVSS",
+	x86_DPPD:            "DPPD",
+	x86_DPPS:            "DPPS",
+	x86_EMMS:            "EMMS",
+	x86_ENTER:           "ENTER",
+	x86_EXTRACTPS:       "EXTRACTPS",
+	x86_F2XM1:           "F2XM1",
+	x86_FABS:            "FABS",
+	x86_FADD:            "FADD",
+	x86_FADDP:           "FADDP",
+	x86_FBLD:            "FBLD",
+	x86_FBSTP:           "FBSTP",
+	x86_FCHS:            "FCHS",
+	x86_FCMOVB:          "FCMOVB",
+	x86_FCMOVBE:         "FCMOVBE",
+	x86_FCMOVE:          "FCMOVE",
+	x86_FCMOVNB:         "FCMOVNB",
+	x86_FCMOVNBE:        "FCMOVNBE",
+	x86_FCMOVNE:         "FCMOVNE",
+	x86_FCMOVNU:         "FCMOVNU",
+	x86_FCMOVU:          "FCMOVU",
+	x86_FCOM:            "FCOM",
+	x86_FCOMI:           "FCOMI",
+	x86_FCOMIP:          "FCOMIP",
+	x86_FCOMP:           "FCOMP",
+	x86_FCOMPP:          "FCOMPP",
+	x86_FCOS:            "FCOS",
+	x86_FDECSTP:         "FDECSTP",
+	x86_FDIV:            "FDIV",
+	x86_FDIVP:           "FDIVP",
+	x86_FDIVR:           "FDIVR",
+	x86_FDIVRP:          "FDIVRP",
+	x86_FFREE:           "FFREE",
+	x86_FFREEP:          "FFREEP",
+	x86_FIADD:           "FIADD",
+	x86_FICOM:           "FICOM",
+	x86_FICOMP:          "FICOMP",
+	x86_FIDIV:           "FIDIV",
+	x86_FIDIVR:          "FIDIVR",
+	x86_FILD:            "FILD",
+	x86_FIMUL:           "FIMUL",
+	x86_FINCSTP:         "FINCSTP",
+	x86_FIST:            "FIST",
+	x86_FISTP:           "FISTP",
+	x86_FISTTP:          "FISTTP",
+	x86_FISUB:           "FISUB",
+	x86_FISUBR:          "FISUBR",
+	x86_FLD:             "FLD",
+	x86_FLD1:            "FLD1",
+	x86_FLDCW:           "FLDCW",
+	x86_FLDENV:          "FLDENV",
+	x86_FLDL2E:          "FLDL2E",
+	x86_FLDL2T:          "FLDL2T",
+	x86_FLDLG2:          "FLDLG2",
+	x86_FLDPI:           "FLDPI",
+	x86_FMUL:            "FMUL",
+	x86_FMULP:           "FMULP",
+	x86_FNCLEX:          "FNCLEX",
+	x86_FNINIT:          "FNINIT",
+	x86_FNOP:            "FNOP",
+	x86_FNSAVE:          "FNSAVE",
+	x86_FNSTCW:          "FNSTCW",
+	x86_FNSTENV:         "FNSTENV",
+	x86_FNSTSW:          "FNSTSW",
+	x86_FPATAN:          "FPATAN",
+	x86_FPREM:           "FPREM",
+	x86_FPREM1:          "FPREM1",
+	x86_FPTAN:           "FPTAN",
+	x86_FRNDINT:         "FRNDINT",
+	x86_FRSTOR:          "FRSTOR",
+	x86_FSCALE:          "FSCALE",
+	x86_FSIN:            "FSIN",
+	x86_FSINCOS:         "FSINCOS",
+	x86_FSQRT:           "FSQRT",
+	x86_FST:             "FST",
+	x86_FSTP:            "FSTP",
+	x86_FSUB:            "FSUB",
+	x86_FSUBP:           "FSUBP",
+	x86_FSUBR:           "FSUBR",
+	x86_FSUBRP:          "FSUBRP",
+	x86_FTST:            "FTST",
+	x86_FUCOM:           "FUCOM",
+	x86_FUCOMI:          "FUCOMI",
+	x86_FUCOMIP:         "FUCOMIP",
+	x86_FUCOMP:          "FUCOMP",
+	x86_FUCOMPP:         "FUCOMPP",
+	x86_FWAIT:           "FWAIT",
+	x86_FXAM:            "FXAM",
+	x86_FXCH:            "FXCH",
+	x86_FXRSTOR:         "FXRSTOR",
+	x86_FXRSTOR64:       "FXRSTOR64",
+	x86_FXSAVE:          "FXSAVE",
+	x86_FXSAVE64:        "FXSAVE64",
+	x86_FXTRACT:         "FXTRACT",
+	x86_FYL2X:           "FYL2X",
+	x86_FYL2XP1:         "FYL2XP1",
+	x86_HADDPD:          "HADDPD",
+	x86_HADDPS:          "HADDPS",
+	x86_HLT:             "HLT",
+	x86_HSUBPD:          "HSUBPD",
+	x86_HSUBPS:          "HSUBPS",
+	x86_ICEBP:           "ICEBP",
+	x86_IDIV:            "IDIV",
+	x86_IMUL:            "IMUL",
+	x86_IN:              "IN",
+	x86_INC:             "INC",
+	x86_INSB:            "INSB",
+	x86_INSD:            "INSD",
+	x86_INSERTPS:        "INSERTPS",
+	x86_INSW:            "INSW",
+	x86_INT:             "INT",
+	x86_INTO:            "INTO",
+	x86_INVD:            "INVD",
+	x86_INVLPG:          "INVLPG",
+	x86_INVPCID:         "INVPCID",
+	x86_IRET:            "IRET",
+	x86_IRETD:           "IRETD",
+	x86_IRETQ:           "IRETQ",
+	x86_JA:              "JA",
+	x86_JAE:             "JAE",
+	x86_JB:              "JB",
+	x86_JBE:             "JBE",
+	x86_JCXZ:            "JCXZ",
+	x86_JE:              "JE",
+	x86_JECXZ:           "JECXZ",
+	x86_JG:              "JG",
+	x86_JGE:             "JGE",
+	x86_JL:              "JL",
+	x86_JLE:             "JLE",
+	x86_JMP:             "JMP",
+	x86_JNE:             "JNE",
+	x86_JNO:             "JNO",
+	x86_JNP:             "JNP",
+	x86_JNS:             "JNS",
+	x86_JO:              "JO",
+	x86_JP:              "JP",
+	x86_JRCXZ:           "JRCXZ",
+	x86_JS:              "JS",
+	x86_LAHF:            "LAHF",
+	x86_LAR:             "LAR",
+	x86_LCALL:           "LCALL",
+	x86_LDDQU:           "LDDQU",
+	x86_LDMXCSR:         "LDMXCSR",
+	x86_LDS:             "LDS",
+	x86_LEA:             "LEA",
+	x86_LEAVE:           "LEAVE",
+	x86_LES:             "LES",
+	x86_LFENCE:          "LFENCE",
+	x86_LFS:             "LFS",
+	x86_LGDT:            "LGDT",
+	x86_LGS:             "LGS",
+	x86_LIDT:            "LIDT",
+	x86_LJMP:            "LJMP",
+	x86_LLDT:            "LLDT",
+	x86_LMSW:            "LMSW",
+	x86_LODSB:           "LODSB",
+	x86_LODSD:           "LODSD",
+	x86_LODSQ:           "LODSQ",
+	x86_LODSW:           "LODSW",
+	x86_LOOP:            "LOOP",
+	x86_LOOPE:           "LOOPE",
+	x86_LOOPNE:          "LOOPNE",
+	x86_LRET:            "LRET",
+	x86_LSL:             "LSL",
+	x86_LSS:             "LSS",
+	x86_LTR:             "LTR",
+	x86_LZCNT:           "LZCNT",
+	x86_MASKMOVDQU:      "MASKMOVDQU",
+	x86_MASKMOVQ:        "MASKMOVQ",
+	x86_MAXPD:           "MAXPD",
+	x86_MAXPS:           "MAXPS",
+	x86_MAXSD:           "MAXSD",
+	x86_MAXSS:           "MAXSS",
+	x86_MFENCE:          "MFENCE",
+	x86_MINPD:           "MINPD",
+	x86_MINPS:           "MINPS",
+	x86_MINSD:           "MINSD",
+	x86_MINSS:           "MINSS",
+	x86_MONITOR:         "MONITOR",
+	x86_MOV:             "MOV",
+	x86_MOVAPD:          "MOVAPD",
+	x86_MOVAPS:          "MOVAPS",
+	x86_MOVBE:           "MOVBE",
+	x86_MOVD:            "MOVD",
+	x86_MOVDDUP:         "MOVDDUP",
+	x86_MOVDQ2Q:         "MOVDQ2Q",
+	x86_MOVDQA:          "MOVDQA",
+	x86_MOVDQU:          "MOVDQU",
+	x86_MOVHLPS:         "MOVHLPS",
+	x86_MOVHPD:          "MOVHPD",
+	x86_MOVHPS:          "MOVHPS",
+	x86_MOVLHPS:         "MOVLHPS",
+	x86_MOVLPD:          "MOVLPD",
+	x86_MOVLPS:          "MOVLPS",
+	x86_MOVMSKPD:        "MOVMSKPD",
+	x86_MOVMSKPS:        "MOVMSKPS",
+	x86_MOVNTDQ:         "MOVNTDQ",
+	x86_MOVNTDQA:        "MOVNTDQA",
+	x86_MOVNTI:          "MOVNTI",
+	x86_MOVNTPD:         "MOVNTPD",
+	x86_MOVNTPS:         "MOVNTPS",
+	x86_MOVNTQ:          "MOVNTQ",
+	x86_MOVNTSD:         "MOVNTSD",
+	x86_MOVNTSS:         "MOVNTSS",
+	x86_MOVQ:            "MOVQ",
+	x86_MOVQ2DQ:         "MOVQ2DQ",
+	x86_MOVSB:           "MOVSB",
+	x86_MOVSD:           "MOVSD",
+	x86_MOVSD_XMM:       "MOVSD_XMM",
+	x86_MOVSHDUP:        "MOVSHDUP",
+	x86_MOVSLDUP:        "MOVSLDUP",
+	x86_MOVSQ:           "MOVSQ",
+	x86_MOVSS:           "MOVSS",
+	x86_MOVSW:           "MOVSW",
+	x86_MOVSX:           "MOVSX",
+	x86_MOVSXD:          "MOVSXD",
+	x86_MOVUPD:          "MOVUPD",
+	x86_MOVUPS:          "MOVUPS",
+	x86_MOVZX:           "MOVZX",
+	x86_MPSADBW:         "MPSADBW",
+	x86_MUL:             "MUL",
+	x86_MULPD:           "MULPD",
+	x86_MULPS:           "MULPS",
+	x86_MULSD:           "MULSD",
+	x86_MULSS:           "MULSS",
+	x86_MWAIT:           "MWAIT",
+	x86_NEG:             "NEG",
+	x86_NOP:             "NOP",
+	x86_NOT:             "NOT",
+	x86_OR:              "OR",
+	x86_ORPD:            "ORPD",
+	x86_ORPS:            "ORPS",
+	x86_OUT:             "OUT",
+	x86_OUTSB:           "OUTSB",
+	x86_OUTSD:           "OUTSD",
+	x86_OUTSW:           "OUTSW",
+	x86_PABSB:           "PABSB",
+	x86_PABSD:           "PABSD",
+	x86_PABSW:           "PABSW",
+	x86_PACKSSDW:        "PACKSSDW",
+	x86_PACKSSWB:        "PACKSSWB",
+	x86_PACKUSDW:        "PACKUSDW",
+	x86_PACKUSWB:        "PACKUSWB",
+	x86_PADDB:           "PADDB",
+	x86_PADDD:           "PADDD",
+	x86_PADDQ:           "PADDQ",
+	x86_PADDSB:          "PADDSB",
+	x86_PADDSW:          "PADDSW",
+	x86_PADDUSB:         "PADDUSB",
+	x86_PADDUSW:         "PADDUSW",
+	x86_PADDW:           "PADDW",
+	x86_PALIGNR:         "PALIGNR",
+	x86_PAND:            "PAND",
+	x86_PANDN:           "PANDN",
+	x86_PAUSE:           "PAUSE",
+	x86_PAVGB:           "PAVGB",
+	x86_PAVGW:           "PAVGW",
+	x86_PBLENDVB:        "PBLENDVB",
+	x86_PBLENDW:         "PBLENDW",
+	x86_PCLMULQDQ:       "PCLMULQDQ",
+	x86_PCMPEQB:         "PCMPEQB",
+	x86_PCMPEQD:         "PCMPEQD",
+	x86_PCMPEQQ:         "PCMPEQQ",
+	x86_PCMPEQW:         "PCMPEQW",
+	x86_PCMPESTRI:       "PCMPESTRI",
+	x86_PCMPESTRM:       "PCMPESTRM",
+	x86_PCMPGTB:         "PCMPGTB",
+	x86_PCMPGTD:         "PCMPGTD",
+	x86_PCMPGTQ:         "PCMPGTQ",
+	x86_PCMPGTW:         "PCMPGTW",
+	x86_PCMPISTRI:       "PCMPISTRI",
+	x86_PCMPISTRM:       "PCMPISTRM",
+	x86_PEXTRB:          "PEXTRB",
+	x86_PEXTRD:          "PEXTRD",
+	x86_PEXTRQ:          "PEXTRQ",
+	x86_PEXTRW:          "PEXTRW",
+	x86_PHADDD:          "PHADDD",
+	x86_PHADDSW:         "PHADDSW",
+	x86_PHADDW:          "PHADDW",
+	x86_PHMINPOSUW:      "PHMINPOSUW",
+	x86_PHSUBD:          "PHSUBD",
+	x86_PHSUBSW:         "PHSUBSW",
+	x86_PHSUBW:          "PHSUBW",
+	x86_PINSRB:          "PINSRB",
+	x86_PINSRD:          "PINSRD",
+	x86_PINSRQ:          "PINSRQ",
+	x86_PINSRW:          "PINSRW",
+	x86_PMADDUBSW:       "PMADDUBSW",
+	x86_PMADDWD:         "PMADDWD",
+	x86_PMAXSB:          "PMAXSB",
+	x86_PMAXSD:          "PMAXSD",
+	x86_PMAXSW:          "PMAXSW",
+	x86_PMAXUB:          "PMAXUB",
+	x86_PMAXUD:          "PMAXUD",
+	x86_PMAXUW:          "PMAXUW",
+	x86_PMINSB:          "PMINSB",
+	x86_PMINSD:          "PMINSD",
+	x86_PMINSW:          "PMINSW",
+	x86_PMINUB:          "PMINUB",
+	x86_PMINUD:          "PMINUD",
+	x86_PMINUW:          "PMINUW",
+	x86_PMOVMSKB:        "PMOVMSKB",
+	x86_PMOVSXBD:        "PMOVSXBD",
+	x86_PMOVSXBQ:        "PMOVSXBQ",
+	x86_PMOVSXBW:        "PMOVSXBW",
+	x86_PMOVSXDQ:        "PMOVSXDQ",
+	x86_PMOVSXWD:        "PMOVSXWD",
+	x86_PMOVSXWQ:        "PMOVSXWQ",
+	x86_PMOVZXBD:        "PMOVZXBD",
+	x86_PMOVZXBQ:        "PMOVZXBQ",
+	x86_PMOVZXBW:        "PMOVZXBW",
+	x86_PMOVZXDQ:        "PMOVZXDQ",
+	x86_PMOVZXWD:        "PMOVZXWD",
+	x86_PMOVZXWQ:        "PMOVZXWQ",
+	x86_PMULDQ:          "PMULDQ",
+	x86_PMULHRSW:        "PMULHRSW",
+	x86_PMULHUW:         "PMULHUW",
+	x86_PMULHW:          "PMULHW",
+	x86_PMULLD:          "PMULLD",
+	x86_PMULLW:          "PMULLW",
+	x86_PMULUDQ:         "PMULUDQ",
+	x86_POP:             "POP",
+	x86_POPA:            "POPA",
+	x86_POPAD:           "POPAD",
+	x86_POPCNT:          "POPCNT",
+	x86_POPF:            "POPF",
+	x86_POPFD:           "POPFD",
+	x86_POPFQ:           "POPFQ",
+	x86_POR:             "POR",
+	x86_PREFETCHNTA:     "PREFETCHNTA",
+	x86_PREFETCHT0:      "PREFETCHT0",
+	x86_PREFETCHT1:      "PREFETCHT1",
+	x86_PREFETCHT2:      "PREFETCHT2",
+	x86_PREFETCHW:       "PREFETCHW",
+	x86_PSADBW:          "PSADBW",
+	x86_PSHUFB:          "PSHUFB",
+	x86_PSHUFD:          "PSHUFD",
+	x86_PSHUFHW:         "PSHUFHW",
+	x86_PSHUFLW:         "PSHUFLW",
+	x86_PSHUFW:          "PSHUFW",
+	x86_PSIGNB:          "PSIGNB",
+	x86_PSIGND:          "PSIGND",
+	x86_PSIGNW:          "PSIGNW",
+	x86_PSLLD:           "PSLLD",
+	x86_PSLLDQ:          "PSLLDQ",
+	x86_PSLLQ:           "PSLLQ",
+	x86_PSLLW:           "PSLLW",
+	x86_PSRAD:           "PSRAD",
+	x86_PSRAW:           "PSRAW",
+	x86_PSRLD:           "PSRLD",
+	x86_PSRLDQ:          "PSRLDQ",
+	x86_PSRLQ:           "PSRLQ",
+	x86_PSRLW:           "PSRLW",
+	x86_PSUBB:           "PSUBB",
+	x86_PSUBD:           "PSUBD",
+	x86_PSUBQ:           "PSUBQ",
+	x86_PSUBSB:          "PSUBSB",
+	x86_PSUBSW:          "PSUBSW",
+	x86_PSUBUSB:         "PSUBUSB",
+	x86_PSUBUSW:         "PSUBUSW",
+	x86_PSUBW:           "PSUBW",
+	x86_PTEST:           "PTEST",
+	x86_PUNPCKHBW:       "PUNPCKHBW",
+	x86_PUNPCKHDQ:       "PUNPCKHDQ",
+	x86_PUNPCKHQDQ:      "PUNPCKHQDQ",
+	x86_PUNPCKHWD:       "PUNPCKHWD",
+	x86_PUNPCKLBW:       "PUNPCKLBW",
+	x86_PUNPCKLDQ:       "PUNPCKLDQ",
+	x86_PUNPCKLQDQ:      "PUNPCKLQDQ",
+	x86_PUNPCKLWD:       "PUNPCKLWD",
+	x86_PUSH:            "PUSH",
+	x86_PUSHA:           "PUSHA",
+	x86_PUSHAD:          "PUSHAD",
+	x86_PUSHF:           "PUSHF",
+	x86_PUSHFD:          "PUSHFD",
+	x86_PUSHFQ:          "PUSHFQ",
+	x86_PXOR:            "PXOR",
+	x86_RCL:             "RCL",
+	x86_RCPPS:           "RCPPS",
+	x86_RCPSS:           "RCPSS",
+	x86_RCR:             "RCR",
+	x86_RDFSBASE:        "RDFSBASE",
+	x86_RDGSBASE:        "RDGSBASE",
+	x86_RDMSR:           "RDMSR",
+	x86_RDPMC:           "RDPMC",
+	x86_RDRAND:          "RDRAND",
+	x86_RDTSC:           "RDTSC",
+	x86_RDTSCP:          "RDTSCP",
+	x86_RET:             "RET",
+	x86_ROL:             "ROL",
+	x86_ROR:             "ROR",
+	x86_ROUNDPD:         "ROUNDPD",
+	x86_ROUNDPS:         "ROUNDPS",
+	x86_ROUNDSD:         "ROUNDSD",
+	x86_ROUNDSS:         "ROUNDSS",
+	x86_RSM:             "RSM",
+	x86_RSQRTPS:         "RSQRTPS",
+	x86_RSQRTSS:         "RSQRTSS",
+	x86_SAHF:            "SAHF",
+	x86_SAR:             "SAR",
+	x86_SBB:             "SBB",
+	x86_SCASB:           "SCASB",
+	x86_SCASD:           "SCASD",
+	x86_SCASQ:           "SCASQ",
+	x86_SCASW:           "SCASW",
+	x86_SETA:            "SETA",
+	x86_SETAE:           "SETAE",
+	x86_SETB:            "SETB",
+	x86_SETBE:           "SETBE",
+	x86_SETE:            "SETE",
+	x86_SETG:            "SETG",
+	x86_SETGE:           "SETGE",
+	x86_SETL:            "SETL",
+	x86_SETLE:           "SETLE",
+	x86_SETNE:           "SETNE",
+	x86_SETNO:           "SETNO",
+	x86_SETNP:           "SETNP",
+	x86_SETNS:           "SETNS",
+	x86_SETO:            "SETO",
+	x86_SETP:            "SETP",
+	x86_SETS:            "SETS",
+	x86_SFENCE:          "SFENCE",
+	x86_SGDT:            "SGDT",
+	x86_SHL:             "SHL",
+	x86_SHLD:            "SHLD",
+	x86_SHR:             "SHR",
+	x86_SHRD:            "SHRD",
+	x86_SHUFPD:          "SHUFPD",
+	x86_SHUFPS:          "SHUFPS",
+	x86_SIDT:            "SIDT",
+	x86_SLDT:            "SLDT",
+	x86_SMSW:            "SMSW",
+	x86_SQRTPD:          "SQRTPD",
+	x86_SQRTPS:          "SQRTPS",
+	x86_SQRTSD:          "SQRTSD",
+	x86_SQRTSS:          "SQRTSS",
+	x86_STC:             "STC",
+	x86_STD:             "STD",
+	x86_STI:             "STI",
+	x86_STMXCSR:         "STMXCSR",
+	x86_STOSB:           "STOSB",
+	x86_STOSD:           "STOSD",
+	x86_STOSQ:           "STOSQ",
+	x86_STOSW:           "STOSW",
+	x86_STR:             "STR",
+	x86_SUB:             "SUB",
+	x86_SUBPD:           "SUBPD",
+	x86_SUBPS:           "SUBPS",
+	x86_SUBSD:           "SUBSD",
+	x86_SUBSS:           "SUBSS",
+	x86_SWAPGS:          "SWAPGS",
+	x86_SYSCALL:         "SYSCALL",
+	x86_SYSENTER:        "SYSENTER",
+	x86_SYSEXIT:         "SYSEXIT",
+	x86_SYSRET:          "SYSRET",
+	x86_TEST:            "TEST",
+	x86_TZCNT:           "TZCNT",
+	x86_UCOMISD:         "UCOMISD",
+	x86_UCOMISS:         "UCOMISS",
+	x86_UD1:             "UD1",
+	x86_UD2:             "UD2",
+	x86_UNPCKHPD:        "UNPCKHPD",
+	x86_UNPCKHPS:        "UNPCKHPS",
+	x86_UNPCKLPD:        "UNPCKLPD",
+	x86_UNPCKLPS:        "UNPCKLPS",
+	x86_VERR:            "VERR",
+	x86_VERW:            "VERW",
+	x86_WBINVD:          "WBINVD",
+	x86_WRFSBASE:        "WRFSBASE",
+	x86_WRGSBASE:        "WRGSBASE",
+	x86_WRMSR:           "WRMSR",
+	x86_XABORT:          "XABORT",
+	x86_XADD:            "XADD",
+	x86_XBEGIN:          "XBEGIN",
+	x86_XCHG:            "XCHG",
+	x86_XEND:            "XEND",
+	x86_XGETBV:          "XGETBV",
+	x86_XLATB:           "XLATB",
+	x86_XOR:             "XOR",
+	x86_XORPD:           "XORPD",
+	x86_XORPS:           "XORPS",
+	x86_XRSTOR:          "XRSTOR",
+	x86_XRSTOR64:        "XRSTOR64",
+	x86_XRSTORS:         "XRSTORS",
+	x86_XRSTORS64:       "XRSTORS64",
+	x86_XSAVE:           "XSAVE",
+	x86_XSAVE64:         "XSAVE64",
+	x86_XSAVEC:          "XSAVEC",
+	x86_XSAVEC64:        "XSAVEC64",
+	x86_XSAVEOPT:        "XSAVEOPT",
+	x86_XSAVEOPT64:      "XSAVEOPT64",
+	x86_XSAVES:          "XSAVES",
+	x86_XSAVES64:        "XSAVES64",
+	x86_XSETBV:          "XSETBV",
+	x86_XTEST:           "XTEST",
+}
diff --git a/src/cmd/pack/Makefile b/src/cmd/pack/Makefile
deleted file mode 100644
index 3f528d7..0000000
--- a/src/cmd/pack/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/pack/ar.c b/src/cmd/pack/ar.c
deleted file mode 100644
index 5b300db..0000000
--- a/src/cmd/pack/ar.c
+++ /dev/null
@@ -1,1727 +0,0 @@
-// Inferno utils/iar/ar.c
-// http://code.google.com/p/inferno-os/source/browse/utils/iar/ar.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-/*
- * ar - portable (ascii) format version
- */
-
-/* protect a couple of our names */
-#define select your_select
-#define rcmd your_rcmd
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-#include "../../libmach/obj.h"
-#include <ar.h>
-
-#undef select
-#undef rcmd
-
-/*
- *	The algorithm uses up to 3 temp files.  The "pivot member" is the
- *	archive member specified by and a, b, or i option.  The temp files are
- *	astart - contains existing members up to and including the pivot member.
- *	amiddle - contains new files moved or inserted behind the pivot.
- *	aend - contains the existing members that follow the pivot member.
- *	When all members have been processed, function 'install' streams the
- * 	temp files, in order, back into the archive.
- */
-
-typedef struct	Arsymref
-{
-	char	*name;
-	char *file;
-	int	type;
-	int	len;
-	vlong	offset;
-	struct	Arsymref *next;
-} Arsymref;
-
-typedef struct	Armember	/* Temp file entry - one per archive member */
-{
-	struct Armember	*next;
-	struct ar_hdr	hdr;
-	long		size;
-	long		date;
-	void		*member;
-} Armember;
-
-typedef	struct Arfile		/* Temp file control block - one per tempfile */
-{
-	char	*fname;		/* paging file name */
-	vlong	size;
-	Armember *head;		/* head of member chain */
-	Armember *tail;		/* tail of member chain */
-	Arsymref *sym;		/* head of defined symbol chain */
-} Arfile;
-
-typedef struct Hashchain
-{
-	char	*name;
-	char *file;
-	struct Hashchain *next;
-} Hashchain;
-
-#define	NHASH	1024
-
-/*
- *	macro to portably read/write archive header.
- *	'cmd' is read/write/Bread/Bwrite, etc.
- */
-#define	HEADER_IO(cmd, f, h)	cmd(f, h.name, sizeof(h.name)) != sizeof(h.name)\
-				|| cmd(f, h.date, sizeof(h.date)) != sizeof(h.date)\
-				|| cmd(f, h.uid, sizeof(h.uid)) != sizeof(h.uid)\
-				|| cmd(f, h.gid, sizeof(h.gid)) != sizeof(h.gid)\
-				|| cmd(f, h.mode, sizeof(h.mode)) != sizeof(h.mode)\
-				|| cmd(f, h.size, sizeof(h.size)) != sizeof(h.size)\
-				|| cmd(f, h.fmag, sizeof(h.fmag)) != sizeof(h.fmag)
-
-		/* constants and flags */
-char	*man =		"mrxtdpq";
-char	*opt =		"uvnbailogS";
-char	artemp[] =	"/tmp/vXXXXX";
-char	movtemp[] =	"/tmp/v1XXXXX";
-char	tailtemp[] =	"/tmp/v2XXXXX";
-char	symdef[] =	"__.GOSYMDEF";
-char	pkgdef[] =	"__.PKGDEF";
-
-int	aflag;				/* command line flags */
-int	bflag;
-int	cflag;
-int	gflag;
-int	oflag;
-int	uflag;
-int	vflag;
-int	Pflag;	/* remove leading file prefix */
-int	Sflag;	/* force mark Go package as safe */
-
-int	errors;
-
-Arfile *astart, *amiddle, *aend;	/* Temp file control block pointers */
-int	allobj = 1;			/* set when all members are object files of the same type */
-int	symdefsize;			/* size of symdef file */
-char	*pkgstmt;		/* string "package foo" */
-char	*objhdr;		/* string "go object darwin 386 release.2010-01-01 2345+" */
-int	dupfound;			/* flag for duplicate symbol */
-Hashchain	*hash[NHASH];		/* hash table of text symbols */
-
-#define	ARNAMESIZE	sizeof(astart->tail->hdr.name)
-
-char	poname[ARNAMESIZE+1];		/* name of pivot member */
-char	*file;				/* current file or member being worked on */
-Biobuf	bout;
-Biobuf bar;
-char	*prefix;
-int	pkgdefsafe;		/* was __.PKGDEF marked safe? */
-
-void	arcopy(Biobuf*, Arfile*, Armember*);
-int	arcreate(char*);
-void	arfree(Arfile*);
-void	arinsert(Arfile*, Armember*);
-void	*armalloc(int);
-char *arstrdup(char*);
-void	armove(Biobuf*, Arfile*, Armember*);
-void	arread(Biobuf*, Armember*);
-void	arstream(int, Arfile*);
-int	arwrite(int, Armember*);
-int	bamatch(char*, char*);
-int	duplicate(char*, char**);
-Armember *getdir(Biobuf*);
-void	getpkgdef(char**, int*);
-void	install(char*, Arfile*, Arfile*, Arfile*, int);
-void	loadpkgdata(char*, int);
-void	longt(Armember*);
-int	match(int, char**);
-void	mesg(int, char*);
-Arfile	*newtempfile(char*);
-Armember *newmember(void);
-void	objsym(Sym*, void*);
-int	openar(char*, int, int);
-void	pmode(long);
-void	rl(int);
-void	scanobj(Biobuf*, Arfile*, long);
-void	scanpkg(Biobuf*, long);
-void	select(int*, long);
-void	setcom(void(*)(char*, int, char**));
-void	skip(Biobuf*, vlong);
-void	checksafe(Biobuf*, vlong);
-int	symcomp(void*, void*);
-void	trim(char*, char*, int);
-void	usage(void);
-void	wrerr(void);
-void	wrsym(Biobuf*, long, Arsymref*);
-int	arread_cutprefix(Biobuf*, Armember*);
-
-void	rcmd(char*, int, char**);		/* command processing */
-void	dcmd(char*, int, char**);
-void	xcmd(char*, int, char**);
-void	tcmd(char*, int, char**);
-void	pcmd(char*, int, char**);
-void	mcmd(char*, int, char**);
-void	qcmd(char*, int, char**);
-void	(*comfun)(char*, int, char**);
-
-void
-main(int argc, char *argv[])
-{
-	char *cp;
-
-	Binit(&bout, 1, OWRITE);
-	if(argc < 3)
-		usage();
-	for (cp = argv[1]; *cp; cp++) {
-		switch(*cp) {
-		case 'a':	aflag = 1;	break;
-		case 'b':	bflag = 1;	break;
-		case 'c':	cflag = 1;	break;
-		case 'd':	setcom(dcmd);	break;
-		case 'g':	gflag = 1; break;
-		case 'i':	bflag = 1;	break;
-		case 'l':
-				strcpy(artemp, "vXXXXX");
-				strcpy(movtemp, "v1XXXXX");
-				strcpy(tailtemp, "v2XXXXX");
-				break;
-		case 'm':	setcom(mcmd);	break;
-		case 'o':	oflag = 1;	break;
-		case 'p':	setcom(pcmd);	break;
-		case 'q':	setcom(qcmd);	break;
-		case 'r':	setcom(rcmd);	break;
-		case 't':	setcom(tcmd);	break;
-		case 'u':	uflag = 1;	break;
-		case 'v':	vflag = 1;	break;
-		case 'x':	setcom(xcmd);	break;
-		case 'S':	Sflag = 1;  break;
-		case 'P':	Pflag = 1;  break;
-		default:
-			fprint(2, "pack: bad option `%c'\n", *cp);
-			exits("error");
-		}
-	}
-	if (aflag && bflag) {
-		fprint(2, "pack: only one of 'a' and 'b' can be specified\n");
-		usage();
-	}
-	if(aflag || bflag) {
-		trim(argv[2], poname, sizeof(poname));
-		argv++;
-		argc--;
-		if(argc < 3)
-			usage();
-	}
-	if(Pflag) {
-		if(argc < 4) {
-			fprint(2, "pack: P flag requires prefix argument\n");
-			usage();
-		}
-		prefix = argv[2];
-		argv++;
-		argc--;
-	}
-	if(comfun == 0) {
-		if(uflag == 0) {
-			fprint(2, "pack: one of [%s] must be specified\n", man);
-			usage();
-		}
-		setcom(rcmd);
-	}
-	cp = argv[2];
-	argc -= 3;
-	argv += 3;
-	(*comfun)(cp, argc, argv);	/* do the command */
-	if(errors && cflag)
-		remove(cp);
-	cp = 0;
-	while (argc--) {
-		if (*argv) {
-			fprint(2, "pack: %s not found\n", *argv);
-			cp = "error";
-		}
-		argv++;
-	}
-	if (errors)
-		cp = "error";
-	exits(cp);
-}
-/*
- *	select a command
- */
-void
-setcom(void (*fun)(char *, int, char**))
-{
-
-	if(comfun != 0) {
-		fprint(2, "pack: only one of [%s] allowed\n", man);
-		usage();
-	}
-	comfun = fun;
-}
-/*
- *	perform the 'r' and 'u' commands
- */
-void
-rcmd(char *arname, int count, char **files)
-{
-	int fd;
-	int i;
-	Arfile *ap;
-	Armember *bp;
-	Dir *d;
-	Biobuf *bfile;
-
-	fd = openar(arname, ORDWR, 1);
-	if (fd >= 0) {
-		Binit(&bar, fd, OREAD);
-		Bseek(&bar,seek(fd,0,1), 1);
-	}
-	astart = newtempfile(artemp);
-	ap = astart;
-	aend = 0;
-	for(i = 0; fd >= 0; i++) {
-		bp = getdir(&bar);
-		if (!bp)
-			break;
-		if (bamatch(file, poname)) {		/* check for pivot */
-			aend = newtempfile(tailtemp);
-			ap = aend;
-		}
-			/* pitch symdef file */
-		if (i == 0 && strcmp(file, symdef) == 0) {
-			skip(&bar, bp->size);
-			continue;
-		}
-			/* pitch pkgdef file but remember whether it was marked safe */
-		if (gflag && strcmp(file, pkgdef) == 0) {
-			checksafe(&bar, bp->size);
-			continue;
-		}
-		/*
-		 * the plan 9 ar treats count == 0 as equivalent
-		 * to listing all the archive's files on the command line:
-		 * it will try to open every file name in the archive
-		 * and copy that file into the archive if it exists.
-		 * for go we disable that behavior, because we use
-		 * r with no files to make changes to the archive itself,
-		 * using the S or P flags.
-		 */
-		if (!match(count, files)) {
-			scanobj(&bar, ap, bp->size);
-			arcopy(&bar, ap, bp);
-			continue;
-		}
-		bfile = Bopen(file, OREAD);
-		if (!bfile) {
-			if (count != 0) {
-				fprint(2, "pack: cannot open %s\n", file);
-				errors++;
-			}
-			scanobj(&bar, ap, bp->size);
-			arcopy(&bar, ap, bp);
-			continue;
-		}
-		d = dirfstat(Bfildes(bfile));
-		if(d == nil)
-			fprint(2, "pack: cannot stat %s: %r\n", file);
-		if (uflag && (d==nil || d->mtime <= bp->date)) {
-			scanobj(&bar, ap, bp->size);
-			arcopy(&bar, ap, bp);
-			Bterm(bfile);
-			free(d);
-			continue;
-		}
-		mesg('r', file);
-		skip(&bar, bp->size);
-		scanobj(bfile, ap, d->length);
-		free(d);
-		armove(bfile, ap, bp);
-		Bterm(bfile);
-	}
-	if(fd >= 0)
-		close(fd);
-		/* copy in remaining files named on command line */
-	for (i = 0; i < count; i++) {
-		file = files[i];
-		if(file == 0)
-			continue;
-		files[i] = 0;
-		bfile = Bopen(file, OREAD);
-		if (!bfile) {
-			fprint(2, "pack: cannot open %s\n", file);
-			errors++;
-		} else {
-			mesg('a', file);
-			d = dirfstat(Bfildes(bfile));
-			if (d == nil)
-				fprint(2, "can't stat %s\n", file);
-			else {
-				scanobj(bfile, astart, d->length);
-				armove(bfile, astart, newmember());
-				free(d);
-			}
-			Bterm(bfile);
-		}
-	}
-	if(fd < 0 && !cflag)
-		install(arname, astart, 0, aend, 1);	/* issue 'creating' msg */
-	else
-		install(arname, astart, 0, aend, 0);
-}
-
-void
-dcmd(char *arname, int count, char **files)
-{
-	Armember *bp;
-	int fd, i;
-
-	if (!count)
-		return;
-	fd = openar(arname, ORDWR, 0);
-	Binit(&bar, fd, OREAD);
-	Bseek(&bar,seek(fd,0,1), 1);
-	astart = newtempfile(artemp);
-	for (i = 0; bp = getdir(&bar); i++) {
-		if(match(count, files)) {
-			mesg('d', file);
-			skip(&bar, bp->size);
-			if (strcmp(file, symdef) == 0)
-				allobj = 0;
-		} else if (i == 0 && strcmp(file, symdef) == 0) {
-			skip(&bar, bp->size);
-		} else if (gflag && strcmp(file, pkgdef) == 0) {
-			skip(&bar, bp->size);
-		} else {
-			scanobj(&bar, astart, bp->size);
-			arcopy(&bar, astart, bp);
-		}
-	}
-	close(fd);
-	install(arname, astart, 0, 0, 0);
-}
-
-void
-xcmd(char *arname, int count, char **files)
-{
-	int fd, f, mode, i;
-	Armember *bp;
-	Dir dx;
-
-	fd = openar(arname, OREAD, 0);
-	Binit(&bar, fd, OREAD);
-	Bseek(&bar,seek(fd,0,1), 1);
-	i = 0;
-	while (bp = getdir(&bar)) {
-		if(count == 0 || match(count, files)) {
-			mode = strtoul(bp->hdr.mode, 0, 8) & 0777;
-			f = create(file, OWRITE, mode);
-			if(f < 0) {
-				fprint(2, "pack: %s cannot create\n", file);
-				skip(&bar, bp->size);
-			} else {
-				mesg('x', file);
-				arcopy(&bar, 0, bp);
-				if (write(f, bp->member, bp->size) < 0)
-					wrerr();
-				if(oflag && bp->date != 0) {
-					nulldir(&dx);
-					dx.atime = bp->date;
-					dx.mtime = bp->date;
-					if(dirwstat(file, &dx) < 0)
-						perror(file);
-				}
-				free(bp->member);
-				close(f);
-			}
-			free(bp);
-			if (count && ++i >= count)
-				break;
-		} else {
-			skip(&bar, bp->size);
-			free(bp);
-		}
-	}
-	close(fd);
-}
-void
-pcmd(char *arname, int count, char **files)
-{
-	int fd;
-	Armember *bp;
-
-	fd = openar(arname, OREAD, 0);
-	Binit(&bar, fd, OREAD);
-	Bseek(&bar,seek(fd,0,1), 1);
-	while(bp = getdir(&bar)) {
-		if(count == 0 || match(count, files)) {
-			if(vflag)
-				print("\n<%s>\n\n", file);
-			arcopy(&bar, 0, bp);
-			if (write(1, bp->member, bp->size) < 0)
-				wrerr();
-		} else
-			skip(&bar, bp->size);
-		free(bp);
-	}
-	close(fd);
-}
-void
-mcmd(char *arname, int count, char **files)
-{
-	int fd, i;
-	Arfile *ap;
-	Armember *bp;
-
-	if (count == 0)
-		return;
-	fd = openar(arname, ORDWR, 0);
-	Binit(&bar, fd, OREAD);
-	Bseek(&bar,seek(fd,0,1), 1);
-	astart = newtempfile(artemp);
-	amiddle = newtempfile(movtemp);
-	aend = 0;
-	ap = astart;
-	for (i = 0; bp = getdir(&bar); i++) {
-		if (bamatch(file, poname)) {
-			aend = newtempfile(tailtemp);
-			ap = aend;
-		}
-		if(match(count, files)) {
-			mesg('m', file);
-			scanobj(&bar, amiddle, bp->size);
-			arcopy(&bar, amiddle, bp);
-		} else if (ap == astart && i == 0 && strcmp(file, symdef) == 0) {
-			/*
-			 * pitch the symdef file if it is at the beginning
-			 * of the archive and we aren't inserting in front
-			 * of it (ap == astart).
-			 */
-			skip(&bar, bp->size);
-		} else if (ap == astart && gflag && strcmp(file, pkgdef) == 0) {
-			/*
-			 * pitch the pkgdef file if we aren't inserting in front
-			 * of it (ap == astart).
-			 */
-			skip(&bar, bp->size);
-		} else {
-			scanobj(&bar, ap, bp->size);
-			arcopy(&bar, ap, bp);
-		}
-	}
-	close(fd);
-	if (poname[0] && aend == 0)
-		fprint(2, "pack: %s not found - files moved to end.\n", poname);
-	install(arname, astart, amiddle, aend, 0);
-}
-void
-tcmd(char *arname, int count, char **files)
-{
-	int fd;
-	Armember *bp;
-	char name[ARNAMESIZE+1];
-
-	fd = openar(arname, OREAD, 0);
-	Binit(&bar, fd, OREAD);
-	Bseek(&bar,seek(fd,0,1), 1);
-	while(bp = getdir(&bar)) {
-		if(count == 0 || match(count, files)) {
-			if(vflag)
-				longt(bp);
-			trim(file, name, ARNAMESIZE);
-			Bprint(&bout, "%s\n", name);
-		}
-		skip(&bar, bp->size);
-		free(bp);
-	}
-	close(fd);
-}
-void
-qcmd(char *arname, int count, char **files)
-{
-	int fd, i;
-	Armember *bp;
-	Biobuf *bfile;
-
-	if(aflag || bflag) {
-		fprint(2, "pack: abi not allowed with q\n");
-		exits("error");
-	}
-	fd = openar(arname, ORDWR, 1);
-	if (fd < 0) {
-		if(!cflag)
-			fprint(2, "pack: creating %s\n", arname);
-		fd = arcreate(arname);
-	}
-	Binit(&bar, fd, OREAD);
-	Bseek(&bar,seek(fd,0,1), 1);
-	/* leave note group behind when writing archive; i.e. sidestep interrupts */
-	rfork(RFNOTEG);
-	Bseek(&bar, 0, 2);
-	bp = newmember();
-	for(i=0; i<count && files[i]; i++) {
-		file = files[i];
-		files[i] = 0;
-		bfile = Bopen(file, OREAD);
-		if(!bfile) {
-			fprint(2, "pack: cannot open %s\n", file);
-			errors++;
-		} else {
-			mesg('q', file);
-			armove(bfile, 0, bp);
-			if (!arwrite(fd, bp))
-				wrerr();
-			free(bp->member);
-			bp->member = 0;
-			Bterm(bfile);
-		}
-	}
-	free(bp);
-	close(fd);
-}
-
-/*
- *	does the object header line p match the last one we saw?
- *	update *lastp if it gets more specific.
- */
-int
-matchhdr(char *p, char **lastp)
-{
-	int n;
-	char *last;
-	
-	// no information?
-	last = *lastp;
-	if(last == nil) {
-		*lastp = strdup(p);
-		return 1;
-	}
-
-	// identical match?
-	if(strcmp(last, p) == 0)
-		return 1;
-
-	// last has extra fields
-	n = strlen(p);
-	if(n < strlen(last) && last[n] == ' ')
-		return 1;
-
-	// p has extra fields - save in last
-	n = strlen(last);
-	if(n < strlen(p) && p[n] == ' ') {
-		free(last);
-		*lastp = strdup(p);
-		return 1;
-	}
-	
-	return 0;
-}	
-
-/*
- *	extract the symbol references from an object file
- */
-void
-scanobj(Biobuf *b, Arfile *ap, long size)
-{
-	int obj, goobject;
-	vlong offset, offset1;
-	Dir *d;
-	static int lastobj = -1;
-	uchar buf[4];
-	char *p;
-
-	if (!allobj)			/* non-object file encountered */
-		return;
-	offset = Boffset(b);
-	obj = objtype(b, 0);
-	if (obj < 0) {			/* not an object file */
-		/* maybe a foreign object file */
-		Bseek(b, offset, 0);
-		memset(buf, 0, sizeof buf);
-		Bread(b, buf, 4);
-		
-		/* maybe a foreign object file?  that's okay */
-		if((buf[0] == 0x7F && buf[1] == 'E' && buf[2] == 'L' && buf[3] == 'F') ||   // ELF
-		   (buf[0] == 0x4c && buf[1] == 0x01 || buf[0] == 0x64 && buf[1] == 0x86) || // Windows PE
-		   (buf[0] == 0xFE && buf[1] == 0xED && buf[2] == 0xFA && (buf[3]&~1) == 0xCE) ||  // Mach-O big-endian
-		   (buf[3] == 0xFE && buf[2] == 0xED && buf[1] == 0xFA && (buf[0]&~1) == 0xCE)) {  // Mach-O little-endian
-			Bseek(b, offset, 0);
-			return;
-		}
-		
-		if (!gflag || strcmp(file, pkgdef) != 0) {  /* don't clear allobj if it's pkg defs */
-			fprint(2, "pack: non-object file %s\n", file);
-			errors++;
-			allobj = 0;
-		}
-		d = dirfstat(Bfildes(b));
-		if (d != nil && d->length == 0) {
-			fprint(2, "pack: zero length file %s\n", file);
-			errors++;
-		}
-		free(d);
-		Bseek(b, offset, 0);
-		return;
-	}
-
-	goobject = 1;
-	offset1 = Boffset(b);
-	Bseek(b, offset, 0);
-	p = Brdstr(b, '\n', 1);
-	
-	// After the go object header comes the Go metadata,
-	// followed by ! on a line by itself.  If this is not a Go object,
-	// the ! comes immediately.  Catch that so we can avoid
-	// the call to scanpkg below, since scanpkg assumes that the
-	// Go metadata is present.
-	if(BGETC(b) == '!')
-		goobject = 0;
-
-	Bseek(b, offset1, 0);
-	if(p == nil || strncmp(p, "go object ", 10) != 0) {
-		fprint(2, "pack: malformed object file %s\n", file);
-		errors++;
-		Bseek(b, offset, 0);
-		free(p);
-		return;
-	}
-	
-	if (!matchhdr(p, &objhdr)) {
-		fprint(2, "pack: inconsistent object file %s: [%s] vs [%s]\n", file, p, objhdr);
-		errors++;
-		allobj = 0;
-		free(p);
-		return;
-	}
-	free(p);
-
-	// Old check.  Should be impossible since objhdrs match, but keep the check anyway.
-	if (lastobj >= 0 && obj != lastobj) {
-		fprint(2, "pack: inconsistent object file %s\n", file);
-		errors++;
-		allobj = 0;
-		return;
-	}
-	lastobj = obj;
-		
-	if (!readar(b, obj, offset+size, 0)) {
-		fprint(2, "pack: invalid symbol reference in file %s\n", file);
-		errors++;
-		allobj = 0;
-		Bseek(b, offset, 0);
-		return;
-	}
-	Bseek(b, offset, 0);
-	objtraverse(objsym, ap);
-	if (gflag && goobject) {
-		scanpkg(b, size);
-		Bseek(b, offset, 0);
-	}
-}
-
-/*
- *	does line contain substring (length-limited)
- */
-int
-strstrn(char *line, int len, char *sub)
-{
-	int i;
-	int sublen;
-
-	sublen = strlen(sub);
-	for (i = 0; i < len - sublen; i++)
-		if (memcmp(line+i, sub, sublen) == 0)
-			return 1;
-	return 0;
-}
-
-/*
- *	package import data
- */
-int	safe = 1;
-char*	pkgname;
-char*	importblock;
-
-void
-getpkgdef(char **datap, int *lenp)
-{
-	char *tag, *hdr;
-
-	if(pkgname == nil) {
-		pkgname = "__emptyarchive__";
-		importblock = "";
-	}
-	
-	tag = "";
-	if(safe || Sflag)
-		tag = "safe";
-
-	hdr = "empty archive";
-	if(objhdr != nil)
-		hdr = objhdr;
-
-	*datap = smprint("%s\nimport\n$$\npackage %s %s\n%s\n$$\n", hdr, pkgname, tag, importblock);
-	*lenp = strlen(*datap);
-}
-
-/*
- *	extract the package definition data from an object file.
- *	there can be only one.
- */
-void
-scanpkg(Biobuf *b, long size)
-{
-	long n;
-	int c;
-	long start, end, pkgsize;
-	char *data, *line, pkgbuf[1024], *pkg;
-	int first;
-
-	/*
-	 * scan until $$
-	 */
-	for (n=0; n<size; ) {
-		c = BGETC(b);
-		if(c == Beof)
-			break;
-		n++;
-		if(c != '$')
-			continue;
-		c = BGETC(b);
-		if(c == Beof)
-			break;
-		n++;
-		if(c != '$')
-			continue;
-		goto foundstart;
-	}
-	// fprint(2, "pack: warning: no package import section in %s\n", file);
-	if(b != &bar || !pkgdefsafe)
-		safe = 0;	// non-Go file (C or assembly)
-	return;
-
-foundstart:
-	/* found $$; skip rest of line */
-	while((c = BGETC(b)) != '\n')
-		if(c == Beof)
-			goto bad;
-
-	/* how big is it? */
-	first = 1;
-	start = end = 0;
-	for (n=0; n<size; n+=Blinelen(b)) {
-		line = Brdstr(b, '\n', 0);
-		if (line == nil)
-			goto bad;
-		if (first && strstrn(line, Blinelen(b), "package ")) {
-			if (Blinelen(b) > sizeof(pkgbuf)-1)
-				goto bad;
-			memmove(pkgbuf, line, Blinelen(b));
-			pkgbuf[Blinelen(b)] = '\0';
-			pkg = pkgbuf;
-			while(*pkg == ' ' || *pkg == '\t')
-				pkg++;
-			if(strncmp(pkg, "package ", 8) != 0)
-				goto bad;
-			pkg += 8;
-			data = pkg;
-			while(*pkg != ' ' && *pkg != '\n' && *pkg != '\0')
-				pkg++;
-			pkgname = armalloc(pkg - data + 1);
-			memmove(pkgname, data, pkg - data);
-			pkgname[pkg-data] = '\0';
-			if(strcmp(pkg, " safe\n") != 0 && (b != &bar || !pkgdefsafe))
-				safe = 0;
-			start = Boffset(b);  // after package statement
-			first = 0;
-			free(line);
-			continue;
-		}
-		if(line[0] == '$' && line[1] == '$') {
-			free(line);
-			goto foundend;
-		}
-		end = Boffset(b);  // before closing $$
-		free(line);
-	}
-bad:
-	fprint(2, "pack: bad package import section in %s\n", file);
-	errors++;
-	return;
-
-foundend:
-	if (start == 0)
-		return;
-	if (end == 0)
-		goto bad;
-	if(importblock != nil) {
-		fprint(2, "pack: multiple Go object files\n");
-		errors++;
-		return;
-	}
-	pkgsize = end-start;
-	data = armalloc(end - start + 1);
-	Bseek(b, start, 0);
-	if (Bread(b, data, pkgsize) != pkgsize) {
-		fprint(2, "pack: error reading package import section in %s\n", file);
-		errors++;
-		return;
-	}
-	data[end-start] = '\0';
-	importblock = data;
-}
-
-/*
- *	add text and data symbols to the symbol list
- */
-void
-objsym(Sym *s, void *p)
-{
-	int n;
-	Arsymref *as;
-	Arfile *ap;
-	char *ofile;
-
-	if (s->type != 'T' &&  s->type != 'D')
-		return;
-	ap = (Arfile*)p;
-	as = armalloc(sizeof(Arsymref));
-	as->offset = ap->size;
-	as->name = arstrdup(s->name);
-	as->file = arstrdup(file);
-	if(s->type == 'T' && duplicate(as->name, &ofile)) {
-		dupfound = 1;
-		fprint(2, "duplicate text symbol: %s and %s: %s\n", as->file, ofile, as->name);
-		errors++;
-		free(as->name);
-		free(as);
-		return;
-	}
-	as->type = s->type;
-	n = strlen(s->name);
-	symdefsize += 4+(n+1)+1;
-	as->len = n;
-	as->next = ap->sym;
-	ap->sym = as;
-}
-
-/*
- *	Check the symbol table for duplicate text symbols
- */
-int
-hashstr(char *name)
-{
-	uint32 h;
-	char *cp;
-
-	h = 0;
-	for(cp = name; *cp; h += *cp++)
-		h *= 1119;
-	return h & 0xfffffff;
-}
-
-int
-duplicate(char *name, char **ofile)
-{
-	Hashchain *p;
-	int h;
-
-	h = hashstr(name) % NHASH;
-
-	for(p = hash[h]; p; p = p->next)
-		if(strcmp(p->name, name) == 0) {
-			*ofile = p->file;
-			return 1;
-		}
-	p = armalloc(sizeof(Hashchain));
-	p->next = hash[h];
-	p->name = name;
-	p->file = file;
-	hash[h] = p;
-	*ofile = nil;
-	return 0;
-}
-
-/*
- *	open an archive and validate its header
- */
-int
-openar(char *arname, int mode, int errok)
-{
-	int fd;
-	char mbuf[SARMAG];
-
-	fd = open(arname, mode);
-	if(fd >= 0){
-		if(read(fd, mbuf, SARMAG) != SARMAG || strncmp(mbuf, ARMAG, SARMAG)) {
-			fprint(2, "pack: %s not in archive format\n", arname);
-			exits("error");
-		}
-	}else if(!errok){
-		fprint(2, "pack: cannot open %s: %r\n", arname);
-		exits("error");
-	}
-	return fd;
-}
-
-/*
- *	create an archive and set its header
- */
-int
-arcreate(char *arname)
-{
-	int fd;
-
-	fd = create(arname, OWRITE, 0664);
-	if(fd < 0){
-		fprint(2, "pack: cannot create %s: %r\n", arname);
-		exits("error");
-	}
-	if(write(fd, ARMAG, SARMAG) != SARMAG)
-		wrerr();
-	return fd;
-}
-
-/*
- *		error handling
- */
-void
-wrerr(void)
-{
-	perror("pack: write error");
-	exits("error");
-}
-
-void
-rderr(void)
-{
-	perror("pack: read error");
-	exits("error");
-}
-
-void
-phaseerr(int offset)
-{
-	fprint(2, "pack: phase error at offset %d\n", offset);
-	exits("error");
-}
-
-void
-usage(void)
-{
-	fprint(2, "usage: pack [%s][%s][P prefix] archive files ...\n", opt, man);
-	exits("error");
-}
-
-/*
- *	read the header for the next archive member
- */
-Armember *
-getdir(Biobuf *b)
-{
-	Armember *bp;
-	char *cp;
-	static char name[ARNAMESIZE+1];
-
-	bp = newmember();
-	if(HEADER_IO(Bread, b, bp->hdr)) {
-		free(bp);
-		return 0;
-	}
-	if(strncmp(bp->hdr.fmag, ARFMAG, sizeof(bp->hdr.fmag)))
-		phaseerr(Boffset(b));
-	strncpy(name, bp->hdr.name, sizeof(bp->hdr.name));
-	cp = name+sizeof(name)-1;
-	while(*--cp==' ')
-		;
-	cp[1] = '\0';
-	file = arstrdup(name);
-	bp->date = strtol(bp->hdr.date, 0, 0);
-	bp->size = strtol(bp->hdr.size, 0, 0);
-	return bp;
-}
-
-/*
- *	Copy the file referenced by fd to the temp file
- */
-void
-armove(Biobuf *b, Arfile *ap, Armember *bp)
-{
-	char *cp;
-	Dir *d;
-	vlong n;
-
-	d = dirfstat(Bfildes(b));
-	if (d == nil) {
-		fprint(2, "pack: cannot stat %s\n", file);
-		return;
-	}
-
-	trim(file, bp->hdr.name, sizeof(bp->hdr.name));
-	for (cp = strchr(bp->hdr.name, 0);		/* blank pad on right */
-		cp < bp->hdr.name+sizeof(bp->hdr.name); cp++)
-			*cp = ' ';
-	sprint(bp->hdr.date, "%-12ld", 0L);  // was d->mtime but removed for idempotent builds
-	sprint(bp->hdr.uid, "%-6d", 0);
-	sprint(bp->hdr.gid, "%-6d", 0);
-	sprint(bp->hdr.mode, "%-8lo", d->mode);
-	sprint(bp->hdr.size, "%-10lld", d->length);
-	strncpy(bp->hdr.fmag, ARFMAG, 2);
-	bp->size = d->length;
-	arread(b, bp);
-	n = bp->size;
-	if (n&1)
-		n++;
-	if (ap) {
-		arinsert(ap, bp);
-		ap->size += n+SAR_HDR;
-	}
-	free(d);
-}
-
-/*
- *	Copy the archive member at the current offset into the temp file.
- */
-void
-arcopy(Biobuf *b, Arfile *ap, Armember *bp)
-{
-	long n;
-
-	arread(b, bp);
-	n = bp->size;
-	if (n & 01)
-		n++;
-	if (ap) {
-		arinsert(ap, bp);
-		ap->size += n+SAR_HDR;
-	}
-}
-
-/*
- *	Skip an archive member
- */
-void
-skip(Biobuf *bp, vlong len)
-{
-	if (len & 01)
-		len++;
-	Bseek(bp, len, 1);
-}
-
-void
-checksafe(Biobuf *bp, vlong len)
-{
-	char *p;
-	vlong end;
-
-	if (len & 01)
-		len++;
-	end = Boffset(bp) + len;
-
-	p = Brdline(bp, '\n');
-	if(p == nil || strncmp(p, "go object ", 10) != 0)
-		goto done;
-	for(;;) {
-		p = Brdline(bp, '\n');
-		if(p == nil || Boffset(bp) >= end)
-			goto done;
-		if(strncmp(p, "$$\n", 3) == 0)
-			break;
-	}
-	p = Brdline(bp, '\n');
-	if(p == nil || Boffset(bp) > end)
-		goto done;
-	if(Blinelen(bp) > 8+6 && strncmp(p, "package ", 8) == 0 && strncmp(p+Blinelen(bp)-6, " safe\n", 6) == 0)
-		pkgdefsafe = 1;
-
-done:
-	Bseek(bp, end, 0);
-}
-
-/*
- *	Stream the three temp files to an archive
- */
-void
-install(char *arname, Arfile *astart, Arfile *amiddle, Arfile *aend, int createflag)
-{
-	int fd;
-
-	if(allobj && dupfound) {
-		fprint(2, "%s not changed\n", arname);
-		return;
-	}
-	/* leave note group behind when copying back; i.e. sidestep interrupts */
-	rfork(RFNOTEG);
-
-	if(createflag)
-		fprint(2, "pack: creating %s\n", arname);
-	fd = arcreate(arname);
-
-	if(allobj)
-		rl(fd);
-
-	if (astart) {
-		arstream(fd, astart);
-		arfree(astart);
-	}
-	if (amiddle) {
-		arstream(fd, amiddle);
-		arfree(amiddle);
-	}
-	if (aend) {
-		arstream(fd, aend);
-		arfree(aend);
-	}
-	close(fd);
-}
-
-void
-rl(int fd)
-{
-	Biobuf b;
-	char *cp;
-	struct ar_hdr a;
-	long len;
-	int headlen;
-	char *pkgdefdata;
-	int pkgdefsize;
-
-	pkgdefdata = nil;
-	pkgdefsize = 0;
-
-	Binit(&b, fd, OWRITE);
-	Bseek(&b,seek(fd,0,1), 0);
-
-	len = symdefsize;
-	if(len&01)
-		len++;
-	sprint(a.date, "%-12ld", 0L);  // time(0)
-	sprint(a.uid, "%-6d", 0);
-	sprint(a.gid, "%-6d", 0);
-	sprint(a.mode, "%-8lo", 0644L);
-	sprint(a.size, "%-10ld", len);
-	strncpy(a.fmag, ARFMAG, 2);
-	strcpy(a.name, symdef);
-	for (cp = strchr(a.name, 0);		/* blank pad on right */
-		cp < a.name+sizeof(a.name); cp++)
-			*cp = ' ';
-	if(HEADER_IO(Bwrite, &b, a))
-			wrerr();
-
-	headlen = Boffset(&b);
-	len += headlen;
-	if (gflag) {
-		getpkgdef(&pkgdefdata, &pkgdefsize);
-		len += SAR_HDR + pkgdefsize;
-		if (len & 1)
-			len++;
-	}
-	if (astart) {
-		wrsym(&b, len, astart->sym);
-		len += astart->size;
-	}
-	if(amiddle) {
-		wrsym(&b, len, amiddle->sym);
-		len += amiddle->size;
-	}
-	if(aend)
-		wrsym(&b, len, aend->sym);
-
-	if(symdefsize&0x01)
-		BPUTC(&b, 0);
-
-	if (gflag) {
-		len = pkgdefsize;
-		sprint(a.date, "%-12ld", 0L);  // time(0)
-		sprint(a.uid, "%-6d", 0);
-		sprint(a.gid, "%-6d", 0);
-		sprint(a.mode, "%-8lo", 0644L);
-		sprint(a.size, "%-10ld", (len + 1) & ~1);
-		strncpy(a.fmag, ARFMAG, 2);
-		strcpy(a.name, pkgdef);
-		for (cp = strchr(a.name, 0);		/* blank pad on right */
-			cp < a.name+sizeof(a.name); cp++)
-				*cp = ' ';
-		if(HEADER_IO(Bwrite, &b, a))
-				wrerr();
-
-		if (Bwrite(&b, pkgdefdata, pkgdefsize) != pkgdefsize)
-			wrerr();
-		if(len&0x01)
-			BPUTC(&b, 0);
-	}
-	Bterm(&b);
-}
-
-/*
- *	Write the defined symbols to the symdef file
- */
-void
-wrsym(Biobuf *bp, long offset, Arsymref *as)
-{
-	int off;
-
-	while(as) {
-		BPUTC(bp, as->type);
-		off = as->offset+offset;
-		BPUTLE4(bp, off);
-		if (Bwrite(bp, as->name, as->len+1) != as->len+1)
-			wrerr();
-		as = as->next;
-	}
-}
-
-/*
- *	Check if the archive member matches an entry on the command line.
- */
-int
-match(int count, char **files)
-{
-	int i;
-	char name[ARNAMESIZE+1];
-
-	for(i=0; i<count; i++) {
-		if(files[i] == 0)
-			continue;
-		trim(files[i], name, ARNAMESIZE);
-		if(strncmp(name, file, ARNAMESIZE) == 0) {
-			file = files[i];
-			files[i] = 0;
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- *	compare the current member to the name of the pivot member
- */
-int
-bamatch(char *file, char *pivot)
-{
-	static int state = 0;
-
-	switch(state)
-	{
-	case 0:			/* looking for position file */
-		if (aflag) {
-			if (strncmp(file, pivot, ARNAMESIZE) == 0)
-				state = 1;
-		} else if (bflag) {
-			if (strncmp(file, pivot, ARNAMESIZE) == 0) {
-				state = 2;	/* found */
-				return 1;
-			}
-		}
-		break;
-	case 1:			/* found - after previous file */
-		state = 2;
-		return 1;
-	case 2:			/* already found position file */
-		break;
-	}
-	return 0;
-}
-
-/*
- *	output a message, if 'v' option was specified
- */
-void
-mesg(int c, char *file)
-{
-
-	if(vflag)
-		Bprint(&bout, "%c - %s\n", c, file);
-}
-
-/*
- *	isolate file name by stripping leading directories and trailing slashes
- */
-void
-trim(char *s, char *buf, int n)
-{
-	char *p, *q;
-
-	for(;;) {
-		p = strrchr(s, '/');
-		q = strrchr(s, '\\');
-		if (q > p)
-			p = q;
-		if (!p) {		/* no (back)slash in name */
-			strncpy(buf, s, n);
-			return;
-		}
-		if (p[1] != 0) {	/* p+1 is first char of file name */
-			strncpy(buf, p+1, n);
-			return;
-		}
-		*p = 0;			/* strip trailing (back)slash */
-	}
-}
-
-/*
- *	utilities for printing long form of 't' command
- */
-#define	SUID	04000
-#define	SGID	02000
-#define	ROWN	0400
-#define	WOWN	0200
-#define	XOWN	0100
-#define	RGRP	040
-#define	WGRP	020
-#define	XGRP	010
-#define	ROTH	04
-#define	WOTH	02
-#define	XOTH	01
-#define	STXT	01000
-
-void
-longt(Armember *bp)
-{
-	char *cp;
-
-	pmode(strtoul(bp->hdr.mode, 0, 8));
-	Bprint(&bout, "%3ld/%1ld", strtol(bp->hdr.uid, 0, 0), strtol(bp->hdr.gid, 0, 0));
-	Bprint(&bout, "%7ld", bp->size);
-	cp = ctime(bp->date);
-	Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24);
-}
-
-int	m1[] = { 1, ROWN, 'r', '-' };
-int	m2[] = { 1, WOWN, 'w', '-' };
-int	m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
-int	m4[] = { 1, RGRP, 'r', '-' };
-int	m5[] = { 1, WGRP, 'w', '-' };
-int	m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
-int	m7[] = { 1, ROTH, 'r', '-' };
-int	m8[] = { 1, WOTH, 'w', '-' };
-int	m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
-
-int	*m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};
-
-void
-pmode(long mode)
-{
-	int **mp;
-
-	for(mp = &m[0]; mp < &m[9];)
-		select(*mp++, mode);
-}
-
-void
-select(int *ap, long mode)
-{
-	int n;
-
-	n = *ap++;
-	while(--n>=0 && (mode&*ap++)==0)
-		ap++;
-	BPUTC(&bout, *ap);
-}
-
-/*
- *	Temp file I/O subsystem.  We attempt to cache all three temp files in
- *	core.  When we run out of memory we spill to disk.
- *	The I/O model assumes that temp files:
- *		1) are only written on the end
- *		2) are only read from the beginning
- *		3) are only read after all writing is complete.
- *	The architecture uses one control block per temp file.  Each control
- *	block anchors a chain of buffers, each containing an archive member.
- */
-Arfile *
-newtempfile(char *name)		/* allocate a file control block */
-{
-	Arfile *ap;
-
-	ap = armalloc(sizeof(Arfile));
-	ap->fname = name;
-	return ap;
-}
-
-Armember *
-newmember(void)			/* allocate a member buffer */
-{
-	return armalloc(sizeof(Armember));
-}
-
-void
-arread(Biobuf *b, Armember *bp)	/* read an image into a member buffer */
-{
-	int i;
-	vlong off;
-
-	bp->member = armalloc(bp->size);
-	
-	// If P flag is set, let arread_cutprefix try.
-	// If it succeeds, we're done.  If not, fall back
-	// to a direct copy.
-	off = Boffset(b);
-	if(Pflag && arread_cutprefix(b, bp))
-		return;
-	Bseek(b, off, 0);
-
-	i = Bread(b, bp->member, bp->size);
-	if (i < 0) {
-		free(bp->member);
-		bp->member = 0;
-		rderr();
-	}
-	if(bp->size&1)
-		BGETC(b);
-}
-
-/*
- * insert a member buffer into the member chain
- */
-void
-arinsert(Arfile *ap, Armember *bp)
-{
-	bp->next = 0;
-	if (!ap->tail)
-		ap->head = bp;
-	else
-		ap->tail->next = bp;
-	ap->tail = bp;
-}
-
-/*
- *	stream the members in a temp file to the file referenced by 'fd'.
- */
-void
-arstream(int fd, Arfile *ap)
-{
-	Armember *bp;
-
-	/* dump the in-core buffers */
-	for (bp = ap->head; bp; bp = bp->next) {
-		if (!arwrite(fd, bp))
-			wrerr();
-	}
-}
-
-/*
- *	write a member to 'fd'.
- */
-int
-arwrite(int fd, Armember *bp)
-{
-	int len;
-
-	if(HEADER_IO(write, fd, bp->hdr))
-		return 0;
-	len = bp->size;
-	if (len & 01)
-		len++;
-	if (write(fd, bp->member, len) != len)
-		return 0;
-	return 1;
-}
-
-void
-arfree(Arfile *ap)		/* free a member buffer */
-{
-	Armember *bp, *next;
-
-	for (bp = ap->head; bp; bp = next) {
-		next = bp->next;
-		if (bp->member)
-			free(bp->member);
-		free(bp);
-	}
-	free(ap);
-}
-
-/*
- *	allocate space for a control block or member buffer.  if the malloc
- *	fails we try to reclaim space by spilling previously allocated
- *	member buffers.
- */
-void *
-armalloc(int n)
-{
-	char *cp;
-
-	// bump so that arwrite can do the same
-	if(n&1)
-		n++;
-
-	cp = malloc(n);
-	if (cp) {
-		memset(cp, 0, n);
-		return cp;
-	}
-	fprint(2, "pack: out of memory\n");
-	exits("malloc");
-	return 0;
-}
-
-char *
-arstrdup(char *s)
-{
-	char *t;
-
-	t = armalloc(strlen(s) + 1);
-	strcpy(t, s);
-	return t;
-}
-
-
-/*
- *	Parts of libmach we're not supposed
- *	to look at but need for arread_cutprefix.
- */
-extern int _read5(Biobuf*, Prog*);
-extern int _read6(Biobuf*, Prog*);
-extern int _read8(Biobuf*, Prog*);
-int (*reader[256])(Biobuf*, Prog*) = {
-	[ObjArm] = _read5,
-	[ObjAmd64] = _read6,
-	[Obj386] = _read8,
-};
-
-#define isdelim(c) ((c) == '/' || (c) == '\\')
-
-/*
- *	check if p is start of windows full path, like C:\ or c:/.
- *	return 1 if so. also set drive parameter to its
- *	upper-case drive letter.
- */
-int
-iswinpathstart(char *p, char *drive)
-{
-	if('A' <= p[0] || p[0] <= 'Z')
-		*drive = p[0];
-	else if('a' <= p[0] || p[0] <= 'z')
-		*drive = p[0] - ('a' - 'A');
-	else
-		return 0;
-	return p[1] == ':' && isdelim(p[2]);
-}
-
-/*
- *	copy b into bp->member but rewrite object
- *	during copy to drop prefix from all file names.
- *	return 1 if b was recognized as an object file
- *	and copied successfully, 0 otherwise.
- */
-int
-arread_cutprefix(Biobuf *b, Armember *bp)
-{
-	vlong offset, o, end;
-	int n, t;
-	int (*rd)(Biobuf*, Prog*);
-	char *w, *inprefix, d1, d2;
-	Prog p;
-	
-	offset = Boffset(b);
-	end = offset + bp->size;
-	t = objtype(b, nil);
-	if(t < 0)
-		return 0;
-	if((rd = reader[t]) == nil)
-		return 0;
-	
-	// copy header
-	w = bp->member;
-	n = Boffset(b) - offset;
-	Bseek(b, -n, 1);
-	if(Bread(b, w, n) != n)
-		return 0;
-	offset += n;
-	w += n;
-	
-	// read object file one pseudo-instruction at a time,
-	// eliding the file name instructions that refer to
-	// the prefix.
-	memset(&p, 0, sizeof p);
-	inprefix = nil;
-	while(Boffset(b) < end && rd(b, &p)) {
-		if(p.kind == aName && p.type == UNKNOWN && p.sym == 1 && p.id[0] == '<') {
-			// part of a file path.
-			// we'll keep continuing (skipping the copy)
-			// around the loop until either we get to a
-			// name piece that should be kept or we see
-			// the whole prefix.
-
-			if(inprefix == nil && prefix[0] == '/' && p.id[1] == '/' && p.id[2] == '\0') {
-				// leading /
-				inprefix = prefix+1;
-			} else if(inprefix == nil && iswinpathstart(prefix, &d1) && iswinpathstart(p.id + 1, &d2) && d1 == d2 && p.id[4] == '\0') {
-				// leading c:\ ...
-				inprefix = prefix+3;
-			} else if(inprefix != nil) {
-				// handle subsequent elements
-				n = strlen(p.id+1);
-				if(strncmp(p.id+1, inprefix, n) == 0 && (isdelim(inprefix[n]) || inprefix[n] == '\0')) {
-					inprefix += n;
-					if(isdelim(inprefix[0]))
-						inprefix++;
-				}
-			}
-			
-			if(inprefix && inprefix[0] == '\0') {
-				// reached end of prefix.
-				// if we another path element follows,
-				// nudge the offset to skip over the prefix we saw.
-				// if not, leave offset alone, to emit the whole name.
-				// additional name elements will not be skipped
-				// because inprefix is now nil and we won't see another
-				// leading / in this name.
-				inprefix = nil;
-				o = Boffset(b);
-				if(o < end && rd(b, &p) && p.kind == aName && p.type == UNKNOWN && p.sym == 1 && p.id[0] == '<') {
-					// print("skip %lld-%lld\n", offset, o);
-					offset = o;
-				}
-			}
-		} else {
-			// didn't find the whole prefix.
-			// give up and let it emit the entire name.
-			inprefix = nil;
-		}
-
-		// copy instructions
-		if(!inprefix) {
-			n = Boffset(b) - offset;
-			Bseek(b, -n, 1);
-			if(Bread(b, w, n) != n)
-				return 0;
-			offset += n;
-			w += n;
-		}
-	}
-	bp->size = w - (char*)bp->member;
-	sprint(bp->hdr.size, "%-10lld", (vlong)bp->size);
-	strncpy(bp->hdr.fmag, ARFMAG, 2);
-	Bseek(b, end, 0);
-	if(Boffset(b)&1)
-		BGETC(b);
-	return 1;
-}
diff --git a/src/cmd/pack/doc.go b/src/cmd/pack/doc.go
index 67b7897..1529e07 100644
--- a/src/cmd/pack/doc.go
+++ b/src/cmd/pack/doc.go
@@ -1,29 +1,37 @@
-// Copyright 2009 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.
 
-// +build ignore
-
 /*
 
-Pack is a variant of the Plan 9 ar tool.  The original is documented at
+Pack is a simple version of the traditional Unix ar tool.
+It implements only the operations needed by Go.
 
-	http://plan9.bell-labs.com/magic/man2html/1/ar
+Usage:
+	go tool pack op file.a [name...]
 
-It adds a special Go-specific section __.PKGDEF that collects all the
-Go type information from the files in the archive; that section is
-used by the compiler when importing the package during compilation.
+Pack applies the operation to the archive, using the names as arguments to the operation.
 
-Usage:
-	go tool pack [uvnbailogS][mrxtdpq][P prefix] archive files ...
+The operation op is given by one of these letters:
+
+	c	append files (from the file system) to a new archive
+	p	print files from the archive
+	r	append files (from the file system) to the archive
+	t	list files from the archive
+	x	extract files from the archive
+
+For the p, t, and x commands, listing no names on the command line
+causes the operation to apply to all files in the archive.
 
-The new option 'g' causes pack to maintain the __.PKGDEF section
-as files are added to the archive.
+In contrast to Unix ar, the r operation always appends to the archive,
+even if a file with the given name already exists in the archive. In this way
+pack's r operation is more like Unix ar's rq operation.
 
-The new option 'S' forces pack to mark the archive as safe.
+Adding the letter v to an operation, as in pv or rv, enables verbose operation:
+For the c and r commands, names are printed as files are added.
+For the p command, each file is prefixed by the name on a line by itself.
+For the t command, the listing includes additional file metadata.
+For the x command, names are printed as files are extracted.
 
-The new option 'P' causes pack to remove the given prefix
-from file names in the line number information in object files
-that are already stored in or added to the archive.
 */
 package main
diff --git a/src/cmd/pack/pack.go b/src/cmd/pack/pack.go
new file mode 100644
index 0000000..5944337
--- /dev/null
+++ b/src/cmd/pack/pack.go
@@ -0,0 +1,486 @@
+// 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"
+	"errors"
+	"fmt"
+	"io"
+	"log"
+	"os"
+	"strconv"
+	"strings"
+	"time"
+	"unicode/utf8"
+)
+
+/*
+The archive format is:
+
+First, on a line by itself
+	!<arch>
+
+Then zero or more file records. Each file record has a fixed-size one-line header
+followed by data bytes followed by an optional padding byte. The header is:
+
+	%-16s%-12d%-6d%-6d%-8o%-10d`
+	name mtime uid gid mode size
+
+(note the trailing backquote). The %-16s here means at most 16 *bytes* of
+the name, and if shorter, space padded on the right.
+*/
+
+const usageMessage = `Usage: pack op file.a [name....]
+Where op is one of cprtx optionally followed by v for verbose output.
+For compatibility with old Go build environments the op string grc is
+accepted as a synonym for c.
+
+For more information, run
+	godoc cmd/pack`
+
+func usage() {
+	fmt.Fprintln(os.Stderr, usageMessage)
+	os.Exit(2)
+}
+
+func main() {
+	log.SetFlags(0)
+	log.SetPrefix("pack: ")
+	// need "pack op archive" at least.
+	if len(os.Args) < 3 {
+		log.Print("not enough arguments")
+		fmt.Fprintln(os.Stderr)
+		usage()
+	}
+	setOp(os.Args[1])
+	var ar *Archive
+	switch op {
+	case 'p':
+		ar = archive(os.Args[2], os.O_RDONLY, os.Args[3:])
+		ar.scan(ar.printContents)
+	case 'r':
+		ar = archive(os.Args[2], os.O_RDWR, os.Args[3:])
+		ar.scan(ar.skipContents)
+		ar.addFiles()
+	case 'c':
+		ar = archive(os.Args[2], os.O_RDWR|os.O_TRUNC, os.Args[3:])
+		ar.addPkgdef()
+		ar.addFiles()
+	case 't':
+		ar = archive(os.Args[2], os.O_RDONLY, os.Args[3:])
+		ar.scan(ar.tableOfContents)
+	case 'x':
+		ar = archive(os.Args[2], os.O_RDONLY, os.Args[3:])
+		ar.scan(ar.extractContents)
+	default:
+		log.Printf("invalid operation %q", os.Args[1])
+		fmt.Fprintln(os.Stderr)
+		usage()
+	}
+	if len(ar.files) > 0 {
+		log.Fatalf("file %q not in archive", ar.files[0])
+	}
+}
+
+// The unusual ancestry means the arguments are not Go-standard.
+// These variables hold the decoded operation specified by the first argument.
+// op holds the operation we are doing (prtx).
+// verbose tells whether the 'v' option was specified.
+var (
+	op      rune
+	verbose bool
+)
+
+// setOp parses the operation string (first argument).
+func setOp(arg string) {
+	// Recognize 'go tool pack grc' because that was the
+	// formerly canonical way to build a new archive
+	// from a set of input files. Accepting it keeps old
+	// build systems working with both Go 1.2 and Go 1.3.
+	if arg == "grc" {
+		arg = "c"
+	}
+
+	for _, r := range arg {
+		switch r {
+		case 'c', 'p', 'r', 't', 'x':
+			if op != 0 {
+				// At most one can be set.
+				usage()
+			}
+			op = r
+		case 'v':
+			if verbose {
+				// Can be set only once.
+				usage()
+			}
+			verbose = true
+		default:
+			usage()
+		}
+	}
+}
+
+const (
+	arHeader    = "!<arch>\n"
+	entryHeader = "%s%-12d%-6d%-6d%-8o%-10d`\n"
+	// In entryHeader the first entry, the name, is always printed as 16 bytes right-padded.
+	entryLen   = 16 + 12 + 6 + 6 + 8 + 10 + 1 + 1
+	timeFormat = "Jan _2 15:04 2006"
+)
+
+// An Archive represents an open archive file. It is always scanned sequentially
+// from start to end, without backing up.
+type Archive struct {
+	fd       *os.File // Open file descriptor.
+	files    []string // Explicit list of files to be processed.
+	pad      int      // Padding bytes required at end of current archive file
+	matchAll bool     // match all files in archive
+}
+
+// archive opens (or if necessary creates) the named archive.
+func archive(name string, mode int, files []string) *Archive {
+	fd, err := os.OpenFile(name, mode, 0)
+	if err != nil && mode&^os.O_TRUNC == os.O_RDWR && os.IsNotExist(err) {
+		fd, err = create(name)
+	}
+	if err != nil {
+		log.Fatal(err)
+	}
+	mustBeArchive(fd)
+	return &Archive{
+		fd:       fd,
+		files:    files,
+		matchAll: len(files) == 0,
+	}
+}
+
+// create creates and initializes an archive that does not exist.
+func create(name string) (*os.File, error) {
+	fd, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
+	if err != nil {
+		return nil, err
+	}
+	fmt.Fprint(fd, arHeader)
+	fd.Seek(0, 0)
+	return fd, nil
+}
+
+// mustBeArchive verifies the header of the file. It assumes the file offset
+// is 0 coming in, and leaves it positioned immediately after the header.
+func mustBeArchive(fd *os.File) {
+	buf := make([]byte, len(arHeader))
+	_, err := io.ReadFull(fd, buf)
+	if err != nil || string(buf) != arHeader {
+		log.Fatal("file is not an archive: bad header")
+	}
+}
+
+// An Entry is the internal representation of the per-file header information of one entry in the archive.
+type Entry struct {
+	name  string
+	mtime int64
+	uid   int
+	gid   int
+	mode  os.FileMode
+	size  int64
+}
+
+func (e *Entry) String() string {
+	return fmt.Sprintf("%s %6d/%-6d %12d %s %s",
+		(e.mode & 0777).String(),
+		e.uid,
+		e.gid,
+		e.size,
+		time.Unix(e.mtime, 0).Format(timeFormat),
+		e.name)
+}
+
+// readMetadata reads and parses the metadata for the next entry in the archive.
+func (ar *Archive) readMetadata() *Entry {
+	buf := make([]byte, entryLen)
+	_, err := io.ReadFull(ar.fd, buf)
+	if err == io.EOF {
+		// No entries left.
+		return nil
+	}
+	if err != nil || buf[entryLen-2] != '`' || buf[entryLen-1] != '\n' {
+		log.Fatal("file is not an archive: bad entry")
+	}
+	entry := new(Entry)
+	entry.name = strings.TrimRight(string(buf[:16]), " ")
+	if len(entry.name) == 0 {
+		log.Fatal("file is not an archive: bad name")
+	}
+	buf = buf[16:]
+	str := string(buf)
+	get := func(width, base, bitsize int) int64 {
+		v, err := strconv.ParseInt(strings.TrimRight(str[:width], " "), base, bitsize)
+		if err != nil {
+			log.Fatal("file is not an archive: bad number in entry: ", err)
+		}
+		str = str[width:]
+		return v
+	}
+	// %-16s%-12d%-6d%-6d%-8o%-10d`
+	entry.mtime = get(12, 10, 64)
+	entry.uid = int(get(6, 10, 32))
+	entry.gid = int(get(6, 10, 32))
+	entry.mode = os.FileMode(get(8, 8, 32))
+	entry.size = get(10, 10, 64)
+	return entry
+}
+
+// scan scans the archive and executes the specified action on each entry.
+// When action returns, the file offset is at the start of the next entry.
+func (ar *Archive) scan(action func(*Entry)) {
+	for {
+		entry := ar.readMetadata()
+		if entry == nil {
+			break
+		}
+		action(entry)
+	}
+}
+
+// listEntry prints to standard output a line describing the entry.
+func listEntry(ar *Archive, entry *Entry, verbose bool) {
+	if verbose {
+		fmt.Fprintf(stdout, "%s\n", entry)
+	} else {
+		fmt.Fprintf(stdout, "%s\n", entry.name)
+	}
+}
+
+// output copies the entry to the specified writer.
+func (ar *Archive) output(entry *Entry, w io.Writer) {
+	n, err := io.Copy(w, io.LimitReader(ar.fd, entry.size))
+	if err != nil {
+		log.Fatal(err)
+	}
+	if n != entry.size {
+		log.Fatal("short file")
+	}
+	if entry.size&1 == 1 {
+		_, err := ar.fd.Seek(1, 1)
+		if err != nil {
+			log.Fatal(err)
+		}
+	}
+}
+
+// skip skips the entry without reading it.
+func (ar *Archive) skip(entry *Entry) {
+	size := entry.size
+	if size&1 == 1 {
+		size++
+	}
+	_, err := ar.fd.Seek(size, 1)
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
+// match reports whether the entry matches the argument list.
+// If it does, it also drops the file from the to-be-processed list.
+func (ar *Archive) match(entry *Entry) bool {
+	if ar.matchAll {
+		return true
+	}
+	for i, name := range ar.files {
+		if entry.name == name {
+			copy(ar.files[i:], ar.files[i+1:])
+			ar.files = ar.files[:len(ar.files)-1]
+			return true
+		}
+	}
+	return false
+}
+
+// addFiles adds files to the archive. The archive is known to be
+// sane and we are positioned at the end. No attempt is made
+// to check for existing files.
+func (ar *Archive) addFiles() {
+	if len(ar.files) == 0 {
+		usage()
+	}
+	for _, file := range ar.files {
+		if verbose {
+			fmt.Printf("%s\n", file)
+		}
+		fd, err := os.Open(file)
+		if err != nil {
+			log.Fatal(err)
+		}
+		ar.addFile(fd)
+	}
+	ar.files = nil
+}
+
+// FileLike abstracts the few methods we need, so we can test without needing real files.
+type FileLike interface {
+	Name() string
+	Stat() (os.FileInfo, error)
+	Read([]byte) (int, error)
+	Close() error
+}
+
+// addFile adds a single file to the archive
+func (ar *Archive) addFile(fd FileLike) {
+	defer fd.Close()
+	// Format the entry.
+	// First, get its info.
+	info, err := fd.Stat()
+	if err != nil {
+		log.Fatal(err)
+	}
+	// mtime, uid, gid are all zero so repeated builds produce identical output.
+	mtime := int64(0)
+	uid := 0
+	gid := 0
+	ar.startFile(info.Name(), mtime, uid, gid, info.Mode(), info.Size())
+	n64, err := io.Copy(ar.fd, fd)
+	if err != nil {
+		log.Fatal("writing file: ", err)
+	}
+	if n64 != info.Size() {
+		log.Fatalf("writing file: wrote %d bytes; file is size %d", n64, info.Size())
+	}
+	ar.endFile()
+}
+
+// startFile writes the archive entry header.
+func (ar *Archive) startFile(name string, mtime int64, uid, gid int, mode os.FileMode, size int64) {
+	n, err := fmt.Fprintf(ar.fd, entryHeader, exactly16Bytes(name), mtime, uid, gid, mode, size)
+	if err != nil || n != entryLen {
+		log.Fatal("writing entry header: ", err)
+	}
+	ar.pad = int(size & 1)
+}
+
+// endFile writes the archive entry tail (a single byte of padding, if the file size was odd).
+func (ar *Archive) endFile() {
+	if ar.pad != 0 {
+		_, err := ar.fd.Write([]byte{0})
+		if err != nil {
+			log.Fatal("writing archive: ", err)
+		}
+		ar.pad = 0
+	}
+}
+
+// addPkgdef adds the __.PKGDEF file to the archive, copied
+// from the first Go object file on the file list, if any.
+// The archive is known to be empty.
+func (ar *Archive) addPkgdef() {
+	for _, file := range ar.files {
+		pkgdef, err := readPkgdef(file)
+		if err != nil {
+			continue
+		}
+		if verbose {
+			fmt.Printf("__.PKGDEF # %s\n", file)
+		}
+		ar.startFile("__.PKGDEF", 0, 0, 0, 0644, int64(len(pkgdef)))
+		_, err = ar.fd.Write(pkgdef)
+		if err != nil {
+			log.Fatal("writing __.PKGDEF: ", err)
+		}
+		ar.endFile()
+		break
+	}
+}
+
+// readPkgdef extracts the __.PKGDEF data from a Go object file.
+func readPkgdef(file string) (data []byte, err error) {
+	f, err := os.Open(file)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+
+	// Read from file, collecting header for __.PKGDEF.
+	// The header is from the beginning of the file until a line
+	// containing just "!". The first line must begin with "go object ".
+	rbuf := bufio.NewReader(f)
+	var wbuf bytes.Buffer
+	for {
+		line, err := rbuf.ReadBytes('\n')
+		if err != nil {
+			return nil, err
+		}
+		if wbuf.Len() == 0 && !bytes.HasPrefix(line, []byte("go object ")) {
+			return nil, errors.New("not a Go object file")
+		}
+		if bytes.Equal(line, []byte("!\n")) {
+			break
+		}
+		wbuf.Write(line)
+	}
+	return wbuf.Bytes(), nil
+}
+
+// exactly16Bytes truncates the string if necessary so it is at most 16 bytes long,
+// then pads the result with spaces to be exactly 16 bytes.
+// Fmt uses runes for its width calculation, but we need bytes in the entry header.
+func exactly16Bytes(s string) string {
+	for len(s) > 16 {
+		_, wid := utf8.DecodeLastRuneInString(s)
+		s = s[:len(s)-wid]
+	}
+	const sixteenSpaces = "                "
+	s += sixteenSpaces[:16-len(s)]
+	return s
+}
+
+// Finally, the actual commands. Each is an action.
+
+// can be modified for testing.
+var stdout io.Writer = os.Stdout
+
+// printContents implements the 'p' command.
+func (ar *Archive) printContents(entry *Entry) {
+	if ar.match(entry) {
+		if verbose {
+			listEntry(ar, entry, false)
+		}
+		ar.output(entry, stdout)
+	} else {
+		ar.skip(entry)
+	}
+}
+
+// skipContents implements the first part of the 'r' command.
+// It just scans the archive to make sure it's intact.
+func (ar *Archive) skipContents(entry *Entry) {
+	ar.skip(entry)
+}
+
+// tableOfContents implements the 't' command.
+func (ar *Archive) tableOfContents(entry *Entry) {
+	if ar.match(entry) {
+		listEntry(ar, entry, verbose)
+	}
+	ar.skip(entry)
+}
+
+// extractContents implements the 'x' command.
+func (ar *Archive) extractContents(entry *Entry) {
+	if ar.match(entry) {
+		if verbose {
+			listEntry(ar, entry, false)
+		}
+		fd, err := os.OpenFile(entry.name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, entry.mode)
+		if err != nil {
+			log.Fatal(err)
+		}
+		ar.output(entry, fd)
+		fd.Close()
+	} else {
+		ar.skip(entry)
+	}
+}
diff --git a/src/cmd/pack/pack_test.go b/src/cmd/pack/pack_test.go
new file mode 100644
index 0000000..4862426
--- /dev/null
+++ b/src/cmd/pack/pack_test.go
@@ -0,0 +1,402 @@
+// 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"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"runtime"
+	"testing"
+	"time"
+	"unicode/utf8"
+)
+
+func TestExactly16Bytes(t *testing.T) {
+	var tests = []string{
+		"",
+		"a",
+		"日本語",
+		"1234567890123456",
+		"12345678901234567890",
+		"1234567890123本語4567890",
+		"12345678901234日本語567890",
+		"123456789012345日本語67890",
+		"1234567890123456日本語7890",
+		"1234567890123456日本語7日本語890",
+	}
+	for _, str := range tests {
+		got := exactly16Bytes(str)
+		if len(got) != 16 {
+			t.Errorf("exactly16Bytes(%q) is %q, length %d", str, got, len(got))
+		}
+		// Make sure it is full runes.
+		for _, c := range got {
+			if c == utf8.RuneError {
+				t.Errorf("exactly16Bytes(%q) is %q, has partial rune", str, got)
+			}
+		}
+	}
+}
+
+// tmpDir creates a temporary directory and returns its name.
+func tmpDir(t *testing.T) string {
+	name, err := ioutil.TempDir("", "pack")
+	if err != nil {
+		t.Fatal(err)
+	}
+	return name
+}
+
+// Test that we can create an archive, write to it, and get the same contents back.
+// Tests the rv and then the pv command on a new archive.
+func TestCreate(t *testing.T) {
+	dir := tmpDir(t)
+	defer os.RemoveAll(dir)
+	name := filepath.Join(dir, "pack.a")
+	ar := archive(name, os.O_RDWR, nil)
+	// Add an entry by hand.
+	ar.addFile(helloFile.Reset())
+	ar.fd.Close()
+	// Now check it.
+	ar = archive(name, os.O_RDONLY, []string{helloFile.name})
+	var buf bytes.Buffer
+	stdout = &buf
+	verbose = true
+	defer func() {
+		stdout = os.Stdout
+		verbose = false
+	}()
+	ar.scan(ar.printContents)
+	ar.fd.Close()
+	result := buf.String()
+	// Expect verbose output plus file contents.
+	expect := fmt.Sprintf("%s\n%s", helloFile.name, helloFile.contents)
+	if result != expect {
+		t.Fatalf("expected %q got %q", expect, result)
+	}
+}
+
+// Test that we can create an archive, put some files in it, and get back a correct listing.
+// Tests the tv command.
+func TestTableOfContents(t *testing.T) {
+	dir := tmpDir(t)
+	defer os.RemoveAll(dir)
+	name := filepath.Join(dir, "pack.a")
+	ar := archive(name, os.O_RDWR, nil)
+
+	// Add some entries by hand.
+	ar.addFile(helloFile.Reset())
+	ar.addFile(goodbyeFile.Reset())
+	ar.fd.Close()
+
+	// Now print it.
+	ar = archive(name, os.O_RDONLY, nil)
+	var buf bytes.Buffer
+	stdout = &buf
+	verbose = true
+	defer func() {
+		stdout = os.Stdout
+		verbose = false
+	}()
+	ar.scan(ar.tableOfContents)
+	ar.fd.Close()
+	result := buf.String()
+	// Expect verbose listing.
+	expect := fmt.Sprintf("%s\n%s\n", helloFile.Entry(), goodbyeFile.Entry())
+	if result != expect {
+		t.Fatalf("expected %q got %q", expect, result)
+	}
+
+	// Do it again without verbose.
+	verbose = false
+	buf.Reset()
+	ar = archive(name, os.O_RDONLY, nil)
+	ar.scan(ar.tableOfContents)
+	ar.fd.Close()
+	result = buf.String()
+	// Expect non-verbose listing.
+	expect = fmt.Sprintf("%s\n%s\n", helloFile.name, goodbyeFile.name)
+	if result != expect {
+		t.Fatalf("expected %q got %q", expect, result)
+	}
+
+	// Do it again with file list arguments.
+	verbose = false
+	buf.Reset()
+	ar = archive(name, os.O_RDONLY, []string{helloFile.name})
+	ar.scan(ar.tableOfContents)
+	ar.fd.Close()
+	result = buf.String()
+	// Expect only helloFile.
+	expect = fmt.Sprintf("%s\n", helloFile.name)
+	if result != expect {
+		t.Fatalf("expected %q got %q", expect, result)
+	}
+}
+
+// Test that we can create an archive, put some files in it, and get back a file.
+// Tests the x command.
+func TestExtract(t *testing.T) {
+	dir := tmpDir(t)
+	defer os.RemoveAll(dir)
+	name := filepath.Join(dir, "pack.a")
+	ar := archive(name, os.O_RDWR, nil)
+	// Add some entries by hand.
+	ar.addFile(helloFile.Reset())
+	ar.addFile(goodbyeFile.Reset())
+	ar.fd.Close()
+	// Now extract one file. We chdir to the directory of the archive for simplicity.
+	pwd, err := os.Getwd()
+	if err != nil {
+		t.Fatal("os.Getwd: ", err)
+	}
+	err = os.Chdir(dir)
+	if err != nil {
+		t.Fatal("os.Chdir: ", err)
+	}
+	defer func() {
+		err := os.Chdir(pwd)
+		if err != nil {
+			t.Fatal("os.Chdir: ", err)
+		}
+	}()
+	ar = archive(name, os.O_RDONLY, []string{goodbyeFile.name})
+	ar.scan(ar.extractContents)
+	ar.fd.Close()
+	data, err := ioutil.ReadFile(goodbyeFile.name)
+	if err != nil {
+		t.Fatal(err)
+	}
+	// Expect contents of file.
+	result := string(data)
+	expect := goodbyeFile.contents
+	if result != expect {
+		t.Fatalf("expected %q got %q", expect, result)
+	}
+}
+
+// Test that pack-created archives can be understood by the tools.
+func TestHello(t *testing.T) {
+	if runtime.GOOS == "nacl" {
+		t.Skip("skipping on nacl")
+	}
+
+	dir := tmpDir(t)
+	defer os.RemoveAll(dir)
+	hello := filepath.Join(dir, "hello.go")
+	prog := `
+		package main
+		func main() {
+			println("hello world")
+		}
+	`
+	err := ioutil.WriteFile(hello, []byte(prog), 0666)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	char := findChar(t, dir)
+
+	run := func(args ...string) string {
+		return doRun(t, dir, args...)
+	}
+
+	run("go", "build", "cmd/pack") // writes pack binary to dir
+	run("go", "tool", char+"g", "hello.go")
+	run("./pack", "grc", "hello.a", "hello."+char)
+	run("go", "tool", char+"l", "-o", "a.out", "hello.a")
+	out := run("./a.out")
+	if out != "hello world\n" {
+		t.Fatalf("incorrect output: %q, want %q", out, "hello world\n")
+	}
+}
+
+// Test that pack works with very long lines in PKGDEF.
+func TestLargeDefs(t *testing.T) {
+	if runtime.GOOS == "nacl" {
+		t.Skip("skipping on nacl")
+	}
+
+	dir := tmpDir(t)
+	defer os.RemoveAll(dir)
+	large := filepath.Join(dir, "large.go")
+	f, err := os.Create(large)
+	if err != nil {
+		t.Fatal(err)
+	}
+	b := bufio.NewWriter(f)
+
+	printf := func(format string, args ...interface{}) {
+		_, err := fmt.Fprintf(b, format, args...)
+		if err != nil {
+			t.Fatalf("Writing to %s: %v", large, err)
+		}
+	}
+
+	printf("package large\n\ntype T struct {\n")
+	for i := 0; i < 10000; i++ {
+		printf("f%d int `tag:\"", i)
+		for j := 0; j < 100; j++ {
+			printf("t%d=%d,", j, j)
+		}
+		printf("\"`\n")
+	}
+	printf("}\n")
+	if err = b.Flush(); err != nil {
+		t.Fatal(err)
+	}
+	if err = f.Close(); err != nil {
+		t.Fatal(err)
+	}
+
+	main := filepath.Join(dir, "main.go")
+	prog := `
+		package main
+		import "large"
+		var V large.T
+		func main() {
+			println("ok")
+		}
+	`
+	err = ioutil.WriteFile(main, []byte(prog), 0666)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	char := findChar(t, dir)
+
+	run := func(args ...string) string {
+		return doRun(t, dir, args...)
+	}
+
+	run("go", "build", "cmd/pack") // writes pack binary to dir
+	run("go", "tool", char+"g", "large.go")
+	run("./pack", "grc", "large.a", "large."+char)
+	run("go", "tool", char+"g", "-I", ".", "main.go")
+	run("go", "tool", char+"l", "-L", ".", "-o", "a.out", "main."+char)
+	out := run("./a.out")
+	if out != "ok\n" {
+		t.Fatalf("incorrect output: %q, want %q", out, "ok\n")
+	}
+}
+
+// doRun runs a program in a directory and returns the output.
+func doRun(t *testing.T, dir string, args ...string) string {
+	cmd := exec.Command(args[0], args[1:]...)
+	cmd.Dir = dir
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("%v: %v\n%s", args, err, string(out))
+	}
+	return string(out)
+}
+
+// findChar returns the architecture character for the go command.
+func findChar(t *testing.T, dir string) string {
+	out := doRun(t, dir, "go", "env")
+	re, err := regexp.Compile(`\s*GOCHAR=['"]?(\w)['"]?`)
+	if err != nil {
+		t.Fatal(err)
+	}
+	fields := re.FindStringSubmatch(out)
+	if fields == nil {
+		t.Fatal("cannot find GOCHAR in 'go env' output:\n", out)
+	}
+	return fields[1]
+}
+
+// Fake implementation of files.
+
+var helloFile = &FakeFile{
+	name:     "hello",
+	contents: "hello world", // 11 bytes, an odd number.
+	mode:     0644,
+}
+
+var goodbyeFile = &FakeFile{
+	name:     "goodbye",
+	contents: "Sayonara, Jim", // 13 bytes, another odd number.
+	mode:     0644,
+}
+
+// FakeFile implements FileLike and also os.FileInfo.
+type FakeFile struct {
+	name     string
+	contents string
+	mode     os.FileMode
+	offset   int
+}
+
+// Reset prepares a FakeFile for reuse.
+func (f *FakeFile) Reset() *FakeFile {
+	f.offset = 0
+	return f
+}
+
+// FileLike methods.
+
+func (f *FakeFile) Name() string {
+	// A bit of a cheat: we only have a basename, so that's also ok for FileInfo.
+	return f.name
+}
+
+func (f *FakeFile) Stat() (os.FileInfo, error) {
+	return f, nil
+}
+
+func (f *FakeFile) Read(p []byte) (int, error) {
+	if f.offset >= len(f.contents) {
+		return 0, io.EOF
+	}
+	n := copy(p, f.contents[f.offset:])
+	f.offset += n
+	return n, nil
+}
+
+func (f *FakeFile) Close() error {
+	return nil
+}
+
+// os.FileInfo methods.
+
+func (f *FakeFile) Size() int64 {
+	return int64(len(f.contents))
+}
+
+func (f *FakeFile) Mode() os.FileMode {
+	return f.mode
+}
+
+func (f *FakeFile) ModTime() time.Time {
+	return time.Time{}
+}
+
+func (f *FakeFile) IsDir() bool {
+	return false
+}
+
+func (f *FakeFile) Sys() interface{} {
+	return nil
+}
+
+// Special helpers.
+
+func (f *FakeFile) Entry() *Entry {
+	return &Entry{
+		name:  f.name,
+		mtime: 0, // Defined to be zero.
+		uid:   0, // Ditto.
+		gid:   0, // Ditto.
+		mode:  f.mode,
+		size:  int64(len(f.contents)),
+	}
+}
diff --git a/src/cmd/yacc/Makefile b/src/cmd/yacc/Makefile
index 4808448..f8c8169 100644
--- a/src/cmd/yacc/Makefile
+++ b/src/cmd/yacc/Makefile
@@ -2,9 +2,11 @@
 # Use of this source code is governed by a BSD-style
 # license that can be found in the LICENSE file.
 
-expr: yacc.go expr.y
+TARG=expr$(shell go env GOEXE)
+
+$(TARG): yacc.go expr.y
 	go run yacc.go -p expr expr.y
-	go build -o expr y.go
+	go build -o $(TARG) y.go
 
 clean:
-	rm -f y.go y.output expr
+	rm -f y.go y.output $(TARG)
diff --git a/src/cmd/yacc/expr.y b/src/cmd/yacc/expr.y
index 3afffe7..77e9259 100644
--- a/src/cmd/yacc/expr.y
+++ b/src/cmd/yacc/expr.y
@@ -125,7 +125,7 @@ func (x *exprLex) Lex(yylval *exprSymType) int {
 		case '÷':
 			return '/'
 
-		case ' ', '\t', '\n':
+		case ' ', '\t', '\n', '\r':
 		default:
 			log.Printf("unrecognized character %q", c)
 		}
diff --git a/src/cmd/yacc/yacc.go b/src/cmd/yacc/yacc.go
index c53dc3b..c534032 100644
--- a/src/cmd/yacc/yacc.go
+++ b/src/cmd/yacc/yacc.go
@@ -49,6 +49,8 @@ import (
 	"bytes"
 	"flag"
 	"fmt"
+	"go/format"
+	"io/ioutil"
 	"os"
 	"strings"
 	"unicode"
@@ -3212,6 +3214,7 @@ func exit(status int) {
 	if ftable != nil {
 		ftable.Flush()
 		ftable = nil
+		gofmt()
 	}
 	if foutput != nil {
 		foutput.Flush()
@@ -3224,6 +3227,18 @@ func exit(status int) {
 	os.Exit(status)
 }
 
+func gofmt() {
+	src, err := ioutil.ReadFile(oflag)
+	if err != nil {
+		return
+	}
+	src, err = format.Source(src)
+	if err != nil {
+		return
+	}
+	ioutil.WriteFile(oflag, src, 0666)
+}
+
 var yaccpar string // will be processed version of yaccpartext: s/$$/prefix/g
 var yaccpartext = `
 /*	parser for yacc output	*/
diff --git a/src/lib9/_exits.c b/src/lib9/_exits.c
index ea8ea74..af55181 100644
--- a/src/lib9/_exits.c
+++ b/src/lib9/_exits.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/_exits.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/_exits.c
diff --git a/src/lib9/_p9dir.c b/src/lib9/_p9dir.c
index d65edcf..6b5a04e 100644
--- a/src/lib9/_p9dir.c
+++ b/src/lib9/_p9dir.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/_p9dir.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/_p9dir.c
diff --git a/src/lib9/atoi.c b/src/lib9/atoi.c
index 3162b01..5b002df 100644
--- a/src/lib9/atoi.c
+++ b/src/lib9/atoi.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/ato*.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/atoi.c
diff --git a/src/lib9/await.c b/src/lib9/await.c
index 690a61e..dfb155b 100644
--- a/src/lib9/await.c
+++ b/src/lib9/await.c
@@ -1,3 +1,4 @@
+// +build !plan9
 // +build !windows
 
 /*
diff --git a/src/lib9/cleanname.c b/src/lib9/cleanname.c
index fee4038..cb8fce6 100644
--- a/src/lib9/cleanname.c
+++ b/src/lib9/cleanname.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Inferno libkern/cleanname.c
 http://code.google.com/p/inferno-os/source/browse/libkern/cleanname.c
diff --git a/src/lib9/create.c b/src/lib9/create.c
index d7023ae..4ac7f7d 100644
--- a/src/lib9/create.c
+++ b/src/lib9/create.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/create.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/create.c
diff --git a/src/lib9/ctime.c b/src/lib9/ctime.c
index 6317b59..e16ad4a 100644
--- a/src/lib9/ctime.c
+++ b/src/lib9/ctime.c
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build !plan9
+
 #define NOPLAN9DEFINES
 #include <u.h>
 #include <libc.h>
diff --git a/src/lib9/dirfstat.c b/src/lib9/dirfstat.c
index 8cc3384..c092a2a 100644
--- a/src/lib9/dirfstat.c
+++ b/src/lib9/dirfstat.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/dirfstat.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/dirfstat.c
diff --git a/src/lib9/dirfwstat.c b/src/lib9/dirfwstat.c
index e32ddea..4666e21 100644
--- a/src/lib9/dirfwstat.c
+++ b/src/lib9/dirfwstat.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/dirfwstat.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/dirfwstat.c
diff --git a/src/lib9/dirstat.c b/src/lib9/dirstat.c
index df2f85b..33f0d7c 100644
--- a/src/lib9/dirstat.c
+++ b/src/lib9/dirstat.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/dirstat.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/dirstat.c
diff --git a/src/lib9/dirwstat.c b/src/lib9/dirwstat.c
index 9bf348a..22e25ff 100644
--- a/src/lib9/dirwstat.c
+++ b/src/lib9/dirwstat.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/dirwstat.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/dirwstat.c
diff --git a/src/lib9/dup.c b/src/lib9/dup.c
index 9fdfdb8..5cac831 100644
--- a/src/lib9/dup.c
+++ b/src/lib9/dup.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/dup.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/dup.c
diff --git a/src/lib9/errstr.c b/src/lib9/errstr.c
index f42f2b5..9d91975 100644
--- a/src/lib9/errstr.c
+++ b/src/lib9/errstr.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/errstr.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/errstr.c
@@ -32,7 +34,6 @@ THE SOFTWARE.
 
 #include <u.h>
 #include <errno.h>
-#include <string.h>
 #include <libc.h>
 
 enum
diff --git a/src/lib9/exec.c b/src/lib9/exec.c
index f2ad0f9..8e5fc57 100644
--- a/src/lib9/exec.c
+++ b/src/lib9/exec.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/exec.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/exec.c
diff --git a/src/lib9/execl.c b/src/lib9/execl.c
index 81d3158..fd4d23d 100644
--- a/src/lib9/execl.c
+++ b/src/lib9/execl.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/execl.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/execl.c
diff --git a/src/lib9/exitcode.c b/src/lib9/exitcode.c
index a952b2d..fc86344 100644
--- a/src/lib9/exitcode.c
+++ b/src/lib9/exitcode.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/exitcode.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/exitcode.c
diff --git a/src/lib9/exits.c b/src/lib9/exits.c
index 5caef83..0be7cb9 100644
--- a/src/lib9/exits.c
+++ b/src/lib9/exits.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/_exits.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/_exits.c
diff --git a/src/lib9/fmt/dorfmt.c b/src/lib9/fmt/dorfmt.c
index c18d9ee..f760d47 100644
--- a/src/lib9/fmt/dorfmt.c
+++ b/src/lib9/fmt/dorfmt.c
@@ -61,5 +61,4 @@ dorfmt(Fmt *f, const Rune *fmt)
 		if(fmt == nil)
 			return -1;
 	}
-	return 0;		/* not reached */
 }
diff --git a/src/lib9/fmt/errfmt.c b/src/lib9/fmt/errfmt.c
new file mode 100644
index 0000000..a867093
--- /dev/null
+++ b/src/lib9/fmt/errfmt.c
@@ -0,0 +1,32 @@
+// +build plan9
+
+/*
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ *     Copyright (c) 2002-2006 by Lucent Technologies.
+ *     Portions Copyright (c) 2004 Google Inc.
+ * 
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES 
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+int
+__errfmt(Fmt *f)
+{
+	char buf[ERRMAX];
+
+	rerrstr(buf, sizeof buf);
+	return __fmtcpy(f, buf, utflen(buf), strlen(buf));
+}
diff --git a/src/lib9/fmt/fltfmt.c b/src/lib9/fmt/fltfmt.c
index dec6f84..6fe8192 100644
--- a/src/lib9/fmt/fltfmt.c
+++ b/src/lib9/fmt/fltfmt.c
@@ -154,6 +154,7 @@ xsub1(char *a, int n)
 	 * so that it has a nonzero first digit.
 	 */
 	abort();
+	return 0;
 }
 
 /*
@@ -180,7 +181,7 @@ xfmtexp(char *p, int e, int ucase)
 		se[i++] = '0';
 	while(i > 0)
 		*p++ = se[--i];
-	*p++ = '\0';
+	*p = '\0';
 }
 
 /*
@@ -192,7 +193,8 @@ xfmtexp(char *p, int e, int ucase)
 static void
 xdtoa(double f, char *s, int *exp, int *neg, int *ns)
 {
-	int d, e2, e, ee, i, ndigit, oerrno;
+	int d, e2, e, ee, i, ndigit;
+	int oerrno;
 	char c;
 	char tmp[NSIGNIF+10];
 	double g;
diff --git a/src/lib9/fmt/fmtfd.c b/src/lib9/fmt/fmtfd.c
index c32abf1..dde05b7 100644
--- a/src/lib9/fmt/fmtfd.c
+++ b/src/lib9/fmt/fmtfd.c
@@ -43,7 +43,7 @@ fmtfdinit(Fmt *f, int fd, char *buf, int size)
 	f->to = buf;
 	f->stop = buf + size;
 	f->flush = __fmtFdFlush;
-	f->farg = (void*)(uintptr_t)fd;
+	f->farg = (void*)(uintptr)fd;
 	f->flags = 0;
 	f->nfmt = 0;
 	fmtlocaleinit(f, nil, nil, nil);
diff --git a/src/lib9/fmtlock2.c b/src/lib9/fmtlock2.c
index 75406b5..a0e2636 100644
--- a/src/lib9/fmtlock2.c
+++ b/src/lib9/fmtlock2.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/fmtlock2.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/fmtlock2.c
diff --git a/src/lib9/getenv.c b/src/lib9/getenv.c
index 9d805b5..2454b6b 100644
--- a/src/lib9/getenv.c
+++ b/src/lib9/getenv.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/getenv.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/getenv.c
diff --git a/src/lib9/getwd.c b/src/lib9/getwd.c
index cbfd9d6..03a8ff1 100644
--- a/src/lib9/getwd.c
+++ b/src/lib9/getwd.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/getwd.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/getwd.c
diff --git a/src/lib9/jmp.c b/src/lib9/jmp.c
index c44e040..733ed70 100644
--- a/src/lib9/jmp.c
+++ b/src/lib9/jmp.c
@@ -1,3 +1,4 @@
+// +build !plan9
 // +build !windows
 
 /*
diff --git a/src/lib9/main.c b/src/lib9/main.c
index 816494a..088b095 100644
--- a/src/lib9/main.c
+++ b/src/lib9/main.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/main.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/main.c
@@ -50,8 +52,8 @@ main(int argc, char **argv)
 	// don't display the crash dialog
 	DWORD mode = SetErrorMode(SEM_NOGPFAULTERRORBOX);
 	SetErrorMode(mode | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
-	argv0 = argv[0];
 #endif
+	argv0 = argv[0];
 	p9main(argc, argv);
 	exits("main");
 	return 99;
diff --git a/src/lib9/nan.c b/src/lib9/nan.c
index fa2277f..f17b441 100644
--- a/src/lib9/nan.c
+++ b/src/lib9/nan.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/nan.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/nan.c
diff --git a/src/lib9/notify.c b/src/lib9/notify.c
index c424aed..7843d34 100644
--- a/src/lib9/notify.c
+++ b/src/lib9/notify.c
@@ -1,3 +1,4 @@
+// +build !plan9
 // +build !windows
 
 /*
diff --git a/src/lib9/nulldir.c b/src/lib9/nulldir.c
index aa1a123..2157ff3 100644
--- a/src/lib9/nulldir.c
+++ b/src/lib9/nulldir.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Inferno lib9/nulldir.c
 http://code.google.com/p/inferno-os/source/browse/lib9/nulldir.c
diff --git a/src/lib9/open.c b/src/lib9/open.c
index 4ac81ba..7f53c8e 100644
--- a/src/lib9/open.c
+++ b/src/lib9/open.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/open.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/open.c
diff --git a/src/lib9/readn.c b/src/lib9/readn.c
index 3c80a4f..7dfe9e5 100644
--- a/src/lib9/readn.c
+++ b/src/lib9/readn.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Inferno lib9/readn.c
 http://code.google.com/p/inferno-os/source/browse/lib9/readn.c
diff --git a/src/lib9/rfork.c b/src/lib9/rfork.c
index c4ae90f..23b3ee6 100644
--- a/src/lib9/rfork.c
+++ b/src/lib9/rfork.c
@@ -1,3 +1,4 @@
+// +build !plan9
 // +build !windows
 
 /*
diff --git a/src/lib9/run_plan9.c b/src/lib9/run_plan9.c
index cd85652..2993262 100644
--- a/src/lib9/run_plan9.c
+++ b/src/lib9/run_plan9.c
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build plan9
+
 #include <u.h>
 #include <libc.h>
 
diff --git a/src/lib9/run_unix.c b/src/lib9/run_unix.c
index 3db33c7..1acaefe 100644
--- a/src/lib9/run_unix.c
+++ b/src/lib9/run_unix.c
@@ -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 netbsd openbsd solaris
 
 #include <u.h>
 #include <errno.h>
diff --git a/src/lib9/seek.c b/src/lib9/seek.c
index 9170038..0a0706c 100644
--- a/src/lib9/seek.c
+++ b/src/lib9/seek.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/seek.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/seek.c
diff --git a/src/lib9/strecpy.c b/src/lib9/strecpy.c
index 03dc6ea..4b2b92b 100644
--- a/src/lib9/strecpy.c
+++ b/src/lib9/strecpy.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Inferno lib9/strecpy.c
 http://code.google.com/p/inferno-os/source/browse/lib9/strecpy.c
diff --git a/src/lib9/sysfatal.c b/src/lib9/sysfatal.c
index a5af3e1..9789061 100644
--- a/src/lib9/sysfatal.c
+++ b/src/lib9/sysfatal.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/sysfatal.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/sysfatal.c
diff --git a/src/lib9/tempdir_plan9.c b/src/lib9/tempdir_plan9.c
index 092d00d..80d7ddb 100644
--- a/src/lib9/tempdir_plan9.c
+++ b/src/lib9/tempdir_plan9.c
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build plan9
+
 #include <u.h>
 #include <libc.h>
 
diff --git a/src/lib9/tempdir_unix.c b/src/lib9/tempdir_unix.c
index 3ce8775..269d538 100644
--- a/src/lib9/tempdir_unix.c
+++ b/src/lib9/tempdir_unix.c
@@ -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 netbsd openbsd solaris
 
 #include <u.h>
 #include <dirent.h>
diff --git a/src/lib9/time.c b/src/lib9/time.c
index 7394e9e..e1b87a7 100644
--- a/src/lib9/time.c
+++ b/src/lib9/time.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Plan 9 from User Space src/lib9/time.c
 http://code.swtch.com/plan9port/src/tip/src/lib9/time.c
diff --git a/src/lib9/tokenize.c b/src/lib9/tokenize.c
index a9b5935..a095fcd 100644
--- a/src/lib9/tokenize.c
+++ b/src/lib9/tokenize.c
@@ -1,3 +1,5 @@
+// +build !plan9
+
 /*
 Inferno lib9/tokenize.c
 http://code.google.com/p/inferno-os/source/browse/lib9/tokenize.c
diff --git a/src/lib9/utf/Makefile b/src/lib9/utf/Makefile
index 5c9cdf0..fe6f635 100644
--- a/src/lib9/utf/Makefile
+++ b/src/lib9/utf/Makefile
@@ -21,10 +21,10 @@ runetypebody-%.h: mkrunetype UnicodeData-%.txt
 
 CLEANFILES+=UnicodeData.txt
 
-UNICODE_VERSION=6.2.0
+UNICODE_VERSION=6.3.0
 
 test: mkrunetype UnicodeData-$(UNICODE_VERSION).txt
 	mkrunetype -c UnicodeData-$(UNICODE_VERSION).txt
 
 clean:
-	rm -f UnicodeData.txt mkrunetype
\ No newline at end of file
+	rm -f UnicodeData.txt mkrunetype
diff --git a/src/lib9/utf/runetype.c b/src/lib9/utf/runetype.c
index b363496..ed775af 100644
--- a/src/lib9/utf/runetype.c
+++ b/src/lib9/utf/runetype.c
@@ -35,4 +35,4 @@ rbsearch(Rune c, Rune *t, int n, int ne)
 	return 0;
 }
 
-#include "runetypebody-6.2.0.h"
+#include "runetypebody-6.3.0.h"
diff --git a/src/lib9/utf/runetypebody-6.2.0.h b/src/lib9/utf/runetypebody-6.2.0.h
deleted file mode 100644
index a603af0..0000000
--- a/src/lib9/utf/runetypebody-6.2.0.h
+++ /dev/null
@@ -1,1639 +0,0 @@
-/* generated automatically by mkrunetype.c from UnicodeData-6.2.0.txt */
-
-static Rune __isspacer[] = {
-	0x0009, 0x000d,
-	0x0020, 0x0020,
-	0x0085, 0x0085,
-	0x00a0, 0x00a0,
-	0x1680, 0x1680,
-	0x180e, 0x180e,
-	0x2000, 0x200a,
-	0x2028, 0x2029,
-	0x202f, 0x202f,
-	0x205f, 0x205f,
-	0x3000, 0x3000,
-	0xfeff, 0xfeff,
-};
-
-int
-isspacerune(Rune c)
-{
-	Rune *p;
-
-	p = rbsearch(c, __isspacer, nelem(__isspacer)/2, 2);
-	if(p && c >= p[0] && c <= p[1])
-		return 1;
-	return 0;
-}
-
-static Rune __isdigitr[] = {
-	0x0030, 0x0039,
-	0x0660, 0x0669,
-	0x06f0, 0x06f9,
-	0x07c0, 0x07c9,
-	0x0966, 0x096f,
-	0x09e6, 0x09ef,
-	0x0a66, 0x0a6f,
-	0x0ae6, 0x0aef,
-	0x0b66, 0x0b6f,
-	0x0be6, 0x0bef,
-	0x0c66, 0x0c6f,
-	0x0ce6, 0x0cef,
-	0x0d66, 0x0d6f,
-	0x0e50, 0x0e59,
-	0x0ed0, 0x0ed9,
-	0x0f20, 0x0f29,
-	0x1040, 0x1049,
-	0x1090, 0x1099,
-	0x17e0, 0x17e9,
-	0x1810, 0x1819,
-	0x1946, 0x194f,
-	0x19d0, 0x19d9,
-	0x1a80, 0x1a89,
-	0x1a90, 0x1a99,
-	0x1b50, 0x1b59,
-	0x1bb0, 0x1bb9,
-	0x1c40, 0x1c49,
-	0x1c50, 0x1c59,
-	0xa620, 0xa629,
-	0xa8d0, 0xa8d9,
-	0xa900, 0xa909,
-	0xa9d0, 0xa9d9,
-	0xaa50, 0xaa59,
-	0xabf0, 0xabf9,
-	0xff10, 0xff19,
-	0x104a0, 0x104a9,
-	0x11066, 0x1106f,
-	0x110f0, 0x110f9,
-	0x11136, 0x1113f,
-	0x111d0, 0x111d9,
-	0x116c0, 0x116c9,
-	0x1d7ce, 0x1d7ff,
-};
-
-int
-isdigitrune(Rune c)
-{
-	Rune *p;
-
-	p = rbsearch(c, __isdigitr, nelem(__isdigitr)/2, 2);
-	if(p && c >= p[0] && c <= p[1])
-		return 1;
-	return 0;
-}
-
-static Rune __isalphar[] = {
-	0x0041, 0x005a,
-	0x0061, 0x007a,
-	0x00c0, 0x00d6,
-	0x00d8, 0x00f6,
-	0x00f8, 0x02c1,
-	0x02c6, 0x02d1,
-	0x02e0, 0x02e4,
-	0x0370, 0x0374,
-	0x0376, 0x0377,
-	0x037a, 0x037d,
-	0x0388, 0x038a,
-	0x038e, 0x03a1,
-	0x03a3, 0x03f5,
-	0x03f7, 0x0481,
-	0x048a, 0x0527,
-	0x0531, 0x0556,
-	0x0561, 0x0587,
-	0x05d0, 0x05ea,
-	0x05f0, 0x05f2,
-	0x0620, 0x064a,
-	0x066e, 0x066f,
-	0x0671, 0x06d3,
-	0x06e5, 0x06e6,
-	0x06ee, 0x06ef,
-	0x06fa, 0x06fc,
-	0x0712, 0x072f,
-	0x074d, 0x07a5,
-	0x07ca, 0x07ea,
-	0x07f4, 0x07f5,
-	0x0800, 0x0815,
-	0x0840, 0x0858,
-	0x08a2, 0x08ac,
-	0x0904, 0x0939,
-	0x0958, 0x0961,
-	0x0971, 0x0977,
-	0x0979, 0x097f,
-	0x0985, 0x098c,
-	0x098f, 0x0990,
-	0x0993, 0x09a8,
-	0x09aa, 0x09b0,
-	0x09b6, 0x09b9,
-	0x09dc, 0x09dd,
-	0x09df, 0x09e1,
-	0x09f0, 0x09f1,
-	0x0a05, 0x0a0a,
-	0x0a0f, 0x0a10,
-	0x0a13, 0x0a28,
-	0x0a2a, 0x0a30,
-	0x0a32, 0x0a33,
-	0x0a35, 0x0a36,
-	0x0a38, 0x0a39,
-	0x0a59, 0x0a5c,
-	0x0a72, 0x0a74,
-	0x0a85, 0x0a8d,
-	0x0a8f, 0x0a91,
-	0x0a93, 0x0aa8,
-	0x0aaa, 0x0ab0,
-	0x0ab2, 0x0ab3,
-	0x0ab5, 0x0ab9,
-	0x0ae0, 0x0ae1,
-	0x0b05, 0x0b0c,
-	0x0b0f, 0x0b10,
-	0x0b13, 0x0b28,
-	0x0b2a, 0x0b30,
-	0x0b32, 0x0b33,
-	0x0b35, 0x0b39,
-	0x0b5c, 0x0b5d,
-	0x0b5f, 0x0b61,
-	0x0b85, 0x0b8a,
-	0x0b8e, 0x0b90,
-	0x0b92, 0x0b95,
-	0x0b99, 0x0b9a,
-	0x0b9e, 0x0b9f,
-	0x0ba3, 0x0ba4,
-	0x0ba8, 0x0baa,
-	0x0bae, 0x0bb9,
-	0x0c05, 0x0c0c,
-	0x0c0e, 0x0c10,
-	0x0c12, 0x0c28,
-	0x0c2a, 0x0c33,
-	0x0c35, 0x0c39,
-	0x0c58, 0x0c59,
-	0x0c60, 0x0c61,
-	0x0c85, 0x0c8c,
-	0x0c8e, 0x0c90,
-	0x0c92, 0x0ca8,
-	0x0caa, 0x0cb3,
-	0x0cb5, 0x0cb9,
-	0x0ce0, 0x0ce1,
-	0x0cf1, 0x0cf2,
-	0x0d05, 0x0d0c,
-	0x0d0e, 0x0d10,
-	0x0d12, 0x0d3a,
-	0x0d60, 0x0d61,
-	0x0d7a, 0x0d7f,
-	0x0d85, 0x0d96,
-	0x0d9a, 0x0db1,
-	0x0db3, 0x0dbb,
-	0x0dc0, 0x0dc6,
-	0x0e01, 0x0e30,
-	0x0e32, 0x0e33,
-	0x0e40, 0x0e46,
-	0x0e81, 0x0e82,
-	0x0e87, 0x0e88,
-	0x0e94, 0x0e97,
-	0x0e99, 0x0e9f,
-	0x0ea1, 0x0ea3,
-	0x0eaa, 0x0eab,
-	0x0ead, 0x0eb0,
-	0x0eb2, 0x0eb3,
-	0x0ec0, 0x0ec4,
-	0x0edc, 0x0edf,
-	0x0f40, 0x0f47,
-	0x0f49, 0x0f6c,
-	0x0f88, 0x0f8c,
-	0x1000, 0x102a,
-	0x1050, 0x1055,
-	0x105a, 0x105d,
-	0x1065, 0x1066,
-	0x106e, 0x1070,
-	0x1075, 0x1081,
-	0x10a0, 0x10c5,
-	0x10d0, 0x10fa,
-	0x10fc, 0x1248,
-	0x124a, 0x124d,
-	0x1250, 0x1256,
-	0x125a, 0x125d,
-	0x1260, 0x1288,
-	0x128a, 0x128d,
-	0x1290, 0x12b0,
-	0x12b2, 0x12b5,
-	0x12b8, 0x12be,
-	0x12c2, 0x12c5,
-	0x12c8, 0x12d6,
-	0x12d8, 0x1310,
-	0x1312, 0x1315,
-	0x1318, 0x135a,
-	0x1380, 0x138f,
-	0x13a0, 0x13f4,
-	0x1401, 0x166c,
-	0x166f, 0x167f,
-	0x1681, 0x169a,
-	0x16a0, 0x16ea,
-	0x1700, 0x170c,
-	0x170e, 0x1711,
-	0x1720, 0x1731,
-	0x1740, 0x1751,
-	0x1760, 0x176c,
-	0x176e, 0x1770,
-	0x1780, 0x17b3,
-	0x1820, 0x1877,
-	0x1880, 0x18a8,
-	0x18b0, 0x18f5,
-	0x1900, 0x191c,
-	0x1950, 0x196d,
-	0x1970, 0x1974,
-	0x1980, 0x19ab,
-	0x19c1, 0x19c7,
-	0x1a00, 0x1a16,
-	0x1a20, 0x1a54,
-	0x1b05, 0x1b33,
-	0x1b45, 0x1b4b,
-	0x1b83, 0x1ba0,
-	0x1bae, 0x1baf,
-	0x1bba, 0x1be5,
-	0x1c00, 0x1c23,
-	0x1c4d, 0x1c4f,
-	0x1c5a, 0x1c7d,
-	0x1ce9, 0x1cec,
-	0x1cee, 0x1cf1,
-	0x1cf5, 0x1cf6,
-	0x1d00, 0x1dbf,
-	0x1e00, 0x1f15,
-	0x1f18, 0x1f1d,
-	0x1f20, 0x1f45,
-	0x1f48, 0x1f4d,
-	0x1f50, 0x1f57,
-	0x1f5f, 0x1f7d,
-	0x1f80, 0x1fb4,
-	0x1fb6, 0x1fbc,
-	0x1fc2, 0x1fc4,
-	0x1fc6, 0x1fcc,
-	0x1fd0, 0x1fd3,
-	0x1fd6, 0x1fdb,
-	0x1fe0, 0x1fec,
-	0x1ff2, 0x1ff4,
-	0x1ff6, 0x1ffc,
-	0x2090, 0x209c,
-	0x210a, 0x2113,
-	0x2119, 0x211d,
-	0x212a, 0x212d,
-	0x212f, 0x2139,
-	0x213c, 0x213f,
-	0x2145, 0x2149,
-	0x2183, 0x2184,
-	0x2c00, 0x2c2e,
-	0x2c30, 0x2c5e,
-	0x2c60, 0x2ce4,
-	0x2ceb, 0x2cee,
-	0x2cf2, 0x2cf3,
-	0x2d00, 0x2d25,
-	0x2d30, 0x2d67,
-	0x2d80, 0x2d96,
-	0x2da0, 0x2da6,
-	0x2da8, 0x2dae,
-	0x2db0, 0x2db6,
-	0x2db8, 0x2dbe,
-	0x2dc0, 0x2dc6,
-	0x2dc8, 0x2dce,
-	0x2dd0, 0x2dd6,
-	0x2dd8, 0x2dde,
-	0x3005, 0x3006,
-	0x3031, 0x3035,
-	0x303b, 0x303c,
-	0x3041, 0x3096,
-	0x309d, 0x309f,
-	0x30a1, 0x30fa,
-	0x30fc, 0x30ff,
-	0x3105, 0x312d,
-	0x3131, 0x318e,
-	0x31a0, 0x31ba,
-	0x31f0, 0x31ff,
-	0x3400, 0x4db5,
-	0x4e00, 0x9fcc,
-	0xa000, 0xa48c,
-	0xa4d0, 0xa4fd,
-	0xa500, 0xa60c,
-	0xa610, 0xa61f,
-	0xa62a, 0xa62b,
-	0xa640, 0xa66e,
-	0xa67f, 0xa697,
-	0xa6a0, 0xa6e5,
-	0xa717, 0xa71f,
-	0xa722, 0xa788,
-	0xa78b, 0xa78e,
-	0xa790, 0xa793,
-	0xa7a0, 0xa7aa,
-	0xa7f8, 0xa801,
-	0xa803, 0xa805,
-	0xa807, 0xa80a,
-	0xa80c, 0xa822,
-	0xa840, 0xa873,
-	0xa882, 0xa8b3,
-	0xa8f2, 0xa8f7,
-	0xa90a, 0xa925,
-	0xa930, 0xa946,
-	0xa960, 0xa97c,
-	0xa984, 0xa9b2,
-	0xaa00, 0xaa28,
-	0xaa40, 0xaa42,
-	0xaa44, 0xaa4b,
-	0xaa60, 0xaa76,
-	0xaa80, 0xaaaf,
-	0xaab5, 0xaab6,
-	0xaab9, 0xaabd,
-	0xaadb, 0xaadd,
-	0xaae0, 0xaaea,
-	0xaaf2, 0xaaf4,
-	0xab01, 0xab06,
-	0xab09, 0xab0e,
-	0xab11, 0xab16,
-	0xab20, 0xab26,
-	0xab28, 0xab2e,
-	0xabc0, 0xabe2,
-	0xac00, 0xd7a3,
-	0xd7b0, 0xd7c6,
-	0xd7cb, 0xd7fb,
-	0xf900, 0xfa6d,
-	0xfa70, 0xfad9,
-	0xfb00, 0xfb06,
-	0xfb13, 0xfb17,
-	0xfb1f, 0xfb28,
-	0xfb2a, 0xfb36,
-	0xfb38, 0xfb3c,
-	0xfb40, 0xfb41,
-	0xfb43, 0xfb44,
-	0xfb46, 0xfbb1,
-	0xfbd3, 0xfd3d,
-	0xfd50, 0xfd8f,
-	0xfd92, 0xfdc7,
-	0xfdf0, 0xfdfb,
-	0xfe70, 0xfe74,
-	0xfe76, 0xfefc,
-	0xff21, 0xff3a,
-	0xff41, 0xff5a,
-	0xff66, 0xffbe,
-	0xffc2, 0xffc7,
-	0xffca, 0xffcf,
-	0xffd2, 0xffd7,
-	0xffda, 0xffdc,
-	0x10000, 0x1000b,
-	0x1000d, 0x10026,
-	0x10028, 0x1003a,
-	0x1003c, 0x1003d,
-	0x1003f, 0x1004d,
-	0x10050, 0x1005d,
-	0x10080, 0x100fa,
-	0x10280, 0x1029c,
-	0x102a0, 0x102d0,
-	0x10300, 0x1031e,
-	0x10330, 0x10340,
-	0x10342, 0x10349,
-	0x10380, 0x1039d,
-	0x103a0, 0x103c3,
-	0x103c8, 0x103cf,
-	0x10400, 0x1049d,
-	0x10800, 0x10805,
-	0x1080a, 0x10835,
-	0x10837, 0x10838,
-	0x1083f, 0x10855,
-	0x10900, 0x10915,
-	0x10920, 0x10939,
-	0x10980, 0x109b7,
-	0x109be, 0x109bf,
-	0x10a10, 0x10a13,
-	0x10a15, 0x10a17,
-	0x10a19, 0x10a33,
-	0x10a60, 0x10a7c,
-	0x10b00, 0x10b35,
-	0x10b40, 0x10b55,
-	0x10b60, 0x10b72,
-	0x10c00, 0x10c48,
-	0x11003, 0x11037,
-	0x11083, 0x110af,
-	0x110d0, 0x110e8,
-	0x11103, 0x11126,
-	0x11183, 0x111b2,
-	0x111c1, 0x111c4,
-	0x11680, 0x116aa,
-	0x12000, 0x1236e,
-	0x13000, 0x1342e,
-	0x16800, 0x16a38,
-	0x16f00, 0x16f44,
-	0x16f93, 0x16f9f,
-	0x1b000, 0x1b001,
-	0x1d400, 0x1d454,
-	0x1d456, 0x1d49c,
-	0x1d49e, 0x1d49f,
-	0x1d4a5, 0x1d4a6,
-	0x1d4a9, 0x1d4ac,
-	0x1d4ae, 0x1d4b9,
-	0x1d4bd, 0x1d4c3,
-	0x1d4c5, 0x1d505,
-	0x1d507, 0x1d50a,
-	0x1d50d, 0x1d514,
-	0x1d516, 0x1d51c,
-	0x1d51e, 0x1d539,
-	0x1d53b, 0x1d53e,
-	0x1d540, 0x1d544,
-	0x1d54a, 0x1d550,
-	0x1d552, 0x1d6a5,
-	0x1d6a8, 0x1d6c0,
-	0x1d6c2, 0x1d6da,
-	0x1d6dc, 0x1d6fa,
-	0x1d6fc, 0x1d714,
-	0x1d716, 0x1d734,
-	0x1d736, 0x1d74e,
-	0x1d750, 0x1d76e,
-	0x1d770, 0x1d788,
-	0x1d78a, 0x1d7a8,
-	0x1d7aa, 0x1d7c2,
-	0x1d7c4, 0x1d7cb,
-	0x1ee00, 0x1ee03,
-	0x1ee05, 0x1ee1f,
-	0x1ee21, 0x1ee22,
-	0x1ee29, 0x1ee32,
-	0x1ee34, 0x1ee37,
-	0x1ee4d, 0x1ee4f,
-	0x1ee51, 0x1ee52,
-	0x1ee61, 0x1ee62,
-	0x1ee67, 0x1ee6a,
-	0x1ee6c, 0x1ee72,
-	0x1ee74, 0x1ee77,
-	0x1ee79, 0x1ee7c,
-	0x1ee80, 0x1ee89,
-	0x1ee8b, 0x1ee9b,
-	0x1eea1, 0x1eea3,
-	0x1eea5, 0x1eea9,
-	0x1eeab, 0x1eebb,
-	0x20000, 0x2a6d6,
-	0x2a700, 0x2b734,
-	0x2b740, 0x2b81d,
-	0x2f800, 0x2fa1d,
-};
-
-static Rune __isalphas[] = {
-	0x00aa,
-	0x00b5,
-	0x00ba,
-	0x02ec,
-	0x02ee,
-	0x0386,
-	0x038c,
-	0x0559,
-	0x06d5,
-	0x06ff,
-	0x0710,
-	0x07b1,
-	0x07fa,
-	0x081a,
-	0x0824,
-	0x0828,
-	0x08a0,
-	0x093d,
-	0x0950,
-	0x09b2,
-	0x09bd,
-	0x09ce,
-	0x0a5e,
-	0x0abd,
-	0x0ad0,
-	0x0b3d,
-	0x0b71,
-	0x0b83,
-	0x0b9c,
-	0x0bd0,
-	0x0c3d,
-	0x0cbd,
-	0x0cde,
-	0x0d3d,
-	0x0d4e,
-	0x0dbd,
-	0x0e84,
-	0x0e8a,
-	0x0e8d,
-	0x0ea5,
-	0x0ea7,
-	0x0ebd,
-	0x0ec6,
-	0x0f00,
-	0x103f,
-	0x1061,
-	0x108e,
-	0x10c7,
-	0x10cd,
-	0x1258,
-	0x12c0,
-	0x17d7,
-	0x17dc,
-	0x18aa,
-	0x1aa7,
-	0x1f59,
-	0x1f5b,
-	0x1f5d,
-	0x1fbe,
-	0x2071,
-	0x207f,
-	0x2102,
-	0x2107,
-	0x2115,
-	0x2124,
-	0x2126,
-	0x2128,
-	0x214e,
-	0x2d27,
-	0x2d2d,
-	0x2d6f,
-	0x2e2f,
-	0xa8fb,
-	0xa9cf,
-	0xaa7a,
-	0xaab1,
-	0xaac0,
-	0xaac2,
-	0xfb1d,
-	0xfb3e,
-	0x10808,
-	0x1083c,
-	0x10a00,
-	0x16f50,
-	0x1d4a2,
-	0x1d4bb,
-	0x1d546,
-	0x1ee24,
-	0x1ee27,
-	0x1ee39,
-	0x1ee3b,
-	0x1ee42,
-	0x1ee47,
-	0x1ee49,
-	0x1ee4b,
-	0x1ee54,
-	0x1ee57,
-	0x1ee59,
-	0x1ee5b,
-	0x1ee5d,
-	0x1ee5f,
-	0x1ee64,
-	0x1ee7e,
-};
-
-int
-isalpharune(Rune c)
-{
-	Rune *p;
-
-	p = rbsearch(c, __isalphar, nelem(__isalphar)/2, 2);
-	if(p && c >= p[0] && c <= p[1])
-		return 1;
-	p = rbsearch(c, __isalphas, nelem(__isalphas), 1);
-	if(p && c == p[0])
-		return 1;
-	return 0;
-}
-
-static Rune __isupperr[] = {
-	0x0041, 0x005a,
-	0x00c0, 0x00d6,
-	0x00d8, 0x00de,
-	0x0178, 0x0179,
-	0x0181, 0x0182,
-	0x0186, 0x0187,
-	0x0189, 0x018b,
-	0x018e, 0x0191,
-	0x0193, 0x0194,
-	0x0196, 0x0198,
-	0x019c, 0x019d,
-	0x019f, 0x01a0,
-	0x01a6, 0x01a7,
-	0x01ae, 0x01af,
-	0x01b1, 0x01b3,
-	0x01b7, 0x01b8,
-	0x01f6, 0x01f8,
-	0x023a, 0x023b,
-	0x023d, 0x023e,
-	0x0243, 0x0246,
-	0x0388, 0x038a,
-	0x038e, 0x038f,
-	0x0391, 0x03a1,
-	0x03a3, 0x03ab,
-	0x03d2, 0x03d4,
-	0x03f9, 0x03fa,
-	0x03fd, 0x042f,
-	0x04c0, 0x04c1,
-	0x0531, 0x0556,
-	0x10a0, 0x10c5,
-	0x1f08, 0x1f0f,
-	0x1f18, 0x1f1d,
-	0x1f28, 0x1f2f,
-	0x1f38, 0x1f3f,
-	0x1f48, 0x1f4d,
-	0x1f68, 0x1f6f,
-	0x1f88, 0x1f8f,
-	0x1f98, 0x1f9f,
-	0x1fa8, 0x1faf,
-	0x1fb8, 0x1fbc,
-	0x1fc8, 0x1fcc,
-	0x1fd8, 0x1fdb,
-	0x1fe8, 0x1fec,
-	0x1ff8, 0x1ffc,
-	0x210b, 0x210d,
-	0x2110, 0x2112,
-	0x2119, 0x211d,
-	0x212a, 0x212d,
-	0x2130, 0x2133,
-	0x213e, 0x213f,
-	0x2160, 0x216f,
-	0x24b6, 0x24cf,
-	0x2c00, 0x2c2e,
-	0x2c62, 0x2c64,
-	0x2c6d, 0x2c70,
-	0x2c7e, 0x2c80,
-	0xa77d, 0xa77e,
-	0xff21, 0xff3a,
-	0x10400, 0x10427,
-	0x1d400, 0x1d419,
-	0x1d434, 0x1d44d,
-	0x1d468, 0x1d481,
-	0x1d49e, 0x1d49f,
-	0x1d4a5, 0x1d4a6,
-	0x1d4a9, 0x1d4ac,
-	0x1d4ae, 0x1d4b5,
-	0x1d4d0, 0x1d4e9,
-	0x1d504, 0x1d505,
-	0x1d507, 0x1d50a,
-	0x1d50d, 0x1d514,
-	0x1d516, 0x1d51c,
-	0x1d538, 0x1d539,
-	0x1d53b, 0x1d53e,
-	0x1d540, 0x1d544,
-	0x1d54a, 0x1d550,
-	0x1d56c, 0x1d585,
-	0x1d5a0, 0x1d5b9,
-	0x1d5d4, 0x1d5ed,
-	0x1d608, 0x1d621,
-	0x1d63c, 0x1d655,
-	0x1d670, 0x1d689,
-	0x1d6a8, 0x1d6c0,
-	0x1d6e2, 0x1d6fa,
-	0x1d71c, 0x1d734,
-	0x1d756, 0x1d76e,
-	0x1d790, 0x1d7a8,
-};
-
-static Rune __isupperp[] = {
-	0x0100, 0x0136,
-	0x0139, 0x0147,
-	0x014a, 0x0176,
-	0x017b, 0x017d,
-	0x01a2, 0x01a4,
-	0x01cd, 0x01db,
-	0x01de, 0x01ee,
-	0x01fa, 0x0232,
-	0x0248, 0x024e,
-	0x0370, 0x0372,
-	0x03d8, 0x03ee,
-	0x0460, 0x0480,
-	0x048a, 0x04be,
-	0x04c3, 0x04cd,
-	0x04d0, 0x0526,
-	0x1e00, 0x1e94,
-	0x1e9e, 0x1efe,
-	0x1f59, 0x1f5f,
-	0x2124, 0x2128,
-	0x2c67, 0x2c6b,
-	0x2c82, 0x2ce2,
-	0x2ceb, 0x2ced,
-	0xa640, 0xa66c,
-	0xa680, 0xa696,
-	0xa722, 0xa72e,
-	0xa732, 0xa76e,
-	0xa779, 0xa77b,
-	0xa780, 0xa786,
-	0xa78b, 0xa78d,
-	0xa790, 0xa792,
-	0xa7a0, 0xa7aa,
-};
-
-static Rune __isuppers[] = {
-	0x0184,
-	0x01a9,
-	0x01ac,
-	0x01b5,
-	0x01bc,
-	0x01c4,
-	0x01c7,
-	0x01ca,
-	0x01f1,
-	0x01f4,
-	0x0241,
-	0x0376,
-	0x0386,
-	0x038c,
-	0x03cf,
-	0x03f4,
-	0x03f7,
-	0x10c7,
-	0x10cd,
-	0x2102,
-	0x2107,
-	0x2115,
-	0x2145,
-	0x2183,
-	0x2c60,
-	0x2c72,
-	0x2c75,
-	0x2cf2,
-	0x1d49c,
-	0x1d4a2,
-	0x1d546,
-	0x1d7ca,
-};
-
-int
-isupperrune(Rune c)
-{
-	Rune *p;
-
-	p = rbsearch(c, __isupperr, nelem(__isupperr)/2, 2);
-	if(p && c >= p[0] && c <= p[1])
-		return 1;
-	p = rbsearch(c, __isupperp, nelem(__isupperp)/2, 2);
-	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
-		return 1;
-	p = rbsearch(c, __isuppers, nelem(__isuppers), 1);
-	if(p && c == p[0])
-		return 1;
-	return 0;
-}
-
-static Rune __islowerr[] = {
-	0x0061, 0x007a,
-	0x00df, 0x00f6,
-	0x00f8, 0x00ff,
-	0x0137, 0x0138,
-	0x0148, 0x0149,
-	0x017e, 0x0180,
-	0x018c, 0x018d,
-	0x0199, 0x019b,
-	0x01aa, 0x01ab,
-	0x01b9, 0x01ba,
-	0x01bd, 0x01bf,
-	0x01dc, 0x01dd,
-	0x01ef, 0x01f0,
-	0x0233, 0x0239,
-	0x023f, 0x0240,
-	0x024f, 0x0293,
-	0x0295, 0x02af,
-	0x037b, 0x037d,
-	0x03ac, 0x03ce,
-	0x03d0, 0x03d1,
-	0x03d5, 0x03d7,
-	0x03ef, 0x03f3,
-	0x03fb, 0x03fc,
-	0x0430, 0x045f,
-	0x04ce, 0x04cf,
-	0x0561, 0x0587,
-	0x1d00, 0x1d2b,
-	0x1d6b, 0x1d77,
-	0x1d79, 0x1d9a,
-	0x1e95, 0x1e9d,
-	0x1eff, 0x1f07,
-	0x1f10, 0x1f15,
-	0x1f20, 0x1f27,
-	0x1f30, 0x1f37,
-	0x1f40, 0x1f45,
-	0x1f50, 0x1f57,
-	0x1f60, 0x1f67,
-	0x1f70, 0x1f7d,
-	0x1f80, 0x1f87,
-	0x1f90, 0x1f97,
-	0x1fa0, 0x1fa7,
-	0x1fb0, 0x1fb4,
-	0x1fb6, 0x1fb7,
-	0x1fc2, 0x1fc4,
-	0x1fc6, 0x1fc7,
-	0x1fd0, 0x1fd3,
-	0x1fd6, 0x1fd7,
-	0x1fe0, 0x1fe7,
-	0x1ff2, 0x1ff4,
-	0x1ff6, 0x1ff7,
-	0x210e, 0x210f,
-	0x213c, 0x213d,
-	0x2146, 0x2149,
-	0x2170, 0x217f,
-	0x24d0, 0x24e9,
-	0x2c30, 0x2c5e,
-	0x2c65, 0x2c66,
-	0x2c73, 0x2c74,
-	0x2c76, 0x2c7b,
-	0x2ce3, 0x2ce4,
-	0x2d00, 0x2d25,
-	0xa72f, 0xa731,
-	0xa771, 0xa778,
-	0xfb00, 0xfb06,
-	0xfb13, 0xfb17,
-	0xff41, 0xff5a,
-	0x10428, 0x1044f,
-	0x1d41a, 0x1d433,
-	0x1d44e, 0x1d454,
-	0x1d456, 0x1d467,
-	0x1d482, 0x1d49b,
-	0x1d4b6, 0x1d4b9,
-	0x1d4bd, 0x1d4c3,
-	0x1d4c5, 0x1d4cf,
-	0x1d4ea, 0x1d503,
-	0x1d51e, 0x1d537,
-	0x1d552, 0x1d56b,
-	0x1d586, 0x1d59f,
-	0x1d5ba, 0x1d5d3,
-	0x1d5ee, 0x1d607,
-	0x1d622, 0x1d63b,
-	0x1d656, 0x1d66f,
-	0x1d68a, 0x1d6a5,
-	0x1d6c2, 0x1d6da,
-	0x1d6dc, 0x1d6e1,
-	0x1d6fc, 0x1d714,
-	0x1d716, 0x1d71b,
-	0x1d736, 0x1d74e,
-	0x1d750, 0x1d755,
-	0x1d770, 0x1d788,
-	0x1d78a, 0x1d78f,
-	0x1d7aa, 0x1d7c2,
-	0x1d7c4, 0x1d7c9,
-};
-
-static Rune __islowerp[] = {
-	0x0101, 0x0135,
-	0x013a, 0x0146,
-	0x014b, 0x0177,
-	0x017a, 0x017c,
-	0x0183, 0x0185,
-	0x01a1, 0x01a5,
-	0x01b4, 0x01b6,
-	0x01cc, 0x01da,
-	0x01df, 0x01ed,
-	0x01f3, 0x01f5,
-	0x01f9, 0x0231,
-	0x0247, 0x024d,
-	0x0371, 0x0373,
-	0x03d9, 0x03ed,
-	0x0461, 0x0481,
-	0x048b, 0x04bf,
-	0x04c2, 0x04cc,
-	0x04d1, 0x0527,
-	0x1e01, 0x1e93,
-	0x1e9f, 0x1efd,
-	0x2c68, 0x2c6c,
-	0x2c81, 0x2ce1,
-	0x2cec, 0x2cee,
-	0xa641, 0xa66d,
-	0xa681, 0xa697,
-	0xa723, 0xa72d,
-	0xa733, 0xa76f,
-	0xa77a, 0xa77c,
-	0xa77f, 0xa787,
-	0xa78c, 0xa78e,
-	0xa791, 0xa793,
-	0xa7a1, 0xa7a9,
-};
-
-static Rune __islowers[] = {
-	0x00b5,
-	0x0188,
-	0x0192,
-	0x0195,
-	0x019e,
-	0x01a8,
-	0x01ad,
-	0x01b0,
-	0x01c6,
-	0x01c9,
-	0x023c,
-	0x0242,
-	0x0377,
-	0x0390,
-	0x03f5,
-	0x03f8,
-	0x1fbe,
-	0x210a,
-	0x2113,
-	0x212f,
-	0x2134,
-	0x2139,
-	0x214e,
-	0x2184,
-	0x2c61,
-	0x2c71,
-	0x2cf3,
-	0x2d27,
-	0x2d2d,
-	0xa7fa,
-	0x1d4bb,
-	0x1d7cb,
-};
-
-int
-islowerrune(Rune c)
-{
-	Rune *p;
-
-	p = rbsearch(c, __islowerr, nelem(__islowerr)/2, 2);
-	if(p && c >= p[0] && c <= p[1])
-		return 1;
-	p = rbsearch(c, __islowerp, nelem(__islowerp)/2, 2);
-	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
-		return 1;
-	p = rbsearch(c, __islowers, nelem(__islowers), 1);
-	if(p && c == p[0])
-		return 1;
-	return 0;
-}
-
-static Rune __istitler[] = {
-	0x0041, 0x005a,
-	0x00c0, 0x00d6,
-	0x00d8, 0x00de,
-	0x0178, 0x0179,
-	0x0181, 0x0182,
-	0x0186, 0x0187,
-	0x0189, 0x018b,
-	0x018e, 0x0191,
-	0x0193, 0x0194,
-	0x0196, 0x0198,
-	0x019c, 0x019d,
-	0x019f, 0x01a0,
-	0x01a6, 0x01a7,
-	0x01ae, 0x01af,
-	0x01b1, 0x01b3,
-	0x01b7, 0x01b8,
-	0x01f6, 0x01f8,
-	0x023a, 0x023b,
-	0x023d, 0x023e,
-	0x0243, 0x0246,
-	0x0388, 0x038a,
-	0x038e, 0x038f,
-	0x0391, 0x03a1,
-	0x03a3, 0x03ab,
-	0x03f9, 0x03fa,
-	0x03fd, 0x042f,
-	0x04c0, 0x04c1,
-	0x0531, 0x0556,
-	0x10a0, 0x10c5,
-	0x1f08, 0x1f0f,
-	0x1f18, 0x1f1d,
-	0x1f28, 0x1f2f,
-	0x1f38, 0x1f3f,
-	0x1f48, 0x1f4d,
-	0x1f68, 0x1f6f,
-	0x1f88, 0x1f8f,
-	0x1f98, 0x1f9f,
-	0x1fa8, 0x1faf,
-	0x1fb8, 0x1fbc,
-	0x1fc8, 0x1fcc,
-	0x1fd8, 0x1fdb,
-	0x1fe8, 0x1fec,
-	0x1ff8, 0x1ffc,
-	0x2160, 0x216f,
-	0x24b6, 0x24cf,
-	0x2c00, 0x2c2e,
-	0x2c62, 0x2c64,
-	0x2c6d, 0x2c70,
-	0x2c7e, 0x2c80,
-	0xa77d, 0xa77e,
-	0xff21, 0xff3a,
-	0x10400, 0x10427,
-};
-
-static Rune __istitlep[] = {
-	0x0100, 0x012e,
-	0x0132, 0x0136,
-	0x0139, 0x0147,
-	0x014a, 0x0176,
-	0x017b, 0x017d,
-	0x01a2, 0x01a4,
-	0x01cb, 0x01db,
-	0x01de, 0x01ee,
-	0x01f2, 0x01f4,
-	0x01fa, 0x0232,
-	0x0248, 0x024e,
-	0x0370, 0x0372,
-	0x03d8, 0x03ee,
-	0x0460, 0x0480,
-	0x048a, 0x04be,
-	0x04c3, 0x04cd,
-	0x04d0, 0x0526,
-	0x1e00, 0x1e94,
-	0x1ea0, 0x1efe,
-	0x1f59, 0x1f5f,
-	0x2c67, 0x2c6b,
-	0x2c82, 0x2ce2,
-	0x2ceb, 0x2ced,
-	0xa640, 0xa66c,
-	0xa680, 0xa696,
-	0xa722, 0xa72e,
-	0xa732, 0xa76e,
-	0xa779, 0xa77b,
-	0xa780, 0xa786,
-	0xa78b, 0xa78d,
-	0xa790, 0xa792,
-	0xa7a0, 0xa7aa,
-};
-
-static Rune __istitles[] = {
-	0x0184,
-	0x01a9,
-	0x01ac,
-	0x01b5,
-	0x01bc,
-	0x01c5,
-	0x01c8,
-	0x0241,
-	0x0376,
-	0x0386,
-	0x038c,
-	0x03cf,
-	0x03f7,
-	0x10c7,
-	0x10cd,
-	0x2132,
-	0x2183,
-	0x2c60,
-	0x2c72,
-	0x2c75,
-	0x2cf2,
-};
-
-int
-istitlerune(Rune c)
-{
-	Rune *p;
-
-	p = rbsearch(c, __istitler, nelem(__istitler)/2, 2);
-	if(p && c >= p[0] && c <= p[1])
-		return 1;
-	p = rbsearch(c, __istitlep, nelem(__istitlep)/2, 2);
-	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
-		return 1;
-	p = rbsearch(c, __istitles, nelem(__istitles), 1);
-	if(p && c == p[0])
-		return 1;
-	return 0;
-}
-
-static Rune __toupperr[] = {
-	0x0061, 0x007a, 1048544,
-	0x00e0, 0x00f6, 1048544,
-	0x00f8, 0x00fe, 1048544,
-	0x023f, 0x0240, 1059391,
-	0x0256, 0x0257, 1048371,
-	0x028a, 0x028b, 1048359,
-	0x037b, 0x037d, 1048706,
-	0x03ad, 0x03af, 1048539,
-	0x03b1, 0x03c1, 1048544,
-	0x03c3, 0x03cb, 1048544,
-	0x03cd, 0x03ce, 1048513,
-	0x0430, 0x044f, 1048544,
-	0x0450, 0x045f, 1048496,
-	0x0561, 0x0586, 1048528,
-	0x1f00, 0x1f07, 1048584,
-	0x1f10, 0x1f15, 1048584,
-	0x1f20, 0x1f27, 1048584,
-	0x1f30, 0x1f37, 1048584,
-	0x1f40, 0x1f45, 1048584,
-	0x1f60, 0x1f67, 1048584,
-	0x1f70, 0x1f71, 1048650,
-	0x1f72, 0x1f75, 1048662,
-	0x1f76, 0x1f77, 1048676,
-	0x1f78, 0x1f79, 1048704,
-	0x1f7a, 0x1f7b, 1048688,
-	0x1f7c, 0x1f7d, 1048702,
-	0x1f80, 0x1f87, 1048584,
-	0x1f90, 0x1f97, 1048584,
-	0x1fa0, 0x1fa7, 1048584,
-	0x1fb0, 0x1fb1, 1048584,
-	0x1fd0, 0x1fd1, 1048584,
-	0x1fe0, 0x1fe1, 1048584,
-	0x2170, 0x217f, 1048560,
-	0x24d0, 0x24e9, 1048550,
-	0x2c30, 0x2c5e, 1048528,
-	0x2d00, 0x2d25, 1041312,
-	0xff41, 0xff5a, 1048544,
-	0x10428, 0x1044f, 1048536,
-};
-
-static Rune __toupperp[] = {
-	0x0101, 0x012f, 1048575,
-	0x0133, 0x0137, 1048575,
-	0x013a, 0x0148, 1048575,
-	0x014b, 0x0177, 1048575,
-	0x017a, 0x017e, 1048575,
-	0x0183, 0x0185, 1048575,
-	0x01a1, 0x01a5, 1048575,
-	0x01b4, 0x01b6, 1048575,
-	0x01ce, 0x01dc, 1048575,
-	0x01df, 0x01ef, 1048575,
-	0x01f9, 0x021f, 1048575,
-	0x0223, 0x0233, 1048575,
-	0x0247, 0x024f, 1048575,
-	0x0371, 0x0373, 1048575,
-	0x03d9, 0x03ef, 1048575,
-	0x0461, 0x0481, 1048575,
-	0x048b, 0x04bf, 1048575,
-	0x04c2, 0x04ce, 1048575,
-	0x04d1, 0x0527, 1048575,
-	0x1e01, 0x1e95, 1048575,
-	0x1ea1, 0x1eff, 1048575,
-	0x1f51, 0x1f57, 1048584,
-	0x2c68, 0x2c6c, 1048575,
-	0x2c81, 0x2ce3, 1048575,
-	0x2cec, 0x2cee, 1048575,
-	0xa641, 0xa66d, 1048575,
-	0xa681, 0xa697, 1048575,
-	0xa723, 0xa72f, 1048575,
-	0xa733, 0xa76f, 1048575,
-	0xa77a, 0xa77c, 1048575,
-	0xa77f, 0xa787, 1048575,
-	0xa791, 0xa793, 1048575,
-	0xa7a1, 0xa7a9, 1048575,
-};
-
-static Rune __touppers[] = {
-	0x00b5, 1049319,
-	0x00ff, 1048697,
-	0x0131, 1048344,
-	0x017f, 1048276,
-	0x0180, 1048771,
-	0x0188, 1048575,
-	0x018c, 1048575,
-	0x0192, 1048575,
-	0x0195, 1048673,
-	0x0199, 1048575,
-	0x019a, 1048739,
-	0x019e, 1048706,
-	0x01a8, 1048575,
-	0x01ad, 1048575,
-	0x01b0, 1048575,
-	0x01b9, 1048575,
-	0x01bd, 1048575,
-	0x01bf, 1048632,
-	0x01c5, 1048575,
-	0x01c6, 1048574,
-	0x01c8, 1048575,
-	0x01c9, 1048574,
-	0x01cb, 1048575,
-	0x01cc, 1048574,
-	0x01dd, 1048497,
-	0x01f2, 1048575,
-	0x01f3, 1048574,
-	0x01f5, 1048575,
-	0x023c, 1048575,
-	0x0242, 1048575,
-	0x0250, 1059359,
-	0x0251, 1059356,
-	0x0252, 1059358,
-	0x0253, 1048366,
-	0x0254, 1048370,
-	0x0259, 1048374,
-	0x025b, 1048373,
-	0x0260, 1048371,
-	0x0263, 1048369,
-	0x0265, 1090856,
-	0x0266, 1090884,
-	0x0268, 1048367,
-	0x0269, 1048365,
-	0x026b, 1059319,
-	0x026f, 1048365,
-	0x0271, 1059325,
-	0x0272, 1048363,
-	0x0275, 1048362,
-	0x027d, 1059303,
-	0x0280, 1048358,
-	0x0283, 1048358,
-	0x0288, 1048358,
-	0x0289, 1048507,
-	0x028c, 1048505,
-	0x0292, 1048357,
-	0x0345, 1048660,
-	0x0377, 1048575,
-	0x03ac, 1048538,
-	0x03c2, 1048545,
-	0x03cc, 1048512,
-	0x03d0, 1048514,
-	0x03d1, 1048519,
-	0x03d5, 1048529,
-	0x03d6, 1048522,
-	0x03d7, 1048568,
-	0x03f0, 1048490,
-	0x03f1, 1048496,
-	0x03f2, 1048583,
-	0x03f5, 1048480,
-	0x03f8, 1048575,
-	0x03fb, 1048575,
-	0x04cf, 1048561,
-	0x1d79, 1083908,
-	0x1d7d, 1052390,
-	0x1e9b, 1048517,
-	0x1fb3, 1048585,
-	0x1fbe, 1041371,
-	0x1fc3, 1048585,
-	0x1fe5, 1048583,
-	0x1ff3, 1048585,
-	0x214e, 1048548,
-	0x2184, 1048575,
-	0x2c61, 1048575,
-	0x2c65, 1037781,
-	0x2c66, 1037784,
-	0x2c73, 1048575,
-	0x2c76, 1048575,
-	0x2cf3, 1048575,
-	0x2d27, 1041312,
-	0x2d2d, 1041312,
-	0xa78c, 1048575,
-};
-
-Rune
-toupperrune(Rune c)
-{
-	Rune *p;
-
-	p = rbsearch(c, __toupperr, nelem(__toupperr)/3, 3);
-	if(p && c >= p[0] && c <= p[1])
-		return c + p[2] - 1048576;
-	p = rbsearch(c, __toupperp, nelem(__toupperp)/3, 3);
-	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
-		return c + p[2] - 1048576;
-	p = rbsearch(c, __touppers, nelem(__touppers)/2, 2);
-	if(p && c == p[0])
-		return c + p[1] - 1048576;
-	return c;
-}
-
-static Rune __tolowerr[] = {
-	0x0041, 0x005a, 1048608,
-	0x00c0, 0x00d6, 1048608,
-	0x00d8, 0x00de, 1048608,
-	0x0189, 0x018a, 1048781,
-	0x01b1, 0x01b2, 1048793,
-	0x0388, 0x038a, 1048613,
-	0x038e, 0x038f, 1048639,
-	0x0391, 0x03a1, 1048608,
-	0x03a3, 0x03ab, 1048608,
-	0x03fd, 0x03ff, 1048446,
-	0x0400, 0x040f, 1048656,
-	0x0410, 0x042f, 1048608,
-	0x0531, 0x0556, 1048624,
-	0x10a0, 0x10c5, 1055840,
-	0x1f08, 0x1f0f, 1048568,
-	0x1f18, 0x1f1d, 1048568,
-	0x1f28, 0x1f2f, 1048568,
-	0x1f38, 0x1f3f, 1048568,
-	0x1f48, 0x1f4d, 1048568,
-	0x1f68, 0x1f6f, 1048568,
-	0x1f88, 0x1f8f, 1048568,
-	0x1f98, 0x1f9f, 1048568,
-	0x1fa8, 0x1faf, 1048568,
-	0x1fb8, 0x1fb9, 1048568,
-	0x1fba, 0x1fbb, 1048502,
-	0x1fc8, 0x1fcb, 1048490,
-	0x1fd8, 0x1fd9, 1048568,
-	0x1fda, 0x1fdb, 1048476,
-	0x1fe8, 0x1fe9, 1048568,
-	0x1fea, 0x1feb, 1048464,
-	0x1ff8, 0x1ff9, 1048448,
-	0x1ffa, 0x1ffb, 1048450,
-	0x2160, 0x216f, 1048592,
-	0x24b6, 0x24cf, 1048602,
-	0x2c00, 0x2c2e, 1048624,
-	0x2c7e, 0x2c7f, 1037761,
-	0xff21, 0xff3a, 1048608,
-	0x10400, 0x10427, 1048616,
-};
-
-static Rune __tolowerp[] = {
-	0x0100, 0x012e, 1048577,
-	0x0132, 0x0136, 1048577,
-	0x0139, 0x0147, 1048577,
-	0x014a, 0x0176, 1048577,
-	0x017b, 0x017d, 1048577,
-	0x01a2, 0x01a4, 1048577,
-	0x01b3, 0x01b5, 1048577,
-	0x01cd, 0x01db, 1048577,
-	0x01de, 0x01ee, 1048577,
-	0x01f8, 0x021e, 1048577,
-	0x0222, 0x0232, 1048577,
-	0x0248, 0x024e, 1048577,
-	0x0370, 0x0372, 1048577,
-	0x03d8, 0x03ee, 1048577,
-	0x0460, 0x0480, 1048577,
-	0x048a, 0x04be, 1048577,
-	0x04c3, 0x04cd, 1048577,
-	0x04d0, 0x0526, 1048577,
-	0x1e00, 0x1e94, 1048577,
-	0x1ea0, 0x1efe, 1048577,
-	0x1f59, 0x1f5f, 1048568,
-	0x2c67, 0x2c6b, 1048577,
-	0x2c80, 0x2ce2, 1048577,
-	0x2ceb, 0x2ced, 1048577,
-	0xa640, 0xa66c, 1048577,
-	0xa680, 0xa696, 1048577,
-	0xa722, 0xa72e, 1048577,
-	0xa732, 0xa76e, 1048577,
-	0xa779, 0xa77b, 1048577,
-	0xa780, 0xa786, 1048577,
-	0xa790, 0xa792, 1048577,
-	0xa7a0, 0xa7a8, 1048577,
-};
-
-static Rune __tolowers[] = {
-	0x0130, 1048377,
-	0x0178, 1048455,
-	0x0179, 1048577,
-	0x0181, 1048786,
-	0x0182, 1048577,
-	0x0184, 1048577,
-	0x0186, 1048782,
-	0x0187, 1048577,
-	0x018b, 1048577,
-	0x018e, 1048655,
-	0x018f, 1048778,
-	0x0190, 1048779,
-	0x0191, 1048577,
-	0x0193, 1048781,
-	0x0194, 1048783,
-	0x0196, 1048787,
-	0x0197, 1048785,
-	0x0198, 1048577,
-	0x019c, 1048787,
-	0x019d, 1048789,
-	0x019f, 1048790,
-	0x01a0, 1048577,
-	0x01a6, 1048794,
-	0x01a7, 1048577,
-	0x01a9, 1048794,
-	0x01ac, 1048577,
-	0x01ae, 1048794,
-	0x01af, 1048577,
-	0x01b7, 1048795,
-	0x01b8, 1048577,
-	0x01bc, 1048577,
-	0x01c4, 1048578,
-	0x01c5, 1048577,
-	0x01c7, 1048578,
-	0x01c8, 1048577,
-	0x01ca, 1048578,
-	0x01cb, 1048577,
-	0x01f1, 1048578,
-	0x01f2, 1048577,
-	0x01f4, 1048577,
-	0x01f6, 1048479,
-	0x01f7, 1048520,
-	0x0220, 1048446,
-	0x023a, 1059371,
-	0x023b, 1048577,
-	0x023d, 1048413,
-	0x023e, 1059368,
-	0x0241, 1048577,
-	0x0243, 1048381,
-	0x0244, 1048645,
-	0x0245, 1048647,
-	0x0246, 1048577,
-	0x0376, 1048577,
-	0x0386, 1048614,
-	0x038c, 1048640,
-	0x03cf, 1048584,
-	0x03f4, 1048516,
-	0x03f7, 1048577,
-	0x03f9, 1048569,
-	0x03fa, 1048577,
-	0x04c0, 1048591,
-	0x04c1, 1048577,
-	0x10c7, 1055840,
-	0x10cd, 1055840,
-	0x1e9e, 1040961,
-	0x1fbc, 1048567,
-	0x1fcc, 1048567,
-	0x1fec, 1048569,
-	0x1ffc, 1048567,
-	0x2126, 1041059,
-	0x212a, 1040193,
-	0x212b, 1040314,
-	0x2132, 1048604,
-	0x2183, 1048577,
-	0x2c60, 1048577,
-	0x2c62, 1037833,
-	0x2c63, 1044762,
-	0x2c64, 1037849,
-	0x2c6d, 1037796,
-	0x2c6e, 1037827,
-	0x2c6f, 1037793,
-	0x2c70, 1037794,
-	0x2c72, 1048577,
-	0x2c75, 1048577,
-	0x2cf2, 1048577,
-	0xa77d, 1013244,
-	0xa77e, 1048577,
-	0xa78b, 1048577,
-	0xa78d, 1006296,
-	0xa7aa, 1006268,
-};
-
-Rune
-tolowerrune(Rune c)
-{
-	Rune *p;
-
-	p = rbsearch(c, __tolowerr, nelem(__tolowerr)/3, 3);
-	if(p && c >= p[0] && c <= p[1])
-		return c + p[2] - 1048576;
-	p = rbsearch(c, __tolowerp, nelem(__tolowerp)/3, 3);
-	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
-		return c + p[2] - 1048576;
-	p = rbsearch(c, __tolowers, nelem(__tolowers)/2, 2);
-	if(p && c == p[0])
-		return c + p[1] - 1048576;
-	return c;
-}
-
-static Rune __totitler[] = {
-	0x0061, 0x007a, 1048544,
-	0x00e0, 0x00f6, 1048544,
-	0x00f8, 0x00fe, 1048544,
-	0x023f, 0x0240, 1059391,
-	0x0256, 0x0257, 1048371,
-	0x028a, 0x028b, 1048359,
-	0x037b, 0x037d, 1048706,
-	0x03ad, 0x03af, 1048539,
-	0x03b1, 0x03c1, 1048544,
-	0x03c3, 0x03cb, 1048544,
-	0x03cd, 0x03ce, 1048513,
-	0x0430, 0x044f, 1048544,
-	0x0450, 0x045f, 1048496,
-	0x0561, 0x0586, 1048528,
-	0x1f00, 0x1f07, 1048584,
-	0x1f10, 0x1f15, 1048584,
-	0x1f20, 0x1f27, 1048584,
-	0x1f30, 0x1f37, 1048584,
-	0x1f40, 0x1f45, 1048584,
-	0x1f60, 0x1f67, 1048584,
-	0x1f70, 0x1f71, 1048650,
-	0x1f72, 0x1f75, 1048662,
-	0x1f76, 0x1f77, 1048676,
-	0x1f78, 0x1f79, 1048704,
-	0x1f7a, 0x1f7b, 1048688,
-	0x1f7c, 0x1f7d, 1048702,
-	0x1f80, 0x1f87, 1048584,
-	0x1f90, 0x1f97, 1048584,
-	0x1fa0, 0x1fa7, 1048584,
-	0x1fb0, 0x1fb1, 1048584,
-	0x1fd0, 0x1fd1, 1048584,
-	0x1fe0, 0x1fe1, 1048584,
-	0x2170, 0x217f, 1048560,
-	0x24d0, 0x24e9, 1048550,
-	0x2c30, 0x2c5e, 1048528,
-	0x2d00, 0x2d25, 1041312,
-	0xff41, 0xff5a, 1048544,
-	0x10428, 0x1044f, 1048536,
-};
-
-static Rune __totitlep[] = {
-	0x0101, 0x012f, 1048575,
-	0x0133, 0x0137, 1048575,
-	0x013a, 0x0148, 1048575,
-	0x014b, 0x0177, 1048575,
-	0x017a, 0x017e, 1048575,
-	0x0183, 0x0185, 1048575,
-	0x01a1, 0x01a5, 1048575,
-	0x01b4, 0x01b6, 1048575,
-	0x01cc, 0x01dc, 1048575,
-	0x01df, 0x01ef, 1048575,
-	0x01f3, 0x01f5, 1048575,
-	0x01f9, 0x021f, 1048575,
-	0x0223, 0x0233, 1048575,
-	0x0247, 0x024f, 1048575,
-	0x0371, 0x0373, 1048575,
-	0x03d9, 0x03ef, 1048575,
-	0x0461, 0x0481, 1048575,
-	0x048b, 0x04bf, 1048575,
-	0x04c2, 0x04ce, 1048575,
-	0x04d1, 0x0527, 1048575,
-	0x1e01, 0x1e95, 1048575,
-	0x1ea1, 0x1eff, 1048575,
-	0x1f51, 0x1f57, 1048584,
-	0x2c68, 0x2c6c, 1048575,
-	0x2c81, 0x2ce3, 1048575,
-	0x2cec, 0x2cee, 1048575,
-	0xa641, 0xa66d, 1048575,
-	0xa681, 0xa697, 1048575,
-	0xa723, 0xa72f, 1048575,
-	0xa733, 0xa76f, 1048575,
-	0xa77a, 0xa77c, 1048575,
-	0xa77f, 0xa787, 1048575,
-	0xa791, 0xa793, 1048575,
-	0xa7a1, 0xa7a9, 1048575,
-};
-
-static Rune __totitles[] = {
-	0x00b5, 1049319,
-	0x00ff, 1048697,
-	0x0131, 1048344,
-	0x017f, 1048276,
-	0x0180, 1048771,
-	0x0188, 1048575,
-	0x018c, 1048575,
-	0x0192, 1048575,
-	0x0195, 1048673,
-	0x0199, 1048575,
-	0x019a, 1048739,
-	0x019e, 1048706,
-	0x01a8, 1048575,
-	0x01ad, 1048575,
-	0x01b0, 1048575,
-	0x01b9, 1048575,
-	0x01bd, 1048575,
-	0x01bf, 1048632,
-	0x01c4, 1048577,
-	0x01c6, 1048575,
-	0x01c7, 1048577,
-	0x01c9, 1048575,
-	0x01ca, 1048577,
-	0x01dd, 1048497,
-	0x01f1, 1048577,
-	0x023c, 1048575,
-	0x0242, 1048575,
-	0x0250, 1059359,
-	0x0251, 1059356,
-	0x0252, 1059358,
-	0x0253, 1048366,
-	0x0254, 1048370,
-	0x0259, 1048374,
-	0x025b, 1048373,
-	0x0260, 1048371,
-	0x0263, 1048369,
-	0x0265, 1090856,
-	0x0266, 1090884,
-	0x0268, 1048367,
-	0x0269, 1048365,
-	0x026b, 1059319,
-	0x026f, 1048365,
-	0x0271, 1059325,
-	0x0272, 1048363,
-	0x0275, 1048362,
-	0x027d, 1059303,
-	0x0280, 1048358,
-	0x0283, 1048358,
-	0x0288, 1048358,
-	0x0289, 1048507,
-	0x028c, 1048505,
-	0x0292, 1048357,
-	0x0345, 1048660,
-	0x0377, 1048575,
-	0x03ac, 1048538,
-	0x03c2, 1048545,
-	0x03cc, 1048512,
-	0x03d0, 1048514,
-	0x03d1, 1048519,
-	0x03d5, 1048529,
-	0x03d6, 1048522,
-	0x03d7, 1048568,
-	0x03f0, 1048490,
-	0x03f1, 1048496,
-	0x03f2, 1048583,
-	0x03f5, 1048480,
-	0x03f8, 1048575,
-	0x03fb, 1048575,
-	0x04cf, 1048561,
-	0x1d79, 1083908,
-	0x1d7d, 1052390,
-	0x1e9b, 1048517,
-	0x1fb3, 1048585,
-	0x1fbe, 1041371,
-	0x1fc3, 1048585,
-	0x1fe5, 1048583,
-	0x1ff3, 1048585,
-	0x214e, 1048548,
-	0x2184, 1048575,
-	0x2c61, 1048575,
-	0x2c65, 1037781,
-	0x2c66, 1037784,
-	0x2c73, 1048575,
-	0x2c76, 1048575,
-	0x2cf3, 1048575,
-	0x2d27, 1041312,
-	0x2d2d, 1041312,
-	0xa78c, 1048575,
-};
-
-Rune
-totitlerune(Rune c)
-{
-	Rune *p;
-
-	p = rbsearch(c, __totitler, nelem(__totitler)/3, 3);
-	if(p && c >= p[0] && c <= p[1])
-		return c + p[2] - 1048576;
-	p = rbsearch(c, __totitlep, nelem(__totitlep)/3, 3);
-	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
-		return c + p[2] - 1048576;
-	p = rbsearch(c, __totitles, nelem(__totitles)/2, 2);
-	if(p && c == p[0])
-		return c + p[1] - 1048576;
-	return c;
-}
-
diff --git a/src/lib9/utf/runetypebody-6.3.0.h b/src/lib9/utf/runetypebody-6.3.0.h
new file mode 100644
index 0000000..5554dca
--- /dev/null
+++ b/src/lib9/utf/runetypebody-6.3.0.h
@@ -0,0 +1,1638 @@
+/* generated automatically by mkrunetype.c from UnicodeData-6.3.0.txt */
+
+static Rune __isspacer[] = {
+	0x0009, 0x000d,
+	0x0020, 0x0020,
+	0x0085, 0x0085,
+	0x00a0, 0x00a0,
+	0x1680, 0x1680,
+	0x2000, 0x200a,
+	0x2028, 0x2029,
+	0x202f, 0x202f,
+	0x205f, 0x205f,
+	0x3000, 0x3000,
+	0xfeff, 0xfeff,
+};
+
+int
+isspacerune(Rune c)
+{
+	Rune *p;
+
+	p = rbsearch(c, __isspacer, nelem(__isspacer)/2, 2);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	return 0;
+}
+
+static Rune __isdigitr[] = {
+	0x0030, 0x0039,
+	0x0660, 0x0669,
+	0x06f0, 0x06f9,
+	0x07c0, 0x07c9,
+	0x0966, 0x096f,
+	0x09e6, 0x09ef,
+	0x0a66, 0x0a6f,
+	0x0ae6, 0x0aef,
+	0x0b66, 0x0b6f,
+	0x0be6, 0x0bef,
+	0x0c66, 0x0c6f,
+	0x0ce6, 0x0cef,
+	0x0d66, 0x0d6f,
+	0x0e50, 0x0e59,
+	0x0ed0, 0x0ed9,
+	0x0f20, 0x0f29,
+	0x1040, 0x1049,
+	0x1090, 0x1099,
+	0x17e0, 0x17e9,
+	0x1810, 0x1819,
+	0x1946, 0x194f,
+	0x19d0, 0x19d9,
+	0x1a80, 0x1a89,
+	0x1a90, 0x1a99,
+	0x1b50, 0x1b59,
+	0x1bb0, 0x1bb9,
+	0x1c40, 0x1c49,
+	0x1c50, 0x1c59,
+	0xa620, 0xa629,
+	0xa8d0, 0xa8d9,
+	0xa900, 0xa909,
+	0xa9d0, 0xa9d9,
+	0xaa50, 0xaa59,
+	0xabf0, 0xabf9,
+	0xff10, 0xff19,
+	0x104a0, 0x104a9,
+	0x11066, 0x1106f,
+	0x110f0, 0x110f9,
+	0x11136, 0x1113f,
+	0x111d0, 0x111d9,
+	0x116c0, 0x116c9,
+	0x1d7ce, 0x1d7ff,
+};
+
+int
+isdigitrune(Rune c)
+{
+	Rune *p;
+
+	p = rbsearch(c, __isdigitr, nelem(__isdigitr)/2, 2);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	return 0;
+}
+
+static Rune __isalphar[] = {
+	0x0041, 0x005a,
+	0x0061, 0x007a,
+	0x00c0, 0x00d6,
+	0x00d8, 0x00f6,
+	0x00f8, 0x02c1,
+	0x02c6, 0x02d1,
+	0x02e0, 0x02e4,
+	0x0370, 0x0374,
+	0x0376, 0x0377,
+	0x037a, 0x037d,
+	0x0388, 0x038a,
+	0x038e, 0x03a1,
+	0x03a3, 0x03f5,
+	0x03f7, 0x0481,
+	0x048a, 0x0527,
+	0x0531, 0x0556,
+	0x0561, 0x0587,
+	0x05d0, 0x05ea,
+	0x05f0, 0x05f2,
+	0x0620, 0x064a,
+	0x066e, 0x066f,
+	0x0671, 0x06d3,
+	0x06e5, 0x06e6,
+	0x06ee, 0x06ef,
+	0x06fa, 0x06fc,
+	0x0712, 0x072f,
+	0x074d, 0x07a5,
+	0x07ca, 0x07ea,
+	0x07f4, 0x07f5,
+	0x0800, 0x0815,
+	0x0840, 0x0858,
+	0x08a2, 0x08ac,
+	0x0904, 0x0939,
+	0x0958, 0x0961,
+	0x0971, 0x0977,
+	0x0979, 0x097f,
+	0x0985, 0x098c,
+	0x098f, 0x0990,
+	0x0993, 0x09a8,
+	0x09aa, 0x09b0,
+	0x09b6, 0x09b9,
+	0x09dc, 0x09dd,
+	0x09df, 0x09e1,
+	0x09f0, 0x09f1,
+	0x0a05, 0x0a0a,
+	0x0a0f, 0x0a10,
+	0x0a13, 0x0a28,
+	0x0a2a, 0x0a30,
+	0x0a32, 0x0a33,
+	0x0a35, 0x0a36,
+	0x0a38, 0x0a39,
+	0x0a59, 0x0a5c,
+	0x0a72, 0x0a74,
+	0x0a85, 0x0a8d,
+	0x0a8f, 0x0a91,
+	0x0a93, 0x0aa8,
+	0x0aaa, 0x0ab0,
+	0x0ab2, 0x0ab3,
+	0x0ab5, 0x0ab9,
+	0x0ae0, 0x0ae1,
+	0x0b05, 0x0b0c,
+	0x0b0f, 0x0b10,
+	0x0b13, 0x0b28,
+	0x0b2a, 0x0b30,
+	0x0b32, 0x0b33,
+	0x0b35, 0x0b39,
+	0x0b5c, 0x0b5d,
+	0x0b5f, 0x0b61,
+	0x0b85, 0x0b8a,
+	0x0b8e, 0x0b90,
+	0x0b92, 0x0b95,
+	0x0b99, 0x0b9a,
+	0x0b9e, 0x0b9f,
+	0x0ba3, 0x0ba4,
+	0x0ba8, 0x0baa,
+	0x0bae, 0x0bb9,
+	0x0c05, 0x0c0c,
+	0x0c0e, 0x0c10,
+	0x0c12, 0x0c28,
+	0x0c2a, 0x0c33,
+	0x0c35, 0x0c39,
+	0x0c58, 0x0c59,
+	0x0c60, 0x0c61,
+	0x0c85, 0x0c8c,
+	0x0c8e, 0x0c90,
+	0x0c92, 0x0ca8,
+	0x0caa, 0x0cb3,
+	0x0cb5, 0x0cb9,
+	0x0ce0, 0x0ce1,
+	0x0cf1, 0x0cf2,
+	0x0d05, 0x0d0c,
+	0x0d0e, 0x0d10,
+	0x0d12, 0x0d3a,
+	0x0d60, 0x0d61,
+	0x0d7a, 0x0d7f,
+	0x0d85, 0x0d96,
+	0x0d9a, 0x0db1,
+	0x0db3, 0x0dbb,
+	0x0dc0, 0x0dc6,
+	0x0e01, 0x0e30,
+	0x0e32, 0x0e33,
+	0x0e40, 0x0e46,
+	0x0e81, 0x0e82,
+	0x0e87, 0x0e88,
+	0x0e94, 0x0e97,
+	0x0e99, 0x0e9f,
+	0x0ea1, 0x0ea3,
+	0x0eaa, 0x0eab,
+	0x0ead, 0x0eb0,
+	0x0eb2, 0x0eb3,
+	0x0ec0, 0x0ec4,
+	0x0edc, 0x0edf,
+	0x0f40, 0x0f47,
+	0x0f49, 0x0f6c,
+	0x0f88, 0x0f8c,
+	0x1000, 0x102a,
+	0x1050, 0x1055,
+	0x105a, 0x105d,
+	0x1065, 0x1066,
+	0x106e, 0x1070,
+	0x1075, 0x1081,
+	0x10a0, 0x10c5,
+	0x10d0, 0x10fa,
+	0x10fc, 0x1248,
+	0x124a, 0x124d,
+	0x1250, 0x1256,
+	0x125a, 0x125d,
+	0x1260, 0x1288,
+	0x128a, 0x128d,
+	0x1290, 0x12b0,
+	0x12b2, 0x12b5,
+	0x12b8, 0x12be,
+	0x12c2, 0x12c5,
+	0x12c8, 0x12d6,
+	0x12d8, 0x1310,
+	0x1312, 0x1315,
+	0x1318, 0x135a,
+	0x1380, 0x138f,
+	0x13a0, 0x13f4,
+	0x1401, 0x166c,
+	0x166f, 0x167f,
+	0x1681, 0x169a,
+	0x16a0, 0x16ea,
+	0x1700, 0x170c,
+	0x170e, 0x1711,
+	0x1720, 0x1731,
+	0x1740, 0x1751,
+	0x1760, 0x176c,
+	0x176e, 0x1770,
+	0x1780, 0x17b3,
+	0x1820, 0x1877,
+	0x1880, 0x18a8,
+	0x18b0, 0x18f5,
+	0x1900, 0x191c,
+	0x1950, 0x196d,
+	0x1970, 0x1974,
+	0x1980, 0x19ab,
+	0x19c1, 0x19c7,
+	0x1a00, 0x1a16,
+	0x1a20, 0x1a54,
+	0x1b05, 0x1b33,
+	0x1b45, 0x1b4b,
+	0x1b83, 0x1ba0,
+	0x1bae, 0x1baf,
+	0x1bba, 0x1be5,
+	0x1c00, 0x1c23,
+	0x1c4d, 0x1c4f,
+	0x1c5a, 0x1c7d,
+	0x1ce9, 0x1cec,
+	0x1cee, 0x1cf1,
+	0x1cf5, 0x1cf6,
+	0x1d00, 0x1dbf,
+	0x1e00, 0x1f15,
+	0x1f18, 0x1f1d,
+	0x1f20, 0x1f45,
+	0x1f48, 0x1f4d,
+	0x1f50, 0x1f57,
+	0x1f5f, 0x1f7d,
+	0x1f80, 0x1fb4,
+	0x1fb6, 0x1fbc,
+	0x1fc2, 0x1fc4,
+	0x1fc6, 0x1fcc,
+	0x1fd0, 0x1fd3,
+	0x1fd6, 0x1fdb,
+	0x1fe0, 0x1fec,
+	0x1ff2, 0x1ff4,
+	0x1ff6, 0x1ffc,
+	0x2090, 0x209c,
+	0x210a, 0x2113,
+	0x2119, 0x211d,
+	0x212a, 0x212d,
+	0x212f, 0x2139,
+	0x213c, 0x213f,
+	0x2145, 0x2149,
+	0x2183, 0x2184,
+	0x2c00, 0x2c2e,
+	0x2c30, 0x2c5e,
+	0x2c60, 0x2ce4,
+	0x2ceb, 0x2cee,
+	0x2cf2, 0x2cf3,
+	0x2d00, 0x2d25,
+	0x2d30, 0x2d67,
+	0x2d80, 0x2d96,
+	0x2da0, 0x2da6,
+	0x2da8, 0x2dae,
+	0x2db0, 0x2db6,
+	0x2db8, 0x2dbe,
+	0x2dc0, 0x2dc6,
+	0x2dc8, 0x2dce,
+	0x2dd0, 0x2dd6,
+	0x2dd8, 0x2dde,
+	0x3005, 0x3006,
+	0x3031, 0x3035,
+	0x303b, 0x303c,
+	0x3041, 0x3096,
+	0x309d, 0x309f,
+	0x30a1, 0x30fa,
+	0x30fc, 0x30ff,
+	0x3105, 0x312d,
+	0x3131, 0x318e,
+	0x31a0, 0x31ba,
+	0x31f0, 0x31ff,
+	0x3400, 0x4db5,
+	0x4e00, 0x9fcc,
+	0xa000, 0xa48c,
+	0xa4d0, 0xa4fd,
+	0xa500, 0xa60c,
+	0xa610, 0xa61f,
+	0xa62a, 0xa62b,
+	0xa640, 0xa66e,
+	0xa67f, 0xa697,
+	0xa6a0, 0xa6e5,
+	0xa717, 0xa71f,
+	0xa722, 0xa788,
+	0xa78b, 0xa78e,
+	0xa790, 0xa793,
+	0xa7a0, 0xa7aa,
+	0xa7f8, 0xa801,
+	0xa803, 0xa805,
+	0xa807, 0xa80a,
+	0xa80c, 0xa822,
+	0xa840, 0xa873,
+	0xa882, 0xa8b3,
+	0xa8f2, 0xa8f7,
+	0xa90a, 0xa925,
+	0xa930, 0xa946,
+	0xa960, 0xa97c,
+	0xa984, 0xa9b2,
+	0xaa00, 0xaa28,
+	0xaa40, 0xaa42,
+	0xaa44, 0xaa4b,
+	0xaa60, 0xaa76,
+	0xaa80, 0xaaaf,
+	0xaab5, 0xaab6,
+	0xaab9, 0xaabd,
+	0xaadb, 0xaadd,
+	0xaae0, 0xaaea,
+	0xaaf2, 0xaaf4,
+	0xab01, 0xab06,
+	0xab09, 0xab0e,
+	0xab11, 0xab16,
+	0xab20, 0xab26,
+	0xab28, 0xab2e,
+	0xabc0, 0xabe2,
+	0xac00, 0xd7a3,
+	0xd7b0, 0xd7c6,
+	0xd7cb, 0xd7fb,
+	0xf900, 0xfa6d,
+	0xfa70, 0xfad9,
+	0xfb00, 0xfb06,
+	0xfb13, 0xfb17,
+	0xfb1f, 0xfb28,
+	0xfb2a, 0xfb36,
+	0xfb38, 0xfb3c,
+	0xfb40, 0xfb41,
+	0xfb43, 0xfb44,
+	0xfb46, 0xfbb1,
+	0xfbd3, 0xfd3d,
+	0xfd50, 0xfd8f,
+	0xfd92, 0xfdc7,
+	0xfdf0, 0xfdfb,
+	0xfe70, 0xfe74,
+	0xfe76, 0xfefc,
+	0xff21, 0xff3a,
+	0xff41, 0xff5a,
+	0xff66, 0xffbe,
+	0xffc2, 0xffc7,
+	0xffca, 0xffcf,
+	0xffd2, 0xffd7,
+	0xffda, 0xffdc,
+	0x10000, 0x1000b,
+	0x1000d, 0x10026,
+	0x10028, 0x1003a,
+	0x1003c, 0x1003d,
+	0x1003f, 0x1004d,
+	0x10050, 0x1005d,
+	0x10080, 0x100fa,
+	0x10280, 0x1029c,
+	0x102a0, 0x102d0,
+	0x10300, 0x1031e,
+	0x10330, 0x10340,
+	0x10342, 0x10349,
+	0x10380, 0x1039d,
+	0x103a0, 0x103c3,
+	0x103c8, 0x103cf,
+	0x10400, 0x1049d,
+	0x10800, 0x10805,
+	0x1080a, 0x10835,
+	0x10837, 0x10838,
+	0x1083f, 0x10855,
+	0x10900, 0x10915,
+	0x10920, 0x10939,
+	0x10980, 0x109b7,
+	0x109be, 0x109bf,
+	0x10a10, 0x10a13,
+	0x10a15, 0x10a17,
+	0x10a19, 0x10a33,
+	0x10a60, 0x10a7c,
+	0x10b00, 0x10b35,
+	0x10b40, 0x10b55,
+	0x10b60, 0x10b72,
+	0x10c00, 0x10c48,
+	0x11003, 0x11037,
+	0x11083, 0x110af,
+	0x110d0, 0x110e8,
+	0x11103, 0x11126,
+	0x11183, 0x111b2,
+	0x111c1, 0x111c4,
+	0x11680, 0x116aa,
+	0x12000, 0x1236e,
+	0x13000, 0x1342e,
+	0x16800, 0x16a38,
+	0x16f00, 0x16f44,
+	0x16f93, 0x16f9f,
+	0x1b000, 0x1b001,
+	0x1d400, 0x1d454,
+	0x1d456, 0x1d49c,
+	0x1d49e, 0x1d49f,
+	0x1d4a5, 0x1d4a6,
+	0x1d4a9, 0x1d4ac,
+	0x1d4ae, 0x1d4b9,
+	0x1d4bd, 0x1d4c3,
+	0x1d4c5, 0x1d505,
+	0x1d507, 0x1d50a,
+	0x1d50d, 0x1d514,
+	0x1d516, 0x1d51c,
+	0x1d51e, 0x1d539,
+	0x1d53b, 0x1d53e,
+	0x1d540, 0x1d544,
+	0x1d54a, 0x1d550,
+	0x1d552, 0x1d6a5,
+	0x1d6a8, 0x1d6c0,
+	0x1d6c2, 0x1d6da,
+	0x1d6dc, 0x1d6fa,
+	0x1d6fc, 0x1d714,
+	0x1d716, 0x1d734,
+	0x1d736, 0x1d74e,
+	0x1d750, 0x1d76e,
+	0x1d770, 0x1d788,
+	0x1d78a, 0x1d7a8,
+	0x1d7aa, 0x1d7c2,
+	0x1d7c4, 0x1d7cb,
+	0x1ee00, 0x1ee03,
+	0x1ee05, 0x1ee1f,
+	0x1ee21, 0x1ee22,
+	0x1ee29, 0x1ee32,
+	0x1ee34, 0x1ee37,
+	0x1ee4d, 0x1ee4f,
+	0x1ee51, 0x1ee52,
+	0x1ee61, 0x1ee62,
+	0x1ee67, 0x1ee6a,
+	0x1ee6c, 0x1ee72,
+	0x1ee74, 0x1ee77,
+	0x1ee79, 0x1ee7c,
+	0x1ee80, 0x1ee89,
+	0x1ee8b, 0x1ee9b,
+	0x1eea1, 0x1eea3,
+	0x1eea5, 0x1eea9,
+	0x1eeab, 0x1eebb,
+	0x20000, 0x2a6d6,
+	0x2a700, 0x2b734,
+	0x2b740, 0x2b81d,
+	0x2f800, 0x2fa1d,
+};
+
+static Rune __isalphas[] = {
+	0x00aa,
+	0x00b5,
+	0x00ba,
+	0x02ec,
+	0x02ee,
+	0x0386,
+	0x038c,
+	0x0559,
+	0x06d5,
+	0x06ff,
+	0x0710,
+	0x07b1,
+	0x07fa,
+	0x081a,
+	0x0824,
+	0x0828,
+	0x08a0,
+	0x093d,
+	0x0950,
+	0x09b2,
+	0x09bd,
+	0x09ce,
+	0x0a5e,
+	0x0abd,
+	0x0ad0,
+	0x0b3d,
+	0x0b71,
+	0x0b83,
+	0x0b9c,
+	0x0bd0,
+	0x0c3d,
+	0x0cbd,
+	0x0cde,
+	0x0d3d,
+	0x0d4e,
+	0x0dbd,
+	0x0e84,
+	0x0e8a,
+	0x0e8d,
+	0x0ea5,
+	0x0ea7,
+	0x0ebd,
+	0x0ec6,
+	0x0f00,
+	0x103f,
+	0x1061,
+	0x108e,
+	0x10c7,
+	0x10cd,
+	0x1258,
+	0x12c0,
+	0x17d7,
+	0x17dc,
+	0x18aa,
+	0x1aa7,
+	0x1f59,
+	0x1f5b,
+	0x1f5d,
+	0x1fbe,
+	0x2071,
+	0x207f,
+	0x2102,
+	0x2107,
+	0x2115,
+	0x2124,
+	0x2126,
+	0x2128,
+	0x214e,
+	0x2d27,
+	0x2d2d,
+	0x2d6f,
+	0x2e2f,
+	0xa8fb,
+	0xa9cf,
+	0xaa7a,
+	0xaab1,
+	0xaac0,
+	0xaac2,
+	0xfb1d,
+	0xfb3e,
+	0x10808,
+	0x1083c,
+	0x10a00,
+	0x16f50,
+	0x1d4a2,
+	0x1d4bb,
+	0x1d546,
+	0x1ee24,
+	0x1ee27,
+	0x1ee39,
+	0x1ee3b,
+	0x1ee42,
+	0x1ee47,
+	0x1ee49,
+	0x1ee4b,
+	0x1ee54,
+	0x1ee57,
+	0x1ee59,
+	0x1ee5b,
+	0x1ee5d,
+	0x1ee5f,
+	0x1ee64,
+	0x1ee7e,
+};
+
+int
+isalpharune(Rune c)
+{
+	Rune *p;
+
+	p = rbsearch(c, __isalphar, nelem(__isalphar)/2, 2);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	p = rbsearch(c, __isalphas, nelem(__isalphas), 1);
+	if(p && c == p[0])
+		return 1;
+	return 0;
+}
+
+static Rune __isupperr[] = {
+	0x0041, 0x005a,
+	0x00c0, 0x00d6,
+	0x00d8, 0x00de,
+	0x0178, 0x0179,
+	0x0181, 0x0182,
+	0x0186, 0x0187,
+	0x0189, 0x018b,
+	0x018e, 0x0191,
+	0x0193, 0x0194,
+	0x0196, 0x0198,
+	0x019c, 0x019d,
+	0x019f, 0x01a0,
+	0x01a6, 0x01a7,
+	0x01ae, 0x01af,
+	0x01b1, 0x01b3,
+	0x01b7, 0x01b8,
+	0x01f6, 0x01f8,
+	0x023a, 0x023b,
+	0x023d, 0x023e,
+	0x0243, 0x0246,
+	0x0388, 0x038a,
+	0x038e, 0x038f,
+	0x0391, 0x03a1,
+	0x03a3, 0x03ab,
+	0x03d2, 0x03d4,
+	0x03f9, 0x03fa,
+	0x03fd, 0x042f,
+	0x04c0, 0x04c1,
+	0x0531, 0x0556,
+	0x10a0, 0x10c5,
+	0x1f08, 0x1f0f,
+	0x1f18, 0x1f1d,
+	0x1f28, 0x1f2f,
+	0x1f38, 0x1f3f,
+	0x1f48, 0x1f4d,
+	0x1f68, 0x1f6f,
+	0x1f88, 0x1f8f,
+	0x1f98, 0x1f9f,
+	0x1fa8, 0x1faf,
+	0x1fb8, 0x1fbc,
+	0x1fc8, 0x1fcc,
+	0x1fd8, 0x1fdb,
+	0x1fe8, 0x1fec,
+	0x1ff8, 0x1ffc,
+	0x210b, 0x210d,
+	0x2110, 0x2112,
+	0x2119, 0x211d,
+	0x212a, 0x212d,
+	0x2130, 0x2133,
+	0x213e, 0x213f,
+	0x2160, 0x216f,
+	0x24b6, 0x24cf,
+	0x2c00, 0x2c2e,
+	0x2c62, 0x2c64,
+	0x2c6d, 0x2c70,
+	0x2c7e, 0x2c80,
+	0xa77d, 0xa77e,
+	0xff21, 0xff3a,
+	0x10400, 0x10427,
+	0x1d400, 0x1d419,
+	0x1d434, 0x1d44d,
+	0x1d468, 0x1d481,
+	0x1d49e, 0x1d49f,
+	0x1d4a5, 0x1d4a6,
+	0x1d4a9, 0x1d4ac,
+	0x1d4ae, 0x1d4b5,
+	0x1d4d0, 0x1d4e9,
+	0x1d504, 0x1d505,
+	0x1d507, 0x1d50a,
+	0x1d50d, 0x1d514,
+	0x1d516, 0x1d51c,
+	0x1d538, 0x1d539,
+	0x1d53b, 0x1d53e,
+	0x1d540, 0x1d544,
+	0x1d54a, 0x1d550,
+	0x1d56c, 0x1d585,
+	0x1d5a0, 0x1d5b9,
+	0x1d5d4, 0x1d5ed,
+	0x1d608, 0x1d621,
+	0x1d63c, 0x1d655,
+	0x1d670, 0x1d689,
+	0x1d6a8, 0x1d6c0,
+	0x1d6e2, 0x1d6fa,
+	0x1d71c, 0x1d734,
+	0x1d756, 0x1d76e,
+	0x1d790, 0x1d7a8,
+};
+
+static Rune __isupperp[] = {
+	0x0100, 0x0136,
+	0x0139, 0x0147,
+	0x014a, 0x0176,
+	0x017b, 0x017d,
+	0x01a2, 0x01a4,
+	0x01cd, 0x01db,
+	0x01de, 0x01ee,
+	0x01fa, 0x0232,
+	0x0248, 0x024e,
+	0x0370, 0x0372,
+	0x03d8, 0x03ee,
+	0x0460, 0x0480,
+	0x048a, 0x04be,
+	0x04c3, 0x04cd,
+	0x04d0, 0x0526,
+	0x1e00, 0x1e94,
+	0x1e9e, 0x1efe,
+	0x1f59, 0x1f5f,
+	0x2124, 0x2128,
+	0x2c67, 0x2c6b,
+	0x2c82, 0x2ce2,
+	0x2ceb, 0x2ced,
+	0xa640, 0xa66c,
+	0xa680, 0xa696,
+	0xa722, 0xa72e,
+	0xa732, 0xa76e,
+	0xa779, 0xa77b,
+	0xa780, 0xa786,
+	0xa78b, 0xa78d,
+	0xa790, 0xa792,
+	0xa7a0, 0xa7aa,
+};
+
+static Rune __isuppers[] = {
+	0x0184,
+	0x01a9,
+	0x01ac,
+	0x01b5,
+	0x01bc,
+	0x01c4,
+	0x01c7,
+	0x01ca,
+	0x01f1,
+	0x01f4,
+	0x0241,
+	0x0376,
+	0x0386,
+	0x038c,
+	0x03cf,
+	0x03f4,
+	0x03f7,
+	0x10c7,
+	0x10cd,
+	0x2102,
+	0x2107,
+	0x2115,
+	0x2145,
+	0x2183,
+	0x2c60,
+	0x2c72,
+	0x2c75,
+	0x2cf2,
+	0x1d49c,
+	0x1d4a2,
+	0x1d546,
+	0x1d7ca,
+};
+
+int
+isupperrune(Rune c)
+{
+	Rune *p;
+
+	p = rbsearch(c, __isupperr, nelem(__isupperr)/2, 2);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	p = rbsearch(c, __isupperp, nelem(__isupperp)/2, 2);
+	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+		return 1;
+	p = rbsearch(c, __isuppers, nelem(__isuppers), 1);
+	if(p && c == p[0])
+		return 1;
+	return 0;
+}
+
+static Rune __islowerr[] = {
+	0x0061, 0x007a,
+	0x00df, 0x00f6,
+	0x00f8, 0x00ff,
+	0x0137, 0x0138,
+	0x0148, 0x0149,
+	0x017e, 0x0180,
+	0x018c, 0x018d,
+	0x0199, 0x019b,
+	0x01aa, 0x01ab,
+	0x01b9, 0x01ba,
+	0x01bd, 0x01bf,
+	0x01dc, 0x01dd,
+	0x01ef, 0x01f0,
+	0x0233, 0x0239,
+	0x023f, 0x0240,
+	0x024f, 0x0293,
+	0x0295, 0x02af,
+	0x037b, 0x037d,
+	0x03ac, 0x03ce,
+	0x03d0, 0x03d1,
+	0x03d5, 0x03d7,
+	0x03ef, 0x03f3,
+	0x03fb, 0x03fc,
+	0x0430, 0x045f,
+	0x04ce, 0x04cf,
+	0x0561, 0x0587,
+	0x1d00, 0x1d2b,
+	0x1d6b, 0x1d77,
+	0x1d79, 0x1d9a,
+	0x1e95, 0x1e9d,
+	0x1eff, 0x1f07,
+	0x1f10, 0x1f15,
+	0x1f20, 0x1f27,
+	0x1f30, 0x1f37,
+	0x1f40, 0x1f45,
+	0x1f50, 0x1f57,
+	0x1f60, 0x1f67,
+	0x1f70, 0x1f7d,
+	0x1f80, 0x1f87,
+	0x1f90, 0x1f97,
+	0x1fa0, 0x1fa7,
+	0x1fb0, 0x1fb4,
+	0x1fb6, 0x1fb7,
+	0x1fc2, 0x1fc4,
+	0x1fc6, 0x1fc7,
+	0x1fd0, 0x1fd3,
+	0x1fd6, 0x1fd7,
+	0x1fe0, 0x1fe7,
+	0x1ff2, 0x1ff4,
+	0x1ff6, 0x1ff7,
+	0x210e, 0x210f,
+	0x213c, 0x213d,
+	0x2146, 0x2149,
+	0x2170, 0x217f,
+	0x24d0, 0x24e9,
+	0x2c30, 0x2c5e,
+	0x2c65, 0x2c66,
+	0x2c73, 0x2c74,
+	0x2c76, 0x2c7b,
+	0x2ce3, 0x2ce4,
+	0x2d00, 0x2d25,
+	0xa72f, 0xa731,
+	0xa771, 0xa778,
+	0xfb00, 0xfb06,
+	0xfb13, 0xfb17,
+	0xff41, 0xff5a,
+	0x10428, 0x1044f,
+	0x1d41a, 0x1d433,
+	0x1d44e, 0x1d454,
+	0x1d456, 0x1d467,
+	0x1d482, 0x1d49b,
+	0x1d4b6, 0x1d4b9,
+	0x1d4bd, 0x1d4c3,
+	0x1d4c5, 0x1d4cf,
+	0x1d4ea, 0x1d503,
+	0x1d51e, 0x1d537,
+	0x1d552, 0x1d56b,
+	0x1d586, 0x1d59f,
+	0x1d5ba, 0x1d5d3,
+	0x1d5ee, 0x1d607,
+	0x1d622, 0x1d63b,
+	0x1d656, 0x1d66f,
+	0x1d68a, 0x1d6a5,
+	0x1d6c2, 0x1d6da,
+	0x1d6dc, 0x1d6e1,
+	0x1d6fc, 0x1d714,
+	0x1d716, 0x1d71b,
+	0x1d736, 0x1d74e,
+	0x1d750, 0x1d755,
+	0x1d770, 0x1d788,
+	0x1d78a, 0x1d78f,
+	0x1d7aa, 0x1d7c2,
+	0x1d7c4, 0x1d7c9,
+};
+
+static Rune __islowerp[] = {
+	0x0101, 0x0135,
+	0x013a, 0x0146,
+	0x014b, 0x0177,
+	0x017a, 0x017c,
+	0x0183, 0x0185,
+	0x01a1, 0x01a5,
+	0x01b4, 0x01b6,
+	0x01cc, 0x01da,
+	0x01df, 0x01ed,
+	0x01f3, 0x01f5,
+	0x01f9, 0x0231,
+	0x0247, 0x024d,
+	0x0371, 0x0373,
+	0x03d9, 0x03ed,
+	0x0461, 0x0481,
+	0x048b, 0x04bf,
+	0x04c2, 0x04cc,
+	0x04d1, 0x0527,
+	0x1e01, 0x1e93,
+	0x1e9f, 0x1efd,
+	0x2c68, 0x2c6c,
+	0x2c81, 0x2ce1,
+	0x2cec, 0x2cee,
+	0xa641, 0xa66d,
+	0xa681, 0xa697,
+	0xa723, 0xa72d,
+	0xa733, 0xa76f,
+	0xa77a, 0xa77c,
+	0xa77f, 0xa787,
+	0xa78c, 0xa78e,
+	0xa791, 0xa793,
+	0xa7a1, 0xa7a9,
+};
+
+static Rune __islowers[] = {
+	0x00b5,
+	0x0188,
+	0x0192,
+	0x0195,
+	0x019e,
+	0x01a8,
+	0x01ad,
+	0x01b0,
+	0x01c6,
+	0x01c9,
+	0x023c,
+	0x0242,
+	0x0377,
+	0x0390,
+	0x03f5,
+	0x03f8,
+	0x1fbe,
+	0x210a,
+	0x2113,
+	0x212f,
+	0x2134,
+	0x2139,
+	0x214e,
+	0x2184,
+	0x2c61,
+	0x2c71,
+	0x2cf3,
+	0x2d27,
+	0x2d2d,
+	0xa7fa,
+	0x1d4bb,
+	0x1d7cb,
+};
+
+int
+islowerrune(Rune c)
+{
+	Rune *p;
+
+	p = rbsearch(c, __islowerr, nelem(__islowerr)/2, 2);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	p = rbsearch(c, __islowerp, nelem(__islowerp)/2, 2);
+	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+		return 1;
+	p = rbsearch(c, __islowers, nelem(__islowers), 1);
+	if(p && c == p[0])
+		return 1;
+	return 0;
+}
+
+static Rune __istitler[] = {
+	0x0041, 0x005a,
+	0x00c0, 0x00d6,
+	0x00d8, 0x00de,
+	0x0178, 0x0179,
+	0x0181, 0x0182,
+	0x0186, 0x0187,
+	0x0189, 0x018b,
+	0x018e, 0x0191,
+	0x0193, 0x0194,
+	0x0196, 0x0198,
+	0x019c, 0x019d,
+	0x019f, 0x01a0,
+	0x01a6, 0x01a7,
+	0x01ae, 0x01af,
+	0x01b1, 0x01b3,
+	0x01b7, 0x01b8,
+	0x01f6, 0x01f8,
+	0x023a, 0x023b,
+	0x023d, 0x023e,
+	0x0243, 0x0246,
+	0x0388, 0x038a,
+	0x038e, 0x038f,
+	0x0391, 0x03a1,
+	0x03a3, 0x03ab,
+	0x03f9, 0x03fa,
+	0x03fd, 0x042f,
+	0x04c0, 0x04c1,
+	0x0531, 0x0556,
+	0x10a0, 0x10c5,
+	0x1f08, 0x1f0f,
+	0x1f18, 0x1f1d,
+	0x1f28, 0x1f2f,
+	0x1f38, 0x1f3f,
+	0x1f48, 0x1f4d,
+	0x1f68, 0x1f6f,
+	0x1f88, 0x1f8f,
+	0x1f98, 0x1f9f,
+	0x1fa8, 0x1faf,
+	0x1fb8, 0x1fbc,
+	0x1fc8, 0x1fcc,
+	0x1fd8, 0x1fdb,
+	0x1fe8, 0x1fec,
+	0x1ff8, 0x1ffc,
+	0x2160, 0x216f,
+	0x24b6, 0x24cf,
+	0x2c00, 0x2c2e,
+	0x2c62, 0x2c64,
+	0x2c6d, 0x2c70,
+	0x2c7e, 0x2c80,
+	0xa77d, 0xa77e,
+	0xff21, 0xff3a,
+	0x10400, 0x10427,
+};
+
+static Rune __istitlep[] = {
+	0x0100, 0x012e,
+	0x0132, 0x0136,
+	0x0139, 0x0147,
+	0x014a, 0x0176,
+	0x017b, 0x017d,
+	0x01a2, 0x01a4,
+	0x01cb, 0x01db,
+	0x01de, 0x01ee,
+	0x01f2, 0x01f4,
+	0x01fa, 0x0232,
+	0x0248, 0x024e,
+	0x0370, 0x0372,
+	0x03d8, 0x03ee,
+	0x0460, 0x0480,
+	0x048a, 0x04be,
+	0x04c3, 0x04cd,
+	0x04d0, 0x0526,
+	0x1e00, 0x1e94,
+	0x1ea0, 0x1efe,
+	0x1f59, 0x1f5f,
+	0x2c67, 0x2c6b,
+	0x2c82, 0x2ce2,
+	0x2ceb, 0x2ced,
+	0xa640, 0xa66c,
+	0xa680, 0xa696,
+	0xa722, 0xa72e,
+	0xa732, 0xa76e,
+	0xa779, 0xa77b,
+	0xa780, 0xa786,
+	0xa78b, 0xa78d,
+	0xa790, 0xa792,
+	0xa7a0, 0xa7aa,
+};
+
+static Rune __istitles[] = {
+	0x0184,
+	0x01a9,
+	0x01ac,
+	0x01b5,
+	0x01bc,
+	0x01c5,
+	0x01c8,
+	0x0241,
+	0x0376,
+	0x0386,
+	0x038c,
+	0x03cf,
+	0x03f7,
+	0x10c7,
+	0x10cd,
+	0x2132,
+	0x2183,
+	0x2c60,
+	0x2c72,
+	0x2c75,
+	0x2cf2,
+};
+
+int
+istitlerune(Rune c)
+{
+	Rune *p;
+
+	p = rbsearch(c, __istitler, nelem(__istitler)/2, 2);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	p = rbsearch(c, __istitlep, nelem(__istitlep)/2, 2);
+	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+		return 1;
+	p = rbsearch(c, __istitles, nelem(__istitles), 1);
+	if(p && c == p[0])
+		return 1;
+	return 0;
+}
+
+static Rune __toupperr[] = {
+	0x0061, 0x007a, 1048544,
+	0x00e0, 0x00f6, 1048544,
+	0x00f8, 0x00fe, 1048544,
+	0x023f, 0x0240, 1059391,
+	0x0256, 0x0257, 1048371,
+	0x028a, 0x028b, 1048359,
+	0x037b, 0x037d, 1048706,
+	0x03ad, 0x03af, 1048539,
+	0x03b1, 0x03c1, 1048544,
+	0x03c3, 0x03cb, 1048544,
+	0x03cd, 0x03ce, 1048513,
+	0x0430, 0x044f, 1048544,
+	0x0450, 0x045f, 1048496,
+	0x0561, 0x0586, 1048528,
+	0x1f00, 0x1f07, 1048584,
+	0x1f10, 0x1f15, 1048584,
+	0x1f20, 0x1f27, 1048584,
+	0x1f30, 0x1f37, 1048584,
+	0x1f40, 0x1f45, 1048584,
+	0x1f60, 0x1f67, 1048584,
+	0x1f70, 0x1f71, 1048650,
+	0x1f72, 0x1f75, 1048662,
+	0x1f76, 0x1f77, 1048676,
+	0x1f78, 0x1f79, 1048704,
+	0x1f7a, 0x1f7b, 1048688,
+	0x1f7c, 0x1f7d, 1048702,
+	0x1f80, 0x1f87, 1048584,
+	0x1f90, 0x1f97, 1048584,
+	0x1fa0, 0x1fa7, 1048584,
+	0x1fb0, 0x1fb1, 1048584,
+	0x1fd0, 0x1fd1, 1048584,
+	0x1fe0, 0x1fe1, 1048584,
+	0x2170, 0x217f, 1048560,
+	0x24d0, 0x24e9, 1048550,
+	0x2c30, 0x2c5e, 1048528,
+	0x2d00, 0x2d25, 1041312,
+	0xff41, 0xff5a, 1048544,
+	0x10428, 0x1044f, 1048536,
+};
+
+static Rune __toupperp[] = {
+	0x0101, 0x012f, 1048575,
+	0x0133, 0x0137, 1048575,
+	0x013a, 0x0148, 1048575,
+	0x014b, 0x0177, 1048575,
+	0x017a, 0x017e, 1048575,
+	0x0183, 0x0185, 1048575,
+	0x01a1, 0x01a5, 1048575,
+	0x01b4, 0x01b6, 1048575,
+	0x01ce, 0x01dc, 1048575,
+	0x01df, 0x01ef, 1048575,
+	0x01f9, 0x021f, 1048575,
+	0x0223, 0x0233, 1048575,
+	0x0247, 0x024f, 1048575,
+	0x0371, 0x0373, 1048575,
+	0x03d9, 0x03ef, 1048575,
+	0x0461, 0x0481, 1048575,
+	0x048b, 0x04bf, 1048575,
+	0x04c2, 0x04ce, 1048575,
+	0x04d1, 0x0527, 1048575,
+	0x1e01, 0x1e95, 1048575,
+	0x1ea1, 0x1eff, 1048575,
+	0x1f51, 0x1f57, 1048584,
+	0x2c68, 0x2c6c, 1048575,
+	0x2c81, 0x2ce3, 1048575,
+	0x2cec, 0x2cee, 1048575,
+	0xa641, 0xa66d, 1048575,
+	0xa681, 0xa697, 1048575,
+	0xa723, 0xa72f, 1048575,
+	0xa733, 0xa76f, 1048575,
+	0xa77a, 0xa77c, 1048575,
+	0xa77f, 0xa787, 1048575,
+	0xa791, 0xa793, 1048575,
+	0xa7a1, 0xa7a9, 1048575,
+};
+
+static Rune __touppers[] = {
+	0x00b5, 1049319,
+	0x00ff, 1048697,
+	0x0131, 1048344,
+	0x017f, 1048276,
+	0x0180, 1048771,
+	0x0188, 1048575,
+	0x018c, 1048575,
+	0x0192, 1048575,
+	0x0195, 1048673,
+	0x0199, 1048575,
+	0x019a, 1048739,
+	0x019e, 1048706,
+	0x01a8, 1048575,
+	0x01ad, 1048575,
+	0x01b0, 1048575,
+	0x01b9, 1048575,
+	0x01bd, 1048575,
+	0x01bf, 1048632,
+	0x01c5, 1048575,
+	0x01c6, 1048574,
+	0x01c8, 1048575,
+	0x01c9, 1048574,
+	0x01cb, 1048575,
+	0x01cc, 1048574,
+	0x01dd, 1048497,
+	0x01f2, 1048575,
+	0x01f3, 1048574,
+	0x01f5, 1048575,
+	0x023c, 1048575,
+	0x0242, 1048575,
+	0x0250, 1059359,
+	0x0251, 1059356,
+	0x0252, 1059358,
+	0x0253, 1048366,
+	0x0254, 1048370,
+	0x0259, 1048374,
+	0x025b, 1048373,
+	0x0260, 1048371,
+	0x0263, 1048369,
+	0x0265, 1090856,
+	0x0266, 1090884,
+	0x0268, 1048367,
+	0x0269, 1048365,
+	0x026b, 1059319,
+	0x026f, 1048365,
+	0x0271, 1059325,
+	0x0272, 1048363,
+	0x0275, 1048362,
+	0x027d, 1059303,
+	0x0280, 1048358,
+	0x0283, 1048358,
+	0x0288, 1048358,
+	0x0289, 1048507,
+	0x028c, 1048505,
+	0x0292, 1048357,
+	0x0345, 1048660,
+	0x0377, 1048575,
+	0x03ac, 1048538,
+	0x03c2, 1048545,
+	0x03cc, 1048512,
+	0x03d0, 1048514,
+	0x03d1, 1048519,
+	0x03d5, 1048529,
+	0x03d6, 1048522,
+	0x03d7, 1048568,
+	0x03f0, 1048490,
+	0x03f1, 1048496,
+	0x03f2, 1048583,
+	0x03f5, 1048480,
+	0x03f8, 1048575,
+	0x03fb, 1048575,
+	0x04cf, 1048561,
+	0x1d79, 1083908,
+	0x1d7d, 1052390,
+	0x1e9b, 1048517,
+	0x1fb3, 1048585,
+	0x1fbe, 1041371,
+	0x1fc3, 1048585,
+	0x1fe5, 1048583,
+	0x1ff3, 1048585,
+	0x214e, 1048548,
+	0x2184, 1048575,
+	0x2c61, 1048575,
+	0x2c65, 1037781,
+	0x2c66, 1037784,
+	0x2c73, 1048575,
+	0x2c76, 1048575,
+	0x2cf3, 1048575,
+	0x2d27, 1041312,
+	0x2d2d, 1041312,
+	0xa78c, 1048575,
+};
+
+Rune
+toupperrune(Rune c)
+{
+	Rune *p;
+
+	p = rbsearch(c, __toupperr, nelem(__toupperr)/3, 3);
+	if(p && c >= p[0] && c <= p[1])
+		return c + p[2] - 1048576;
+	p = rbsearch(c, __toupperp, nelem(__toupperp)/3, 3);
+	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+		return c + p[2] - 1048576;
+	p = rbsearch(c, __touppers, nelem(__touppers)/2, 2);
+	if(p && c == p[0])
+		return c + p[1] - 1048576;
+	return c;
+}
+
+static Rune __tolowerr[] = {
+	0x0041, 0x005a, 1048608,
+	0x00c0, 0x00d6, 1048608,
+	0x00d8, 0x00de, 1048608,
+	0x0189, 0x018a, 1048781,
+	0x01b1, 0x01b2, 1048793,
+	0x0388, 0x038a, 1048613,
+	0x038e, 0x038f, 1048639,
+	0x0391, 0x03a1, 1048608,
+	0x03a3, 0x03ab, 1048608,
+	0x03fd, 0x03ff, 1048446,
+	0x0400, 0x040f, 1048656,
+	0x0410, 0x042f, 1048608,
+	0x0531, 0x0556, 1048624,
+	0x10a0, 0x10c5, 1055840,
+	0x1f08, 0x1f0f, 1048568,
+	0x1f18, 0x1f1d, 1048568,
+	0x1f28, 0x1f2f, 1048568,
+	0x1f38, 0x1f3f, 1048568,
+	0x1f48, 0x1f4d, 1048568,
+	0x1f68, 0x1f6f, 1048568,
+	0x1f88, 0x1f8f, 1048568,
+	0x1f98, 0x1f9f, 1048568,
+	0x1fa8, 0x1faf, 1048568,
+	0x1fb8, 0x1fb9, 1048568,
+	0x1fba, 0x1fbb, 1048502,
+	0x1fc8, 0x1fcb, 1048490,
+	0x1fd8, 0x1fd9, 1048568,
+	0x1fda, 0x1fdb, 1048476,
+	0x1fe8, 0x1fe9, 1048568,
+	0x1fea, 0x1feb, 1048464,
+	0x1ff8, 0x1ff9, 1048448,
+	0x1ffa, 0x1ffb, 1048450,
+	0x2160, 0x216f, 1048592,
+	0x24b6, 0x24cf, 1048602,
+	0x2c00, 0x2c2e, 1048624,
+	0x2c7e, 0x2c7f, 1037761,
+	0xff21, 0xff3a, 1048608,
+	0x10400, 0x10427, 1048616,
+};
+
+static Rune __tolowerp[] = {
+	0x0100, 0x012e, 1048577,
+	0x0132, 0x0136, 1048577,
+	0x0139, 0x0147, 1048577,
+	0x014a, 0x0176, 1048577,
+	0x017b, 0x017d, 1048577,
+	0x01a2, 0x01a4, 1048577,
+	0x01b3, 0x01b5, 1048577,
+	0x01cd, 0x01db, 1048577,
+	0x01de, 0x01ee, 1048577,
+	0x01f8, 0x021e, 1048577,
+	0x0222, 0x0232, 1048577,
+	0x0248, 0x024e, 1048577,
+	0x0370, 0x0372, 1048577,
+	0x03d8, 0x03ee, 1048577,
+	0x0460, 0x0480, 1048577,
+	0x048a, 0x04be, 1048577,
+	0x04c3, 0x04cd, 1048577,
+	0x04d0, 0x0526, 1048577,
+	0x1e00, 0x1e94, 1048577,
+	0x1ea0, 0x1efe, 1048577,
+	0x1f59, 0x1f5f, 1048568,
+	0x2c67, 0x2c6b, 1048577,
+	0x2c80, 0x2ce2, 1048577,
+	0x2ceb, 0x2ced, 1048577,
+	0xa640, 0xa66c, 1048577,
+	0xa680, 0xa696, 1048577,
+	0xa722, 0xa72e, 1048577,
+	0xa732, 0xa76e, 1048577,
+	0xa779, 0xa77b, 1048577,
+	0xa780, 0xa786, 1048577,
+	0xa790, 0xa792, 1048577,
+	0xa7a0, 0xa7a8, 1048577,
+};
+
+static Rune __tolowers[] = {
+	0x0130, 1048377,
+	0x0178, 1048455,
+	0x0179, 1048577,
+	0x0181, 1048786,
+	0x0182, 1048577,
+	0x0184, 1048577,
+	0x0186, 1048782,
+	0x0187, 1048577,
+	0x018b, 1048577,
+	0x018e, 1048655,
+	0x018f, 1048778,
+	0x0190, 1048779,
+	0x0191, 1048577,
+	0x0193, 1048781,
+	0x0194, 1048783,
+	0x0196, 1048787,
+	0x0197, 1048785,
+	0x0198, 1048577,
+	0x019c, 1048787,
+	0x019d, 1048789,
+	0x019f, 1048790,
+	0x01a0, 1048577,
+	0x01a6, 1048794,
+	0x01a7, 1048577,
+	0x01a9, 1048794,
+	0x01ac, 1048577,
+	0x01ae, 1048794,
+	0x01af, 1048577,
+	0x01b7, 1048795,
+	0x01b8, 1048577,
+	0x01bc, 1048577,
+	0x01c4, 1048578,
+	0x01c5, 1048577,
+	0x01c7, 1048578,
+	0x01c8, 1048577,
+	0x01ca, 1048578,
+	0x01cb, 1048577,
+	0x01f1, 1048578,
+	0x01f2, 1048577,
+	0x01f4, 1048577,
+	0x01f6, 1048479,
+	0x01f7, 1048520,
+	0x0220, 1048446,
+	0x023a, 1059371,
+	0x023b, 1048577,
+	0x023d, 1048413,
+	0x023e, 1059368,
+	0x0241, 1048577,
+	0x0243, 1048381,
+	0x0244, 1048645,
+	0x0245, 1048647,
+	0x0246, 1048577,
+	0x0376, 1048577,
+	0x0386, 1048614,
+	0x038c, 1048640,
+	0x03cf, 1048584,
+	0x03f4, 1048516,
+	0x03f7, 1048577,
+	0x03f9, 1048569,
+	0x03fa, 1048577,
+	0x04c0, 1048591,
+	0x04c1, 1048577,
+	0x10c7, 1055840,
+	0x10cd, 1055840,
+	0x1e9e, 1040961,
+	0x1fbc, 1048567,
+	0x1fcc, 1048567,
+	0x1fec, 1048569,
+	0x1ffc, 1048567,
+	0x2126, 1041059,
+	0x212a, 1040193,
+	0x212b, 1040314,
+	0x2132, 1048604,
+	0x2183, 1048577,
+	0x2c60, 1048577,
+	0x2c62, 1037833,
+	0x2c63, 1044762,
+	0x2c64, 1037849,
+	0x2c6d, 1037796,
+	0x2c6e, 1037827,
+	0x2c6f, 1037793,
+	0x2c70, 1037794,
+	0x2c72, 1048577,
+	0x2c75, 1048577,
+	0x2cf2, 1048577,
+	0xa77d, 1013244,
+	0xa77e, 1048577,
+	0xa78b, 1048577,
+	0xa78d, 1006296,
+	0xa7aa, 1006268,
+};
+
+Rune
+tolowerrune(Rune c)
+{
+	Rune *p;
+
+	p = rbsearch(c, __tolowerr, nelem(__tolowerr)/3, 3);
+	if(p && c >= p[0] && c <= p[1])
+		return c + p[2] - 1048576;
+	p = rbsearch(c, __tolowerp, nelem(__tolowerp)/3, 3);
+	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+		return c + p[2] - 1048576;
+	p = rbsearch(c, __tolowers, nelem(__tolowers)/2, 2);
+	if(p && c == p[0])
+		return c + p[1] - 1048576;
+	return c;
+}
+
+static Rune __totitler[] = {
+	0x0061, 0x007a, 1048544,
+	0x00e0, 0x00f6, 1048544,
+	0x00f8, 0x00fe, 1048544,
+	0x023f, 0x0240, 1059391,
+	0x0256, 0x0257, 1048371,
+	0x028a, 0x028b, 1048359,
+	0x037b, 0x037d, 1048706,
+	0x03ad, 0x03af, 1048539,
+	0x03b1, 0x03c1, 1048544,
+	0x03c3, 0x03cb, 1048544,
+	0x03cd, 0x03ce, 1048513,
+	0x0430, 0x044f, 1048544,
+	0x0450, 0x045f, 1048496,
+	0x0561, 0x0586, 1048528,
+	0x1f00, 0x1f07, 1048584,
+	0x1f10, 0x1f15, 1048584,
+	0x1f20, 0x1f27, 1048584,
+	0x1f30, 0x1f37, 1048584,
+	0x1f40, 0x1f45, 1048584,
+	0x1f60, 0x1f67, 1048584,
+	0x1f70, 0x1f71, 1048650,
+	0x1f72, 0x1f75, 1048662,
+	0x1f76, 0x1f77, 1048676,
+	0x1f78, 0x1f79, 1048704,
+	0x1f7a, 0x1f7b, 1048688,
+	0x1f7c, 0x1f7d, 1048702,
+	0x1f80, 0x1f87, 1048584,
+	0x1f90, 0x1f97, 1048584,
+	0x1fa0, 0x1fa7, 1048584,
+	0x1fb0, 0x1fb1, 1048584,
+	0x1fd0, 0x1fd1, 1048584,
+	0x1fe0, 0x1fe1, 1048584,
+	0x2170, 0x217f, 1048560,
+	0x24d0, 0x24e9, 1048550,
+	0x2c30, 0x2c5e, 1048528,
+	0x2d00, 0x2d25, 1041312,
+	0xff41, 0xff5a, 1048544,
+	0x10428, 0x1044f, 1048536,
+};
+
+static Rune __totitlep[] = {
+	0x0101, 0x012f, 1048575,
+	0x0133, 0x0137, 1048575,
+	0x013a, 0x0148, 1048575,
+	0x014b, 0x0177, 1048575,
+	0x017a, 0x017e, 1048575,
+	0x0183, 0x0185, 1048575,
+	0x01a1, 0x01a5, 1048575,
+	0x01b4, 0x01b6, 1048575,
+	0x01cc, 0x01dc, 1048575,
+	0x01df, 0x01ef, 1048575,
+	0x01f3, 0x01f5, 1048575,
+	0x01f9, 0x021f, 1048575,
+	0x0223, 0x0233, 1048575,
+	0x0247, 0x024f, 1048575,
+	0x0371, 0x0373, 1048575,
+	0x03d9, 0x03ef, 1048575,
+	0x0461, 0x0481, 1048575,
+	0x048b, 0x04bf, 1048575,
+	0x04c2, 0x04ce, 1048575,
+	0x04d1, 0x0527, 1048575,
+	0x1e01, 0x1e95, 1048575,
+	0x1ea1, 0x1eff, 1048575,
+	0x1f51, 0x1f57, 1048584,
+	0x2c68, 0x2c6c, 1048575,
+	0x2c81, 0x2ce3, 1048575,
+	0x2cec, 0x2cee, 1048575,
+	0xa641, 0xa66d, 1048575,
+	0xa681, 0xa697, 1048575,
+	0xa723, 0xa72f, 1048575,
+	0xa733, 0xa76f, 1048575,
+	0xa77a, 0xa77c, 1048575,
+	0xa77f, 0xa787, 1048575,
+	0xa791, 0xa793, 1048575,
+	0xa7a1, 0xa7a9, 1048575,
+};
+
+static Rune __totitles[] = {
+	0x00b5, 1049319,
+	0x00ff, 1048697,
+	0x0131, 1048344,
+	0x017f, 1048276,
+	0x0180, 1048771,
+	0x0188, 1048575,
+	0x018c, 1048575,
+	0x0192, 1048575,
+	0x0195, 1048673,
+	0x0199, 1048575,
+	0x019a, 1048739,
+	0x019e, 1048706,
+	0x01a8, 1048575,
+	0x01ad, 1048575,
+	0x01b0, 1048575,
+	0x01b9, 1048575,
+	0x01bd, 1048575,
+	0x01bf, 1048632,
+	0x01c4, 1048577,
+	0x01c6, 1048575,
+	0x01c7, 1048577,
+	0x01c9, 1048575,
+	0x01ca, 1048577,
+	0x01dd, 1048497,
+	0x01f1, 1048577,
+	0x023c, 1048575,
+	0x0242, 1048575,
+	0x0250, 1059359,
+	0x0251, 1059356,
+	0x0252, 1059358,
+	0x0253, 1048366,
+	0x0254, 1048370,
+	0x0259, 1048374,
+	0x025b, 1048373,
+	0x0260, 1048371,
+	0x0263, 1048369,
+	0x0265, 1090856,
+	0x0266, 1090884,
+	0x0268, 1048367,
+	0x0269, 1048365,
+	0x026b, 1059319,
+	0x026f, 1048365,
+	0x0271, 1059325,
+	0x0272, 1048363,
+	0x0275, 1048362,
+	0x027d, 1059303,
+	0x0280, 1048358,
+	0x0283, 1048358,
+	0x0288, 1048358,
+	0x0289, 1048507,
+	0x028c, 1048505,
+	0x0292, 1048357,
+	0x0345, 1048660,
+	0x0377, 1048575,
+	0x03ac, 1048538,
+	0x03c2, 1048545,
+	0x03cc, 1048512,
+	0x03d0, 1048514,
+	0x03d1, 1048519,
+	0x03d5, 1048529,
+	0x03d6, 1048522,
+	0x03d7, 1048568,
+	0x03f0, 1048490,
+	0x03f1, 1048496,
+	0x03f2, 1048583,
+	0x03f5, 1048480,
+	0x03f8, 1048575,
+	0x03fb, 1048575,
+	0x04cf, 1048561,
+	0x1d79, 1083908,
+	0x1d7d, 1052390,
+	0x1e9b, 1048517,
+	0x1fb3, 1048585,
+	0x1fbe, 1041371,
+	0x1fc3, 1048585,
+	0x1fe5, 1048583,
+	0x1ff3, 1048585,
+	0x214e, 1048548,
+	0x2184, 1048575,
+	0x2c61, 1048575,
+	0x2c65, 1037781,
+	0x2c66, 1037784,
+	0x2c73, 1048575,
+	0x2c76, 1048575,
+	0x2cf3, 1048575,
+	0x2d27, 1041312,
+	0x2d2d, 1041312,
+	0xa78c, 1048575,
+};
+
+Rune
+totitlerune(Rune c)
+{
+	Rune *p;
+
+	p = rbsearch(c, __totitler, nelem(__totitler)/3, 3);
+	if(p && c >= p[0] && c <= p[1])
+		return c + p[2] - 1048576;
+	p = rbsearch(c, __totitlep, nelem(__totitlep)/3, 3);
+	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+		return c + p[2] - 1048576;
+	p = rbsearch(c, __totitles, nelem(__totitles)/2, 2);
+	if(p && c == p[0])
+		return c + p[1] - 1048576;
+	return c;
+}
+
diff --git a/src/lib9/utf/utfdef.h b/src/lib9/utf/utfdef.h
index adc6d95..4bbdfc6 100644
--- a/src/lib9/utf/utfdef.h
+++ b/src/lib9/utf/utfdef.h
@@ -25,4 +25,3 @@ typedef unsigned int		uint;
 typedef unsigned long		ulong;
 
 #define nelem(x) (sizeof(x)/sizeof((x)[0]))
-#define nil ((void*)0)
diff --git a/src/lib9/utf/utfecpy.c b/src/lib9/utf/utfecpy.c
index 2eca85e..8540664 100644
--- a/src/lib9/utf/utfecpy.c
+++ b/src/lib9/utf/utfecpy.c
@@ -11,8 +11,8 @@
  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
  */
-#define _BSD_SOURCE 1
-#include <string.h>
+#include <u.h>
+#include <libc.h>
 #include "utf.h"
 #include "utfdef.h"
 
diff --git a/src/lib9/utf/utflen.c b/src/lib9/utf/utflen.c
index 42fcb33..9b96185 100644
--- a/src/lib9/utf/utflen.c
+++ b/src/lib9/utf/utflen.c
@@ -32,5 +32,4 @@ utflen(const char *s)
 			s += chartorune(&rune, s);
 		n++;
 	}
-	return 0;
 }
diff --git a/src/lib9/utf/utfrrune.c b/src/lib9/utf/utfrrune.c
index 9e28af8..b1ea93b 100644
--- a/src/lib9/utf/utfrrune.c
+++ b/src/lib9/utf/utfrrune.c
@@ -11,7 +11,8 @@
  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
  */
-#include <string.h>
+#include <u.h>
+#include <libc.h>
 #include "utf.h"
 #include "utfdef.h"
 
@@ -42,5 +43,4 @@ utfrrune(const char *s, Rune c)
 			s1 = s;
 		s += c1;
 	}
-	return 0;
 }
diff --git a/src/lib9/utf/utfrune.c b/src/lib9/utf/utfrune.c
index 0136b28..44675c9 100644
--- a/src/lib9/utf/utfrune.c
+++ b/src/lib9/utf/utfrune.c
@@ -11,7 +11,8 @@
  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
  */
-#include <string.h>
+#include <u.h>
+#include <libc.h>
 #include "utf.h"
 #include "utfdef.h"
 
@@ -41,5 +42,4 @@ utfrune(const char *s, Rune c)
 			return (char*)s;
 		s += n;
 	}
-	return 0;
 }
diff --git a/src/lib9/utf/utfutf.c b/src/lib9/utf/utfutf.c
index e46ddd9..05335b2 100644
--- a/src/lib9/utf/utfutf.c
+++ b/src/lib9/utf/utfutf.c
@@ -11,7 +11,8 @@
  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
  */
-#include <string.h>
+#include <u.h>
+#include <libc.h>
 #include "utf.h"
 #include "utfdef.h"
 
diff --git a/src/libbio/bgetc.c b/src/libbio/bgetc.c
index 3399fb1..ceb5cb1 100644
--- a/src/libbio/bgetc.c
+++ b/src/libbio/bgetc.c
@@ -83,7 +83,7 @@ Bgetle4(Biobuf *bp)
 
 	l = Bgetle2(bp);
 	h = Bgetle2(bp);
-	return l|((uint32)h<<16);
+	return (int)((uint32)l|((uint32)h<<16));
 }
 
 int
diff --git a/src/libbio/bgetrune.c b/src/libbio/bgetrune.c
index 441c079..b5db391 100644
--- a/src/libbio/bgetrune.c
+++ b/src/libbio/bgetrune.c
@@ -26,7 +26,6 @@ THE SOFTWARE.
 #include	<u.h>
 #include	<libc.h>
 #include	<bio.h>
-#include	<utf.h>
 
 long
 Bgetrune(Biobuf *bp)
diff --git a/src/libbio/bputrune.c b/src/libbio/bputrune.c
index 7fe0e65..f207795 100644
--- a/src/libbio/bputrune.c
+++ b/src/libbio/bputrune.c
@@ -26,7 +26,6 @@ THE SOFTWARE.
 #include	<u.h>
 #include	<libc.h>
 #include	<bio.h>
-#include	<utf.h>
 
 int
 Bputrune(Biobuf *bp, long c)
@@ -37,7 +36,8 @@ Bputrune(Biobuf *bp, long c)
 
 	rune = (Rune)c;
 	if(rune < Runeself) {
-		BPUTC(bp, (int)rune);
+		n = BPUTC(bp, (int)rune);
+		USED(n);
 		return 1;
 	}
 	n = runetochar(str, &rune);
diff --git a/src/libbio/bseek.c b/src/libbio/bseek.c
index eb426cc..5289585 100644
--- a/src/libbio/bseek.c
+++ b/src/libbio/bseek.c
@@ -33,7 +33,7 @@ Bseek(Biobuf *bp, vlong offset, int base)
 	vlong n, d;
 	int bufsz;
 
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(PLAN9)
 	if(sizeof(offset) != sizeof(off_t)) {
 		fprint(2, "Bseek: libbio compiled with %d-byte offset\n", sizeof(off_t));
 		abort();
diff --git a/src/liblink/Makefile b/src/liblink/Makefile
new file mode 100644
index 0000000..2a31746
--- /dev/null
+++ b/src/liblink/Makefile
@@ -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 ../Make.dist
diff --git a/src/liblink/asm5.c b/src/liblink/asm5.c
new file mode 100644
index 0000000..465b645
--- /dev/null
+++ b/src/liblink/asm5.c
@@ -0,0 +1,2458 @@
+// 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 at 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 at 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/5l/5.out.h"
+#include "../pkg/runtime/stack.h"
+
+typedef	struct	Optab	Optab;
+typedef	struct	Oprang	Oprang;
+typedef	uchar	Opcross[32][2][32];
+
+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;
+};
+
+enum
+{
+	LFROM		= 1<<0,
+	LTO		= 1<<1,
+	LPOOL		= 1<<2,
+	LPCREL		= 1<<3,
+
+	C_NONE		= 0,
+	C_REG,
+	C_REGREG,
+	C_REGREG2,
+	C_SHIFT,
+	C_FREG,
+	C_PSR,
+	C_FCR,
+
+	C_RCON,		/* 0xff rotated */
+	C_NCON,		/* ~RCON */
+	C_SCON,		/* 0xffff */
+	C_LCON,
+	C_LCONADDR,
+	C_ZFCON,
+	C_SFCON,
+	C_LFCON,
+
+	C_RACON,
+	C_LACON,
+
+	C_SBRA,
+	C_LBRA,
+
+	C_HAUTO,	/* halfword insn offset (-0xff to 0xff) */
+	C_FAUTO,	/* float insn offset (0 to 0x3fc, word aligned) */
+	C_HFAUTO,	/* both H and F */
+	C_SAUTO,	/* -0xfff to 0xfff */
+	C_LAUTO,
+
+	C_HOREG,
+	C_FOREG,
+	C_HFOREG,
+	C_SOREG,
+	C_ROREG,
+	C_SROREG,	/* both nil and R */
+	C_LOREG,
+
+	C_PC,
+	C_SP,
+	C_HREG,
+
+	C_ADDR,		/* reference to relocatable address */
+
+	C_GOK,
+};
+
+static 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 },
+
+	{ ADUFFZERO,	C_NONE,	C_NONE,	C_SBRA,		 5, 4, 0 },  // same as ABL
+	{ ADUFFCOPY,	C_NONE,	C_NONE,	C_SBRA,		 5, 4, 0 },  // same as ABL
+
+	{ AXXX,		C_NONE,	C_NONE,	C_NONE,		 0, 4, 0 },
+};
+
+static struct {
+	uint32	start;
+	uint32	size;
+	uint32	extra;
+} pool;
+
+static int	checkpool(Link*, Prog*, int);
+static int 	flushpool(Link*, Prog*, int, int);
+static void	addpool(Link*, Prog*, Addr*);
+static void	asmout(Link*, Prog*, Optab*, int32*);
+static Optab*	oplook(Link*, Prog*);
+static int32	oprrr(Link*, int, int);
+static int32	olr(Link*, int32, int, int, int);
+static int32	olhr(Link*, int32, int, int, int);
+static int32	olrr(Link*, int, int, int, int);
+static int32	olhrr(Link*, int, int, int, int);
+static int32	osr(Link*, int, int, int32, int, int);
+static int32	oshr(Link*, int, int32, int, int);
+static int32	ofsr(Link*, int, int, int32, int, int, Prog*);
+static int32	osrr(Link*, int, int, int, int);
+static int32	oshrr(Link*, int, int, int, int);
+static int32	omvl(Link*, Prog*, Addr*, int);
+static int32	immaddr(int32);
+static int	aclass(Link*, Addr*);
+static int32	immrot(uint32);
+static int32	immaddr(int32);
+static int32	opbra(Link*, int, int);
+
+static	Opcross	opcross[8];
+static	Oprang	oprange[ALAST];
+static	char	xcmp[C_GOK+1][C_GOK+1];
+static	uchar	repop[ALAST];
+
+static Prog zprg = {
+	.as = AGOK,
+	.scond = C_SCOND_NONE,
+	.reg = NREG,
+	.from = {
+		.name = D_NONE,
+		.type = D_NONE,
+		.reg = NREG,
+	},
+	.to = {
+		.name = D_NONE,
+		.type = D_NONE,
+		.reg = NREG,
+	},
+};
+
+static void
+nocache(Prog *p)
+{
+	p->optab = 0;
+	p->from.class = 0;
+	p->to.class = 0;
+}
+
+static int
+scan(Link *ctxt, Prog *op, Prog *p, int c)
+{
+	Prog *q;
+
+	for(q = op->link; q != p && q != nil; q = q->link){
+		q->pc = c;
+		c += oplook(ctxt, q)->size;
+		nocache(q);
+	}
+	return c;
+}
+
+/* size of a case statement including jump table */
+static int32
+casesz(Link *ctxt, Prog *p)
+{
+	int jt = 0;
+	int32 n = 0;
+	Optab *o;
+
+	for( ; p != nil; p = p->link){
+		if(p->as == ABCASE)
+			jt = 1;
+		else if(jt)
+			break;
+		o = oplook(ctxt, p);
+		n += o->size;
+	}
+	return n;
+}
+
+static void buildop(Link*);
+
+void
+span5(Link *ctxt, LSym *cursym)
+{
+	Prog *p, *op;
+	Optab *o;
+	int m, bflag, i, v;
+	int32 c, out[6];
+	uchar *bp;
+
+	p = cursym->text;
+	if(p == nil || p->link == nil) // handle external functions and ELF section symbols
+		return;
+ 
+ 	if(oprange[AAND].start == nil)
+ 		buildop(ctxt);
+
+ 	ctxt->cursym = cursym;
+
+	ctxt->autosize = p->to.offset + 4;
+	c = 0;	
+
+	for(op = p, p = p->link; p != nil; op = p, p = p->link) {
+		ctxt->curp = p;
+		p->pc = c;
+		o = oplook(ctxt, p);
+		m = o->size;
+		// must check literal pool here in case p generates many instructions
+		if(ctxt->blitrl){
+			if(checkpool(ctxt, op, p->as == ACASE ? casesz(ctxt, p) : m)) {
+				p->pc = scan(ctxt, op, p, c);
+				c = p->pc;
+			}
+		}
+		if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA)) {
+			ctxt->diag("zero-width instruction\n%P", p);
+			continue;
+		}
+		switch(o->flag & (LFROM|LTO|LPOOL)) {
+		case LFROM:
+			addpool(ctxt, p, &p->from);
+			break;
+		case LTO:
+			addpool(ctxt, p, &p->to);
+			break;
+		case LPOOL:
+			if ((p->scond&C_SCOND) == C_SCOND_NONE)
+				flushpool(ctxt, p, 0, 0);
+			break;
+		}
+		if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == C_SCOND_NONE)
+			flushpool(ctxt, p, 0, 0);
+		c += m;
+	}
+	if(ctxt->blitrl){
+		if(checkpool(ctxt, op, 0))
+			c = scan(ctxt, op, nil, c);
+	}
+	cursym->size = c;
+
+	/*
+	 * 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.
+	 */
+	do {
+		if(ctxt->debugvlog)
+			Bprint(ctxt->bso, "%5.2f span1\n", cputime());
+		bflag = 0;
+		c = 0;
+		for(p = cursym->text; p != nil; p = p->link) {
+			ctxt->curp = p;
+			p->pc = c;
+			o = oplook(ctxt,p);
+/* very large branches
+			if(o->type == 6 && p->pcond) {
+				otxt = p->pcond->pc - c;
+				if(otxt < 0)
+					otxt = -otxt;
+				if(otxt >= (1L<<17) - 10) {
+					q = ctxt->arch->prg();
+					q->link = p->link;
+					p->link = q;
+					q->as = AB;
+					q->to.type = D_BRANCH;
+					q->pcond = p->pcond;
+					p->pcond = q;
+					q = ctxt->arch->prg();
+					q->link = p->link;
+					p->link = q;
+					q->as = AB;
+					q->to.type = D_BRANCH;
+					q->pcond = q->link->link;
+					bflag = 1;
+				}
+			}
+ */
+			m = o->size;
+			if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA)) {
+				if(p->as == ATEXT) {
+					ctxt->autosize = p->to.offset + 4;
+					continue;
+				}
+				ctxt->diag("zero-width instruction\n%P", p);
+				continue;
+			}
+			c += m;
+		}
+		cursym->size = c;
+	} while(bflag);
+
+	/*
+	 * 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.
+	 */
+	if(ctxt->gmsym == nil)
+		ctxt->gmsym = linklookup(ctxt, "runtime.tlsgm", 0);
+
+	p = cursym->text;
+	ctxt->autosize = p->to.offset + 4;
+	symgrow(ctxt, cursym, cursym->size);
+
+	bp = cursym->p;
+	for(p = p->link; p != nil; p = p->link) {
+		ctxt->pc = p->pc;
+		ctxt->curp = p;
+		o = oplook(ctxt, p);
+		asmout(ctxt, p, o, out);
+		for(i=0; i<o->size/4; i++) {
+			v = out[i];
+			*bp++ = v;
+			*bp++ = v>>8;
+			*bp++ = v>>16;
+			*bp++ = v>>24;
+		}
+	}
+}
+
+/*
+ * 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.
+ */
+static int
+checkpool(Link *ctxt, Prog *p, int sz)
+{
+	if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0)
+		return flushpool(ctxt, p, 1, 0);
+	else if(p->link == nil)
+		return flushpool(ctxt, p, 2, 0);
+	return 0;
+}
+
+static int
+flushpool(Link *ctxt, Prog *p, int skip, int force)
+{
+	Prog *q;
+
+	if(ctxt->blitrl) {
+		if(skip){
+			if(0 && skip==1)print("note: flush literal pool at %llux: len=%ud ref=%ux\n", p->pc+4, pool.size, pool.start);
+			q = ctxt->arch->prg();
+			q->as = AB;
+			q->to.type = D_BRANCH;
+			q->pcond = p->link;
+			q->link = ctxt->blitrl;
+			q->lineno = p->lineno;
+			ctxt->blitrl = q;
+		}
+		else if(!force && (p->pc+pool.size-pool.start < 2048))
+			return 0;
+		ctxt->elitrl->link = p->link;
+		p->link = ctxt->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(ctxt->blitrl) {
+			ctxt->blitrl->lineno = p->lineno;
+			ctxt->blitrl = ctxt->blitrl->link;
+		}
+		ctxt->blitrl = 0;	/* BUG: should refer back to values until out-of-range */
+		ctxt->elitrl = 0;
+		pool.size = 0;
+		pool.start = 0;
+		pool.extra = 0;
+		return 1;
+	}
+	return 0;
+}
+
+static void
+addpool(Link *ctxt, Prog *p, Addr *a)
+{
+	Prog *q, t;
+	int c;
+
+	c = aclass(ctxt, a);
+
+	t = zprg;
+	t.as = AWORD;
+
+	switch(c) {
+	default:
+		t.to = *a;
+		if(ctxt->flag_shared && t.to.sym != nil)
+			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 = ctxt->instoffset;
+		break;
+	}
+
+	if(t.pcrel == nil) {
+		for(q = ctxt->blitrl; q != nil; q = q->link)	/* could hash on t.t0.offset */
+			if(q->pcrel == nil && memcmp(&q->to, &t.to, sizeof(t.to)) == 0) {
+				p->pcond = q;
+				return;
+			}
+	}
+
+	q = ctxt->arch->prg();
+	*q = t;
+	q->pc = pool.size;
+
+	if(ctxt->blitrl == nil) {
+		ctxt->blitrl = q;
+		pool.start = p->pc;
+	} else
+		ctxt->elitrl->link = q;
+	ctxt->elitrl = q;
+	pool.size += 4;
+
+	p->pcond = q;
+}
+
+static int32
+regoff(Link *ctxt, Addr *a)
+{
+
+	ctxt->instoffset = 0;
+	aclass(ctxt, a);
+	return ctxt->instoffset;
+}
+
+static 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;
+}
+
+static 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;
+}
+
+static int
+immfloat(int32 v)
+{
+	return (v & 0xC03) == 0;	/* offset will fit in floating-point load/store */
+}
+
+static 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;
+}
+
+static int
+aclass(Link *ctxt, Addr *a)
+{
+	LSym *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;
+			}
+			ctxt->instoffset = 0;	// s.b. unused but just in case
+			return C_ADDR;
+
+		case D_AUTO:
+			ctxt->instoffset = ctxt->autosize + a->offset;
+			t = immaddr(ctxt->instoffset);
+			if(t){
+				if(immhalf(ctxt->instoffset))
+					return immfloat(t) ? C_HFAUTO : C_HAUTO;
+				if(immfloat(t))
+					return C_FAUTO;
+				return C_SAUTO;
+			}
+			return C_LAUTO;
+
+		case D_PARAM:
+			ctxt->instoffset = ctxt->autosize + a->offset + 4L;
+			t = immaddr(ctxt->instoffset);
+			if(t){
+				if(immhalf(ctxt->instoffset))
+					return immfloat(t) ? C_HFAUTO : C_HAUTO;
+				if(immfloat(t))
+					return C_FAUTO;
+				return C_SAUTO;
+			}
+			return C_LAUTO;
+		case D_NONE:
+			ctxt->instoffset = a->offset;
+			t = immaddr(ctxt->instoffset);
+			if(t) {
+				if(immhalf(ctxt->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(ctxt->instoffset);
+				if(t)
+					return C_SROREG;
+				if(immhalf(ctxt->instoffset))
+					return C_HOREG;
+				return C_SOREG;
+			}
+			t = immrot(ctxt->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:
+			ctxt->instoffset = 0;	// s.b. unused but just in case
+			return C_ADDR;
+		}
+		return C_GOK;
+
+	case D_FCONST:
+		if(chipzero5(ctxt, a->u.dval) >= 0)
+			return C_ZFCON;
+		if(chipfloat5(ctxt, a->u.dval) >= 0)
+			return C_SFCON;
+		return C_LFCON;
+
+	case D_CONST:
+	case D_CONST2:
+		switch(a->name) {
+
+		case D_NONE:
+			ctxt->instoffset = a->offset;
+			if(a->reg != NREG)
+				goto aconsize;
+
+			t = immrot(ctxt->instoffset);
+			if(t)
+				return C_RCON;
+			t = immrot(~ctxt->instoffset);
+			if(t)
+				return C_NCON;
+			return C_LCON;
+
+		case D_EXTERN:
+		case D_STATIC:
+			s = a->sym;
+			if(s == nil)
+				break;
+			ctxt->instoffset = 0;	// s.b. unused but just in case
+			return C_LCONADDR;
+
+		case D_AUTO:
+			ctxt->instoffset = ctxt->autosize + a->offset;
+			goto aconsize;
+
+		case D_PARAM:
+			ctxt->instoffset = ctxt->autosize + a->offset + 4L;
+		aconsize:
+			t = immrot(ctxt->instoffset);
+			if(t)
+				return C_RACON;
+			return C_LACON;
+		}
+		return C_GOK;
+
+	case D_BRANCH:
+		return C_SBRA;
+	}
+	return C_GOK;
+}
+
+static void
+prasm(Prog *p)
+{
+	print("%P\n", p);
+}
+
+static Optab*
+oplook(Link *ctxt, 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(ctxt, &p->from) + 1;
+		p->from.class = a1;
+	}
+	a1--;
+	a3 = p->to.class;
+	if(a3 == 0) {
+		a3 = aclass(ctxt, &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(0 /*debug['O']*/) {
+		print("oplook %A %d %d %d\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(; o<e; o++)
+		if(o->a2 == a2)
+		if(c1[o->a1])
+		if(c3[o->a3]) {
+			p->optab = (o-optab)+1;
+			return o;
+		}
+	ctxt->diag("illegal combination %P; %d %d %d, %d %d",
+		p, a1, a2, a3, p->from.type, p->to.type);
+	ctxt->diag("from %d %d to %d %d\n", p->from.type, p->from.name, p->to.type, p->to.name);
+	prasm(p);
+	if(o == 0)
+		o = optab;
+	return o;
+}
+
+static 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;
+}
+
+static 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;
+}
+
+static void
+buildop(Link *ctxt)
+{
+	int i, n, r;
+
+	for(i=0; i<C_GOK; i++)
+		for(n=0; n<C_GOK; n++)
+			xcmp[i][n] = cmp(n, i);
+	for(n=0; optab[n].as != AXXX; n++) {
+		if((optab[n].flag & LPCREL) != 0) {
+			if(ctxt->flag_shared)
+				optab[n].size += optab[n].pcrelsiz;
+			else
+				optab[n].flag &= ~LPCREL;
+		}
+	}
+	qsort(optab, n, sizeof(optab[0]), ocmp);
+	for(i=0; i<n; i++) {
+		r = optab[i].as;
+		oprange[r].start = optab+i;
+		while(optab[i].as == r)
+			i++;
+		oprange[r].stop = optab+i;
+		i--;
+
+		switch(r)
+		{
+		default:
+			ctxt->diag("unknown op in build: %A", r);
+			sysfatal("bad code");
+		case AADD:
+			oprange[AAND] = oprange[r];
+			oprange[AEOR] = oprange[r];
+			oprange[ASUB] = oprange[r];
+			oprange[ARSB] = oprange[r];
+			oprange[AADC] = oprange[r];
+			oprange[ASBC] = oprange[r];
+			oprange[ARSC] = oprange[r];
+			oprange[AORR] = oprange[r];
+			oprange[ABIC] = oprange[r];
+			break;
+		case ACMP:
+			oprange[ATEQ] = oprange[r];
+			oprange[ACMN] = oprange[r];
+			break;
+		case AMVN:
+			break;
+		case ABEQ:
+			oprange[ABNE] = oprange[r];
+			oprange[ABCS] = oprange[r];
+			oprange[ABHS] = oprange[r];
+			oprange[ABCC] = oprange[r];
+			oprange[ABLO] = oprange[r];
+			oprange[ABMI] = oprange[r];
+			oprange[ABPL] = oprange[r];
+			oprange[ABVS] = oprange[r];
+			oprange[ABVC] = oprange[r];
+			oprange[ABHI] = oprange[r];
+			oprange[ABLS] = oprange[r];
+			oprange[ABGE] = oprange[r];
+			oprange[ABLT] = oprange[r];
+			oprange[ABGT] = oprange[r];
+			oprange[ABLE] = oprange[r];
+			break;
+		case ASLL:
+			oprange[ASRL] = oprange[r];
+			oprange[ASRA] = oprange[r];
+			break;
+		case AMUL:
+			oprange[AMULU] = oprange[r];
+			break;
+		case ADIV:
+			oprange[AMOD] = oprange[r];
+			oprange[AMODU] = oprange[r];
+			oprange[ADIVU] = oprange[r];
+			break;
+		case AMOVW:
+		case AMOVB:
+		case AMOVBS:
+		case AMOVBU:
+		case AMOVH:
+		case AMOVHS:
+		case AMOVHU:
+			break;
+		case ASWPW:
+			oprange[ASWPBU] = oprange[r];
+			break;
+		case AB:
+		case ABL:
+		case ABX:
+		case ABXRET:
+		case ADUFFZERO:
+		case ADUFFCOPY:
+		case ASWI:
+		case AWORD:
+		case AMOVM:
+		case ARFE:
+		case ATEXT:
+		case AUSEFIELD:
+		case ACASE:
+		case ABCASE:
+		case ATYPE:
+			break;
+		case AADDF:
+			oprange[AADDD] = oprange[r];
+			oprange[ASUBF] = oprange[r];
+			oprange[ASUBD] = oprange[r];
+			oprange[AMULF] = oprange[r];
+			oprange[AMULD] = oprange[r];
+			oprange[ADIVF] = oprange[r];
+			oprange[ADIVD] = oprange[r];
+			oprange[ASQRTF] = oprange[r];
+			oprange[ASQRTD] = oprange[r];
+			oprange[AMOVFD] = oprange[r];
+			oprange[AMOVDF] = oprange[r];
+			oprange[AABSF] = oprange[r];
+			oprange[AABSD] = oprange[r];
+			break;
+
+		case ACMPF:
+			oprange[ACMPD] = oprange[r];
+			break;
+
+		case AMOVF:
+			oprange[AMOVD] = oprange[r];
+			break;
+
+		case AMOVFW:
+			oprange[AMOVDW] = oprange[r];
+			break;
+
+		case AMOVWF:
+			oprange[AMOVWD] = oprange[r];
+			break;
+
+		case AMULL:
+			oprange[AMULAL] = oprange[r];
+			oprange[AMULLU] = oprange[r];
+			oprange[AMULALU] = oprange[r];
+			break;
+
+		case AMULWT:
+			oprange[AMULWB] = oprange[r];
+			break;
+
+		case AMULAWT:
+			oprange[AMULAWB] = oprange[r];
+			break;
+
+		case AMULA:
+		case ALDREX:
+		case ASTREX:
+		case ALDREXD:
+		case ASTREXD:
+		case ATST:
+		case APLD:
+		case AUNDEF:
+		case ACLZ:
+		case AFUNCDATA:
+		case APCDATA:
+			break;
+		}
+	}
+}
+
+static void
+asmout(Link *ctxt, Prog *p, Optab *o, int32 *out)
+{
+	int32 o1, o2, o3, o4, o5, o6, v;
+	int r, rf, rt, rt2;
+	Reloc *rel;
+
+ctxt->printp = p;
+	o1 = 0;
+	o2 = 0;
+	o3 = 0;
+	o4 = 0;
+	o5 = 0;
+	o6 = 0;
+	ctxt->armsize += o->size;
+if(0 /*debug['P']*/) print("%ux: %P	type %d\n", (uint32)(p->pc), p, o->type);
+	switch(o->type) {
+	default:
+		ctxt->diag("unknown asm %d", o->type);
+		prasm(p);
+		break;
+
+	case 0:		/* pseudo ops */
+if(0 /*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(ctxt, 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(ctxt, &p->from);
+		o1 = oprrr(ctxt, p->as, p->scond);
+		o1 |= immrot(ctxt->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(ctxt, &p->from);
+		o1 = oprrr(ctxt, 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(ctxt, &p->from);
+		o1 = oprrr(ctxt, AADD, p->scond);
+		o1 |= immrot(ctxt->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(ctxt, p->as, p->scond);
+		v = -8;
+		if(p->to.sym != nil) {
+			rel = addrel(ctxt->cursym);
+			rel->off = ctxt->pc;
+			rel->siz = 4;
+			rel->sym = p->to.sym;
+			v += p->to.offset;
+			rel->add = o1 | ((v >> 2) & 0xffffff);
+			rel->type = R_CALLARM;
+			break;
+		}
+		if(p->pcond != nil)
+			v = (p->pcond->pc - ctxt->pc) - 8;
+		o1 |= (v >> 2) & 0xffffff;
+		break;
+
+	case 6:		/* b ,O(R) -> add $O,R,PC */
+		aclass(ctxt, &p->to);
+		o1 = oprrr(ctxt, AADD, p->scond);
+		o1 |= immrot(ctxt->instoffset);
+		o1 |= p->to.reg << 16;
+		o1 |= REGPC << 12;
+		break;
+
+	case 7:		/* bl (R) -> blx R */
+		aclass(ctxt, &p->to);
+		if(ctxt->instoffset != 0)
+			ctxt->diag("%P: doesn't support BL offset(REG) where offset != 0", p);
+		o1 = oprrr(ctxt, ABL, p->scond);
+		o1 |= p->to.reg;
+		rel = addrel(ctxt->cursym);
+		rel->off = ctxt->pc;
+		rel->siz = 0;
+		rel->type = R_CALLIND;
+		break;
+
+	case 8:		/* sll $c,[R],R -> mov (R<<$c),R */
+		aclass(ctxt, &p->from);
+		o1 = oprrr(ctxt, p->as, p->scond);
+		r = p->reg;
+		if(r == NREG)
+			r = p->to.reg;
+		o1 |= r;
+		o1 |= (ctxt->instoffset&31) << 7;
+		o1 |= p->to.reg << 12;
+		break;
+
+	case 9:		/* sll R,[R],R -> mov (R<<R),R */
+		o1 = oprrr(ctxt, p->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(ctxt, p->as, p->scond);
+		if(p->to.type != D_NONE) {
+			aclass(ctxt, &p->to);
+			o1 |= ctxt->instoffset & 0xffffff;
+		}
+		break;
+
+	case 11:	/* word */
+		aclass(ctxt, &p->to);
+		o1 = ctxt->instoffset;
+		if(p->to.sym != nil) {
+			// This case happens with words generated
+			// in the PC stream as part of the literal pool.
+			rel = addrel(ctxt->cursym);
+			rel->off = ctxt->pc;
+			rel->siz = 4;
+			rel->sym = p->to.sym;
+			rel->add = p->to.offset;
+			
+			// runtime.tlsgm (aka gmsym) is special.
+			// Its "address" is the offset from the TLS thread pointer
+			// to the thread-local g and m pointers.
+			// Emit a TLS relocation instead of a standard one.
+			if(rel->sym == ctxt->gmsym) {
+				rel->type = R_TLS;
+				if(ctxt->flag_shared)
+					rel->add += ctxt->pc - p->pcrel->pc - 8 - rel->siz;
+				rel->xadd = rel->add;
+				rel->xsym = rel->sym;
+			} else if(ctxt->flag_shared) {
+				rel->type = R_PCREL;
+				rel->add += ctxt->pc - p->pcrel->pc - 8;
+			} else
+				rel->type = R_ADDR;
+			o1 = 0;
+		}
+		break;
+
+	case 12:	/* movw $lcon, reg */
+		o1 = omvl(ctxt, p, &p->from, p->to.reg);
+		if(o->flag & LPCREL) {
+			o2 = oprrr(ctxt, AADD, p->scond) | p->to.reg | REGPC << 16 | p->to.reg << 12;
+		}
+		break;
+
+	case 13:	/* op $lcon, [R], R */
+		o1 = omvl(ctxt, p, &p->from, REGTMP);
+		if(!o1)
+			break;
+		o2 = oprrr(ctxt, 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(ctxt, ASLL, p->scond);
+
+		if(p->as == AMOVBU || p->as == AMOVHU)
+			o2 = oprrr(ctxt, ASRL, p->scond);
+		else
+			o2 = oprrr(ctxt, 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(ctxt, 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) {
+			ctxt->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(ctxt, 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(ctxt, &p->to);
+		r = p->to.reg;
+		if(r == NREG)
+			r = o->param;
+		o1 = osr(ctxt, p->as, p->from.reg, ctxt->instoffset, r, p->scond);
+		break;
+
+	case 21:	/* mov/movbu O(R),R -> lr */
+		aclass(ctxt, &p->from);
+		r = p->from.reg;
+		if(r == NREG)
+			r = o->param;
+		o1 = olr(ctxt, ctxt->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(ctxt, p, &p->to, REGTMP);
+		if(!o1)
+			break;
+		r = p->to.reg;
+		if(r == NREG)
+			r = o->param;
+		o2 = osrr(ctxt, 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(ctxt, p, &p->from, REGTMP);
+		if(!o1)
+			break;
+		r = p->from.reg;
+		if(r == NREG)
+			r = o->param;
+		o2 = olrr(ctxt, 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(ctxt, p, &p->from, REGTMP);
+		if(!o1)
+			break;
+
+		o2 = oprrr(ctxt, 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(ctxt, &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(ctxt->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(ctxt, &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(ctxt, &p->from);
+	movm:
+		if(ctxt->instoffset != 0)
+			ctxt->diag("offset must be zero in MOVM; %P", p);
+		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(ctxt, &p->from);
+		if(ctxt->instoffset != 0)
+			ctxt->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(ctxt, &p->to);
+		r = p->to.reg;
+		if(r == NREG)
+			r = o->param;
+		o1 = ofsr(ctxt, p->as, p->from.reg, v, r, p->scond, p);
+		break;
+
+	case 51:	/* floating point load */
+		v = regoff(ctxt, &p->from);
+		r = p->from.reg;
+		if(r == NREG)
+			r = o->param;
+		o1 = ofsr(ctxt, p->as, p->to.reg, v, r, p->scond, p) | (1<<20);
+		break;
+
+	case 52:	/* floating point store, int32 offset UGLY */
+		o1 = omvl(ctxt, p, &p->to, REGTMP);
+		if(!o1)
+			break;
+		r = p->to.reg;
+		if(r == NREG)
+			r = o->param;
+		o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
+		o3 = ofsr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond, p);
+		break;
+
+	case 53:	/* floating point load, int32 offset UGLY */
+		o1 = omvl(ctxt, p, &p->from, REGTMP);
+		if(!o1)
+			break;
+		r = p->from.reg;
+		if(r == NREG)
+			r = o->param;
+		o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
+		o3 = ofsr(ctxt, p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
+		break;
+
+	case 54:	/* floating point arith */
+		o1 = oprrr(ctxt, 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 == AMOVFD || p->as == AMOVDF ||
+				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(ctxt, 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<<I(R),R -> ldr indexed */
+		if(p->from.reg == NREG) {
+			if(p->as != AMOVW)
+				ctxt->diag("byte MOV from shifter operand");
+			goto mov;
+		}
+		if(p->from.offset&(1<<4))
+			ctxt->diag("bad shift in LDR");
+		o1 = olrr(ctxt, 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) {
+			ctxt->diag("byte MOV from shifter operand");
+			goto mov;
+		}
+		if(p->from.offset&(~0xf))
+			ctxt->diag("bad shift in LDRSB");
+		o1 = olhrr(ctxt, 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)
+			ctxt->diag("MOV to shifter operand");
+		o1 = osrr(ctxt, 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(ctxt, AADD, p->scond) | immrot(1) | p->from.reg << 16 | REGTMP << 12;
+			o2 = olrr(ctxt, REGTMP, REGPC, REGTMP, p->scond);
+			o2 |= 2<<7;
+			o3 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGPC << 12;
+		} else {
+			o1 = olrr(ctxt, p->from.reg, REGPC, REGPC, p->scond);
+			o1 |= 2<<7;
+		}
+		break;
+
+	case 63:	/* bcase */
+		if(p->pcond != nil) {
+			rel = addrel(ctxt->cursym);
+			rel->off = ctxt->pc;
+			rel->siz = 4;
+			if(p->to.sym != nil && p->to.sym->type != 0) {
+				rel->sym = p->to.sym;
+				rel->add = p->to.offset;
+			} else {
+				rel->sym = ctxt->cursym;
+				rel->add = p->pcond->pc;
+			}
+			if(o->flag & LPCREL) {
+				rel->type = R_PCREL;
+				rel->add += ctxt->pc - p->pcrel->pc - 16 + rel->siz;
+			} else
+				rel->type = R_ADDR;
+			o1 = 0;
+		}
+		break;
+
+	/* reloc ops */
+	case 64:	/* mov/movb/movbu R,addr */
+		o1 = omvl(ctxt, p, &p->to, REGTMP);
+		if(!o1)
+			break;
+		o2 = osr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond);
+		if(o->flag & LPCREL) {
+			o3 = o2;
+			o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+		}
+		break;
+
+	case 65:	/* mov/movbu addr,R */
+		o1 = omvl(ctxt, p, &p->from, REGTMP);
+		if(!o1)
+			break;
+		o2 = olr(ctxt, 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(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+		}
+		break;
+
+	case 68:	/* floating point store -> ADDR */
+		o1 = omvl(ctxt, p, &p->to, REGTMP);
+		if(!o1)
+			break;
+		o2 = ofsr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond, p);
+		if(o->flag & LPCREL) {
+			o3 = o2;
+			o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+		}
+		break;
+
+	case 69:	/* floating point load <- ADDR */
+		o1 = omvl(ctxt, p, &p->from, REGTMP);
+		if(!o1)
+			break;
+		o2 = ofsr(ctxt, p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
+		if(o->flag & LPCREL) {
+			o3 = o2;
+			o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+		}
+		break;
+
+	/* ArmV4 ops: */
+	case 70:	/* movh/movhu R,O(R) -> strh */
+		aclass(ctxt, &p->to);
+		r = p->to.reg;
+		if(r == NREG)
+			r = o->param;
+		o1 = oshr(ctxt, p->from.reg, ctxt->instoffset, r, p->scond);
+		break;
+	case 71:	/* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
+		aclass(ctxt, &p->from);
+		r = p->from.reg;
+		if(r == NREG)
+			r = o->param;
+		o1 = olhr(ctxt, ctxt->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(ctxt, p, &p->to, REGTMP);
+		if(!o1)
+			break;
+		r = p->to.reg;
+		if(r == NREG)
+			r = o->param;
+		o2 = oshrr(ctxt, p->from.reg, REGTMP,r, p->scond);
+		break;
+	case 73:	/* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
+		o1 = omvl(ctxt, p, &p->from, REGTMP);
+		if(!o1)
+			break;
+		r = p->from.reg;
+		if(r == NREG)
+			r = o->param;
+		o2 = olhrr(ctxt, 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 */
+		ctxt->diag("ABX $I");
+		break;
+	case 75:	/* bx O(R) */
+		aclass(ctxt, &p->to);
+		if(ctxt->instoffset != 0)
+			ctxt->diag("non-zero offset in ABX");
+/*
+		o1 = 	oprrr(ctxt, 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(ctxt, AADD, p->scond);
+		o1 |= immrot(ctxt->instoffset);
+		o1 |= p->to.reg << 16;
+		o1 |= REGTMP << 12;
+		o2 = oprrr(ctxt, 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*/
+		ctxt->diag("ABXRET");
+		break;
+	case 77:	/* ldrex oreg,reg */
+		aclass(ctxt, &p->from);
+		if(ctxt->instoffset != 0)
+			ctxt->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(ctxt, &p->from);
+		if(ctxt->instoffset != 0)
+			ctxt->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(ctxt, ASUBD, p->scond);
+		} else {
+			o1 = 0x0eb00a00;	// VMOV imm 32
+			o2 = oprrr(ctxt, 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 = chipfloat5(ctxt, p->from.u.dval);
+		o1 |= (v&0xf) << 0;
+		o1 |= (v&0xf0) << 12;
+		break;
+	case 82:	/* fcmp freg,freg, */
+		o1 = oprrr(ctxt, 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(ctxt, 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(ctxt, 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(ctxt, 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(ctxt, p->as, p->scond);
+		o1 |= (p->from.reg<<0);
+		o1 |= (FREGTMP<<12);
+		o2 = oprrr(ctxt, 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(ctxt, AMOVWF+AEND, p->scond);
+		o1 |= (p->from.reg<<12);
+		o1 |= (FREGTMP<<16);
+		o2 = oprrr(ctxt, p->as, p->scond);
+		o2 |= (FREGTMP<<0);
+		o2 |= (p->to.reg<<12);
+		break;
+	case 88:	/* movw reg,freg  */
+		o1 = oprrr(ctxt, AMOVWF+AEND, p->scond);
+		o1 |= (p->from.reg<<12);
+		o1 |= (p->to.reg<<16);
+		break;
+	case 89:	/* movw freg,reg  */
+		o1 = oprrr(ctxt, AMOVFW+AEND, p->scond);
+		o1 |= (p->from.reg<<16);
+		o1 |= (p->to.reg<<12);
+		break;
+	case 90:	/* tst reg  */
+		o1 = oprrr(ctxt, ACMP+AEND, p->scond);
+		o1 |= p->from.reg<<16;
+		break;
+	case 91:	/* ldrexd oreg,reg */
+		aclass(ctxt, &p->from);
+		if(ctxt->instoffset != 0)
+			ctxt->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(ctxt, &p->from);
+		if(ctxt->instoffset != 0)
+			ctxt->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(ctxt, p, &p->from, REGTMP);
+		if(!o1)
+			break;
+		o2 = olhr(ctxt, 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(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
+		}
+		break;
+	case 94:	/* movh/movhu R,addr -> strh */
+		o1 = omvl(ctxt, p, &p->to, REGTMP);
+		if(!o1)
+			break;
+		o2 = oshr(ctxt, p->from.reg, 0, REGTMP, p->scond);
+		if(o->flag & LPCREL) {
+			o3 = o2;
+			o2 = oprrr(ctxt, 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 guaranteed to raise undefined instruction
+		// exception.
+		o1 = 0xf7fabcfd;
+		break;
+	case 97:	/* CLZ Rm, Rd */
+ 		o1 = oprrr(ctxt, p->as, p->scond);
+ 		o1 |= p->to.reg << 12;
+ 		o1 |= p->from.reg;
+		break;
+	case 98:	/* MULW{T,B} Rs, Rm, Rd */
+		o1 = oprrr(ctxt, 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(ctxt, 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
+}
+
+static int32
+oprrr(Link *ctxt, int a, int sc)
+{
+	int32 o;
+
+	o = (sc & C_SCOND) << 28;
+	if(sc & C_SBIT)
+		o |= 1 << 20;
+	if(sc & (C_PBIT|C_WBIT))
+		ctxt->diag(".nil/.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 .nil
+		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);
+	}
+	ctxt->diag("bad rrr %d", a);
+	prasm(ctxt->curp);
+	return 0;
+}
+
+static int32
+opbra(Link *ctxt, int a, int sc)
+{
+
+	if(sc & (C_SBIT|C_PBIT|C_WBIT))
+		ctxt->diag(".nil/.nil/.W on bra instruction");
+	sc &= C_SCOND;
+	if(a == ABL || a == ADUFFZERO || a == ADUFFCOPY)
+		return (sc<<28)|(0x5<<25)|(0x1<<24);
+	if(sc != 0xe)
+		ctxt->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);
+	}
+	ctxt->diag("bad bra %A", a);
+	prasm(ctxt->curp);
+	return 0;
+}
+
+static int32
+olr(Link *ctxt, int32 v, int b, int r, int sc)
+{
+	int32 o;
+
+	if(sc & C_SBIT)
+		ctxt->diag(".nil 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)
+			ctxt->diag(".U on neg offset");
+		v = -v;
+		o ^= 1 << 23;
+	}
+	if(v >= (1<<12) || v < 0)
+		ctxt->diag("literal span too large: %d (R%d)\n%P", v, b, ctxt->printp);
+	o |= v;
+	o |= b << 16;
+	o |= r << 12;
+	return o;
+}
+
+static int32
+olhr(Link *ctxt, int32 v, int b, int r, int sc)
+{
+	int32 o;
+
+	if(sc & C_SBIT)
+		ctxt->diag(".nil 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)
+		ctxt->diag("literal span too large: %d (R%d)\n%P", v, b, ctxt->printp);
+	o |= (v&0xf)|((v>>4)<<8)|(1<<22);
+	o |= b << 16;
+	o |= r << 12;
+	return o;
+}
+
+static int32
+osr(Link *ctxt, int a, int r, int32 v, int b, int sc)
+{
+	int32 o;
+
+	o = olr(ctxt, v, b, r, sc) ^ (1<<20);
+	if(a != AMOVW)
+		o |= 1<<22;
+	return o;
+}
+
+static int32
+oshr(Link *ctxt, int r, int32 v, int b, int sc)
+{
+	int32 o;
+
+	o = olhr(ctxt, v, b, r, sc) ^ (1<<20);
+	return o;
+}
+
+
+static int32
+osrr(Link *ctxt, int r, int i, int b, int sc)
+{
+
+	return olr(ctxt, i, b, r, sc) ^ ((1<<25) | (1<<20));
+}
+
+static int32
+oshrr(Link *ctxt, int r, int i, int b, int sc)
+{
+	return olhr(ctxt, i, b, r, sc) ^ ((1<<22) | (1<<20));
+}
+
+static int32
+olrr(Link *ctxt, int i, int b, int r, int sc)
+{
+
+	return olr(ctxt, i, b, r, sc) ^ (1<<25);
+}
+
+static int32
+olhrr(Link *ctxt, int i, int b, int r, int sc)
+{
+	return olhr(ctxt, i, b, r, sc) ^ (1<<22);
+}
+
+static int32
+ofsr(Link *ctxt, int a, int r, int32 v, int b, int sc, Prog *p)
+{
+	int32 o;
+
+	if(sc & C_SBIT)
+		ctxt->diag(".nil 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)
+		ctxt->diag("odd offset for floating point op: %d\n%P", v, p);
+	else
+	if(v >= (1<<10) || v < 0)
+		ctxt->diag("literal span too large: %d\n%P", v, p);
+	o |= (v>>2) & 0xFF;
+	o |= b << 16;
+	o |= r << 12;
+
+	switch(a) {
+	default:
+		ctxt->diag("bad fst %A", a);
+	case AMOVD:
+		o |= 1 << 8;
+	case AMOVF:
+		break;
+	}
+	return o;
+}
+
+static int32
+omvl(Link *ctxt, Prog *p, Addr *a, int dr)
+{
+	int32 v, o1;
+	if(!p->pcond) {
+		aclass(ctxt, a);
+		v = immrot(~ctxt->instoffset);
+		if(v == 0) {
+			ctxt->diag("missing literal");
+			prasm(p);
+			return 0;
+		}
+		o1 = oprrr(ctxt, AMVN, p->scond&C_SCOND);
+		o1 |= v;
+		o1 |= dr << 12;
+	} else {
+		v = p->pcond->pc - p->pc - 8;
+		o1 = olr(ctxt, v, REGPC, dr, p->scond&C_SCOND);
+	}
+	return o1;
+}
+
+int
+chipzero5(Link *ctxt, float64 e)
+{
+	// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
+	if(ctxt->goarm < 7 || e != 0)
+		return -1;
+	return 0;
+}
+
+int
+chipfloat5(Link *ctxt, float64 e)
+{
+	int n;
+	ulong h1;
+	int32 l, h;
+	uint64 ei;
+
+	// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
+	if(ctxt->goarm < 7)
+		goto no;
+
+	memmove(&ei, &e, 8);
+	l = (int32)ei;
+	h = (int32)(ei>>32);
+
+	if(l != 0 || (h&0xffff) != 0)
+		goto no;
+	h1 = h & 0x7fc00000;
+	if(h1 != 0x40000000 && h1 != 0x3fc00000)
+		goto no;
+	n = 0;
+
+	// sign bit (a)
+	if(h & 0x80000000)
+		n |= 1<<7;
+
+	// exp sign bit (b)
+	if(h1 == 0x3fc00000)
+		n |= 1<<6;
+
+	// rest of exp and mantissa (cd-efgh)
+	n |= (h >> 16) & 0x3f;
+
+//print("match %.8lux %.8lux %d\n", l, h, n);
+	return n;
+
+no:
+	return -1;
+}
diff --git a/src/liblink/asm6.c b/src/liblink/asm6.c
new file mode 100644
index 0000000..66afc7a
--- /dev/null
+++ b/src/liblink/asm6.c
@@ -0,0 +1,3585 @@
+// 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 at 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 at 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/6l/6.out.h"
+#include "../pkg/runtime/stack.h"
+
+enum
+{
+	MaxAlign = 32,	// max data alignment
+	
+	// Loop alignment constants:
+	// want to align loop entry to LoopAlign-byte boundary,
+	// and willing to insert at most MaxLoopPad bytes of NOP to do so.
+	// We define a loop entry as the target of a backward jump.
+	//
+	// gcc uses MaxLoopPad = 10 for its 'generic x86-64' config,
+	// and it aligns all jump targets, not just backward jump targets.
+	//
+	// As of 6/1/2012, the effect of setting MaxLoopPad = 10 here
+	// is very slight but negative, so the alignment is disabled by
+	// setting MaxLoopPad = 0. The code is here for reference and
+	// for future experiments.
+	// 
+	LoopAlign = 16,
+	MaxLoopPad = 0,
+
+	FuncAlign = 16
+};
+
+extern char *anames6[];
+
+typedef	struct	Optab	Optab;
+typedef	struct	Movtab	Movtab;
+
+struct	Optab
+{
+	short	as;
+	uchar*	ytab;
+	uchar	prefix;
+	uchar	op[23];
+};
+struct	Movtab
+{
+	short	as;
+	uchar	ft;
+	uchar	tt;
+	uchar	code;
+	uchar	op[4];
+};
+
+enum
+{
+	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,
+	Ytls,
+	Ymax,
+
+	Zxxx		= 0,
+
+	Zlit,
+	Zlitm_r,
+	Z_rp,
+	Zbr,
+	Zcall,
+	Zcallindreg,
+	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 */
+};
+
+static char ycover[Ymax*Ymax];
+static	int	reg[D_NONE];
+static	int	regrex[D_NONE+1];
+static	void	asmins(Link *ctxt, Prog *p);
+
+static uchar	ynone[] =
+{
+	Ynone,	Ynone,	Zlit,	1,
+	0
+};
+static uchar	ytext[] =
+{
+	Ymb,	Yi64,	Zpseudo,1,
+	0
+};
+static 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
+};
+static uchar	yfuncdata[] =
+{
+	Yi32,	Ym,	Zpseudo,	0,
+	0
+};
+static uchar	ypcdata[] = 
+{
+	Yi32,	Yi32,	Zpseudo,	0,
+	0
+};
+static uchar	yxorb[] =
+{
+	Yi32,	Yal,	Zib_,	1,
+	Yi32,	Ymb,	Zibo_m,	2,
+	Yrb,	Ymb,	Zr_m,	1,
+	Ymb,	Yrb,	Zm_r,	1,
+	0
+};
+static 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
+};
+static 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
+};
+static uchar	yincb[] =
+{
+	Ynone,	Ymb,	Zo_m,	2,
+	0
+};
+static uchar	yincw[] =
+{
+	Ynone,	Yml,	Zo_m,	2,
+	0
+};
+static uchar	yincl[] =
+{
+	Ynone,	Yml,	Zo_m,	2,
+	0
+};
+static uchar	ycmpb[] =
+{
+	Yal,	Yi32,	Z_ib,	1,
+	Ymb,	Yi32,	Zm_ibo,	2,
+	Ymb,	Yrb,	Zm_r,	1,
+	Yrb,	Ymb,	Zr_m,	1,
+	0
+};
+static 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
+};
+static uchar	yshb[] =
+{
+	Yi1,	Ymb,	Zo_m,	2,
+	Yi32,	Ymb,	Zibo_m,	2,
+	Ycx,	Ymb,	Zo_m,	2,
+	0
+};
+static uchar	yshl[] =
+{
+	Yi1,	Yml,	Zo_m,	2,
+	Yi32,	Yml,	Zibo_m,	2,
+	Ycl,	Yml,	Zo_m,	2,
+	Ycx,	Yml,	Zo_m,	2,
+	0
+};
+static uchar	ytestb[] =
+{
+	Yi32,	Yal,	Zib_,	1,
+	Yi32,	Ymb,	Zibo_m,	2,
+	Yrb,	Ymb,	Zr_m,	1,
+	Ymb,	Yrb,	Zm_r,	1,
+	0
+};
+static uchar	ytestl[] =
+{
+	Yi32,	Yax,	Zil_,	1,
+	Yi32,	Yml,	Zilo_m,	2,
+	Yrl,	Yml,	Zr_m,	1,
+	Yml,	Yrl,	Zm_r,	1,
+	0
+};
+static uchar	ymovb[] =
+{
+	Yrb,	Ymb,	Zr_m,	1,
+	Ymb,	Yrb,	Zm_r,	1,
+	Yi32,	Yrb,	Zib_rp,	1,
+	Yi32,	Ymb,	Zibo_m,	2,
+	0
+};
+static uchar	ymbs[] =
+{
+	Ymb,	Ynone,	Zm_o,	2,
+	0
+};
+static uchar	ybtl[] =
+{
+	Yi8,	Yml,	Zibo_m,	2,
+	Yrl,	Yml,	Zr_m,	1,
+	0
+};
+static 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
+};
+static 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
+};
+static uchar	yret[] =
+{
+	Ynone,	Ynone,	Zo_iw,	1,
+	Yi32,	Ynone,	Zo_iw,	1,
+	0
+};
+static 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
+};
+static uchar	ym_rl[] =
+{
+	Ym,	Yrl,	Zm_r,	1,
+	0
+};
+static uchar	yrl_m[] =
+{
+	Yrl,	Ym,	Zr_m,	1,
+	0
+};
+static uchar	ymb_rl[] =
+{
+	Ymb,	Yrl,	Zmb_r,	1,
+	0
+};
+static uchar	yml_rl[] =
+{
+	Yml,	Yrl,	Zm_r,	1,
+	0
+};
+static uchar	yrl_ml[] =
+{
+	Yrl,	Yml,	Zr_m,	1,
+	0
+};
+static uchar	yml_mb[] =
+{
+	Yrb,	Ymb,	Zr_m,	1,
+	Ymb,	Yrb,	Zm_r,	1,
+	0
+};
+static uchar	yrb_mb[] =
+{
+	Yrb,	Ymb,	Zr_m,	1,
+	0
+};
+static uchar	yxchg[] =
+{
+	Yax,	Yrl,	Z_rp,	1,
+	Yrl,	Yax,	Zrp_,	1,
+	Yrl,	Yml,	Zr_m,	1,
+	Yml,	Yrl,	Zm_r,	1,
+	0
+};
+static uchar	ydivl[] =
+{
+	Yml,	Ynone,	Zm_o,	2,
+	0
+};
+static uchar	ydivb[] =
+{
+	Ymb,	Ynone,	Zm_o,	2,
+	0
+};
+static uchar	yimul[] =
+{
+	Yml,	Ynone,	Zm_o,	2,
+	Yi8,	Yrl,	Zib_rr,	1,
+	Yi32,	Yrl,	Zil_rr,	1,
+	Yml,	Yrl,	Zm_r,	2,
+	0
+};
+static uchar	yimul3[] =
+{
+	Yml,	Yrl,	Zibm_r,	2,
+	0
+};
+static uchar	ybyte[] =
+{
+	Yi64,	Ynone,	Zbyte,	1,
+	0
+};
+static uchar	yin[] =
+{
+	Yi32,	Ynone,	Zib_,	1,
+	Ynone,	Ynone,	Zlit,	1,
+	0
+};
+static uchar	yint[] =
+{
+	Yi32,	Ynone,	Zib_,	1,
+	0
+};
+static uchar	ypushl[] =
+{
+	Yrl,	Ynone,	Zrp_,	1,
+	Ym,	Ynone,	Zm_o,	2,
+	Yi8,	Ynone,	Zib_,	1,
+	Yi32,	Ynone,	Zil_,	1,
+	0
+};
+static uchar	ypopl[] =
+{
+	Ynone,	Yrl,	Z_rp,	1,
+	Ynone,	Ym,	Zo_m,	2,
+	0
+};
+static uchar	ybswap[] =
+{
+	Ynone,	Yrl,	Z_rp,	2,
+	0,
+};
+static uchar	yscond[] =
+{
+	Ynone,	Ymb,	Zo_m,	2,
+	0
+};
+static uchar	yjcond[] =
+{
+	Ynone,	Ybr,	Zbr,	0,
+	Yi0,	Ybr,	Zbr,	0,
+	Yi1,	Ybr,	Zbr,	1,
+	0
+};
+static uchar	yloop[] =
+{
+	Ynone,	Ybr,	Zloop,	1,
+	0
+};
+static uchar	ycall[] =
+{
+	Ynone,	Yml,	Zcallindreg,	0,
+	Yrx,	Yrx,	Zcallindreg,	2,
+	Ynone,	Ybr,	Zcall,	1,
+	0
+};
+static uchar	yduff[] =
+{
+	Ynone,	Yi32,	Zcall,	1,
+	0
+};
+static uchar	yjmp[] =
+{
+	Ynone,	Yml,	Zo_m64,	2,
+	Ynone,	Ybr,	Zjmp,	1,
+	0
+};
+
+static uchar	yfmvd[] =
+{
+	Ym,	Yf0,	Zm_o,	2,
+	Yf0,	Ym,	Zo_m,	2,
+	Yrf,	Yf0,	Zm_o,	2,
+	Yf0,	Yrf,	Zo_m,	2,
+	0
+};
+static uchar	yfmvdp[] =
+{
+	Yf0,	Ym,	Zo_m,	2,
+	Yf0,	Yrf,	Zo_m,	2,
+	0
+};
+static uchar	yfmvf[] =
+{
+	Ym,	Yf0,	Zm_o,	2,
+	Yf0,	Ym,	Zo_m,	2,
+	0
+};
+static uchar	yfmvx[] =
+{
+	Ym,	Yf0,	Zm_o,	2,
+	0
+};
+static uchar	yfmvp[] =
+{
+	Yf0,	Ym,	Zo_m,	2,
+	0
+};
+static uchar	yfadd[] =
+{
+	Ym,	Yf0,	Zm_o,	2,
+	Yrf,	Yf0,	Zm_o,	2,
+	Yf0,	Yrf,	Zo_m,	2,
+	0
+};
+static uchar	yfaddp[] =
+{
+	Yf0,	Yrf,	Zo_m,	2,
+	0
+};
+static uchar	yfxch[] =
+{
+	Yf0,	Yrf,	Zo_m,	2,
+	Yrf,	Yf0,	Zm_o,	2,
+	0
+};
+static uchar	ycompp[] =
+{
+	Yf0,	Yrf,	Zo_m,	2,	/* botch is really f0,f1 */
+	0
+};
+static uchar	ystsw[] =
+{
+	Ynone,	Ym,	Zo_m,	2,
+	Ynone,	Yax,	Zlit,	1,
+	0
+};
+static uchar	ystcw[] =
+{
+	Ynone,	Ym,	Zo_m,	2,
+	Ym,	Ynone,	Zm_o,	2,
+	0
+};
+static uchar	ysvrs[] =
+{
+	Ynone,	Ym,	Zo_m,	2,
+	Ym,	Ynone,	Zm_o,	2,
+	0
+};
+static uchar	ymm[] = 
+{
+	Ymm,	Ymr,	Zm_r_xm,	1,
+	Yxm,	Yxr,	Zm_r_xm,	2,
+	0
+};
+static uchar	yxm[] = 
+{
+	Yxm,	Yxr,	Zm_r_xm,	1,
+	0
+};
+static uchar	yxcvm1[] = 
+{
+	Yxm,	Yxr,	Zm_r_xm,	2,
+	Yxm,	Ymr,	Zm_r_xm,	2,
+	0
+};
+static uchar	yxcvm2[] =
+{
+	Yxm,	Yxr,	Zm_r_xm,	2,
+	Ymm,	Yxr,	Zm_r_xm,	2,
+	0
+};
+/*
+static uchar	yxmq[] = 
+{
+	Yxm,	Yxr,	Zm_r_xm,	2,
+	0
+};
+*/
+static uchar	yxr[] = 
+{
+	Yxr,	Yxr,	Zm_r_xm,	1,
+	0
+};
+static uchar	yxr_ml[] =
+{
+	Yxr,	Yml,	Zr_m_xm,	1,
+	0
+};
+static uchar	ymr[] =
+{
+	Ymr,	Ymr,	Zm_r,	1,
+	0
+};
+static uchar	ymr_ml[] =
+{
+	Ymr,	Yml,	Zr_m_xm,	1,
+	0
+};
+static uchar	yxcmp[] =
+{
+	Yxm,	Yxr, Zm_r_xm,	1,
+	0
+};
+static uchar	yxcmpi[] =
+{
+	Yxm,	Yxr, Zm_r_i_xm,	2,
+	0
+};
+static uchar	yxmov[] =
+{
+	Yxm,	Yxr,	Zm_r_xm,	1,
+	Yxr,	Yxm,	Zr_m_xm,	1,
+	0
+};
+static uchar	yxcvfl[] = 
+{
+	Yxm,	Yrl,	Zm_r_xm,	1,
+	0
+};
+static uchar	yxcvlf[] =
+{
+	Yml,	Yxr,	Zm_r_xm,	1,
+	0
+};
+static uchar	yxcvfq[] = 
+{
+	Yxm,	Yrl,	Zm_r_xm,	2,
+	0
+};
+static uchar	yxcvqf[] =
+{
+	Yml,	Yxr,	Zm_r_xm,	2,
+	0
+};
+static 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
+};
+static uchar	yxrrl[] =
+{
+	Yxr,	Yrl,	Zm_r,	1,
+	0
+};
+static uchar	ymfp[] =
+{
+	Ymm,	Ymr,	Zm_r_3d,	1,
+	0,
+};
+static uchar	ymrxr[] =
+{
+	Ymr,	Yxr,	Zm_r,	1,
+	Yxm,	Yxr,	Zm_r_xm,	1,
+	0
+};
+static uchar	ymshuf[] =
+{
+	Ymm,	Ymr,	Zibm_r,	2,
+	0
+};
+static uchar	ymshufb[] =
+{
+	Yxm,	Yxr,	Zm2_r,	2,
+	0
+};
+static uchar	yxshuf[] =
+{
+	Yxm,	Yxr,	Zibm_r,	2,
+	0
+};
+static uchar	yextrw[] =
+{
+	Yxr,	Yrl,	Zibm_r,	2,
+	0
+};
+static uchar	yinsrw[] =
+{
+	Yml,	Yxr,	Zibm_r,	2,
+	0
+};
+static uchar	yinsr[] =
+{
+	Ymm,	Yxr,	Zibm_r,	3,
+	0
+};
+static uchar	ypsdq[] =
+{
+	Yi8,	Yxr,	Zibo_m,	2,
+	0
+};
+static uchar	ymskb[] =
+{
+	Yxr,	Yrl,	Zm_r_xm,	2,
+	Ymr,	Yrl,	Zm_r_xm,	1,
+	0
+};
+static uchar	ycrc32l[] =
+{
+	Yml,	Yrl,	Zlitm_r,	0,
+};
+static uchar	yprefetch[] =
+{
+	Ym,	Ynone,	Zm_o,	2,
+	0,
+};
+static uchar	yaes[] =
+{
+	Yxm,	Yxr,	Zlitm_r,	2,
+	0
+};
+static 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 (Addr*).  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 },
+	{ ATYPE },
+	{ AFUNCDATA,	yfuncdata,	Px, 0,0 },
+	{ APCDATA,	ypcdata,	Px, 0,0 },
+	{ ACHECKNIL },
+	{ AVARDEF },
+	{ AVARKILL },
+	{ ADUFFCOPY,	yduff,	Px, 0xe8 },
+	{ ADUFFZERO,	yduff,	Px, 0xe8 },
+
+	{ AEND },
+	0
+};
+
+static Optab*	opindex[ALAST+1];
+static vlong	vaddr(Link*, Addr*, 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},
+	// Native Client rejects the repeated 0x66 prefix.
+	// {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;
+	}
+}
+
+static void instinit(void);
+
+static int32
+naclpad(Link *ctxt, LSym *s, int32 c, int32 pad)
+{
+	symgrow(ctxt, s, c+pad);
+	fillnop(s->p+c, pad);
+	return c+pad;
+}
+
+static int
+spadjop(Link *ctxt, Prog *p, int l, int q)
+{
+	if(p->mode != 64 || ctxt->arch->ptrsize == 4)
+		return l;
+	return q;
+}
+
+void
+span6(Link *ctxt, LSym *s)
+{
+	Prog *p, *q;
+	int32 c, v, loop;
+	uchar *bp;
+	int n, m, i;
+
+	ctxt->cursym = s;
+	
+	if(s->p != nil)
+		return;
+	
+	if(ycover[0] == 0)
+		instinit();
+	
+	for(p = ctxt->cursym->text; p != nil; p = p->link) {
+		n = 0;
+		if(p->to.type == D_BRANCH)
+			if(p->pcond == nil)
+				p->pcond = p;
+		if((q = p->pcond) != nil)
+			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 = spadjop(ctxt, p, AADDL, AADDQ);
+			if(v < 0) {
+				p->as = spadjop(ctxt, p, ASUBL, ASUBQ);
+				v = -v;
+				p->from.offset = v;
+			}
+			if(v == 0)
+				p->as = ANOP;
+		}
+	}
+
+	for(p = s->text; p != nil; p = p->link) {
+		p->back = 2;	// use short branches first time through
+		if((q = p->pcond) != nil && (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 = spadjop(ctxt, p, AADDL, AADDQ);
+			if(v < 0) {
+				p->as = spadjop(ctxt, p, 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 != nil; p = p->link) {
+			if(ctxt->headtype == Hnacl && p->isize > 0) {
+				static LSym *deferreturn;
+				
+				if(deferreturn == nil)
+					deferreturn = linklookup(ctxt, "runtime.deferreturn", 0);
+
+				// pad everything to avoid crossing 32-byte boundary
+				if((c>>5) != ((c+p->isize-1)>>5))
+					c = naclpad(ctxt, s, c, -c&31);
+				// pad call deferreturn to start at 32-byte boundary
+				// so that subtracting 5 in jmpdefer will jump back
+				// to that boundary and rerun the call.
+				if(p->as == ACALL && p->to.sym == deferreturn)
+					c = naclpad(ctxt, s, c, -c&31);
+				// pad call to end at 32-byte boundary
+				if(p->as == ACALL)
+					c = naclpad(ctxt, s, c, -(c+p->isize)&31);
+				
+				// the linker treats REP and STOSQ as different instructions
+				// but in fact the REP is a prefix on the STOSQ.
+				// make sure REP has room for 2 more bytes, so that
+				// padding will not be inserted before the next instruction.
+				if((p->as == AREP || p->as == AREPN) && (c>>5) != ((c+3-1)>>5))
+					c = naclpad(ctxt, s, c, -c&31);
+				
+				// same for LOCK.
+				// various instructions follow; the longest is 4 bytes.
+				// give ourselves 8 bytes so as to avoid surprises.
+				if(p->as == ALOCK && (c>>5) != ((c+8-1)>>5))
+					c = naclpad(ctxt, s, c, -c&31);
+			}
+
+			if((p->back & 4) && (c&(LoopAlign-1)) != 0) {
+				// pad with NOPs
+				v = -c&(LoopAlign-1);
+				if(v <= MaxLoopPad) {
+					symgrow(ctxt, s, c+v);
+					fillnop(s->p+c, v);
+					c += v;
+				}
+			}
+
+			p->pc = c;
+
+			// process forward jumps to p
+			for(q = p->comefrom; q != nil; 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 = nil;
+
+			p->pc = c;
+			asmins(ctxt, p);
+			m = ctxt->andptr-ctxt->and;
+			if(p->isize != m) {
+				p->isize = m;
+				loop++;
+			}
+			symgrow(ctxt, s, p->pc+m);
+			memmove(s->p+p->pc, ctxt->and, m);
+			p->mark = m;
+			c += m;
+		}
+		if(++n > 20) {
+			ctxt->diag("span must be looping");
+			sysfatal("loop");
+		}
+	} while(loop);
+	
+	if(ctxt->headtype == Hnacl)
+		c = naclpad(ctxt, s, c, -c&31);
+	
+	c += -c&(FuncAlign-1);
+	s->size = c;
+
+	if(0 /* debug['a'] > 1 */) {
+		print("span1 %s %lld (%d tries)\n %.6ux", s->name, s->size, n, 0);
+		for(i=0; i<s->np; i++) {
+			print(" %.2ux", s->p[i]);
+			if(i%16 == 15)
+				print("\n  %.6ux", i+1);
+		}
+		if(i%16)
+			print("\n");
+	
+		for(i=0; i<s->nr; i++) {
+			Reloc *r;
+			
+			r = &s->r[i];
+			print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add);
+		}
+	}
+}
+
+static void
+instinit(void)
+{
+	int c, i;
+
+	for(i=1; optab[i].as; i++) {
+		c = optab[i].as;
+		if(opindex[c] != nil)
+			sysfatal("phase error in optab: %d (%A)", i, c);
+		opindex[c] = &optab[i];
+	}
+
+	for(i=0; i<Ymax; i++)
+		ycover[i*Ymax + i] = 1;
+
+	ycover[Yi0*Ymax + Yi8] = 1;
+	ycover[Yi1*Ymax + Yi8] = 1;
+
+	ycover[Yi0*Ymax + Ys32] = 1;
+	ycover[Yi1*Ymax + Ys32] = 1;
+	ycover[Yi8*Ymax + Ys32] = 1;
+
+	ycover[Yi0*Ymax + Yi32] = 1;
+	ycover[Yi1*Ymax + Yi32] = 1;
+	ycover[Yi8*Ymax + Yi32] = 1;
+	ycover[Ys32*Ymax + Yi32] = 1;
+
+	ycover[Yi0*Ymax + Yi64] = 1;
+	ycover[Yi1*Ymax + Yi64] = 1;
+	ycover[Yi8*Ymax + Yi64] = 1;
+	ycover[Ys32*Ymax + Yi64] = 1;
+	ycover[Yi32*Ymax + Yi64] = 1;
+
+	ycover[Yal*Ymax + Yrb] = 1;
+	ycover[Ycl*Ymax + Yrb] = 1;
+	ycover[Yax*Ymax + Yrb] = 1;
+	ycover[Ycx*Ymax + Yrb] = 1;
+	ycover[Yrx*Ymax + Yrb] = 1;
+	ycover[Yrl*Ymax + Yrb] = 1;
+
+	ycover[Ycl*Ymax + Ycx] = 1;
+
+	ycover[Yax*Ymax + Yrx] = 1;
+	ycover[Ycx*Ymax + Yrx] = 1;
+
+	ycover[Yax*Ymax + Yrl] = 1;
+	ycover[Ycx*Ymax + Yrl] = 1;
+	ycover[Yrx*Ymax + Yrl] = 1;
+
+	ycover[Yf0*Ymax + Yrf] = 1;
+
+	ycover[Yal*Ymax + Ymb] = 1;
+	ycover[Ycl*Ymax + Ymb] = 1;
+	ycover[Yax*Ymax + Ymb] = 1;
+	ycover[Ycx*Ymax + Ymb] = 1;
+	ycover[Yrx*Ymax + Ymb] = 1;
+	ycover[Yrb*Ymax + Ymb] = 1;
+	ycover[Yrl*Ymax + Ymb] = 1;
+	ycover[Ym*Ymax + Ymb] = 1;
+
+	ycover[Yax*Ymax + Yml] = 1;
+	ycover[Ycx*Ymax + Yml] = 1;
+	ycover[Yrx*Ymax + Yml] = 1;
+	ycover[Yrl*Ymax + Yml] = 1;
+	ycover[Ym*Ymax + Yml] = 1;
+
+	ycover[Yax*Ymax + Ymm] = 1;
+	ycover[Ycx*Ymax + Ymm] = 1;
+	ycover[Yrx*Ymax + Ymm] = 1;
+	ycover[Yrl*Ymax + Ymm] = 1;
+	ycover[Ym*Ymax + Ymm] = 1;
+	ycover[Ymr*Ymax + Ymm] = 1;
+
+	ycover[Ym*Ymax + Yxm] = 1;
+	ycover[Yxr*Ymax + Yxm] = 1;
+
+	for(i=0; i<D_NONE; i++) {
+		reg[i] = -1;
+		if(i >= D_AL && i <= D_R15B) {
+			reg[i] = (i-D_AL) & 7;
+			if(i >= D_SPB && i <= D_DIB)
+				regrex[i] = 0x40;
+			if(i >= D_R8B && i <= D_R15B)
+				regrex[i] = Rxr | Rxx | Rxb;
+		}
+		if(i >= D_AH && i<= D_BH)
+			reg[i] = 4 + ((i-D_AH) & 7);
+		if(i >= D_AX && i <= D_R15) {
+			reg[i] = (i-D_AX) & 7;
+			if(i >= D_R8)
+				regrex[i] = Rxr | Rxx | Rxb;
+		}
+		if(i >= D_F0 && i <= D_F0+7)
+			reg[i] = (i-D_F0) & 7;
+		if(i >= D_M0 && i <= D_M0+7)
+			reg[i] = (i-D_M0) & 7;
+		if(i >= D_X0 && i <= D_X0+15) {
+			reg[i] = (i-D_X0) & 7;
+			if(i >= D_X0+8)
+				regrex[i] = Rxr | Rxx | Rxb;
+		}
+		if(i >= D_CR+8 && i <= D_CR+15)
+			regrex[i] = Rxr;
+	}
+}
+
+static int
+prefixof(Link *ctxt, Addr *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;
+	case D_INDIR+D_TLS:
+		// NOTE: Systems listed here should be only systems that
+		// support direct TLS references like 8(TLS) implemented as
+		// direct references from FS or GS. Systems that require
+		// the initial-exec model, where you load the TLS base into
+		// a register and then index from that register, do not reach
+		// this code and should not be listed.
+		switch(ctxt->headtype) {
+		default:
+			sysfatal("unknown TLS base register for %s", headstr(ctxt->headtype));
+		case Hdragonfly:
+		case Hfreebsd:
+		case Hlinux:
+		case Hnetbsd:
+		case Hopenbsd:
+		case Hplan9:
+		case Hsolaris:
+			return 0x64; // FS
+		case Hdarwin:
+			return 0x65; // GS
+		}
+	}
+	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;
+}
+
+static int
+oclass(Link *ctxt, Addr *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(ctxt->flag_shared || ctxt->headtype == Hnacl)
+						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(ctxt->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(ctxt->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_TLS:	return	Ytls;
+
+	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 == nil) {
+			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;
+}
+
+static void
+asmidx(Link *ctxt, 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(ctxt->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(ctxt->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;
+	}
+	*ctxt->andptr++ = i;
+	return;
+bad:
+	ctxt->diag("asmidx: bad address %d/%d/%d", scale, index, base);
+	*ctxt->andptr++ = 0;
+	return;
+}
+
+static void
+put4(Link *ctxt, int32 v)
+{
+	ctxt->andptr[0] = v;
+	ctxt->andptr[1] = v>>8;
+	ctxt->andptr[2] = v>>16;
+	ctxt->andptr[3] = v>>24;
+	ctxt->andptr += 4;
+}
+
+static void
+relput4(Link *ctxt, Prog *p, Addr *a)
+{
+	vlong v;
+	Reloc rel, *r;
+	
+	v = vaddr(ctxt, a, &rel);
+	if(rel.siz != 0) {
+		if(rel.siz != 4)
+			ctxt->diag("bad reloc");
+		r = addrel(ctxt->cursym);
+		*r = rel;
+		r->off = p->pc + ctxt->andptr - ctxt->and;
+	}
+	put4(ctxt, v);
+}
+
+static void
+put8(Link *ctxt, vlong v)
+{
+	ctxt->andptr[0] = v;
+	ctxt->andptr[1] = v>>8;
+	ctxt->andptr[2] = v>>16;
+	ctxt->andptr[3] = v>>24;
+	ctxt->andptr[4] = v>>32;
+	ctxt->andptr[5] = v>>40;
+	ctxt->andptr[6] = v>>48;
+	ctxt->andptr[7] = v>>56;
+	ctxt->andptr += 8;
+}
+
+/*
+static void
+relput8(Prog *p, Addr *a)
+{
+	vlong v;
+	Reloc rel, *r;
+	
+	v = vaddr(ctxt, a, &rel);
+	if(rel.siz != 0) {
+		r = addrel(ctxt->cursym);
+		*r = rel;
+		r->siz = 8;
+		r->off = p->pc + ctxt->andptr - ctxt->and;
+	}
+	put8(ctxt, v);
+}
+*/
+
+static vlong
+vaddr(Link *ctxt, Addr *a, Reloc *r)
+{
+	int t;
+	vlong v;
+	LSym *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(r == nil) {
+			ctxt->diag("need reloc for %D", a);
+			sysfatal("reloc");
+		}
+		r->siz = 4;	// TODO: 8 for external symbols
+		r->off = -1;	// caller must fill in
+		r->sym = s;
+		r->add = v;
+		v = 0;
+		if(ctxt->flag_shared || ctxt->headtype == Hnacl) {
+			if(s->type == STLSBSS) {
+				r->xadd = r->add - r->siz;
+				r->type = R_TLS;
+				r->xsym = s;
+			} else
+				r->type = R_PCREL;
+		} else
+			r->type = R_ADDR;
+		break;
+	
+	case D_INDIR+D_TLS:
+		if(r == nil) {
+			ctxt->diag("need reloc for %D", a);
+			sysfatal("reloc");
+		}
+		r->type = R_TLS_LE;
+		r->siz = 4;
+		r->off = -1;	// caller must fill in
+		r->add = v;
+		v = 0;
+		break;
+	}
+	return v;
+}
+
+static void
+asmandsz(Link *ctxt, Addr *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_TLS) {
+		if(t < D_INDIR) { 
+			switch(t) {
+			default:
+				goto bad;
+			case D_STATIC:
+			case D_EXTERN:
+				if(ctxt->flag_shared || ctxt->headtype == Hnacl)
+					goto bad;
+				t = D_NONE;
+				v = vaddr(ctxt, a, &rel);
+				break;
+			case D_AUTO:
+			case D_PARAM:
+				t = D_SP;
+				break;
+			}
+		} else
+			t -= D_INDIR;
+		ctxt->rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex;
+		if(t == D_NONE) {
+			*ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+			asmidx(ctxt, a->scale, a->index, t);
+			goto putrelv;
+		}
+		if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) {
+			*ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+			asmidx(ctxt, a->scale, a->index, t);
+			return;
+		}
+		if(v >= -128 && v < 128 && rel.siz == 0) {
+			*ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+			asmidx(ctxt, a->scale, a->index, t);
+			*ctxt->andptr++ = v;
+			return;
+		}
+		*ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+		asmidx(ctxt, a->scale, a->index, t);
+		goto putrelv;
+	}
+	if(t >= D_AL && t <= D_X0+15) {
+		if(v)
+			goto bad;
+		*ctxt->andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
+		ctxt->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(ctxt, a, &rel);
+			break;
+		case D_AUTO:
+		case D_PARAM:
+			t = D_SP;
+			break;
+		}
+		scale = 1;
+	} else
+		t -= D_INDIR;
+	if(t == D_TLS)
+		v = vaddr(ctxt, a, &rel);
+
+	ctxt->rexflag |= (regrex[t] & Rxb) | rex;
+	if(t == D_NONE || (D_CS <= t && t <= D_GS) || t == D_TLS) {
+		if((ctxt->flag_shared || ctxt->headtype == Hnacl) && t == D_NONE && (a->type == D_STATIC || a->type == D_EXTERN) || ctxt->asmode != 64) {
+			*ctxt->andptr++ = (0 << 6) | (5 << 0) | (r << 3);
+			goto putrelv;
+		}
+		/* temporary */
+		*ctxt->andptr++ = (0 <<  6) | (4 << 0) | (r << 3);	/* sib present */
+		*ctxt->andptr++ = (0 << 6) | (4 << 3) | (5 << 0);	/* DS:d32 */
+		goto putrelv;
+	}
+	if(t == D_SP || t == D_R12) {
+		if(v == 0) {
+			*ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
+			asmidx(ctxt, scale, D_NONE, t);
+			return;
+		}
+		if(v >= -128 && v < 128) {
+			*ctxt->andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3);
+			asmidx(ctxt, scale, D_NONE, t);
+			*ctxt->andptr++ = v;
+			return;
+		}
+		*ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+		asmidx(ctxt, scale, D_NONE, t);
+		goto putrelv;
+	}
+	if(t >= D_AX && t <= D_R15) {
+		if(a->index == D_TLS) {
+			memset(&rel, 0, sizeof rel);
+			rel.type = R_TLS_IE;
+			rel.siz = 4;
+			rel.sym = nil;
+			rel.add = v;
+			v = 0;
+		}
+		if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) {
+			*ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
+			return;
+		}
+		if(v >= -128 && v < 128 && rel.siz == 0) {
+			ctxt->andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
+			ctxt->andptr[1] = v;
+			ctxt->andptr += 2;
+			return;
+		}
+		*ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+		goto putrelv;
+	}
+	goto bad;
+	
+putrelv:
+	if(rel.siz != 0) {
+		Reloc *r;
+
+		if(rel.siz != 4) {
+			ctxt->diag("bad rel");
+			goto bad;
+		}
+		r = addrel(ctxt->cursym);
+		*r = rel;
+		r->off = ctxt->curp->pc + ctxt->andptr - ctxt->and;
+	}
+		
+	put4(ctxt, v);
+	return;
+
+bad:
+	ctxt->diag("asmand: bad address %D", a);
+	return;
+}
+
+static void
+asmand(Link *ctxt, Addr *a, Addr *ra)
+{
+	asmandsz(ctxt, a, reg[ra->type], regrex[ra->type], 0);
+}
+
+static void
+asmando(Link *ctxt, Addr *a, int o)
+{
+	asmandsz(ctxt, a, o, 0, 0);
+}
+
+static void
+bytereg(Addr *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
+static 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},
+
+/* load TLS base */
+	{AMOVQ,	Ytls,	Yrl,	7,	0,0,0,0},
+
+	0
+};
+
+static int
+isax(Addr *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;
+}
+
+static void
+subreg(Prog *p, int from, int to)
+{
+
+	if(0 /*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(0 /*debug['Q']*/)
+		print("%P\n", p);
+}
+
+static int
+mediaop(Link *ctxt, Optab *o, int op, int osize, int z)
+{
+	switch(op){
+	case Pm:
+	case Pe:
+	case Pf2:
+	case Pf3:
+		if(osize != 1){
+			if(op != Pm)
+				*ctxt->andptr++ = op;
+			*ctxt->andptr++ = Pm;
+			op = o->op[++z];
+			break;
+		}
+	default:
+		if(ctxt->andptr == ctxt->and || ctxt->andptr[-1] != Pm)
+			*ctxt->andptr++ = Pm;
+		break;
+	}
+	*ctxt->andptr++ = op;
+	return z;
+}
+
+static void
+doasm(Link *ctxt, Prog *p)
+{
+	Optab *o;
+	Prog *q, pp;
+	uchar *t;
+	Movtab *mo;
+	int z, op, ft, tt, xo, l, pre;
+	vlong v;
+	Reloc rel, *r;
+	Addr *a;
+	
+	ctxt->curp = p;	// TODO
+
+	o = opindex[p->as];
+	if(o == nil) {
+		ctxt->diag("asmins: missing op %P", p);
+		return;
+	}
+	
+	pre = prefixof(ctxt, &p->from);
+	if(pre)
+		*ctxt->andptr++ = pre;
+	pre = prefixof(ctxt, &p->to);
+	if(pre)
+		*ctxt->andptr++ = pre;
+
+	if(p->ft == 0)
+		p->ft = oclass(ctxt, &p->from);
+	if(p->tt == 0)
+		p->tt = oclass(ctxt, &p->to);
+
+	ft = p->ft * Ymax;
+	tt = p->tt * Ymax;
+
+	t = o->ytab;
+	if(t == 0) {
+		ctxt->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 */
+		*ctxt->andptr++ = Pe;
+		*ctxt->andptr++ = Pm;
+		break;
+	case Pq3:	/* 16 bit escape, Rex.w, and opcode escape */
+		*ctxt->andptr++ = Pe;
+		*ctxt->andptr++ = Pw;
+		*ctxt->andptr++ = Pm;
+		break;
+
+	case Pf2:	/* xmm opcode escape */
+	case Pf3:
+		*ctxt->andptr++ = o->prefix;
+		*ctxt->andptr++ = Pm;
+		break;
+
+	case Pm:	/* opcode escape */
+		*ctxt->andptr++ = Pm;
+		break;
+
+	case Pe:	/* 16 bit escape */
+		*ctxt->andptr++ = Pe;
+		break;
+
+	case Pw:	/* 64-bit escape */
+		if(p->mode != 64)
+			ctxt->diag("asmins: illegal 64: %P", p);
+		ctxt->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)
+			ctxt->diag("asmins: illegal in 64-bit mode: %P", p);
+		break;
+
+	case Py:	/* 64-bit only, no prefix */
+		if(p->mode != 64)
+			ctxt->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) {
+		*ctxt->andptr++ = op;
+		op = o->op[++z];
+	}
+	switch(t[2]) {
+	default:
+		ctxt->diag("asmins: unknown z %d %P", t[2], p);
+		return;
+
+	case Zpseudo:
+		break;
+
+	case Zlit:
+		for(; op = o->op[z]; z++)
+			*ctxt->andptr++ = op;
+		break;
+
+	case Zlitm_r:
+		for(; op = o->op[z]; z++)
+			*ctxt->andptr++ = op;
+		asmand(ctxt, &p->from, &p->to);
+		break;
+
+	case Zmb_r:
+		bytereg(&p->from, &p->ft);
+		/* fall through */
+	case Zm_r:
+		*ctxt->andptr++ = op;
+		asmand(ctxt, &p->from, &p->to);
+		break;
+	case Zm2_r:
+		*ctxt->andptr++ = op;
+		*ctxt->andptr++ = o->op[z+1];
+		asmand(ctxt, &p->from, &p->to);
+		break;
+
+	case Zm_r_xm:
+		mediaop(ctxt, o, op, t[3], z);
+		asmand(ctxt, &p->from, &p->to);
+		break;
+
+	case Zm_r_xm_nr:
+		ctxt->rexflag = 0;
+		mediaop(ctxt, o, op, t[3], z);
+		asmand(ctxt, &p->from, &p->to);
+		break;
+
+	case Zm_r_i_xm:
+		mediaop(ctxt, o, op, t[3], z);
+		asmand(ctxt, &p->from, &p->to);
+		*ctxt->andptr++ = p->to.offset;
+		break;
+
+	case Zm_r_3d:
+		*ctxt->andptr++ = 0x0f;
+		*ctxt->andptr++ = 0x0f;
+		asmand(ctxt, &p->from, &p->to);
+		*ctxt->andptr++ = op;
+		break;
+
+	case Zibm_r:
+		while ((op = o->op[z++]) != 0)
+			*ctxt->andptr++ = op;
+		asmand(ctxt, &p->from, &p->to);
+		*ctxt->andptr++ = p->to.offset;
+		break;
+
+	case Zaut_r:
+		*ctxt->andptr++ = 0x8d;	/* leal */
+		if(p->from.type != D_ADDR)
+			ctxt->diag("asmins: Zaut sb type ADDR");
+		p->from.type = p->from.index;
+		p->from.index = D_NONE;
+		asmand(ctxt, &p->from, &p->to);
+		p->from.index = p->from.type;
+		p->from.type = D_ADDR;
+		break;
+
+	case Zm_o:
+		*ctxt->andptr++ = op;
+		asmando(ctxt, &p->from, o->op[z+1]);
+		break;
+
+	case Zr_m:
+		*ctxt->andptr++ = op;
+		asmand(ctxt, &p->to, &p->from);
+		break;
+
+	case Zr_m_xm:
+		mediaop(ctxt, o, op, t[3], z);
+		asmand(ctxt, &p->to, &p->from);
+		break;
+
+	case Zr_m_xm_nr:
+		ctxt->rexflag = 0;
+		mediaop(ctxt, o, op, t[3], z);
+		asmand(ctxt, &p->to, &p->from);
+		break;
+
+	case Zr_m_i_xm:
+		mediaop(ctxt, o, op, t[3], z);
+		asmand(ctxt, &p->to, &p->from);
+		*ctxt->andptr++ = p->from.offset;
+		break;
+
+	case Zo_m:
+		*ctxt->andptr++ = op;
+		asmando(ctxt, &p->to, o->op[z+1]);
+		break;
+
+	case Zo_m64:
+	case_Zo_m64:
+		*ctxt->andptr++ = op;
+		asmandsz(ctxt, &p->to, o->op[z+1], 0, 1);
+		break;
+
+	case Zm_ibo:
+		*ctxt->andptr++ = op;
+		asmando(ctxt, &p->from, o->op[z+1]);
+		*ctxt->andptr++ = vaddr(ctxt, &p->to, nil);
+		break;
+
+	case Zibo_m:
+		*ctxt->andptr++ = op;
+		asmando(ctxt, &p->to, o->op[z+1]);
+		*ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+		break;
+
+	case Zibo_m_xm:
+		z = mediaop(ctxt, o, op, t[3], z);
+		asmando(ctxt, &p->to, o->op[z+1]);
+		*ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+		break;
+
+	case Z_ib:
+	case Zib_:
+		if(t[2] == Zib_)
+			a = &p->from;
+		else
+			a = &p->to;
+		*ctxt->andptr++ = op;
+		*ctxt->andptr++ = vaddr(ctxt, a, nil);
+		break;
+
+	case Zib_rp:
+		ctxt->rexflag |= regrex[p->to.type] & (Rxb|0x40);
+		*ctxt->andptr++ = op + reg[p->to.type];
+		*ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+		break;
+
+	case Zil_rp:
+		ctxt->rexflag |= regrex[p->to.type] & Rxb;
+		*ctxt->andptr++ = op + reg[p->to.type];
+		if(o->prefix == Pe) {
+			v = vaddr(ctxt, &p->from, nil);
+			*ctxt->andptr++ = v;
+			*ctxt->andptr++ = v>>8;
+		}
+		else
+			relput4(ctxt, p, &p->from);
+		break;
+
+	case Zo_iw:
+		*ctxt->andptr++ = op;
+		if(p->from.type != D_NONE){
+			v = vaddr(ctxt, &p->from, nil);
+			*ctxt->andptr++ = v;
+			*ctxt->andptr++ = v>>8;
+		}
+		break;
+
+	case Ziq_rp:
+		v = vaddr(ctxt, &p->from, &rel);
+		l = v>>32;
+		if(l == 0 && rel.siz != 8){
+			//p->mark |= 0100;
+			//print("zero: %llux %P\n", v, p);
+			ctxt->rexflag &= ~(0x40|Rxw);
+			ctxt->rexflag |= regrex[p->to.type] & Rxb;
+			*ctxt->andptr++ = 0xb8 + reg[p->to.type];
+			if(rel.type != 0) {
+				r = addrel(ctxt->cursym);
+				*r = rel;
+				r->off = p->pc + ctxt->andptr - ctxt->and;
+			}
+			put4(ctxt, v);
+		}else if(l == -1 && (v&((uvlong)1<<31))!=0){	/* sign extend */
+			//p->mark |= 0100;
+			//print("sign: %llux %P\n", v, p);
+			*ctxt->andptr ++ = 0xc7;
+			asmando(ctxt, &p->to, 0);
+			put4(ctxt, v);
+		}else{	/* need all 8 */
+			//print("all: %llux %P\n", v, p);
+			ctxt->rexflag |= regrex[p->to.type] & Rxb;
+			*ctxt->andptr++ = op + reg[p->to.type];
+			if(rel.type != 0) {
+				r = addrel(ctxt->cursym);
+				*r = rel;
+				r->off = p->pc + ctxt->andptr - ctxt->and;
+			}
+			put8(ctxt, v);
+		}
+		break;
+
+	case Zib_rr:
+		*ctxt->andptr++ = op;
+		asmand(ctxt, &p->to, &p->to);
+		*ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+		break;
+
+	case Z_il:
+	case Zil_:
+		if(t[2] == Zil_)
+			a = &p->from;
+		else
+			a = &p->to;
+		*ctxt->andptr++ = op;
+		if(o->prefix == Pe) {
+			v = vaddr(ctxt, a, nil);
+			*ctxt->andptr++ = v;
+			*ctxt->andptr++ = v>>8;
+		}
+		else
+			relput4(ctxt, p, a);
+		break;
+
+	case Zm_ilo:
+	case Zilo_m:
+		*ctxt->andptr++ = op;
+		if(t[2] == Zilo_m) {
+			a = &p->from;
+			asmando(ctxt, &p->to, o->op[z+1]);
+		} else {
+			a = &p->to;
+			asmando(ctxt, &p->from, o->op[z+1]);
+		}
+		if(o->prefix == Pe) {
+			v = vaddr(ctxt, a, nil);
+			*ctxt->andptr++ = v;
+			*ctxt->andptr++ = v>>8;
+		}
+		else
+			relput4(ctxt, p, a);
+		break;
+
+	case Zil_rr:
+		*ctxt->andptr++ = op;
+		asmand(ctxt, &p->to, &p->to);
+		if(o->prefix == Pe) {
+			v = vaddr(ctxt, &p->from, nil);
+			*ctxt->andptr++ = v;
+			*ctxt->andptr++ = v>>8;
+		}
+		else
+			relput4(ctxt, p, &p->from);
+		break;
+
+	case Z_rp:
+		ctxt->rexflag |= regrex[p->to.type] & (Rxb|0x40);
+		*ctxt->andptr++ = op + reg[p->to.type];
+		break;
+
+	case Zrp_:
+		ctxt->rexflag |= regrex[p->from.type] & (Rxb|0x40);
+		*ctxt->andptr++ = op + reg[p->from.type];
+		break;
+
+	case Zclr:
+		*ctxt->andptr++ = op;
+		asmand(ctxt, &p->to, &p->to);
+		break;
+
+	case Zcall:
+		if(p->to.sym == nil) {
+			ctxt->diag("call without target");
+			sysfatal("bad code");
+		}
+		*ctxt->andptr++ = op;
+		r = addrel(ctxt->cursym);
+		r->off = p->pc + ctxt->andptr - ctxt->and;
+		r->sym = p->to.sym;
+		r->add = p->to.offset;
+		r->type = R_CALL;
+		r->siz = 4;
+		put4(ctxt, 0);
+		break;
+
+	case Zcallindreg:
+		r = addrel(ctxt->cursym);
+		r->off = p->pc;
+		r->type = R_CALLIND;
+		r->siz = 0;
+		goto case_Zo_m64;
+
+	case Zbr:
+	case Zjmp:
+	case Zloop:
+		// TODO: jump across functions needs reloc
+		if(p->to.sym != nil) {
+			if(t[2] != Zjmp) {
+				ctxt->diag("branch to ATEXT");
+				sysfatal("bad code");
+			}
+			*ctxt->andptr++ = o->op[z+1];
+			r = addrel(ctxt->cursym);
+			r->off = p->pc + ctxt->andptr - ctxt->and;
+			r->sym = p->to.sym;
+			r->type = R_PCREL;
+			r->siz = 4;
+			put4(ctxt, 0);
+			break;
+		}
+		// Assumes q is in this function.
+		// TODO: Check in input, preserve in brchain.
+
+		// Fill in backward jump now.
+		q = p->pcond;
+		if(q == nil) {
+			ctxt->diag("jmp/branch/loop without target");
+			sysfatal("bad code");
+		}
+		if(p->back & 1) {
+			v = q->pc - (p->pc + 2);
+			if(v >= -128) {
+				if(p->as == AJCXZL)
+					*ctxt->andptr++ = 0x67;
+				*ctxt->andptr++ = op;
+				*ctxt->andptr++ = v;
+			} else if(t[2] == Zloop) {
+				ctxt->diag("loop too far: %P", p);
+			} else {
+				v -= 5-2;
+				if(t[2] == Zbr) {
+					*ctxt->andptr++ = 0x0f;
+					v--;
+				}
+				*ctxt->andptr++ = o->op[z+1];
+				*ctxt->andptr++ = v;
+				*ctxt->andptr++ = v>>8;
+				*ctxt->andptr++ = v>>16;
+				*ctxt->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)
+				*ctxt->andptr++ = 0x67;
+			*ctxt->andptr++ = op;
+			*ctxt->andptr++ = 0;
+		} else if(t[2] == Zloop) {
+			ctxt->diag("loop too far: %P", p);
+		} else {
+			if(t[2] == Zbr)
+				*ctxt->andptr++ = 0x0f;
+			*ctxt->andptr++ = o->op[z+1];
+			*ctxt->andptr++ = 0;
+			*ctxt->andptr++ = 0;
+			*ctxt->andptr++ = 0;
+			*ctxt->andptr++ = 0;
+		}
+		break;
+				
+/*
+		v = q->pc - p->pc - 2;
+		if((v >= -128 && v <= 127) || p->pc == -1 || q->pc == -1) {
+			*ctxt->andptr++ = op;
+			*ctxt->andptr++ = v;
+		} else {
+			v -= 5-2;
+			if(t[2] == Zbr) {
+				*ctxt->andptr++ = 0x0f;
+				v--;
+			}
+			*ctxt->andptr++ = o->op[z+1];
+			*ctxt->andptr++ = v;
+			*ctxt->andptr++ = v>>8;
+			*ctxt->andptr++ = v>>16;
+			*ctxt->andptr++ = v>>24;
+		}
+*/
+		break;
+
+	case Zbyte:
+		v = vaddr(ctxt, &p->from, &rel);
+		if(rel.siz != 0) {
+			rel.siz = op;
+			r = addrel(ctxt->cursym);
+			*r = rel;
+			r->off = p->pc + ctxt->andptr - ctxt->and;
+		}
+		*ctxt->andptr++ = v;
+		if(op > 1) {
+			*ctxt->andptr++ = v>>8;
+			if(op > 2) {
+				*ctxt->andptr++ = v>>16;
+				*ctxt->andptr++ = v>>24;
+				if(op > 4) {
+					*ctxt->andptr++ = v>>32;
+					*ctxt->andptr++ = v>>40;
+					*ctxt->andptr++ = v>>48;
+					*ctxt->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.
+				*ctxt->andptr++ = 0x87;			/* xchg lhs,bx */
+				asmando(ctxt, &p->from, reg[D_BX]);
+				subreg(&pp, z, D_BX);
+				doasm(ctxt, &pp);
+				*ctxt->andptr++ = 0x87;			/* xchg lhs,bx */
+				asmando(ctxt, &p->from, reg[D_BX]);
+			} else {
+				*ctxt->andptr++ = 0x90 + reg[z];		/* xchg lsh,ax */
+				subreg(&pp, z, D_AX);
+				doasm(ctxt, &pp);
+				*ctxt->andptr++ = 0x90 + reg[z];		/* xchg lsh,ax */
+			}
+			return;
+		}
+		z = p->to.type;
+		if(z >= D_BP && z <= D_DI) {
+			if(isax(&p->from)) {
+				*ctxt->andptr++ = 0x87;			/* xchg rhs,bx */
+				asmando(ctxt, &p->to, reg[D_BX]);
+				subreg(&pp, z, D_BX);
+				doasm(ctxt, &pp);
+				*ctxt->andptr++ = 0x87;			/* xchg rhs,bx */
+				asmando(ctxt, &p->to, reg[D_BX]);
+			} else {
+				*ctxt->andptr++ = 0x90 + reg[z];		/* xchg rsh,ax */
+				subreg(&pp, z, D_AX);
+				doasm(ctxt, &pp);
+				*ctxt->andptr++ = 0x90 + reg[z];		/* xchg rsh,ax */
+			}
+			return;
+		}
+	}
+	ctxt->diag("doasm: notfound from=%ux to=%ux %P", p->from.type, p->to.type, p);
+	return;
+
+mfound:
+	switch(mo->code) {
+	default:
+		ctxt->diag("asmins: unknown mov %d %P", mo->code, p);
+		break;
+
+	case 0:	/* lit */
+		for(z=0; t[z]!=E; z++)
+			*ctxt->andptr++ = t[z];
+		break;
+
+	case 1:	/* r,m */
+		*ctxt->andptr++ = t[0];
+		asmando(ctxt, &p->to, t[1]);
+		break;
+
+	case 2:	/* m,r */
+		*ctxt->andptr++ = t[0];
+		asmando(ctxt, &p->from, t[1]);
+		break;
+
+	case 3:	/* r,m - 2op */
+		*ctxt->andptr++ = t[0];
+		*ctxt->andptr++ = t[1];
+		asmando(ctxt, &p->to, t[2]);
+		ctxt->rexflag |= regrex[p->from.type] & (Rxr|0x40);
+		break;
+
+	case 4:	/* m,r - 2op */
+		*ctxt->andptr++ = t[0];
+		*ctxt->andptr++ = t[1];
+		asmando(ctxt, &p->from, t[2]);
+		ctxt->rexflag |= regrex[p->to.type] & (Rxr|0x40);
+		break;
+
+	case 5:	/* load full pointer, trash heap */
+		if(t[0])
+			*ctxt->andptr++ = t[0];
+		switch(p->to.index) {
+		default:
+			goto bad;
+		case D_DS:
+			*ctxt->andptr++ = 0xc5;
+			break;
+		case D_SS:
+			*ctxt->andptr++ = 0x0f;
+			*ctxt->andptr++ = 0xb2;
+			break;
+		case D_ES:
+			*ctxt->andptr++ = 0xc4;
+			break;
+		case D_FS:
+			*ctxt->andptr++ = 0x0f;
+			*ctxt->andptr++ = 0xb4;
+			break;
+		case D_GS:
+			*ctxt->andptr++ = 0x0f;
+			*ctxt->andptr++ = 0xb5;
+			break;
+		}
+		asmand(ctxt, &p->from, &p->to);
+		break;
+
+	case 6:	/* double shift */
+		if(t[0] == Pw){
+			if(p->mode != 64)
+				ctxt->diag("asmins: illegal 64: %P", p);
+			ctxt->rexflag |= Pw;
+			t++;
+		}else if(t[0] == Pe){
+			*ctxt->andptr++ = Pe;
+			t++;
+		}
+		z = p->from.type;
+		switch(z) {
+		default:
+			goto bad;
+		case D_CONST:
+			*ctxt->andptr++ = 0x0f;
+			*ctxt->andptr++ = t[0];
+			asmandsz(ctxt, &p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
+			*ctxt->andptr++ = p->from.offset;
+			break;
+		case D_CL:
+		case D_CX:
+			*ctxt->andptr++ = 0x0f;
+			*ctxt->andptr++ = t[1];
+			asmandsz(ctxt, &p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
+			break;
+		}
+		break;
+	
+	case 7:	/* mov tls, r */
+		// NOTE: The systems listed here are the ones that use the "TLS initial exec" model,
+		// where you load the TLS base register into a register and then index off that
+		// register to access the actual TLS variables. Systems that allow direct TLS access
+		// are handled in prefixof above and should not be listed here.
+		switch(ctxt->headtype) {
+		default:
+			sysfatal("unknown TLS base location for %s", headstr(ctxt->headtype));
+
+		case Hsolaris: // TODO(rsc): Delete Hsolaris from list. Should not use this code. See progedit in obj6.c.
+			// TLS base is 0(FS).
+			pp.from = p->from;
+			pp.from.type = D_INDIR+D_NONE;
+			pp.from.offset = 0;
+			pp.from.index = D_NONE;
+			pp.from.scale = 0;
+			ctxt->rexflag |= Pw;
+			*ctxt->andptr++ = 0x64; // FS
+			*ctxt->andptr++ = 0x8B;
+			asmand(ctxt, &pp.from, &p->to);
+			break;
+		
+		case Hwindows:
+			// Windows TLS base is always 0x28(GS).
+			pp.from = p->from;
+			pp.from.type = D_INDIR+D_GS;
+			pp.from.offset = 0x28;
+			pp.from.index = D_NONE;
+			pp.from.scale = 0;
+			ctxt->rexflag |= Pw;
+			*ctxt->andptr++ = 0x65; // GS
+			*ctxt->andptr++ = 0x8B;
+			asmand(ctxt, &pp.from, &p->to);
+			break;
+		}
+		break;
+	}
+}
+
+static uchar naclret[] = {
+	0x5e, // POPL SI
+	// 0x8b, 0x7d, 0x00, // MOVL (BP), DI - catch return to invalid address, for debugging
+	0x83, 0xe6, 0xe0,	// ANDL $~31, SI
+	0x4c, 0x01, 0xfe,	// ADDQ R15, SI
+	0xff, 0xe6, // JMP SI
+};
+
+static uchar naclspfix[] = {
+	0x4c, 0x01, 0xfc, // ADDQ R15, SP
+};
+
+static uchar naclbpfix[] = {
+	0x4c, 0x01, 0xfd, // ADDQ R15, BP
+};
+
+static uchar naclmovs[] = {
+	0x89, 0xf6,	// MOVL SI, SI
+	0x49, 0x8d, 0x34, 0x37,	// LEAQ (R15)(SI*1), SI
+	0x89, 0xff,	// MOVL DI, DI
+	0x49, 0x8d, 0x3c, 0x3f,	// LEAQ (R15)(DI*1), DI
+};
+
+static uchar naclstos[] = {
+	0x89, 0xff,	// MOVL DI, DI
+	0x49, 0x8d, 0x3c, 0x3f,	// LEAQ (R15)(DI*1), DI
+};
+
+static void
+nacltrunc(Link *ctxt, int reg)
+{	
+	if(reg >= D_R8)
+		*ctxt->andptr++ = 0x45;
+	reg = (reg - D_AX) & 7;
+	*ctxt->andptr++ = 0x89;
+	*ctxt->andptr++ = (3<<6) | (reg<<3) | reg;
+}
+
+static void
+asmins(Link *ctxt, Prog *p)
+{
+	int n, np, c;
+	uchar *and0;
+	Reloc *r;
+	
+	ctxt->andptr = ctxt->and;
+	ctxt->asmode = p->mode;
+	
+	if(p->as == AUSEFIELD) {
+		r = addrel(ctxt->cursym);
+		r->off = 0;
+		r->siz = 0;
+		r->sym = p->from.sym;
+		r->type = R_USEFIELD;
+		return;
+	}
+	
+	if(ctxt->headtype == Hnacl) {
+		if(p->as == AREP) {
+			ctxt->rep++;
+			return;
+		}
+		if(p->as == AREPN) {
+			ctxt->repn++;
+			return;
+		}
+		if(p->as == ALOCK) {
+			ctxt->lock++;
+			return;
+		}
+		if(p->as != ALEAQ && p->as != ALEAL) {
+			if(p->from.index != D_NONE && p->from.scale > 0)
+				nacltrunc(ctxt, p->from.index);
+			if(p->to.index != D_NONE && p->to.scale > 0)
+				nacltrunc(ctxt, p->to.index);
+		}
+		switch(p->as) {
+		case ARET:
+			memmove(ctxt->andptr, naclret, sizeof naclret);
+			ctxt->andptr += sizeof naclret;
+			return;
+		case ACALL:
+		case AJMP:
+			if(D_AX <= p->to.type && p->to.type <= D_DI) {
+				// ANDL $~31, reg
+				*ctxt->andptr++ = 0x83;
+				*ctxt->andptr++ = 0xe0 | (p->to.type - D_AX);
+				*ctxt->andptr++ = 0xe0;
+				// ADDQ R15, reg
+				*ctxt->andptr++ = 0x4c;
+				*ctxt->andptr++ = 0x01;
+				*ctxt->andptr++ = 0xf8 | (p->to.type - D_AX);
+			}
+			if(D_R8 <= p->to.type && p->to.type <= D_R15) {
+				// ANDL $~31, reg
+				*ctxt->andptr++ = 0x41;
+				*ctxt->andptr++ = 0x83;
+				*ctxt->andptr++ = 0xe0 | (p->to.type - D_R8);
+				*ctxt->andptr++ = 0xe0;
+				// ADDQ R15, reg
+				*ctxt->andptr++ = 0x4d;
+				*ctxt->andptr++ = 0x01;
+				*ctxt->andptr++ = 0xf8 | (p->to.type - D_R8);
+			}
+			break;
+		case AINT:
+			*ctxt->andptr++ = 0xf4;
+			return;
+		case ASCASB:
+		case ASCASW:
+		case ASCASL:
+		case ASCASQ:
+		case ASTOSB:
+		case ASTOSW:
+		case ASTOSL:
+		case ASTOSQ:
+			memmove(ctxt->andptr, naclstos, sizeof naclstos);
+			ctxt->andptr += sizeof naclstos;
+			break;
+		case AMOVSB:
+		case AMOVSW:
+		case AMOVSL:
+		case AMOVSQ:
+			memmove(ctxt->andptr, naclmovs, sizeof naclmovs);
+			ctxt->andptr += sizeof naclmovs;
+			break;
+		}
+		if(ctxt->rep) {
+			*ctxt->andptr++ = 0xf3;
+			ctxt->rep = 0;
+		}
+		if(ctxt->repn) {
+			*ctxt->andptr++ = 0xf2;
+			ctxt->repn = 0;
+		}
+		if(ctxt->lock) {
+			*ctxt->andptr++ = 0xf0;
+			ctxt->lock = 0;
+		}
+	}		
+
+	ctxt->rexflag = 0;
+	and0 = ctxt->andptr;
+	ctxt->asmode = p->mode;
+	doasm(ctxt, p);
+	if(ctxt->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)
+			ctxt->diag("asmins: illegal in mode %d: %P", p->mode, p);
+		n = ctxt->andptr - and0;
+		for(np = 0; np < n; np++) {
+			c = and0[np];
+			if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26)
+				break;
+		}
+		memmove(and0+np+1, and0+np, n-np);
+		and0[np] = 0x40 | ctxt->rexflag;
+		ctxt->andptr++;
+	}
+	n = ctxt->andptr - ctxt->and;
+	for(r=ctxt->cursym->r+ctxt->cursym->nr; r-- > ctxt->cursym->r; ) {
+		if(r->off < p->pc)
+			break;
+		if(ctxt->rexflag)
+			r->off++;
+		if(r->type == R_PCREL || r->type == R_CALL)
+			r->add -= p->pc + n - (r->off + r->siz);
+	}
+
+	if(ctxt->headtype == Hnacl && p->as != ACMPL && p->as != ACMPQ) {
+		switch(p->to.type) {
+		case D_SP:
+			memmove(ctxt->andptr, naclspfix, sizeof naclspfix);
+			ctxt->andptr += sizeof naclspfix;
+			break;
+		case D_BP:
+			memmove(ctxt->andptr, naclbpfix, sizeof naclbpfix);
+			ctxt->andptr += sizeof naclbpfix;
+			break;
+		}
+	}
+}
diff --git a/src/liblink/asm8.c b/src/liblink/asm8.c
new file mode 100644
index 0000000..3ab527c
--- /dev/null
+++ b/src/liblink/asm8.c
@@ -0,0 +1,2785 @@
+// 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 at 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 at 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/8l/8.out.h"
+#include "../pkg/runtime/stack.h"
+
+enum
+{
+	MaxAlign = 32,	// max data alignment
+	FuncAlign = 16
+};
+
+extern char *anames6[];
+
+typedef	struct	Optab	Optab;
+
+struct	Optab
+{
+	short	as;
+	uchar*	ytab;
+	uchar	prefix;
+	uchar	op[13];
+};
+
+enum
+{
+	Yxxx		= 0,
+	Ynone,
+	Yi0,
+	Yi1,
+	Yi8,
+	Yi32,
+	Yiauto,
+	Yal,
+	Ycl,
+	Yax,
+	Ycx,
+	Yrb,
+	Yrl,
+	Yrf,
+	Yf0,
+	Yrx,
+	Ymb,
+	Yml,
+	Ym,
+	Ybr,
+	Ycol,
+	Ytls,
+
+	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,
+	Zcallindreg,
+	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 */
+};
+
+static	uchar	ycover[Ymax*Ymax];
+static	char	reg[D_NONE];
+static	void	asmins(Link *ctxt, Prog *p);
+
+static uchar	ynone[] =
+{
+	Ynone,	Ynone,	Zlit,	1,
+	0
+};
+static uchar	ytext[] =
+{
+	Ymb,	Yi32,	Zpseudo,1,
+	0
+};
+static uchar	ynop[] =
+{
+	Ynone,	Ynone,	Zpseudo,0,
+	Ynone,	Yiauto,	Zpseudo,0,
+	Ynone,	Yml,	Zpseudo,0,
+	Ynone,	Yrf,	Zpseudo,0,
+	Yiauto,	Ynone,	Zpseudo,0,
+	Ynone,	Yxr,	Zpseudo,0,
+	Yml,	Ynone,	Zpseudo,0,
+	Yrf,	Ynone,	Zpseudo,0,
+	Yxr,	Ynone,	Zpseudo,1,
+	0
+};
+static uchar	yfuncdata[] =
+{
+	Yi32,	Ym,	Zpseudo,	0,
+	0
+};
+static uchar	ypcdata[] =
+{
+	Yi32,	Yi32,	Zpseudo,	0,
+	0,
+};
+static uchar	yxorb[] =
+{
+	Yi32,	Yal,	Zib_,	1,
+	Yi32,	Ymb,	Zibo_m,	2,
+	Yrb,	Ymb,	Zr_m,	1,
+	Ymb,	Yrb,	Zm_r,	1,
+	0
+};
+static 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
+};
+static 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
+};
+static uchar	yincb[] =
+{
+	Ynone,	Ymb,	Zo_m,	2,
+	0
+};
+static uchar	yincl[] =
+{
+	Ynone,	Yrl,	Z_rp,	1,
+	Ynone,	Yml,	Zo_m,	2,
+	0
+};
+static uchar	ycmpb[] =
+{
+	Yal,	Yi32,	Z_ib,	1,
+	Ymb,	Yi32,	Zm_ibo,	2,
+	Ymb,	Yrb,	Zm_r,	1,
+	Yrb,	Ymb,	Zr_m,	1,
+	0
+};
+static 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
+};
+static uchar	yshb[] =
+{
+	Yi1,	Ymb,	Zo_m,	2,
+	Yi32,	Ymb,	Zibo_m,	2,
+	Ycx,	Ymb,	Zo_m,	2,
+	0
+};
+static uchar	yshl[] =
+{
+	Yi1,	Yml,	Zo_m,	2,
+	Yi32,	Yml,	Zibo_m,	2,
+	Ycl,	Yml,	Zo_m,	2,
+	Ycx,	Yml,	Zo_m,	2,
+	0
+};
+static uchar	ytestb[] =
+{
+	Yi32,	Yal,	Zib_,	1,
+	Yi32,	Ymb,	Zibo_m,	2,
+	Yrb,	Ymb,	Zr_m,	1,
+	Ymb,	Yrb,	Zm_r,	1,
+	0
+};
+static uchar	ytestl[] =
+{
+	Yi32,	Yax,	Zil_,	1,
+	Yi32,	Yml,	Zilo_m,	2,
+	Yrl,	Yml,	Zr_m,	1,
+	Yml,	Yrl,	Zm_r,	1,
+	0
+};
+static uchar	ymovb[] =
+{
+	Yrb,	Ymb,	Zr_m,	1,
+	Ymb,	Yrb,	Zm_r,	1,
+	Yi32,	Yrb,	Zib_rp,	1,
+	Yi32,	Ymb,	Zibo_m,	2,
+	0
+};
+static 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
+};
+static 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
+};
+static uchar	ymovq[] =
+{
+	Yml,	Yxr,	Zm_r_xm,	2,
+	0
+};
+static uchar	ym_rl[] =
+{
+	Ym,	Yrl,	Zm_r,	1,
+	0
+};
+static uchar	yrl_m[] =
+{
+	Yrl,	Ym,	Zr_m,	1,
+	0
+};
+static uchar	ymb_rl[] =
+{
+	Ymb,	Yrl,	Zm_r,	1,
+	0
+};
+static uchar	yml_rl[] =
+{
+	Yml,	Yrl,	Zm_r,	1,
+	0
+};
+static uchar	yrb_mb[] =
+{
+	Yrb,	Ymb,	Zr_m,	1,
+	0
+};
+static uchar	yrl_ml[] =
+{
+	Yrl,	Yml,	Zr_m,	1,
+	0
+};
+static uchar	yml_mb[] =
+{
+	Yrb,	Ymb,	Zr_m,	1,
+	Ymb,	Yrb,	Zm_r,	1,
+	0
+};
+static uchar	yxchg[] =
+{
+	Yax,	Yrl,	Z_rp,	1,
+	Yrl,	Yax,	Zrp_,	1,
+	Yrl,	Yml,	Zr_m,	1,
+	Yml,	Yrl,	Zm_r,	1,
+	0
+};
+static uchar	ydivl[] =
+{
+	Yml,	Ynone,	Zm_o,	2,
+	0
+};
+static uchar	ydivb[] =
+{
+	Ymb,	Ynone,	Zm_o,	2,
+	0
+};
+static uchar	yimul[] =
+{
+	Yml,	Ynone,	Zm_o,	2,
+	Yi8,	Yrl,	Zib_rr,	1,
+	Yi32,	Yrl,	Zil_rr,	1,
+	0
+};
+static uchar	ybyte[] =
+{
+	Yi32,	Ynone,	Zbyte,	1,
+	0
+};
+static uchar	yin[] =
+{
+	Yi32,	Ynone,	Zib_,	1,
+	Ynone,	Ynone,	Zlit,	1,
+	0
+};
+static uchar	yint[] =
+{
+	Yi32,	Ynone,	Zib_,	1,
+	0
+};
+static uchar	ypushl[] =
+{
+	Yrl,	Ynone,	Zrp_,	1,
+	Ym,	Ynone,	Zm_o,	2,
+	Yi8,	Ynone,	Zib_,	1,
+	Yi32,	Ynone,	Zil_,	1,
+	0
+};
+static uchar	ypopl[] =
+{
+	Ynone,	Yrl,	Z_rp,	1,
+	Ynone,	Ym,	Zo_m,	2,
+	0
+};
+static uchar	ybswap[] =
+{
+	Ynone,	Yrl,	Z_rp,	1,
+	0,
+};
+static uchar	yscond[] =
+{
+	Ynone,	Ymb,	Zo_m,	2,
+	0
+};
+static uchar	yjcond[] =
+{
+	Ynone,	Ybr,	Zbr,	0,
+	Yi0,	Ybr,	Zbr,	0,
+	Yi1,	Ybr,	Zbr,	1,
+	0
+};
+static uchar	yloop[] =
+{
+	Ynone,	Ybr,	Zloop,	1,
+	0
+};
+static uchar	ycall[] =
+{
+	Ynone,	Yml,	Zcallindreg,	0,
+	Yrx,	Yrx,	Zcallindreg,	2,
+	Ynone,	Ycol,	Zcallind,	2,
+	Ynone,	Ybr,	Zcall,	0,
+	Ynone,	Yi32,	Zcallcon,	1,
+	0
+};
+static uchar	yduff[] =
+{
+	Ynone,	Yi32,	Zcall,	1,
+	0
+};
+static uchar	yjmp[] =
+{
+	Ynone,	Yml,	Zo_m,	2,
+	Ynone,	Ybr,	Zjmp,	0,
+	Ynone,	Yi32,	Zjmpcon,	1,
+	0
+};
+
+static uchar	yfmvd[] =
+{
+	Ym,	Yf0,	Zm_o,	2,
+	Yf0,	Ym,	Zo_m,	2,
+	Yrf,	Yf0,	Zm_o,	2,
+	Yf0,	Yrf,	Zo_m,	2,
+	0
+};
+static uchar	yfmvdp[] =
+{
+	Yf0,	Ym,	Zo_m,	2,
+	Yf0,	Yrf,	Zo_m,	2,
+	0
+};
+static uchar	yfmvf[] =
+{
+	Ym,	Yf0,	Zm_o,	2,
+	Yf0,	Ym,	Zo_m,	2,
+	0
+};
+static uchar	yfmvx[] =
+{
+	Ym,	Yf0,	Zm_o,	2,
+	0
+};
+static uchar	yfmvp[] =
+{
+	Yf0,	Ym,	Zo_m,	2,
+	0
+};
+static uchar	yfcmv[] =
+{
+	Yrf,	Yf0,	Zm_o,	2,
+	0
+};
+static uchar	yfadd[] =
+{
+	Ym,	Yf0,	Zm_o,	2,
+	Yrf,	Yf0,	Zm_o,	2,
+	Yf0,	Yrf,	Zo_m,	2,
+	0
+};
+static uchar	yfaddp[] =
+{
+	Yf0,	Yrf,	Zo_m,	2,
+	0
+};
+static uchar	yfxch[] =
+{
+	Yf0,	Yrf,	Zo_m,	2,
+	Yrf,	Yf0,	Zm_o,	2,
+	0
+};
+static uchar	ycompp[] =
+{
+	Yf0,	Yrf,	Zo_m,	2,	/* botch is really f0,f1 */
+	0
+};
+static uchar	ystsw[] =
+{
+	Ynone,	Ym,	Zo_m,	2,
+	Ynone,	Yax,	Zlit,	1,
+	0
+};
+static uchar	ystcw[] =
+{
+	Ynone,	Ym,	Zo_m,	2,
+	Ym,	Ynone,	Zm_o,	2,
+	0
+};
+static uchar	ysvrs[] =
+{
+	Ynone,	Ym,	Zo_m,	2,
+	Ym,	Ynone,	Zm_o,	2,
+	0
+};
+static uchar	ymskb[] =
+{
+	Yxr,	Yrl,	Zm_r_xm,	2,
+	Ymr,	Yrl,	Zm_r_xm,	1,
+	0
+};
+static uchar	yxm[] = 
+{
+	Yxm,	Yxr,	Zm_r_xm,	1,
+	0
+};
+static uchar	yxcvm1[] = 
+{
+	Yxm,	Yxr,	Zm_r_xm,	2,
+	Yxm,	Ymr,	Zm_r_xm,	2,
+	0
+};
+static uchar	yxcvm2[] =
+{
+	Yxm,	Yxr,	Zm_r_xm,	2,
+	Ymm,	Yxr,	Zm_r_xm,	2,
+	0
+};
+static uchar	yxmq[] = 
+{
+	Yxm,	Yxr,	Zm_r_xm,	2,
+	0
+};
+static uchar	yxr[] = 
+{
+	Yxr,	Yxr,	Zm_r_xm,	1,
+	0
+};
+static uchar	yxr_ml[] =
+{
+	Yxr,	Yml,	Zr_m_xm,	1,
+	0
+};
+static uchar	yxcmp[] =
+{
+	Yxm,	Yxr, Zm_r_xm,	1,
+	0
+};
+static uchar	yxcmpi[] =
+{
+	Yxm,	Yxr, Zm_r_i_xm,	2,
+	0
+};
+static uchar	yxmov[] =
+{
+	Yxm,	Yxr,	Zm_r_xm,	1,
+	Yxr,	Yxm,	Zr_m_xm,	1,
+	0
+};
+static uchar	yxcvfl[] = 
+{
+	Yxm,	Yrl,	Zm_r_xm,	1,
+	0
+};
+static uchar	yxcvlf[] =
+{
+	Yml,	Yxr,	Zm_r_xm,	1,
+	0
+};
+/*
+static uchar	yxcvfq[] = 
+{
+	Yxm,	Yrl,	Zm_r_xm,	2,
+	0
+};
+static uchar	yxcvqf[] =
+{
+	Yml,	Yxr,	Zm_r_xm,	2,
+	0
+};
+*/
+static uchar	yxrrl[] =
+{
+	Yxr,	Yrl,	Zm_r,	1,
+	0
+};
+static uchar	yprefetch[] =
+{
+	Ym,	Ynone,	Zm_o,	2,
+	0,
+};
+static uchar	yaes[] =
+{
+	Yxm,	Yxr,	Zlitm_r,	2,
+	0
+};
+static uchar	yinsrd[] =
+{
+	Yml,	Yxr,	Zibm_r,	2,
+	0
+};
+static uchar	ymshufb[] =
+{
+	Yxm,	Yxr,	Zm2_r,	2,
+	0
+};
+
+static 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 },
+	{ APXOR,	yxm,	Pe, 0xef },
+	{ 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 },
+	{ ACHECKNIL },
+	{ AVARDEF },
+	{ AVARKILL },
+	{ ADUFFCOPY,	yduff,	Px, 0xe8 },
+	{ ADUFFZERO,	yduff,	Px, 0xe8 },
+
+	0
+};
+
+static int32	vaddr(Link*, Addr*, 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},
+	// Native Client rejects the repeated 0x66 prefix.
+	// {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;
+	}
+}
+
+static int32
+naclpad(Link *ctxt, LSym *s, int32 c, int32 pad)
+{
+	symgrow(ctxt, s, c+pad);
+	fillnop(s->p+c, pad);
+	return c+pad;
+}
+
+static void instinit(void);
+
+void
+span8(Link *ctxt, LSym *s)
+{
+	Prog *p, *q;
+	int32 c, v, loop;
+	uchar *bp;
+	int n, m, i;
+
+	ctxt->cursym = s;
+
+	if(s->text == nil || s->text->link == nil)
+		return;
+
+	if(ycover[0] == 0)
+		instinit();
+
+	for(p = s->text; p != nil; p = p->link) {
+		n = 0;
+		if(p->to.type == D_BRANCH)
+			if(p->pcond == nil)
+				p->pcond = p;
+		if((q = p->pcond) != nil)
+			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;
+		}
+	}
+
+	for(p = s->text; p != nil; p = p->link) {
+		p->back = 2;	// use short branches first time through
+		if((q = p->pcond) != nil && (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 != nil; p = p->link) {
+			if(ctxt->headtype == Hnacl && p->isize > 0) {
+				static LSym *deferreturn;
+				
+				if(deferreturn == nil)
+					deferreturn = linklookup(ctxt, "runtime.deferreturn", 0);
+
+				// pad everything to avoid crossing 32-byte boundary
+				if((c>>5) != ((c+p->isize-1)>>5))
+					c = naclpad(ctxt, s, c, -c&31);
+				// pad call deferreturn to start at 32-byte boundary
+				// so that subtracting 5 in jmpdefer will jump back
+				// to that boundary and rerun the call.
+				if(p->as == ACALL && p->to.sym == deferreturn)
+					c = naclpad(ctxt, s, c, -c&31);
+				// pad call to end at 32-byte boundary
+				if(p->as == ACALL)
+					c = naclpad(ctxt, s, c, -(c+p->isize)&31);
+				
+				// the linker treats REP and STOSQ as different instructions
+				// but in fact the REP is a prefix on the STOSQ.
+				// make sure REP has room for 2 more bytes, so that
+				// padding will not be inserted before the next instruction.
+				if(p->as == AREP && (c>>5) != ((c+3-1)>>5))
+					c = naclpad(ctxt, s, c, -c&31);
+				
+				// same for LOCK.
+				// various instructions follow; the longest is 4 bytes.
+				// give ourselves 8 bytes so as to avoid surprises.
+				if(p->as == ALOCK && (c>>5) != ((c+8-1)>>5))
+					c = naclpad(ctxt, s, c, -c&31);
+			}
+			
+			p->pc = c;
+
+			// process forward jumps to p
+			for(q = p->comefrom; q != nil; 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 = nil;
+
+			p->pc = c;
+			asmins(ctxt, p);
+			m = ctxt->andptr-ctxt->and;
+			if(p->isize != m) {
+				p->isize = m;
+				loop++;
+			}
+			symgrow(ctxt, s, p->pc+m);
+			memmove(s->p+p->pc, ctxt->and, m);
+			p->mark = m;
+			c += m;
+		}
+		if(++n > 20) {
+			ctxt->diag("span must be looping");
+			sysfatal("bad code");
+		}
+	} while(loop);
+	
+	if(ctxt->headtype == Hnacl)
+		c = naclpad(ctxt, s, c, -c&31);
+	c += -c&(FuncAlign-1);
+	s->size = c;
+
+	if(0 /* debug['a'] > 1 */) {
+		print("span1 %s %lld (%d tries)\n %.6ux", s->name, s->size, n, 0);
+		for(i=0; i<s->np; i++) {
+			print(" %.2ux", s->p[i]);
+			if(i%16 == 15)
+				print("\n  %.6ux", i+1);
+		}
+		if(i%16)
+			print("\n");
+	
+		for(i=0; i<s->nr; i++) {
+			Reloc *r;
+			
+			r = &s->r[i];
+			print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add);
+		}
+	}
+}
+
+static void
+instinit(void)
+{
+	int i;
+
+	for(i=1; optab[i].as; i++)
+		if(i != optab[i].as)
+			sysfatal("phase error in optab: at %A found %A", i, optab[i].as);
+
+	for(i=0; i<Ymax; i++)
+		ycover[i*Ymax + i] = 1;
+
+	ycover[Yi0*Ymax + Yi8] = 1;
+	ycover[Yi1*Ymax + Yi8] = 1;
+
+	ycover[Yi0*Ymax + Yi32] = 1;
+	ycover[Yi1*Ymax + Yi32] = 1;
+	ycover[Yi8*Ymax + Yi32] = 1;
+
+	ycover[Yal*Ymax + Yrb] = 1;
+	ycover[Ycl*Ymax + Yrb] = 1;
+	ycover[Yax*Ymax + Yrb] = 1;
+	ycover[Ycx*Ymax + Yrb] = 1;
+	ycover[Yrx*Ymax + Yrb] = 1;
+
+	ycover[Yax*Ymax + Yrx] = 1;
+	ycover[Ycx*Ymax + Yrx] = 1;
+
+	ycover[Yax*Ymax + Yrl] = 1;
+	ycover[Ycx*Ymax + Yrl] = 1;
+	ycover[Yrx*Ymax + Yrl] = 1;
+
+	ycover[Yf0*Ymax + Yrf] = 1;
+
+	ycover[Yal*Ymax + Ymb] = 1;
+	ycover[Ycl*Ymax + Ymb] = 1;
+	ycover[Yax*Ymax + Ymb] = 1;
+	ycover[Ycx*Ymax + Ymb] = 1;
+	ycover[Yrx*Ymax + Ymb] = 1;
+	ycover[Yrb*Ymax + Ymb] = 1;
+	ycover[Ym*Ymax + Ymb] = 1;
+
+	ycover[Yax*Ymax + Yml] = 1;
+	ycover[Ycx*Ymax + Yml] = 1;
+	ycover[Yrx*Ymax + Yml] = 1;
+	ycover[Yrl*Ymax + Yml] = 1;
+	ycover[Ym*Ymax + Yml] = 1;
+
+	ycover[Yax*Ymax + Ymm] = 1;
+	ycover[Ycx*Ymax + Ymm] = 1;
+	ycover[Yrx*Ymax + Ymm] = 1;
+	ycover[Yrl*Ymax + Ymm] = 1;
+	ycover[Ym*Ymax + Ymm] = 1;
+	ycover[Ymr*Ymax + Ymm] = 1;
+
+	ycover[Ym*Ymax + Yxm] = 1;
+	ycover[Yxr*Ymax + Yxm] = 1;
+
+	for(i=0; i<D_NONE; i++) {
+		reg[i] = -1;
+		if(i >= D_AL && i <= D_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;
+	}
+}
+
+static int
+prefixof(Link *ctxt, Addr *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;
+	case D_INDIR+D_TLS:
+		// NOTE: Systems listed here should be only systems that
+		// support direct TLS references like 8(TLS) implemented as
+		// direct references from FS or GS. Systems that require
+		// the initial-exec model, where you load the TLS base into
+		// a register and then index from that register, do not reach
+		// this code and should not be listed.
+		switch(ctxt->headtype) {
+		default:
+			sysfatal("unknown TLS base register for %s", headstr(ctxt->headtype));
+		case Hdarwin:
+		case Hdragonfly:
+		case Hfreebsd:
+		case Hnetbsd:
+		case Hopenbsd:
+			return 0x65; // GS
+		}
+	}
+	return 0;
+}
+
+static int
+oclass(Addr *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_TLS:	return	Ytls;
+
+	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 == nil) {
+			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;
+}
+
+static void
+asmidx(Link *ctxt, 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;
+	}
+	*ctxt->andptr++ = i;
+	return;
+bad:
+	ctxt->diag("asmidx: bad address %d,%d,%d", scale, index, base);
+	*ctxt->andptr++ = 0;
+	return;
+}
+
+static void
+put4(Link *ctxt, int32 v)
+{
+	ctxt->andptr[0] = v;
+	ctxt->andptr[1] = v>>8;
+	ctxt->andptr[2] = v>>16;
+	ctxt->andptr[3] = v>>24;
+	ctxt->andptr += 4;
+}
+
+static void
+relput4(Link *ctxt, Prog *p, Addr *a)
+{
+	vlong v;
+	Reloc rel, *r;
+	
+	v = vaddr(ctxt, a, &rel);
+	if(rel.siz != 0) {
+		if(rel.siz != 4)
+			ctxt->diag("bad reloc");
+		r = addrel(ctxt->cursym);
+		*r = rel;
+		r->off = p->pc + ctxt->andptr - ctxt->and;
+	}
+	put4(ctxt, v);
+}
+
+static int32
+vaddr(Link *ctxt, Addr *a, Reloc *r)
+{
+	int t;
+	int32 v;
+	LSym *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(r == nil) {
+				ctxt->diag("need reloc for %D", a);
+				sysfatal("bad code");
+			}
+			r->type = R_ADDR;
+			r->siz = 4;
+			r->off = -1;
+			r->sym = s;
+			r->add = v;
+			v = 0;
+		}
+		break;
+	
+	case D_INDIR+D_TLS:
+		if(r == nil) {
+			ctxt->diag("need reloc for %D", a);
+			sysfatal("bad code");
+		}
+		r->type = R_TLS_LE;
+		r->siz = 4;
+		r->off = -1; // caller must fill in
+		r->add = v;
+		v = 0;
+		break;
+	}
+	return v;
+}
+
+static void
+asmand(Link *ctxt, Addr *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_TLS) {
+		if(t < D_INDIR || t >= 2*D_INDIR) {
+			switch(t) {
+			default:
+				goto bad;
+			case D_STATIC:
+			case D_EXTERN:
+				t = D_NONE;
+				v = vaddr(ctxt, a, &rel);
+				break;
+			case D_AUTO:
+			case D_PARAM:
+				t = D_SP;
+				break;
+			}
+		} else
+			t -= D_INDIR;
+
+		if(t == D_NONE) {
+			*ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+			asmidx(ctxt, a->scale, a->index, t);
+			goto putrelv;
+		}
+		if(v == 0 && rel.siz == 0 && t != D_BP) {
+			*ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+			asmidx(ctxt, a->scale, a->index, t);
+			return;
+		}
+		if(v >= -128 && v < 128 && rel.siz == 0) {
+			*ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+			asmidx(ctxt, a->scale, a->index, t);
+			*ctxt->andptr++ = v;
+			return;
+		}
+		*ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+		asmidx(ctxt, a->scale, a->index, t);
+		goto putrelv;
+	}
+	if(t >= D_AL && t <= D_F7 || t >= D_X0 && t <= D_X7) {
+		if(v)
+			goto bad;
+		*ctxt->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(ctxt, a, &rel);
+			break;
+		case D_AUTO:
+		case D_PARAM:
+			t = D_SP;
+			break;
+		}
+		scale = 1;
+	} else
+		t -= D_INDIR;
+	if(t == D_TLS)
+		v = vaddr(ctxt, a, &rel);
+
+	if(t == D_NONE || (D_CS <= t && t <= D_GS) || t == D_TLS) {
+		*ctxt->andptr++ = (0 << 6) | (5 << 0) | (r << 3);
+		goto putrelv;
+	}
+	if(t == D_SP) {
+		if(v == 0 && rel.siz == 0) {
+			*ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+			asmidx(ctxt, scale, D_NONE, t);
+			return;
+		}
+		if(v >= -128 && v < 128 && rel.siz == 0) {
+			*ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+			asmidx(ctxt, scale, D_NONE, t);
+			*ctxt->andptr++ = v;
+			return;
+		}
+		*ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+		asmidx(ctxt, scale, D_NONE, t);
+		goto putrelv;
+	}
+	if(t >= D_AX && t <= D_DI) {
+		if(a->index == D_TLS) {
+			memset(&rel, 0, sizeof rel);
+			rel.type = R_TLS_IE;
+			rel.siz = 4;
+			rel.sym = nil;
+			rel.add = v;
+			v = 0;
+		}
+		if(v == 0 && rel.siz == 0 && t != D_BP) {
+			*ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
+			return;
+		}
+		if(v >= -128 && v < 128 && rel.siz == 0)  {
+			ctxt->andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
+			ctxt->andptr[1] = v;
+			ctxt->andptr += 2;
+			return;
+		}
+		*ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+		goto putrelv;
+	}
+	goto bad;
+
+putrelv:
+	if(rel.siz != 0) {
+		Reloc *r;
+		
+		if(rel.siz != 4) {
+			ctxt->diag("bad rel");
+			goto bad;
+		}
+		r = addrel(ctxt->cursym);
+		*r = rel;
+		r->off = ctxt->curp->pc + ctxt->andptr - ctxt->and;
+	}
+
+	put4(ctxt, v);
+	return;
+
+bad:
+	ctxt->diag("asmand: bad address %D", a);
+	return;
+}
+
+#define	E	0xff
+static 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,
+
+/* load TLS base pointer */
+	AMOVL,	Ytls,	Yrl,	8,	0,0,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.
+static int
+byteswapreg(Link *ctxt, Addr *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;
+
+	ctxt->diag("impossible byte register");
+	sysfatal("bad code");
+	return 0;
+}
+
+static void
+subreg(Prog *p, int from, int to)
+{
+
+	if(0 /* 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(0 /* debug['Q'] */)
+		print("%P\n", p);
+}
+
+static int
+mediaop(Link *ctxt, Optab *o, int op, int osize, int z)
+{
+	switch(op){
+	case Pm:
+	case Pe:
+	case Pf2:
+	case Pf3:
+		if(osize != 1){
+			if(op != Pm)
+				*ctxt->andptr++ = op;
+			*ctxt->andptr++ = Pm;
+			op = o->op[++z];
+			break;
+		}
+	default:
+		if(ctxt->andptr == ctxt->and || ctxt->andptr[-1] != Pm)
+			*ctxt->andptr++ = Pm;
+		break;
+	}
+	*ctxt->andptr++ = op;
+	return z;
+}
+
+static void
+doasm(Link *ctxt, Prog *p)
+{
+	Optab *o;
+	Prog *q, pp;
+	uchar *t;
+	int z, op, ft, tt, breg;
+	int32 v, pre;
+	Reloc rel, *r;
+	Addr *a;
+	
+	ctxt->curp = p;	// TODO
+
+	pre = prefixof(ctxt, &p->from);
+	if(pre)
+		*ctxt->andptr++ = pre;
+	pre = prefixof(ctxt, &p->to);
+	if(pre)
+		*ctxt->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) {
+		ctxt->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 */
+		*ctxt->andptr++ = Pe;
+		*ctxt->andptr++ = Pm;
+		break;
+
+	case Pf2:	/* xmm opcode escape */
+	case Pf3:
+		*ctxt->andptr++ = o->prefix;
+		*ctxt->andptr++ = Pm;
+		break;
+
+	case Pm:	/* opcode escape */
+		*ctxt->andptr++ = Pm;
+		break;
+
+	case Pe:	/* 16 bit escape */
+		*ctxt->andptr++ = Pe;
+		break;
+
+	case Pb:	/* botch */
+		break;
+	}
+
+	op = o->op[z];
+	switch(t[2]) {
+	default:
+		ctxt->diag("asmins: unknown z %d %P", t[2], p);
+		return;
+
+	case Zpseudo:
+		break;
+
+	case Zlit:
+		for(; op = o->op[z]; z++)
+			*ctxt->andptr++ = op;
+		break;
+
+	case Zlitm_r:
+		for(; op = o->op[z]; z++)
+			*ctxt->andptr++ = op;
+		asmand(ctxt, &p->from, reg[p->to.type]);
+		break;
+
+	case Zm_r:
+		*ctxt->andptr++ = op;
+		asmand(ctxt, &p->from, reg[p->to.type]);
+		break;
+
+	case Zm2_r:
+		*ctxt->andptr++ = op;
+		*ctxt->andptr++ = o->op[z+1];
+		asmand(ctxt, &p->from, reg[p->to.type]);
+		break;
+
+	case Zm_r_xm:
+		mediaop(ctxt, o, op, t[3], z);
+		asmand(ctxt, &p->from, reg[p->to.type]);
+		break;
+
+	case Zm_r_i_xm:
+		mediaop(ctxt, o, op, t[3], z);
+		asmand(ctxt, &p->from, reg[p->to.type]);
+		*ctxt->andptr++ = p->to.offset;
+		break;
+
+	case Zibm_r:
+		while ((op = o->op[z++]) != 0)
+			*ctxt->andptr++ = op;
+		asmand(ctxt, &p->from, reg[p->to.type]);
+		*ctxt->andptr++ = p->to.offset;
+		break;
+
+	case Zaut_r:
+		*ctxt->andptr++ = 0x8d;	/* leal */
+		if(p->from.type != D_ADDR)
+			ctxt->diag("asmins: Zaut sb type ADDR");
+		p->from.type = p->from.index;
+		p->from.index = D_NONE;
+		p->ft = 0;
+		asmand(ctxt, &p->from, reg[p->to.type]);
+		p->from.index = p->from.type;
+		p->from.type = D_ADDR;
+		p->ft = 0;
+		break;
+
+	case Zm_o:
+		*ctxt->andptr++ = op;
+		asmand(ctxt, &p->from, o->op[z+1]);
+		break;
+
+	case Zr_m:
+		*ctxt->andptr++ = op;
+		asmand(ctxt, &p->to, reg[p->from.type]);
+		break;
+
+	case Zr_m_xm:
+		mediaop(ctxt, o, op, t[3], z);
+		asmand(ctxt, &p->to, reg[p->from.type]);
+		break;
+
+	case Zr_m_i_xm:
+		mediaop(ctxt, o, op, t[3], z);
+		asmand(ctxt, &p->to, reg[p->from.type]);
+		*ctxt->andptr++ = p->from.offset;
+		break;
+
+	case Zo_m:
+	case_Zo_m:
+		*ctxt->andptr++ = op;
+		asmand(ctxt, &p->to, o->op[z+1]);
+		break;
+
+	case Zm_ibo:
+		*ctxt->andptr++ = op;
+		asmand(ctxt, &p->from, o->op[z+1]);
+		*ctxt->andptr++ = vaddr(ctxt, &p->to, nil);
+		break;
+
+	case Zibo_m:
+		*ctxt->andptr++ = op;
+		asmand(ctxt, &p->to, o->op[z+1]);
+		*ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+		break;
+
+	case Z_ib:
+	case Zib_:
+		if(t[2] == Zib_)
+			a = &p->from;
+		else
+			a = &p->to;
+		v = vaddr(ctxt, a, nil);
+		*ctxt->andptr++ = op;
+		*ctxt->andptr++ = v;
+		break;
+
+	case Zib_rp:
+		*ctxt->andptr++ = op + reg[p->to.type];
+		*ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+		break;
+
+	case Zil_rp:
+		*ctxt->andptr++ = op + reg[p->to.type];
+		if(o->prefix == Pe) {
+			v = vaddr(ctxt, &p->from, nil);
+			*ctxt->andptr++ = v;
+			*ctxt->andptr++ = v>>8;
+		}
+		else
+			relput4(ctxt, p, &p->from);
+		break;
+
+	case Zib_rr:
+		*ctxt->andptr++ = op;
+		asmand(ctxt, &p->to, reg[p->to.type]);
+		*ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
+		break;
+
+	case Z_il:
+	case Zil_:
+		if(t[2] == Zil_)
+			a = &p->from;
+		else
+			a = &p->to;
+		*ctxt->andptr++ = op;
+		if(o->prefix == Pe) {
+			v = vaddr(ctxt, a, nil);
+			*ctxt->andptr++ = v;
+			*ctxt->andptr++ = v>>8;
+		}
+		else
+			relput4(ctxt, p, a);
+		break;
+
+	case Zm_ilo:
+	case Zilo_m:
+		*ctxt->andptr++ = op;
+		if(t[2] == Zilo_m) {
+			a = &p->from;
+			asmand(ctxt, &p->to, o->op[z+1]);
+		} else {
+			a = &p->to;
+			asmand(ctxt, &p->from, o->op[z+1]);
+		}
+		if(o->prefix == Pe) {
+			v = vaddr(ctxt, a, nil);
+			*ctxt->andptr++ = v;
+			*ctxt->andptr++ = v>>8;
+		}
+		else
+			relput4(ctxt, p, a);
+		break;
+
+	case Zil_rr:
+		*ctxt->andptr++ = op;
+		asmand(ctxt, &p->to, reg[p->to.type]);
+		if(o->prefix == Pe) {
+			v = vaddr(ctxt, &p->from, nil);
+			*ctxt->andptr++ = v;
+			*ctxt->andptr++ = v>>8;
+		}
+		else
+			relput4(ctxt, p, &p->from);
+		break;
+
+	case Z_rp:
+		*ctxt->andptr++ = op + reg[p->to.type];
+		break;
+
+	case Zrp_:
+		*ctxt->andptr++ = op + reg[p->from.type];
+		break;
+
+	case Zclr:
+		*ctxt->andptr++ = op;
+		asmand(ctxt, &p->to, reg[p->to.type]);
+		break;
+	
+	case Zcall:
+		if(p->to.sym == nil) {
+			ctxt->diag("call without target");
+			sysfatal("bad code");
+		}
+		*ctxt->andptr++ = op;
+		r = addrel(ctxt->cursym);
+		r->off = p->pc + ctxt->andptr - ctxt->and;
+		r->type = R_CALL;
+		r->siz = 4;
+		r->sym = p->to.sym;
+		r->add = p->to.offset;
+		put4(ctxt, 0);
+		break;
+
+	case Zbr:
+	case Zjmp:
+	case Zloop:
+		if(p->to.sym != nil) {
+			if(t[2] != Zjmp) {
+				ctxt->diag("branch to ATEXT");
+				sysfatal("bad code");
+			}
+			*ctxt->andptr++ = o->op[z+1];
+			r = addrel(ctxt->cursym);
+			r->off = p->pc + ctxt->andptr - ctxt->and;
+			r->sym = p->to.sym;
+			r->type = R_PCREL;
+			r->siz = 4;
+			put4(ctxt, 0);
+			break;
+		}
+
+		// Assumes q is in this function.
+		// Fill in backward jump now.
+		q = p->pcond;
+		if(q == nil) {
+			ctxt->diag("jmp/branch/loop without target");
+			sysfatal("bad code");
+		}
+		if(p->back & 1) {
+			v = q->pc - (p->pc + 2);
+			if(v >= -128) {
+				if(p->as == AJCXZW)
+					*ctxt->andptr++ = 0x67;
+				*ctxt->andptr++ = op;
+				*ctxt->andptr++ = v;
+			} else if(t[2] == Zloop) {
+				ctxt->diag("loop too far: %P", p);
+			} else {
+				v -= 5-2;
+				if(t[2] == Zbr) {
+					*ctxt->andptr++ = 0x0f;
+					v--;
+				}
+				*ctxt->andptr++ = o->op[z+1];
+				*ctxt->andptr++ = v;
+				*ctxt->andptr++ = v>>8;
+				*ctxt->andptr++ = v>>16;
+				*ctxt->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)
+				*ctxt->andptr++ = 0x67;
+			*ctxt->andptr++ = op;
+			*ctxt->andptr++ = 0;
+		} else if(t[2] == Zloop) {
+			ctxt->diag("loop too far: %P", p);
+		} else {
+			if(t[2] == Zbr)
+				*ctxt->andptr++ = 0x0f;
+			*ctxt->andptr++ = o->op[z+1];
+			*ctxt->andptr++ = 0;
+			*ctxt->andptr++ = 0;
+			*ctxt->andptr++ = 0;
+			*ctxt->andptr++ = 0;
+		}
+		break;
+
+	case Zcallcon:
+	case Zjmpcon:
+		if(t[2] == Zcallcon)
+			*ctxt->andptr++ = op;
+		else
+			*ctxt->andptr++ = o->op[z+1];
+		r = addrel(ctxt->cursym);
+		r->off = p->pc + ctxt->andptr - ctxt->and;
+		r->type = R_PCREL;
+		r->siz = 4;
+		r->add = p->to.offset;
+		put4(ctxt, 0);
+		break;
+	
+	case Zcallind:
+		*ctxt->andptr++ = op;
+		*ctxt->andptr++ = o->op[z+1];
+		r = addrel(ctxt->cursym);
+		r->off = p->pc + ctxt->andptr - ctxt->and;
+		r->type = R_ADDR;
+		r->siz = 4;
+		r->add = p->to.offset;
+		r->sym = p->to.sym;
+		put4(ctxt, 0);
+		break;
+
+	case Zcallindreg:
+		r = addrel(ctxt->cursym);
+		r->off = p->pc;
+		r->type = R_CALLIND;
+		r->siz = 0;
+		goto case_Zo_m;
+
+	case Zbyte:
+		v = vaddr(ctxt, &p->from, &rel);
+		if(rel.siz != 0) {
+			rel.siz = op;
+			r = addrel(ctxt->cursym);
+			*r = rel;
+			r->off = p->pc + ctxt->andptr - ctxt->and;
+		}
+		*ctxt->andptr++ = v;
+		if(op > 1) {
+			*ctxt->andptr++ = v>>8;
+			if(op > 2) {
+				*ctxt->andptr++ = v>>16;
+				*ctxt->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(ctxt, &p->to)) != D_AX) {
+			*ctxt->andptr++ = 0x87;			/* xchg lhs,bx */
+			asmand(ctxt, &p->from, reg[breg]);
+			subreg(&pp, z, breg);
+			doasm(ctxt, &pp);
+			*ctxt->andptr++ = 0x87;			/* xchg lhs,bx */
+			asmand(ctxt, &p->from, reg[breg]);
+		} else {
+			*ctxt->andptr++ = 0x90 + reg[z];		/* xchg lsh,ax */
+			subreg(&pp, z, D_AX);
+			doasm(ctxt, &pp);
+			*ctxt->andptr++ = 0x90 + reg[z];		/* xchg lsh,ax */
+		}
+		return;
+	}
+	z = p->to.type;
+	if(z >= D_BP && z <= D_DI) {
+		if((breg = byteswapreg(ctxt, &p->from)) != D_AX) {
+			*ctxt->andptr++ = 0x87;			/* xchg rhs,bx */
+			asmand(ctxt, &p->to, reg[breg]);
+			subreg(&pp, z, breg);
+			doasm(ctxt, &pp);
+			*ctxt->andptr++ = 0x87;			/* xchg rhs,bx */
+			asmand(ctxt, &p->to, reg[breg]);
+		} else {
+			*ctxt->andptr++ = 0x90 + reg[z];		/* xchg rsh,ax */
+			subreg(&pp, z, D_AX);
+			doasm(ctxt, &pp);
+			*ctxt->andptr++ = 0x90 + reg[z];		/* xchg rsh,ax */
+		}
+		return;
+	}
+	ctxt->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:
+		ctxt->diag("asmins: unknown mov %d %P", t[3], p);
+		break;
+
+	case 0:	/* lit */
+		for(z=4; t[z]!=E; z++)
+			*ctxt->andptr++ = t[z];
+		break;
+
+	case 1:	/* r,m */
+		*ctxt->andptr++ = t[4];
+		asmand(ctxt, &p->to, t[5]);
+		break;
+
+	case 2:	/* m,r */
+		*ctxt->andptr++ = t[4];
+		asmand(ctxt, &p->from, t[5]);
+		break;
+
+	case 3:	/* r,m - 2op */
+		*ctxt->andptr++ = t[4];
+		*ctxt->andptr++ = t[5];
+		asmand(ctxt, &p->to, t[6]);
+		break;
+
+	case 4:	/* m,r - 2op */
+		*ctxt->andptr++ = t[4];
+		*ctxt->andptr++ = t[5];
+		asmand(ctxt, &p->from, t[6]);
+		break;
+
+	case 5:	/* load full pointer, trash heap */
+		if(t[4])
+			*ctxt->andptr++ = t[4];
+		switch(p->to.index) {
+		default:
+			goto bad;
+		case D_DS:
+			*ctxt->andptr++ = 0xc5;
+			break;
+		case D_SS:
+			*ctxt->andptr++ = 0x0f;
+			*ctxt->andptr++ = 0xb2;
+			break;
+		case D_ES:
+			*ctxt->andptr++ = 0xc4;
+			break;
+		case D_FS:
+			*ctxt->andptr++ = 0x0f;
+			*ctxt->andptr++ = 0xb4;
+			break;
+		case D_GS:
+			*ctxt->andptr++ = 0x0f;
+			*ctxt->andptr++ = 0xb5;
+			break;
+		}
+		asmand(ctxt, &p->from, reg[p->to.type]);
+		break;
+
+	case 6:	/* double shift */
+		z = p->from.type;
+		switch(z) {
+		default:
+			goto bad;
+		case D_CONST:
+			*ctxt->andptr++ = 0x0f;
+			*ctxt->andptr++ = t[4];
+			asmand(ctxt, &p->to, reg[p->from.index]);
+			*ctxt->andptr++ = p->from.offset;
+			break;
+		case D_CL:
+		case D_CX:
+			*ctxt->andptr++ = 0x0f;
+			*ctxt->andptr++ = t[5];
+			asmand(ctxt, &p->to, reg[p->from.index]);
+			break;
+		}
+		break;
+
+	case 7: /* imul rm,r */
+		if(t[4] == Pq) {
+			*ctxt->andptr++ = Pe;
+			*ctxt->andptr++ = Pm;
+		} else
+			*ctxt->andptr++ = t[4];
+		*ctxt->andptr++ = t[5];
+		asmand(ctxt, &p->from, reg[p->to.type]);
+		break;
+	
+	case 8: /* mov tls, r */
+		// NOTE: The systems listed here are the ones that use the "TLS initial exec" model,
+		// where you load the TLS base register into a register and then index off that
+		// register to access the actual TLS variables. Systems that allow direct TLS access
+		// are handled in prefixof above and should not be listed here.
+		switch(ctxt->headtype) {
+		default:
+			sysfatal("unknown TLS base location for %s", headstr(ctxt->headtype));
+
+		case Hlinux:
+		case Hnacl:
+			// ELF TLS base is 0(GS).
+			pp.from = p->from;
+			pp.from.type = D_INDIR+D_GS;
+			pp.from.offset = 0;
+			pp.from.index = D_NONE;
+			pp.from.scale = 0;
+			*ctxt->andptr++ = 0x65; // GS
+			*ctxt->andptr++ = 0x8B;
+			asmand(ctxt, &pp.from, reg[p->to.type]);
+			break;
+		
+		case Hplan9:
+			if(ctxt->plan9tos == nil)
+				ctxt->plan9tos = linklookup(ctxt, "_tos", 0);
+			memset(&pp.from, 0, sizeof pp.from);
+			pp.from.type = D_EXTERN;
+			pp.from.sym = ctxt->plan9tos;
+			pp.from.offset = 0;
+			pp.from.index = D_NONE;
+			*ctxt->andptr++ = 0x8B;
+			asmand(ctxt, &pp.from, reg[p->to.type]);
+			break;
+
+		case Hwindows:
+			// Windows TLS base is always 0x14(FS).
+			pp.from = p->from;
+			pp.from.type = D_INDIR+D_FS;
+			pp.from.offset = 0x14;
+			pp.from.index = D_NONE;
+			pp.from.scale = 0;
+			*ctxt->andptr++ = 0x64; // FS
+			*ctxt->andptr++ = 0x8B;
+			asmand(ctxt, &pp.from, reg[p->to.type]);
+			break;
+		}
+		break;
+	}
+}
+
+static uchar naclret[] = {
+	0x5d, // POPL BP
+	// 0x8b, 0x7d, 0x00, // MOVL (BP), DI - catch return to invalid address, for debugging
+	0x83, 0xe5, 0xe0,	// ANDL $~31, BP
+	0xff, 0xe5, // JMP BP
+};
+
+static void
+asmins(Link *ctxt, Prog *p)
+{
+	Reloc *r;
+
+	ctxt->andptr = ctxt->and;
+	
+	if(p->as == AUSEFIELD) {
+		r = addrel(ctxt->cursym);
+		r->off = 0;
+		r->sym = p->from.sym;
+		r->type = R_USEFIELD;
+		r->siz = 0;
+		return;
+	}
+
+	if(ctxt->headtype == Hnacl) {
+		switch(p->as) {
+		case ARET:
+			memmove(ctxt->andptr, naclret, sizeof naclret);
+			ctxt->andptr += sizeof naclret;
+			return;
+		case ACALL:
+		case AJMP:
+			if(D_AX <= p->to.type && p->to.type <= D_DI) {
+				*ctxt->andptr++ = 0x83;
+				*ctxt->andptr++ = 0xe0 | (p->to.type - D_AX);
+				*ctxt->andptr++ = 0xe0;
+			}
+			break;
+		case AINT:
+			*ctxt->andptr++ = 0xf4;
+			return;
+		}
+	}
+
+	doasm(ctxt, p);
+	if(ctxt->andptr > ctxt->and+sizeof ctxt->and) {
+		print("and[] is too short - %ld byte instruction\n", ctxt->andptr - ctxt->and);
+		sysfatal("bad code");
+	}
+}
diff --git a/src/liblink/data.c b/src/liblink/data.c
new file mode 100644
index 0000000..4504f41
--- /dev/null
+++ b/src/liblink/data.c
@@ -0,0 +1,370 @@
+// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+void
+mangle(char *file)
+{
+	sysfatal("%s: mangled input file", file);
+}
+
+void
+symgrow(Link *ctxt, LSym *s, vlong lsiz)
+{
+	int32 siz;
+
+	USED(ctxt);
+
+	siz = (int32)lsiz;
+	if((vlong)siz != lsiz)
+		sysfatal("symgrow size %lld too long", lsiz);
+
+	if(s->np >= siz)
+		return;
+
+	if(s->np > s->maxp) {
+		ctxt->cursym = s;
+		sysfatal("corrupt symbol data: np=%lld > maxp=%lld", (vlong)s->np, (vlong)s->maxp);
+	}
+
+	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(Link *ctxt, LSym *s, Prog *p, char *pn)
+{
+	int32 off, siz, i, fl;
+	float32 flt;
+	uchar *cast;
+	vlong o;
+	Reloc *r;
+
+	off = p->from.offset;
+	siz = ctxt->arch->datasize(p);
+	if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100)
+		mangle(pn);
+	symgrow(ctxt, s, off+siz);
+
+	if(p->to.type == ctxt->arch->D_FCONST) {
+		switch(siz) {
+		default:
+		case 4:
+			flt = p->to.u.dval;
+			cast = (uchar*)&flt;
+			for(i=0; i<4; i++)
+				s->p[off+i] = cast[fnuxi4[i]];
+			break;
+		case 8:
+			cast = (uchar*)&p->to.u.dval;
+			for(i=0; i<8; i++)
+				s->p[off+i] = cast[fnuxi8[i]];
+			break;
+		}
+	} else if(p->to.type == ctxt->arch->D_SCONST) {
+		for(i=0; i<siz; i++)
+			s->p[off+i] = p->to.u.sval[i];
+	} else if(p->to.type == ctxt->arch->D_CONST) {
+		if(p->to.sym)
+			goto addr;
+		o = p->to.offset;
+		fl = o;
+		cast = (uchar*)&fl;
+		switch(siz) {
+		default:
+			ctxt->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;
+		}
+	} else if(p->to.type == ctxt->arch->D_ADDR) {
+	addr:
+		r = addrel(s);
+		r->off = off;
+		r->siz = siz;
+		r->sym = p->to.sym;
+		r->type = R_ADDR;
+		r->add = p->to.offset;
+	} else {
+		ctxt->diag("bad data: %P", p);
+	}
+}
+
+Reloc*
+addrel(LSym *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++];
+}
+
+vlong
+setuintxx(Link *ctxt, LSym *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(ctxt, 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(Link *ctxt, LSym *s, uint64 v, int wid)
+{
+	vlong off;
+
+	off = s->size;
+	setuintxx(ctxt, s, off, v, wid);
+	return off;
+}
+
+vlong
+adduint8(Link *ctxt, LSym *s, uint8 v)
+{
+	return adduintxx(ctxt, s, v, 1);
+}
+
+vlong
+adduint16(Link *ctxt, LSym *s, uint16 v)
+{
+	return adduintxx(ctxt, s, v, 2);
+}
+
+vlong
+adduint32(Link *ctxt, LSym *s, uint32 v)
+{
+	return adduintxx(ctxt, s, v, 4);
+}
+
+vlong
+adduint64(Link *ctxt, LSym *s, uint64 v)
+{
+	return adduintxx(ctxt, s, v, 8);
+}
+
+vlong
+setuint8(Link *ctxt, LSym *s, vlong r, uint8 v)
+{
+	return setuintxx(ctxt, s, r, v, 1);
+}
+
+vlong
+setuint16(Link *ctxt, LSym *s, vlong r, uint16 v)
+{
+	return setuintxx(ctxt, s, r, v, 2);
+}
+
+vlong
+setuint32(Link *ctxt, LSym *s, vlong r, uint32 v)
+{
+	return setuintxx(ctxt, s, r, v, 4);
+}
+
+vlong
+setuint64(Link *ctxt, LSym *s, vlong r, uint64 v)
+{
+	return setuintxx(ctxt, s, r, v, 8);
+}
+
+vlong
+addaddrplus(Link *ctxt, LSym *s, LSym *t, vlong add)
+{
+	vlong i;
+	Reloc *r;
+
+	if(s->type == 0)
+		s->type = SDATA;
+	s->reachable = 1;
+	i = s->size;
+	s->size += ctxt->arch->ptrsize;
+	symgrow(ctxt, s, s->size);
+	r = addrel(s);
+	r->sym = t;
+	r->off = i;
+	r->siz = ctxt->arch->ptrsize;
+	r->type = R_ADDR;
+	r->add = add;
+	return i + r->siz;
+}
+
+vlong
+addpcrelplus(Link *ctxt, LSym *s, LSym *t, vlong add)
+{
+	vlong i;
+	Reloc *r;
+
+	if(s->type == 0)
+		s->type = SDATA;
+	s->reachable = 1;
+	i = s->size;
+	s->size += 4;
+	symgrow(ctxt, s, s->size);
+	r = addrel(s);
+	r->sym = t;
+	r->off = i;
+	r->add = add;
+	r->type = R_PCREL;
+	r->siz = 4;
+	return i + r->siz;
+}
+
+vlong
+addaddr(Link *ctxt, LSym *s, LSym *t)
+{
+	return addaddrplus(ctxt, s, t, 0);
+}
+
+vlong
+setaddrplus(Link *ctxt, LSym *s, vlong off, LSym *t, vlong add)
+{
+	Reloc *r;
+
+	if(s->type == 0)
+		s->type = SDATA;
+	s->reachable = 1;
+	if(off+ctxt->arch->ptrsize > s->size) {
+		s->size = off + ctxt->arch->ptrsize;
+		symgrow(ctxt, s, s->size);
+	}
+	r = addrel(s);
+	r->sym = t;
+	r->off = off;
+	r->siz = ctxt->arch->ptrsize;
+	r->type = R_ADDR;
+	r->add = add;
+	return off + r->siz;
+}
+
+vlong
+setaddr(Link *ctxt, LSym *s, vlong off, LSym *t)
+{
+	return setaddrplus(ctxt, s, off, t, 0);
+}
+
+vlong
+addsize(Link *ctxt, LSym *s, LSym *t)
+{
+	vlong i;
+	Reloc *r;
+
+	if(s->type == 0)
+		s->type = SDATA;
+	s->reachable = 1;
+	i = s->size;
+	s->size += ctxt->arch->ptrsize;
+	symgrow(ctxt, s, s->size);
+	r = addrel(s);
+	r->sym = t;
+	r->off = i;
+	r->siz = ctxt->arch->ptrsize;
+	r->type = R_SIZE;
+	return i + r->siz;
+}
+
+vlong
+addaddrplus4(Link *ctxt, LSym *s, LSym *t, vlong add)
+{
+	vlong i;
+	Reloc *r;
+
+	if(s->type == 0)
+		s->type = SDATA;
+	s->reachable = 1;
+	i = s->size;
+	s->size += 4;
+	symgrow(ctxt, s, s->size);
+	r = addrel(s);
+	r->sym = t;
+	r->off = i;
+	r->siz = 4;
+	r->type = R_ADDR;
+	r->add = add;
+	return i + r->siz;
+}
diff --git a/src/liblink/go.c b/src/liblink/go.c
new file mode 100644
index 0000000..9f5a423
--- /dev/null
+++ b/src/liblink/go.c
@@ -0,0 +1,74 @@
+// 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.
+
+// go-specific code shared across loaders (5l, 6l, 8l).
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+// 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);
+
+	w0 = emallocz(strlen(t0) + strlen(pkg)*n);
+	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;
+}
+
+void*
+emallocz(long n)
+{
+	void *p;
+
+	p = malloc(n);
+	if(p == nil)
+		sysfatal("out of memory");
+	memset(p, 0, n);
+	return p;
+}
+
+char*
+estrdup(char *p)
+{
+	p = strdup(p);
+	if(p == nil)
+		sysfatal("out of memory");
+	return p;
+}
+
+void*
+erealloc(void *p, long n)
+{
+	p = realloc(p, n);
+	if(p == nil)
+		sysfatal("out of memory");
+	return p;
+}
+
+void
+double2ieee(uint64 *ieee, float64 f)
+{
+	memmove(ieee, &f, 8);
+}
diff --git a/src/liblink/ld.c b/src/liblink/ld.c
new file mode 100644
index 0000000..9ea0e9a
--- /dev/null
+++ b/src/liblink/ld.c
@@ -0,0 +1,258 @@
+// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+void
+addlib(Link *ctxt, char *src, char *obj, char *pathname)
+{
+	char name[1024], pname[1024], *p;
+	int i;
+
+	if(strlen(pathname) >= sizeof name)
+		sysfatal("addlib pathname too long");
+	strcpy(name, pathname);
+	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<ctxt->libraryp; i++)
+		if(strcmp(ctxt->library[i].pkg, name) == 0)
+			return;
+	
+	// runtime -> runtime.a for search
+	if(p != nil)
+		*p = '.';
+
+	if((!ctxt->windows && name[0] == '/') || (ctxt->windows && name[1] == ':'))
+		snprint(pname, sizeof pname, "%s", name);
+	else {
+		// try dot, -L "libdir", and then goroot.
+		for(i=0; i<ctxt->nlibdir; i++) {
+			snprint(pname, sizeof pname, "%s/%s", ctxt->libdir[i], name);
+			if(access(pname, AEXIST) >= 0)
+				break;
+		}
+	}
+	cleanname(pname);
+
+	/* runtime.a -> runtime */
+	if(p != nil)
+		*p = '\0';
+
+	if(ctxt->debugvlog > 1 && ctxt->bso)
+		Bprint(ctxt->bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname);
+
+	addlibpath(ctxt, 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(Link *ctxt, char *srcref, char *objref, char *file, char *pkg)
+{
+	int i;
+	Library *l;
+
+	for(i=0; i<ctxt->libraryp; i++)
+		if(strcmp(file, ctxt->library[i].file) == 0)
+			return;
+
+	if(ctxt->debugvlog > 1 && ctxt->bso)
+		Bprint(ctxt->bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n",
+			cputime(), srcref, objref, file, pkg);
+
+	if(ctxt->libraryp == ctxt->nlibrary){
+		ctxt->nlibrary = 50 + 2*ctxt->libraryp;
+		ctxt->library = erealloc(ctxt->library, sizeof ctxt->library[0] * ctxt->nlibrary);
+	}
+
+	l = &ctxt->library[ctxt->libraryp++];
+	l->objref = estrdup(objref);
+	l->srcref = estrdup(srcref);
+	l->file = estrdup(file);
+	l->pkg = estrdup(pkg);
+}
+
+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;
+}
+
+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;
+	}
+}
+
+uchar	fnuxi8[8];
+uchar	fnuxi4[4];
+uchar	inuxi1[1];
+uchar	inuxi2[2];
+uchar	inuxi4[4];
+uchar	inuxi8[8];
+
+#define	LOG	5
+void
+mkfwd(LSym *sym)
+{
+	Prog *p;
+	int i;
+	int32 dwn[LOG], cnt[LOG];
+	Prog *lst[LOG];
+
+	for(i=0; i<LOG; i++) {
+		if(i == 0)
+			cnt[i] = 1;
+		else
+			cnt[i] = LOG * cnt[i-1];
+		dwn[i] = 1;
+		lst[i] = nil;
+	}
+	i = 0;
+	for(p = sym->text; p != nil && p->link != nil; p = p->link) {
+		i--;
+		if(i < 0)
+			i = LOG-1;
+		p->forwd = nil;
+		dwn[i]--;
+		if(dwn[i] <= 0) {
+			dwn[i] = cnt[i];
+			if(lst[i] != nil)
+				lst[i]->forwd = p;
+			lst[i] = p;
+		}
+	}
+}
+
+Prog*
+copyp(Link *ctxt, Prog *q)
+{
+	Prog *p;
+
+	p = ctxt->arch->prg();
+	*p = *q;
+	return p;
+}
+
+Prog*
+appendp(Link *ctxt, Prog *q)
+{
+	Prog *p;
+
+	p = ctxt->arch->prg();
+	p->link = q->link;
+	q->link = p;
+	p->lineno = q->lineno;
+	p->mode = q->mode;
+	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/liblink/list5.c b/src/liblink/list5.c
new file mode 100644
index 0000000..4a4e8c7
--- /dev/null
+++ b/src/liblink/list5.c
@@ -0,0 +1,356 @@
+// 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 at 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 at 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/5l/5.out.h"
+
+enum
+{
+	STRINGSZ = 1000
+};
+
+static int	Aconv(Fmt *fp);
+static int	Dconv(Fmt *fp);
+static int	Mconv(Fmt *fp);
+static int	Pconv(Fmt *fp);
+static int	Rconv(Fmt *fp);
+static int	RAconv(Fmt *fp);
+static int	DSconv(Fmt *fp);
+
+#pragma	varargck	type	"$"	char*
+#pragma	varargck	type	"M"	Addr*
+#pragma	varargck	type	"@"	Addr*
+
+void
+listinit5(void)
+{
+	fmtinstall('A', Aconv);
+	fmtinstall('D', Dconv);
+	fmtinstall('P', Pconv);
+	fmtinstall('R', Rconv);
+
+	// for internal use
+	fmtinstall('$', DSconv);
+	fmtinstall('M', Mconv);
+	fmtinstall('@', RAconv);
+}
+
+static char *extra [] = {
+	".EQ", ".NE", ".CS", ".CC",
+	".MI", ".PL", ".VS", ".VC",
+	".HI", ".LS", ".GE", ".LT",
+	".GT", ".LE", "", ".NV",
+};
+
+static	Prog*	bigP;
+
+static int
+Pconv(Fmt *fp)
+{
+	char str[STRINGSZ], sc[20];
+	Prog *p;
+	int a, s;
+
+	p = va_arg(fp->args, Prog*);
+	bigP = p;
+	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, "%.5lld (%L)	%A%s	%@,%D", p->pc, p->lineno, a, sc, &p->from, &p->to);
+		else
+		if(p->to.type == D_CONST)
+			sprint(str, "%.5lld (%L)	%A%s	%D,%@", p->pc, p->lineno, a, sc, &p->from, &p->to);
+		else
+			sprint(str, "%.5lld (%L)	%A%s	%D,%D", p->pc, p->lineno, a, sc, &p->from, &p->to);
+	} else
+	if(a == ADATA)
+		sprint(str, "%.5lld (%L)	%A	%D/%d,%D", p->pc, p->lineno, a, &p->from, p->reg, &p->to);
+	else
+	if(p->as == ATEXT)
+		sprint(str, "%.5lld (%L)	%A	%D,%d,%D", p->pc, p->lineno, a, &p->from, p->reg, &p->to);
+	else
+	if(p->reg == NREG)
+		sprint(str, "%.5lld (%L)	%A%s	%D,%D", p->pc, p->lineno, a, sc, &p->from, &p->to);
+	else
+	if(p->from.type != D_FREG)
+		sprint(str, "%.5lld (%L)	%A%s	%D,R%d,%D", p->pc, p->lineno, a, sc, &p->from, p->reg, &p->to);
+	else
+		sprint(str, "%.5lld (%L)	%A%s	%D,F%d,%D", p->pc, p->lineno, a, sc, &p->from, p->reg, &p->to);
+	bigP = nil;
+	return fmtstrcpy(fp, str);
+}
+
+static int
+Aconv(Fmt *fp)
+{
+	char *s;
+	int a;
+
+	a = va_arg(fp->args, int);
+	s = "???";
+	if(a >= AXXX && a < ALAST)
+		s = anames5[a];
+	return fmtstrcpy(fp, s);
+}
+
+static int
+Dconv(Fmt *fp)
+{
+	char str[STRINGSZ];
+	Addr *a;
+	const char *op;
+	int v;
+
+	a = va_arg(fp->args, Addr*);
+	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 != nil)
+			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, "$%lld-%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, "%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 != nil)
+			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 != nil)
+			sprint(str, "%M(R%d)(REG)", a, a->reg);
+		break;
+
+	case D_PSR:
+		sprint(str, "PSR");
+		if(a->name != D_NONE || a->sym != nil)
+			sprint(str, "%M(PSR)(REG)", a);
+		break;
+
+	case D_BRANCH:
+		if(a->sym != nil)
+			sprint(str, "%s(SB)", a->sym->name);
+		else if(bigP != nil && bigP->pcond != nil)
+			sprint(str, "%lld", bigP->pcond->pc);
+		else if(a->u.branch != nil)
+			sprint(str, "%lld", a->u.branch->pc);
+		else
+			sprint(str, "%lld(PC)", a->offset/*-pc*/);
+		break;
+
+	case D_FCONST:
+		sprint(str, "$%.17g", a->u.dval);
+		break;
+
+	case D_SCONST:
+		sprint(str, "$\"%$\"", a->u.sval);
+		break;
+	}
+	return fmtstrcpy(fp, str);
+}
+
+static int
+RAconv(Fmt *fp)
+{
+	char str[STRINGSZ];
+	Addr *a;
+	int i, v;
+
+	a = va_arg(fp->args, Addr*);
+	sprint(str, "GOK-reglist");
+	switch(a->type) {
+	case D_CONST:
+	case D_CONST2:
+		if(a->reg != NREG)
+			break;
+		if(a->sym != nil)
+			break;
+		v = a->offset;
+		strcpy(str, "");
+		for(i=0; i<NREG; i++) {
+			if(v & (1<<i)) {
+				if(str[0] == 0)
+					strcat(str, "[R");
+				else
+					strcat(str, ",R");
+				sprint(strchr(str, 0), "%d", i);
+			}
+		}
+		strcat(str, "]");
+	}
+	return fmtstrcpy(fp, str);
+}
+
+static int
+DSconv(Fmt *fp)
+{
+	int i, c;
+	char str[STRINGSZ], *p, *a;
+
+	a = va_arg(fp->args, char*);
+	p = str;
+	for(i=0; i<NSNAME; i++) {
+		c = a[i] & 0xff;
+		if(c >= '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);
+}
+
+static int
+Rconv(Fmt *fp)
+{
+	int r;
+	char str[STRINGSZ];
+
+	r = va_arg(fp->args, int);
+	sprint(str, "R%d", r);
+	return fmtstrcpy(fp, str);
+}
+
+static int
+Mconv(Fmt *fp)
+{
+	char str[STRINGSZ];
+	Addr *a;
+	LSym *s;
+
+	a = va_arg(fp->args, Addr*);
+	s = a->sym;
+	if(s == nil) {
+		sprint(str, "%d", (int)a->offset);
+		goto out;
+	}
+	switch(a->name) {
+	default:
+		sprint(str, "GOK-name(%d)", a->name);
+		break;
+
+	case D_NONE:
+		sprint(str, "%lld", a->offset);
+		break;
+
+	case D_EXTERN:
+		sprint(str, "%s+%d(SB)", s->name, (int)a->offset);
+		break;
+
+	case D_STATIC:
+		sprint(str, "%s<>+%d(SB)", s->name, (int)a->offset);
+		break;
+
+	case D_AUTO:
+		sprint(str, "%s-%d(SP)", s->name, (int)-a->offset);
+		break;
+
+	case D_PARAM:
+		sprint(str, "%s+%d(FP)", s->name, (int)a->offset);
+		break;
+	}
+out:
+	return fmtstrcpy(fp, str);
+}
diff --git a/src/liblink/list6.c b/src/liblink/list6.c
new file mode 100644
index 0000000..fe708d8
--- /dev/null
+++ b/src/liblink/list6.c
@@ -0,0 +1,406 @@
+// 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 at 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 at 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/6l/6.out.h"
+
+//
+// Format conversions
+//	%A int		Opcodes (instruction mnemonics)
+//
+//	%D Addr*	Addresses (instruction operands)
+//		Flags: "%lD": seperate the high and low words of a constant by "-"
+//
+//	%P Prog*	Instructions
+//
+//	%R int		Registers
+//
+//	%$ char*	String constant addresses (for internal use only)
+
+static int	Aconv(Fmt *fp);
+static int	Dconv(Fmt *fp);
+static int	Pconv(Fmt *fp);
+static int	Rconv(Fmt *fp);
+static int	DSconv(Fmt *fp);
+
+enum
+{
+	STRINGSZ = 1000
+};
+
+#pragma	varargck	type	"$"	char*
+
+void
+listinit6(void)
+{
+	fmtinstall('A', Aconv);
+	fmtinstall('D', Dconv);
+	fmtinstall('P', Pconv);
+	fmtinstall('R', Rconv);
+
+	// for internal use
+	fmtinstall('$', DSconv);
+}
+
+static	Prog*	bigP;
+
+static int
+Pconv(Fmt *fp)
+{
+	char str[STRINGSZ];
+	Prog *p;
+
+	p = va_arg(fp->args, Prog*);
+	bigP = p;
+	switch(p->as) {
+	case ADATA:
+		sprint(str, "%.5lld (%L)	%A	%D/%d,%D",
+			p->pc, p->lineno, p->as, &p->from, p->from.scale, &p->to);
+		break;
+
+	case ATEXT:
+		if(p->from.scale) {
+			sprint(str, "%.5lld (%L)	%A	%D,%d,%lD",
+				p->pc, p->lineno, p->as, &p->from, p->from.scale, &p->to);
+			break;
+		}
+		sprint(str, "%.5lld (%L)	%A	%D,%lD",
+			p->pc, p->lineno, p->as, &p->from, &p->to);
+		break;
+
+	default:
+		sprint(str, "%.5lld (%L)	%A	%D,%D",
+			p->pc, p->lineno, p->as, &p->from, &p->to);
+		break;
+	}
+	bigP = nil;
+	return fmtstrcpy(fp, str);
+}
+
+static int
+Aconv(Fmt *fp)
+{
+	int i;
+
+	i = va_arg(fp->args, int);
+	return fmtstrcpy(fp, anames6[i]);
+}
+
+static int
+Dconv(Fmt *fp)
+{
+	char str[STRINGSZ], s[STRINGSZ];
+	Addr *a;
+	int i;
+
+	a = va_arg(fp->args, Addr*);
+	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:
+		if(a->sym != nil)
+			sprint(str, "%s(SB)", a->sym->name);
+		else if(bigP != nil && bigP->pcond != nil)
+			sprint(str, "%lld", bigP->pcond->pc);
+		else if(a->u.branch != nil)
+			sprint(str, "%lld", a->u.branch->pc);
+		else
+			sprint(str, "%lld(PC)", 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, "$(%.17g)", a->u.dval);
+		break;
+
+	case D_SCONST:
+		sprint(str, "$\"%$\"", a->u.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",
+
+	"TLS",	/* [D_TLS] */
+	"NONE",	/* [D_NONE] */
+};
+
+static 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);
+}
+
+static int
+DSconv(Fmt *fp)
+{
+	int i, c;
+	char str[STRINGSZ], *p, *a;
+
+	a = va_arg(fp->args, char*);
+	p = str;
+	for(i=0; i<sizeof(double); i++) {
+		c = a[i] & 0xff;
+		if(c >= '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/liblink/list8.c b/src/liblink/list8.c
new file mode 100644
index 0000000..7866924
--- /dev/null
+++ b/src/liblink/list8.c
@@ -0,0 +1,354 @@
+// 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 at 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 at 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/8l/8.out.h"
+
+static int	Aconv(Fmt *fp);
+static int	Dconv(Fmt *fp);
+static int	Pconv(Fmt *fp);
+static int	Rconv(Fmt *fp);
+static int	DSconv(Fmt *fp);
+
+enum
+{
+	STRINGSZ = 1000
+};
+
+#pragma	varargck	type	"$"	char*
+
+void
+listinit8(void)
+{
+	fmtinstall('A', Aconv);
+	fmtinstall('D', Dconv);
+	fmtinstall('P', Pconv);
+	fmtinstall('R', Rconv);
+
+	// for internal use
+	fmtinstall('$', DSconv);
+}
+
+static	Prog*	bigP;
+
+static int
+Pconv(Fmt *fp)
+{
+	char str[STRINGSZ];
+	Prog *p;
+
+	p = va_arg(fp->args, Prog*);
+	bigP = p;
+	switch(p->as) {
+	case ADATA:
+		sprint(str, "%.5lld (%L)	%A	%D/%d,%D",
+			p->pc, p->lineno, p->as, &p->from, p->from.scale, &p->to);
+		break;
+
+	case ATEXT:
+		if(p->from.scale) {
+			sprint(str, "%.5lld (%L)	%A	%D,%d,%lD",
+				p->pc, p->lineno, p->as, &p->from, p->from.scale, &p->to);
+			break;
+		}
+		sprint(str, "%.5lld (%L)	%A	%D,%lD",
+			p->pc, p->lineno, p->as, &p->from, &p->to);
+		break;
+
+	default:
+		sprint(str, "%.5lld (%L)	%A	%D,%D",
+			p->pc, p->lineno, p->as, &p->from, &p->to);
+		break;
+	}
+	bigP = nil;
+	return fmtstrcpy(fp, str);
+}
+
+static int
+Aconv(Fmt *fp)
+{
+	int i;
+
+	i = va_arg(fp->args, int);
+	return fmtstrcpy(fp, anames8[i]);
+}
+
+static int
+Dconv(Fmt *fp)
+{
+	char str[STRINGSZ], s[STRINGSZ];
+	Addr *a;
+	int i;
+
+	a = va_arg(fp->args, Addr*);
+	i = a->type;
+
+	if(fp->flags & FmtLong) {
+		if(i == D_CONST2)
+			sprint(str, "$%lld-%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, "%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:
+		if(a->sym != nil)
+			sprint(str, "%s(SB)", a->sym->name);
+		else if(bigP != nil && bigP->pcond != nil)
+			sprint(str, "%lld", bigP->pcond->pc);
+		else if(a->u.branch != nil)
+			sprint(str, "%lld", a->u.branch->pc);
+		else
+			sprint(str, "%lld(PC)", 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_CONST2:
+		if(!(fp->flags & FmtLong)) {
+			// D_CONST2 outside of ATEXT should not happen
+			sprint(str, "!!$%lld-%d", a->offset, a->offset2);
+		}
+		break;
+
+	case D_FCONST:
+		sprint(str, "$(%.17g)", a->u.dval);
+		break;
+
+	case D_SCONST:
+		sprint(str, "$\"%$\"", a->u.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",
+
+	"TLS",	/* [D_TLS] */
+	"NONE",	/* [D_NONE] */
+};
+
+static 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);
+}
+
+static int
+DSconv(Fmt *fp)
+{
+	int i, c;
+	char str[STRINGSZ], *p, *a;
+
+	a = va_arg(fp->args, char*);
+	p = str;
+	for(i=0; i<sizeof(double); i++) {
+		c = a[i] & 0xff;
+		if(c >= '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/liblink/obj.c b/src/liblink/obj.c
new file mode 100644
index 0000000..b8083b0
--- /dev/null
+++ b/src/liblink/obj.c
@@ -0,0 +1,296 @@
+// 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+enum
+{
+	HISTSZ = 10,
+	NSYM = 50,
+};
+
+int
+linklinefmt(Link *ctxt, 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=ctxt->hist; h!=nil; 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(ctxt->debugline || (fp->flags&FmtLong))
+			fmtprint(fp, "%s/", ctxt->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, "<unknown line number>");
+
+	return 0;
+}
+
+// Does s have t as a path prefix?
+// That is, does s == t or does s begin with t followed by a slash?
+// For portability, we allow ASCII case folding, so that haspathprefix("a/b/c", "A/B") is true.
+// Similarly, we allow slash folding, so that haspathprefix("a/b/c", "a\\b") is true.
+static int
+haspathprefix(char *s, char *t)
+{
+	int i, cs, ct;
+
+	if(t == nil)
+		return 0;
+	for(i=0; t[i]; i++) {
+		cs = s[i];
+		ct = t[i];
+		if('A' <= cs && cs <= 'Z')
+			cs += 'a' - 'A';
+		if('A' <= ct && ct <= 'Z')
+			ct += 'a' - 'A';
+		if(cs == '\\')
+			cs = '/';
+		if(ct == '\\')
+			ct = '/';
+		if(cs != ct)
+			return 0;
+	}
+	return s[i] == '\0' || s[i] == '/' || s[i] == '\\';
+}
+
+// This is a simplified copy of linklinefmt above.
+// It doesn't allow printing the full stack, and it returns the file name and line number separately.
+// TODO: Unify with linklinefmt somehow.
+void
+linkgetline(Link *ctxt, int32 line, LSym **f, int32 *l)
+{
+	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, dlno;
+	int n;
+	Hist *h;
+	char buf[1024], buf1[1024], *file;
+
+	lno = line;
+	n = 0;
+	for(h=ctxt->hist; h!=nil; 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;
+
+	if(n <= 0) {
+		*f = linklookup(ctxt, "??", HistVersion);
+		*l = 0;
+		return;
+	}
+	
+	n--;
+	if(a[n].line) {
+		file = a[n].line->name;
+		dlno = a[n].ldel-1;
+	} else {
+		file = a[n].incl->name;
+		dlno = a[n].idel-1;
+	}
+	if((!ctxt->windows && file[0] == '/') || (ctxt->windows && file[1] == ':') || file[0] == '<')
+		snprint(buf, sizeof buf, "%s", file);
+	else
+		snprint(buf, sizeof buf, "%s/%s", ctxt->pathname, file);
+
+	// Remove leading ctxt->trimpath, or else rewrite $GOROOT to $GOROOT_FINAL.
+	if(haspathprefix(buf, ctxt->trimpath)) {
+		if(strlen(buf) == strlen(ctxt->trimpath))
+			strcpy(buf, "??");
+		else {
+			snprint(buf1, sizeof buf1, "%s", buf+strlen(ctxt->trimpath)+1);
+			if(buf1[0] == '\0')
+				strcpy(buf1, "??");
+			strcpy(buf, buf1);
+		}
+	} else if(ctxt->goroot_final != nil && haspathprefix(buf, ctxt->goroot)) {
+		snprint(buf1, sizeof buf1, "%s%s", ctxt->goroot_final, buf+strlen(ctxt->goroot));
+		strcpy(buf, buf1);
+	}
+
+	lno -= dlno;
+	*f = linklookup(ctxt, buf, HistVersion);
+	*l = lno;
+}
+
+void
+linklinehist(Link *ctxt, int lineno, char *f, int offset)
+{
+	Hist *h;
+
+	if(0) // 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: <pop>\n", lineno);
+
+	h = malloc(sizeof(Hist));
+	memset(h, 0, sizeof *h);
+	h->name = f;
+	h->line = lineno;
+	h->offset = offset;
+	h->link = nil;
+	if(ctxt->ehist == nil) {
+		ctxt->hist = h;
+		ctxt->ehist = h;
+		return;
+	}
+	ctxt->ehist->link = h;
+	ctxt->ehist = h;
+}
+
+void
+linkprfile(Link *ctxt, int32 l)
+{
+	int i, n;
+	Hist a[HISTSZ], *h;
+	int32 d;
+
+	n = 0;
+	for(h = ctxt->hist; h != nil; 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<n; i++)
+				a[i].line += d;
+		}
+	}
+	if(n > HISTSZ)
+		n = HISTSZ;
+	for(i=0; i<n; i++)
+		print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1));
+}
+
+/*
+ * start a new Prog list.
+ */
+Plist*
+linknewplist(Link *ctxt)
+{
+	Plist *pl;
+
+	pl = malloc(sizeof(*pl));
+	memset(pl, 0, sizeof *pl);
+	if(ctxt->plist == nil)
+		ctxt->plist = pl;
+	else
+		ctxt->plast->link = pl;
+	ctxt->plast = pl;
+
+	return pl;
+}
diff --git a/src/liblink/obj5.c b/src/liblink/obj5.c
new file mode 100644
index 0000000..ccd4c81
--- /dev/null
+++ b/src/liblink/obj5.c
@@ -0,0 +1,1068 @@
+// Derived from Inferno utils/5c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/swt.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/5l/5.out.h"
+#include "../pkg/runtime/stack.h"
+
+static Prog zprg = {
+	.as = AGOK,
+	.scond = C_SCOND_NONE,
+	.reg = NREG,
+	.from = {
+		.name = D_NONE,
+		.type = D_NONE,
+		.reg = NREG,
+	},
+	.to = {
+		.name = D_NONE,
+		.type = D_NONE,
+		.reg = NREG,
+	},
+};
+
+static int
+symtype(Addr *a)
+{
+	return a->name;
+}
+
+static int
+isdata(Prog *p)
+{
+	return p->as == ADATA || p->as == AGLOBL;
+}
+
+static int
+iscall(Prog *p)
+{
+	return p->as == ABL;
+}
+
+static int
+datasize(Prog *p)
+{
+	return p->reg;
+}
+
+static int
+textflag(Prog *p)
+{
+	return p->reg;
+}
+
+static void
+settextflag(Prog *p, int f)
+{
+	p->reg = f;
+}
+
+static void
+progedit(Link *ctxt, Prog *p)
+{
+	char literal[64];
+	LSym *s;
+	LSym *tlsfallback;
+
+	p->from.class = 0;
+	p->to.class = 0;
+
+	// Rewrite B/BL to symbol as D_BRANCH.
+	switch(p->as) {
+	case AB:
+	case ABL:
+	case ADUFFZERO:
+	case ADUFFCOPY:
+		if(p->to.type == D_OREG && (p->to.name == D_EXTERN || p->to.name == D_STATIC) && p->to.sym != nil)
+			p->to.type = D_BRANCH;
+		break;
+	}
+
+	// Replace TLS register fetches on older ARM procesors.
+	switch(p->as) {
+	case AMRC:
+		// If the instruction matches MRC 15, 0, <reg>, C13, C0, 3, replace it.
+		if(ctxt->goarm < 7 && (p->to.offset & 0xffff0fff) == 0xee1d0f70) {
+			tlsfallback = linklookup(ctxt, "runtime.read_tls_fallback", 0);
+
+			// BL runtime.read_tls_fallback(SB)
+			p->as = ABL;
+			p->to.type = D_BRANCH;
+			p->to.sym = tlsfallback;
+			p->to.offset = 0;
+		} else {
+			// Otherwise, MRC/MCR instructions need no further treatment.
+			p->as = AWORD;
+		}
+		break;
+	}
+
+	// Rewrite float constants to values stored in memory.
+	switch(p->as) {
+	case AMOVF:
+		if(p->from.type == D_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
+		   (chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
+			int32 i32;
+			float32 f32;
+			f32 = p->from.u.dval;
+			memmove(&i32, &f32, 4);
+			sprint(literal, "$f32.%08ux", (uint32)i32);
+			s = linklookup(ctxt, literal, 0);
+			if(s->type == 0) {
+				s->type = SRODATA;
+				adduint32(ctxt, s, i32);
+				s->reachable = 0;
+			}
+			p->from.type = D_OREG;
+			p->from.sym = s;
+			p->from.name = D_EXTERN;
+			p->from.offset = 0;
+		}
+		break;
+
+	case AMOVD:
+		if(p->from.type == D_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
+		   (chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
+			int64 i64;
+			memmove(&i64, &p->from.u.dval, 8);
+			sprint(literal, "$f64.%016llux", (uvlong)i64);
+			s = linklookup(ctxt, literal, 0);
+			if(s->type == 0) {
+				s->type = SRODATA;
+				adduint64(ctxt, s, i64);
+				s->reachable = 0;
+			}
+			p->from.type = D_OREG;
+			p->from.sym = s;
+			p->from.name = D_EXTERN;
+			p->from.offset = 0;
+		}
+		break;
+	}
+
+	if(ctxt->flag_shared) {
+		// Shared libraries use R_ARM_TLS_IE32 instead of 
+		// R_ARM_TLS_LE32, replacing the link time constant TLS offset in
+		// runtime.tlsgm with an address to a GOT entry containing the 
+		// offset. Rewrite $runtime.tlsgm(SB) to runtime.tlsgm(SB) to
+		// compensate.
+		if(ctxt->gmsym == nil)
+			ctxt->gmsym = linklookup(ctxt, "runtime.tlsgm", 0);
+
+		if(p->from.type == D_CONST && p->from.name == D_EXTERN && p->from.sym == ctxt->gmsym)
+			p->from.type = D_OREG;
+		if(p->to.type == D_CONST && p->to.name == D_EXTERN && p->to.sym == ctxt->gmsym)
+			p->to.type = D_OREG;
+	}
+}
+
+static Prog*
+prg(void)
+{
+	Prog *p;
+
+	p = emallocz(sizeof(*p));
+	*p = zprg;
+	return p;
+}
+
+static	Prog*	stacksplit(Link*, Prog*, int32, int);
+static	void		initdiv(Link*);
+static	void	softfloat(Link*, LSym*);
+
+// Prog.mark
+enum
+{
+	FOLL = 1<<0,
+	LABEL = 1<<1,
+	LEAF = 1<<2,
+};
+
+static void
+linkcase(Prog *casep)
+{
+	Prog *p;
+
+	for(p = casep; p != nil; p = p->link){
+		if(p->as == ABCASE) {
+			for(; p != nil && p->as == ABCASE; p = p->link)
+				p->pcrel = casep;
+			break;
+		}
+	}
+}
+
+static void
+nocache(Prog *p)
+{
+	p->optab = 0;
+	p->from.class = 0;
+	p->to.class = 0;
+}
+
+static void
+addstacksplit(Link *ctxt, LSym *cursym)
+{
+	Prog *p, *pl, *q, *q1, *q2;
+	int o;
+	int32 autosize, autoffset;
+	
+	autosize = 0;
+
+	if(ctxt->symmorestack[0] == nil) {
+		ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
+		ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0);
+	}
+
+	q = nil;
+	
+	ctxt->cursym = cursym;
+
+	if(cursym->text == nil || cursym->text->link == nil)
+		return;				
+
+	softfloat(ctxt, cursym);
+
+	p = cursym->text;
+	autoffset = p->to.offset;
+	if(autoffset < 0)
+		autoffset = 0;
+	cursym->locals = autoffset;
+	cursym->args = p->to.offset2;
+
+	if(ctxt->debugzerostack) {
+		if(autoffset && !(p->reg&NOSPLIT)) {
+			// MOVW $4(R13), R1
+			p = appendp(ctxt, 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(ctxt, 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(ctxt, p);
+			p->as = AMOVW;
+			p->from.type = D_CONST;
+			p->from.offset = 0;
+			p->to.type = D_REG;
+			p->to.reg = 3;
+	
+			// L:
+			//	MOVW.nil R3, 0(R1) +4
+			//	CMP R1, R2
+			//	BNE L
+			p = pl = appendp(ctxt, 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(ctxt, p);
+			p->as = ACMP;
+			p->from.type = D_REG;
+			p->from.reg = 1;
+			p->reg = 2;
+	
+			p = appendp(ctxt, p);
+			p->as = ABNE;
+			p->to.type = D_BRANCH;
+			p->pcond = pl;
+		}
+	}
+
+	/*
+	 * find leaf subroutines
+	 * strip NOPs
+	 * expand RET
+	 * expand BECOME pseudo
+	 */
+
+	for(p = cursym->text; p != nil; p = p->link) {
+		switch(p->as) {
+		case ACASE:
+			if(ctxt->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(ctxt->sym_div == nil)
+				initdiv(ctxt);
+			cursym->text->mark &= ~LEAF;
+			continue;
+
+		case ANOP:
+			q1 = p->link;
+			q->link = q1;		/* q is non-nop */
+			if(q1 != nil)
+				q1->mark |= p->mark;
+			continue;
+
+		case ABL:
+		case ABX:
+		case ADUFFZERO:
+		case ADUFFCOPY:
+			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->pcond;
+			if(q1 != nil) {
+				while(q1->as == ANOP) {
+					q1 = q1->link;
+					p->pcond = q1;
+				}
+			}
+			break;
+		}
+		q = p;
+	}
+
+	for(p = cursym->text; p != nil; 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(ctxt->debugvlog) {
+					Bprint(ctxt->bso, "save suppressed in: %s\n",
+						cursym->name);
+					Bflush(ctxt->bso);
+				}
+				cursym->text->mark |= LEAF;
+			}
+			if(cursym->text->mark & LEAF) {
+				cursym->leaf = 1;
+				if(!autosize)
+					break;
+			}
+
+			if(!(p->reg & NOSPLIT))
+				p = stacksplit(ctxt, p, autosize, !(cursym->text->reg&NEEDCTXT)); // emit split check
+			
+			// MOVW.W		R14,$-autosize(SP)
+			p = appendp(ctxt, 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(ctxt, p);
+				p->as = AMOVW;
+				p->from.type = D_OREG;
+				p->from.reg = REGG;
+				p->from.offset = 2*ctxt->arch->ptrsize;
+				p->to.type = D_REG;
+				p->to.reg = 3;
+			
+				p = appendp(ctxt, p);
+				p->as = AADD;
+				p->from.type = D_CONST;
+				p->from.offset = autosize;
+				p->to.type = D_REG;
+				p->to.reg = 3;
+				
+				p = appendp(ctxt, 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*ctxt->arch->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;
+					} else {
+						p->to.type = D_OREG;
+						p->to.offset = 0;
+						p->to.reg = REGLINK;
+					}
+					break;
+				}
+			}
+
+			if(cursym->text->reg & WRAPPER) {
+				int scond;
+				
+				// Preserve original RET's cond, to allow RET.EQ
+				// in the implementation of reflect.call.
+				scond = 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*ctxt->arch->ptrsize;
+				p->to.type = D_REG;
+				p->to.reg = 3;
+				p = appendp(ctxt, p);
+			
+				p->as = ASUB;
+				p->from.type = D_CONST;
+				p->from.offset = autosize;
+				p->to.type = D_REG;
+				p->to.reg = 3;
+				p = appendp(ctxt, 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*ctxt->arch->ptrsize;
+				p = appendp(ctxt, p);
+
+				p->scond = scond;
+			}
+
+			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(ctxt, p);
+				q2->as = AB;
+				q2->to.type = D_BRANCH;
+				q2->to.sym = p->to.sym;
+				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(ctxt->debugdivmod)
+				break;
+			if(p->from.type != D_REG)
+				break;
+			if(p->to.type != D_REG)
+				break;
+			q1 = p;
+
+			/* MOV a,4(SP) */
+			p = appendp(ctxt, p);
+			p->as = AMOVW;
+			p->lineno = q1->lineno;
+			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(ctxt, p);
+			p->as = AMOVW;
+			p->lineno = q1->lineno;
+			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(ctxt, p);
+			p->as = ABL;
+			p->lineno = q1->lineno;
+			p->to.type = D_BRANCH;
+			switch(o) {
+			case ADIV:
+				p->to.sym = ctxt->sym_div;
+				break;
+			case ADIVU:
+				p->to.sym = ctxt->sym_divu;
+				break;
+			case AMOD:
+				p->to.sym = ctxt->sym_mod;
+				break;
+			case AMODU:
+				p->to.sym = ctxt->sym_modu;
+				break;
+			}
+
+			/* MOV REGTMP, b */
+			p = appendp(ctxt, p);
+			p->as = AMOVW;
+			p->lineno = q1->lineno;
+			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(ctxt, p);
+			p->as = AADD;
+			p->lineno = q1->lineno;
+			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(ctxt, 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 void
+softfloat(Link *ctxt, LSym *cursym)
+{
+	Prog *p, *next;
+	LSym *symsfloat;
+	int wasfloat;
+
+	if(ctxt->goarm > 5)
+		return;
+
+	symsfloat = linklookup(ctxt, "_sfloat", 0);
+
+	wasfloat = 0;
+	for(p = cursym->text; p != nil; p = p->link)
+		if(p->pcond != nil)
+			p->pcond->mark |= LABEL;
+	for(p = cursym->text; p != nil; 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 (!wasfloat || (p->mark&LABEL)) {
+				next = ctxt->arch->prg();
+				*next = *p;
+
+				// BL _sfloat(SB)
+				*p = zprg;
+				p->link = next;
+				p->as = ABL;
+ 				p->to.type = D_BRANCH;
+				p->to.sym = symsfloat;
+				p->lineno = next->lineno;
+
+				p = next;
+				wasfloat = 1;
+			}
+			break;
+
+		notsoft:
+			wasfloat = 0;
+		}
+	}
+}
+
+static Prog*
+stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
+{
+	int32 arg;
+
+	// MOVW			g_stackguard(g), R1
+	p = appendp(ctxt, 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(ctxt, 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(ctxt, 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(ctxt, 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(ctxt, p);
+		p->as = ACMP;
+		p->from.type = D_CONST;
+		p->from.offset = (uint32)StackPreempt;
+		p->reg = 1;
+
+		p = appendp(ctxt, 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(ctxt, 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(ctxt, 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(ctxt, 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(ctxt, 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(ctxt, p);
+	p->as = AMOVW;
+	p->scond = C_SCOND_LS;
+	p->from.type = D_CONST;
+	arg = ctxt->cursym->text->to.offset2;
+	if(arg == 1) // special marker for known 0
+		arg = 0;
+	if(arg&3)
+		ctxt->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(ctxt, 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(ctxt, p);
+	p->as = ABL;
+	p->scond = C_SCOND_LS;
+	p->to.type = D_BRANCH;
+	p->to.sym = ctxt->symmorestack[noctxt];
+	
+	// BLS	start
+	p = appendp(ctxt, p);
+	p->as = ABLS;
+	p->to.type = D_BRANCH;
+	p->pcond = ctxt->cursym->text->link;
+	
+	return p;
+}
+
+static void
+initdiv(Link *ctxt)
+{
+	if(ctxt->sym_div != nil)
+		return;
+	ctxt->sym_div = linklookup(ctxt, "_div", 0);
+	ctxt->sym_divu = linklookup(ctxt, "_divu", 0);
+	ctxt->sym_mod = linklookup(ctxt, "_mod", 0);
+	ctxt->sym_modu = linklookup(ctxt, "_modu", 0);
+}
+
+static void xfol(Link*, Prog*, Prog**);
+
+static void
+follow(Link *ctxt, LSym *s)
+{
+	Prog *firstp, *lastp;
+
+	ctxt->cursym = s;
+
+	firstp = ctxt->arch->prg();
+	lastp = firstp;
+	xfol(ctxt, s->text, &lastp);
+	lastp->link = nil;
+	s->text = firstp->link;
+}
+
+static 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;
+	}
+	sysfatal("unknown relation: %s", anames5[a]);
+	return 0;
+}
+
+static void
+xfol(Link *ctxt, Prog *p, Prog **last)
+{
+	Prog *q, *r;
+	int a, i;
+
+loop:
+	if(p == nil)
+		return;
+	a = p->as;
+	if(a == AB) {
+		q = p->pcond;
+		if(q != nil && 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 == C_SCOND_NONE) || a == ARFE || a == AUNDEF)
+				goto copy;
+			if(q->pcond == nil || (q->pcond->mark&FOLL))
+				continue;
+			if(a != ABEQ && a != ABNE)
+				continue;
+		copy:
+			for(;;) {
+				r = ctxt->arch->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 == C_SCOND_NONE) || a == ARFE || a == AUNDEF)
+					return;
+				r->as = ABNE;
+				if(a == ABNE)
+					r->as = ABEQ;
+				r->pcond = p->link;
+				r->link = p->pcond;
+				if(!(r->link->mark&FOLL))
+					xfol(ctxt, r->link, last);
+				if(!(r->pcond->mark&FOLL))
+					print("can't happen 2\n");
+				return;
+			}
+		}
+		a = AB;
+		q = ctxt->arch->prg();
+		q->as = a;
+		q->lineno = p->lineno;
+		q->to.type = D_BRANCH;
+		q->to.offset = p->pc;
+		q->pcond = p;
+		p = q;
+	}
+	p->mark |= FOLL;
+	(*last)->link = p;
+	*last = p;
+	if(a == AB || (a == ARET && p->scond == C_SCOND_NONE) || a == ARFE || a == AUNDEF){
+		return;
+	}
+	if(p->pcond != nil)
+	if(a != ABL && a != ABX && p->link != nil) {
+		q = brchain(ctxt, p->link);
+		if(a != ATEXT && a != ABCASE)
+		if(q != nil && (q->mark&FOLL)) {
+			p->as = relinv(a);
+			p->link = p->pcond;
+			p->pcond = q;
+		}
+		xfol(ctxt, p->link, last);
+		q = brchain(ctxt, p->pcond);
+		if(q == nil)
+			q = p->pcond;
+		if(q->mark&FOLL) {
+			p->pcond = q;
+			return;
+		}
+		p = q;
+		goto loop;
+	}
+	p = p->link;
+	goto loop;
+}
+
+LinkArch linkarm = {
+	.name = "arm",
+	.thechar = '5',
+
+	.addstacksplit = addstacksplit,
+	.assemble = span5,
+	.datasize = datasize,
+	.follow = follow,
+	.iscall = iscall,
+	.isdata = isdata,
+	.prg = prg,
+	.progedit = progedit,
+	.settextflag = settextflag,
+	.symtype = symtype,
+	.textflag = textflag,
+
+	.minlc = 4,
+	.ptrsize = 4,
+	.regsize = 4,
+
+	.D_ADDR = D_ADDR,
+	.D_AUTO = D_AUTO,
+	.D_BRANCH = D_BRANCH,
+	.D_CONST = D_CONST,
+	.D_EXTERN = D_EXTERN,
+	.D_FCONST = D_FCONST,
+	.D_NONE = D_NONE,
+	.D_PARAM = D_PARAM,
+	.D_SCONST = D_SCONST,
+	.D_STATIC = D_STATIC,
+
+	.ACALL = ABL,
+	.ADATA = ADATA,
+	.AEND = AEND,
+	.AFUNCDATA = AFUNCDATA,
+	.AGLOBL = AGLOBL,
+	.AJMP = AB,
+	.ANOP = ANOP,
+	.APCDATA = APCDATA,
+	.ARET = ARET,
+	.ATEXT = ATEXT,
+	.ATYPE = ATYPE,
+	.AUSEFIELD = AUSEFIELD,
+};
diff --git a/src/liblink/obj6.c b/src/liblink/obj6.c
new file mode 100644
index 0000000..b1bcd0d
--- /dev/null
+++ b/src/liblink/obj6.c
@@ -0,0 +1,1171 @@
+// 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 at 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 at 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/6l/6.out.h"
+#include "../pkg/runtime/stack.h"
+
+static Prog zprg = {
+	.back = 2,
+	.as = AGOK,
+	.from = {
+		.type = D_NONE,
+		.index = D_NONE,
+	},
+	.to = {
+		.type = D_NONE,
+		.index = D_NONE,
+	},
+};
+
+static void
+nopout(Prog *p)
+{
+	p->as = ANOP;
+	p->from.type = D_NONE;
+	p->to.type = D_NONE;
+}
+
+static int
+symtype(Addr *a)
+{
+	int t;
+
+	t = a->type;
+	if(t == D_ADDR)
+		t = a->index;
+	return t;
+}
+
+static int
+isdata(Prog *p)
+{
+	return p->as == ADATA || p->as == AGLOBL;
+}
+
+static int
+iscall(Prog *p)
+{
+	return p->as == ACALL;
+}
+
+static int
+datasize(Prog *p)
+{
+	return p->from.scale;
+}
+
+static int
+textflag(Prog *p)
+{
+	return p->from.scale;
+}
+
+static void
+settextflag(Prog *p, int f)
+{
+	p->from.scale = f;
+}
+
+static void nacladdr(Link*, Prog*, Addr*);
+
+static int
+canuselocaltls(Link *ctxt)
+{
+	switch(ctxt->headtype) {
+//	case Hlinux:
+	case Hwindows:
+		return 0;
+	}
+	return 1;
+}
+
+static void
+progedit(Link *ctxt, Prog *p)
+{
+	char literal[64];
+	LSym *s;
+	Prog *q;
+
+	// Thread-local storage references use the TLS pseudo-register.
+	// As a register, TLS refers to the thread-local storage base, and it
+	// can only be loaded into another register:
+	//
+	//         MOVQ TLS, AX
+	//
+	// An offset from the thread-local storage base is written off(reg)(TLS*1).
+	// Semantically it is off(reg), but the (TLS*1) annotation marks this as
+	// indexing from the loaded TLS base. This emits a relocation so that
+	// if the linker needs to adjust the offset, it can. For example:
+	//
+	//         MOVQ TLS, AX
+	//         MOVQ 8(AX)(TLS*1), CX // load m into CX
+	// 
+	// On systems that support direct access to the TLS memory, this
+	// pair of instructions can be reduced to a direct TLS memory reference:
+	// 
+	//         MOVQ 8(TLS), CX // load m into CX
+	//
+	// The 2-instruction and 1-instruction forms correspond roughly to
+	// ELF TLS initial exec mode and ELF TLS local exec mode, respectively.
+	// 
+	// We applies this rewrite on systems that support the 1-instruction form.
+	// The decision is made using only the operating system (and probably
+	// the -shared flag, eventually), not the link mode. If some link modes
+	// on a particular operating system require the 2-instruction form,
+	// then all builds for that operating system will use the 2-instruction
+	// form, so that the link mode decision can be delayed to link time.
+	//
+	// In this way, all supported systems use identical instructions to
+	// access TLS, and they are rewritten appropriately first here in
+	// liblink and then finally using relocations in the linker.
+
+	if(canuselocaltls(ctxt)) {
+		// Reduce TLS initial exec model to TLS local exec model.
+		// Sequences like
+		//	MOVQ TLS, BX
+		//	... off(BX)(TLS*1) ...
+		// become
+		//	NOP
+		//	... off(TLS) ...
+		//
+		// TODO(rsc): Remove the Hsolaris special case. It exists only to
+		// guarantee we are producing byte-identical binaries as before this code.
+		// But it should be unnecessary.
+		if((p->as == AMOVQ || p->as == AMOVL) && p->from.type == D_TLS && D_AX <= p->to.type && p->to.type <= D_R15 && ctxt->headtype != Hsolaris)
+			nopout(p);
+		if(p->from.index == D_TLS && D_INDIR+D_AX <= p->from.type && p->from.type <= D_INDIR+D_R15) {
+			p->from.type = D_INDIR+D_TLS;
+			p->from.scale = 0;
+			p->from.index = D_NONE;
+		}
+		if(p->to.index == D_TLS && D_INDIR+D_AX <= p->to.type && p->to.type <= D_INDIR+D_R15) {
+			p->to.type = D_INDIR+D_TLS;
+			p->to.scale = 0;
+			p->to.index = D_NONE;
+		}
+	} else {
+		// As a courtesy to the C compilers, rewrite TLS local exec load as TLS initial exec load.
+		// The instruction
+		//	MOVQ off(TLS), BX
+		// becomes the sequence
+		//	MOVQ TLS, BX
+		//	MOVQ off(BX)(TLS*1), BX
+		// This allows the C compilers to emit references to m and g using the direct off(TLS) form.
+		if((p->as == AMOVQ || p->as == AMOVL) && p->from.type == D_INDIR+D_TLS && D_AX <= p->to.type && p->to.type <= D_R15) {
+			q = appendp(ctxt, p);
+			q->as = p->as;
+			q->from = p->from;
+			q->from.type = D_INDIR + p->to.type;
+			q->from.index = D_TLS;
+			q->from.scale = 2; // TODO: use 1
+			q->to = p->to;
+			p->from.type = D_TLS;
+			p->from.index = D_NONE;
+			p->from.offset = 0;
+		}
+	}
+
+	// TODO: Remove.
+	if(ctxt->headtype == Hwindows || ctxt->headtype == Hplan9) {
+		if(p->from.scale == 1 && p->from.index == D_TLS)
+			p->from.scale = 2;
+		if(p->to.scale == 1 && p->to.index == D_TLS)
+			p->to.scale = 2;
+	}
+
+	if(ctxt->headtype == Hnacl) {
+		nacladdr(ctxt, p, &p->from);
+		nacladdr(ctxt, p, &p->to);
+	}
+
+	// Maintain information about code generation mode.
+	if(ctxt->mode == 0)
+		ctxt->mode = 64;
+	p->mode = ctxt->mode;
+	
+	switch(p->as) {
+	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:
+				ctxt->mode = p->from.offset;
+				break;
+			}
+		}
+		nopout(p);
+		break;
+	}
+	
+	// Rewrite CALL/JMP/RET to symbol as D_BRANCH.
+	switch(p->as) {
+	case ACALL:
+	case AJMP:
+	case ARET:
+		if((p->to.type == D_EXTERN || p->to.type == D_STATIC) && p->to.sym != nil)
+			p->to.type = D_BRANCH;
+		break;
+	}
+
+	// Rewrite float constants to values stored in memory.
+	switch(p->as) {
+	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(p->from.type == D_FCONST) {
+			int32 i32;
+			float32 f32;
+			f32 = p->from.u.dval;
+			memmove(&i32, &f32, 4);
+			sprint(literal, "$f32.%08ux", (uint32)i32);
+			s = linklookup(ctxt, literal, 0);
+			if(s->type == 0) {
+				s->type = SRODATA;
+				adduint32(ctxt, s, i32);
+				s->reachable = 0;
+			}
+			p->from.type = D_EXTERN;
+			p->from.sym = s;
+			p->from.offset = 0;
+		}
+		break;
+	
+	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(p->from.type == D_FCONST) {
+			int64 i64;
+			memmove(&i64, &p->from.u.dval, 8);
+			sprint(literal, "$f64.%016llux", (uvlong)i64);
+			s = linklookup(ctxt, literal, 0);
+			if(s->type == 0) {
+				s->type = SRODATA;
+				adduint64(ctxt, s, i64);
+				s->reachable = 0;
+			}
+			p->from.type = D_EXTERN;
+			p->from.sym = s;
+			p->from.offset = 0;
+		}
+		break;
+	}
+}
+
+static void
+nacladdr(Link *ctxt, Prog *p, Addr *a)
+{
+	if(p->as == ALEAL || p->as == ALEAQ)
+		return;
+	
+	if(a->type == D_BP || a->type == D_INDIR+D_BP) {
+		ctxt->diag("invalid address: %P", p);
+		return;
+	}
+	if(a->type == D_INDIR+D_TLS)
+		a->type = D_INDIR+D_BP;
+	else if(a->type == D_TLS)
+		a->type = D_BP;
+	if(D_INDIR <= a->type && a->type <= D_INDIR+D_INDIR) {
+		switch(a->type) {
+		case D_INDIR+D_BP:
+		case D_INDIR+D_SP:
+		case D_INDIR+D_R15:
+			// all ok
+			break;
+		default:
+			if(a->index != D_NONE)
+				ctxt->diag("invalid address %P", p);
+			a->index = a->type - D_INDIR;
+			if(a->index != D_NONE)
+				a->scale = 1;
+			a->type = D_INDIR+D_R15;
+			break;
+		}
+	}
+}
+
+static char*
+morename[] =
+{
+	"runtime.morestack00",
+	"runtime.morestack00_noctxt",
+	"runtime.morestack10",
+	"runtime.morestack10_noctxt",
+	"runtime.morestack01",
+	"runtime.morestack01_noctxt",
+	"runtime.morestack11",
+	"runtime.morestack11_noctxt",
+
+	"runtime.morestack8",
+	"runtime.morestack8_noctxt",
+	"runtime.morestack16",
+	"runtime.morestack16_noctxt",
+	"runtime.morestack24",
+	"runtime.morestack24_noctxt",
+	"runtime.morestack32",
+	"runtime.morestack32_noctxt",
+	"runtime.morestack40",
+	"runtime.morestack40_noctxt",
+	"runtime.morestack48",
+	"runtime.morestack48_noctxt",
+};
+
+static Prog*	load_g_cx(Link*, Prog*);
+static Prog*	stacksplit(Link*, Prog*, int32, int32, int, Prog**);
+static void	indir_cx(Link*, Addr*);
+
+static void
+parsetextconst(vlong arg, vlong *textstksiz, vlong *textarg)
+{
+	*textstksiz = arg & 0xffffffffLL;
+	if(*textstksiz & 0x80000000LL)
+		*textstksiz = -(-*textstksiz & 0xffffffffLL);
+
+	*textarg = (arg >> 32) & 0xffffffffLL;
+	if(*textarg & 0x80000000LL)
+		*textarg = 0;
+	*textarg = (*textarg+7) & ~7LL;
+}
+
+static void
+addstacksplit(Link *ctxt, LSym *cursym)
+{
+	Prog *p, *q, *q1;
+	int32 autoffset, deltasp;
+	int a, pcsize;
+	uint32 i;
+	vlong textstksiz, textarg;
+
+	if(ctxt->gmsym == nil)
+		ctxt->gmsym = linklookup(ctxt, "runtime.tlsgm", 0);
+	if(ctxt->symmorestack[0] == nil) {
+		if(nelem(morename) > nelem(ctxt->symmorestack))
+			sysfatal("Link.symmorestack needs at least %d elements", nelem(morename));
+		for(i=0; i<nelem(morename); i++)
+			ctxt->symmorestack[i] = linklookup(ctxt, morename[i], 0);
+	}
+	ctxt->cursym = cursym;
+
+	if(cursym->text == nil || cursym->text->link == nil)
+		return;				
+
+	p = cursym->text;
+	parsetextconst(p->to.offset, &textstksiz, &textarg);
+	autoffset = textstksiz;
+	if(autoffset < 0)
+		autoffset = 0;
+	
+	cursym->args = p->to.offset>>32;
+	cursym->locals = textstksiz;
+
+	if(autoffset < StackSmall && !(p->from.scale & NOSPLIT)) {
+		for(q = p; q != nil; q = q->link) {
+			if(q->as == ACALL)
+				goto noleaf;
+			if((q->as == ADUFFCOPY || q->as == ADUFFZERO) && autoffset >= StackSmall - 8)
+				goto noleaf;
+		}
+		p->from.scale |= NOSPLIT;
+	noleaf:;
+	}
+
+	q = nil;
+	if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
+		p = appendp(ctxt, p);
+		p = load_g_cx(ctxt, p); // load g into CX
+	}
+	if(!(cursym->text->from.scale & NOSPLIT))
+		p = stacksplit(ctxt, p, autoffset, textarg, !(cursym->text->from.scale&NEEDCTXT), &q); // emit split check
+
+	if(autoffset) {
+		if(autoffset%ctxt->arch->regsize != 0)
+			ctxt->diag("unaligned stack size %d", autoffset);
+		p = appendp(ctxt, 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(ctxt, p);
+		p->as = ANOP;
+		p->spadj = -ctxt->arch->ptrsize;
+		p = appendp(ctxt, p);
+		p->as = ANOP;
+		p->spadj = ctxt->arch->ptrsize;
+	}
+	if(q != nil)
+		q->pcond = p;
+	deltasp = autoffset;
+	
+	if(cursym->text->from.scale & WRAPPER) {
+		// g->panicwrap += autoffset + ctxt->arch->regsize;
+		p = appendp(ctxt, p);
+		p->as = AADDL;
+		p->from.type = D_CONST;
+		p->from.offset = autoffset + ctxt->arch->regsize;
+		indir_cx(ctxt, &p->to);
+		p->to.offset = 2*ctxt->arch->ptrsize;
+	}
+
+	if(ctxt->debugstack > 1 && autoffset) {
+		// 6l -K -K means double-check for stack overflow
+		// even after calling morestack and even if the
+		// function is marked as nosplit.
+		p = appendp(ctxt, p);
+		p->as = AMOVQ;
+		indir_cx(ctxt, &p->from);
+		p->from.offset = 0;
+		p->to.type = D_BX;
+
+		p = appendp(ctxt, p);
+		p->as = ASUBQ;
+		p->from.type = D_CONST;
+		p->from.offset = StackSmall+32;
+		p->to.type = D_BX;
+
+		p = appendp(ctxt, p);
+		p->as = ACMPQ;
+		p->from.type = D_SP;
+		p->to.type = D_BX;
+
+		p = appendp(ctxt, p);
+		p->as = AJHI;
+		p->to.type = D_BRANCH;
+		q1 = p;
+
+		p = appendp(ctxt, p);
+		p->as = AINT;
+		p->from.type = D_CONST;
+		p->from.offset = 3;
+
+		p = appendp(ctxt, p);
+		p->as = ANOP;
+		q1->pcond = p;
+	}
+	
+	if(ctxt->debugzerostack && 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(ctxt, p);
+		p->as = AMOVQ;
+		p->from.type = D_SP;
+		p->to.type = D_DI;
+		
+		p = appendp(ctxt, p);
+		p->as = AMOVQ;
+		p->from.type = D_CONST;
+		p->from.offset = autoffset/8;
+		p->to.type = D_CX;
+		
+		p = appendp(ctxt, p);
+		p->as = AMOVQ;
+		p->from.type = D_CONST;
+		p->from.offset = 0;
+		p->to.type = D_AX;
+		
+		p = appendp(ctxt, p);
+		p->as = AREP;
+		
+		p = appendp(ctxt, p);
+		p->as = ASTOSQ;
+	}
+	
+	for(; p != nil; 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)
+			ctxt->diag("unbalanced PUSH/POP");
+
+		if(cursym->text->from.scale & WRAPPER) {
+			p = load_g_cx(ctxt, p);
+			p = appendp(ctxt, p);
+			// g->panicwrap -= autoffset + ctxt->arch->regsize;
+			p->as = ASUBL;
+			p->from.type = D_CONST;
+			p->from.offset = autoffset + ctxt->arch->regsize;
+			indir_cx(ctxt, &p->to);
+			p->to.offset = 2*ctxt->arch->ptrsize;
+			p = appendp(ctxt, p);
+			p->as = ARET;
+		}
+
+		if(autoffset) {
+			p->as = AADJSP;
+			p->from.type = D_CONST;
+			p->from.offset = -autoffset;
+			p->spadj = -autoffset;
+			p = appendp(ctxt, 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;
+	}
+}
+
+static void
+indir_cx(Link *ctxt, Addr *a)
+{
+	if(ctxt->headtype == Hnacl) {
+		a->type = D_INDIR + D_R15;
+		a->index = D_CX;
+		a->scale = 1;
+		return;
+	}
+
+	a->type = D_INDIR+D_CX;
+}
+
+// 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(Link *ctxt, Prog *p)
+{	
+	Prog *next;
+
+	p->as = AMOVQ;
+	if(ctxt->arch->ptrsize == 4)
+		p->as = AMOVL;
+	p->from.type = D_INDIR+D_TLS;
+	p->from.offset = 0;
+	p->to.type = D_CX;
+	
+	next = p->link;
+	progedit(ctxt, p);
+	while(p->link != next)
+		p = p->link;
+	
+	if(p->from.index == D_TLS)
+		p->from.scale = 2;
+
+	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(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog **jmpok)
+{
+	Prog *q, *q1;
+	uint32 moreconst1, moreconst2, i;
+	int cmp, lea, mov, sub;
+
+	cmp = ACMPQ;
+	lea = ALEAQ;
+	mov = AMOVQ;
+	sub = ASUBQ;
+
+	if(ctxt->headtype == Hnacl) {
+		cmp = ACMPL;
+		lea = ALEAL;
+		mov = AMOVL;
+		sub = ASUBL;
+	}
+
+	if(ctxt->debugstack) {
+		// 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(ctxt, p);
+		p->as = cmp;
+		indir_cx(ctxt, &p->from);
+		p->from.offset = 8;
+		p->to.type = D_SP;
+
+		p = appendp(ctxt, p);
+		p->as = AJHI;
+		p->to.type = D_BRANCH;
+		p->to.offset = 4;
+		q1 = p;
+
+		p = appendp(ctxt, p);
+		p->as = AINT;
+		p->from.type = D_CONST;
+		p->from.offset = 3;
+
+		p = appendp(ctxt, p);
+		p->as = ANOP;
+		q1->pcond = p;
+	}
+
+	q1 = nil;
+	if(framesize <= StackSmall) {
+		// small stack: SP <= stackguard
+		//	CMPQ SP, stackguard
+		p = appendp(ctxt, p);
+		p->as = cmp;
+		p->from.type = D_SP;
+		indir_cx(ctxt, &p->to);
+	} else if(framesize <= StackBig) {
+		// large stack: SP-framesize <= stackguard-StackSmall
+		//	LEAQ -xxx(SP), AX
+		//	CMPQ AX, stackguard
+		p = appendp(ctxt, p);
+		p->as = lea;
+		p->from.type = D_INDIR+D_SP;
+		p->from.offset = -(framesize-StackSmall);
+		p->to.type = D_AX;
+
+		p = appendp(ctxt, p);
+		p->as = cmp;
+		p->from.type = D_AX;
+		indir_cx(ctxt, &p->to);
+	} 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(ctxt, p);
+		p->as = mov;
+		indir_cx(ctxt, &p->from);
+		p->from.offset = 0;
+		p->to.type = D_SI;
+
+		p = appendp(ctxt, p);
+		p->as = cmp;
+		p->from.type = D_SI;
+		p->to.type = D_CONST;
+		p->to.offset = StackPreempt;
+
+		p = appendp(ctxt, p);
+		p->as = AJEQ;
+		p->to.type = D_BRANCH;
+		q1 = p;
+
+		p = appendp(ctxt, p);
+		p->as = lea;
+		p->from.type = D_INDIR+D_SP;
+		p->from.offset = StackGuard;
+		p->to.type = D_AX;
+		
+		p = appendp(ctxt, p);
+		p->as = sub;
+		p->from.type = D_SI;
+		p->to.type = D_AX;
+		
+		p = appendp(ctxt, p);
+		p->as = cmp;
+		p->from.type = D_AX;
+		p->to.type = D_CONST;
+		p->to.offset = framesize+(StackGuard-StackSmall);
+	}					
+
+	// common
+	p = appendp(ctxt, 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 + ctxt->arch->ptrsize + framesize + ctxt->arch->ptrsize + StackLimit >= StackMin)
+		moreconst1 = framesize;
+	moreconst2 = textarg;
+	if(moreconst2 == 1) // special marker
+		moreconst2 = 0;
+	if((moreconst2&7) != 0)
+		ctxt->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(ctxt, p);
+	if(moreconst1 == 0 && moreconst2 == 0) {
+		p->as = ACALL;
+		p->to.type = D_BRANCH;
+		p->to.sym = ctxt->symmorestack[0*2+noctxt];
+	} 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(ctxt, p);
+		p->as = ACALL;
+		p->to.type = D_BRANCH;
+		p->to.sym = ctxt->symmorestack[1*2+noctxt];
+	} else
+	if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) {
+		i = moreconst2/8 + 3;
+		p->as = ACALL;
+		p->to.type = D_BRANCH;
+		p->to.sym = ctxt->symmorestack[i*2+noctxt];
+	} 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(ctxt, p);
+		p->as = ACALL;
+		p->to.type = D_BRANCH;
+		p->to.sym = ctxt->symmorestack[2*2+noctxt];
+	} else {
+		// Pass framesize and argsize.
+		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(ctxt, p);
+		p->as = ACALL;
+		p->to.type = D_BRANCH;
+		p->to.sym = ctxt->symmorestack[3*2+noctxt];
+	}
+	
+	p = appendp(ctxt, p);
+	p->as = AJMP;
+	p->to.type = D_BRANCH;
+	p->pcond = ctxt->cursym->text->link;
+	
+	if(q != nil)
+		q->pcond = p->link;
+	if(q1 != nil)
+		q1->pcond = q->link;
+
+	*jmpok = q;
+	return p;
+}
+
+static void xfol(Link*, Prog*, Prog**);
+
+static void
+follow(Link *ctxt, LSym *s)
+{
+	Prog *firstp, *lastp;
+
+	ctxt->cursym = s;
+
+	firstp = ctxt->arch->prg();
+	lastp = firstp;
+	xfol(ctxt, s->text, &lastp);
+	lastp->link = nil;
+	s->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 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;
+	}
+	sysfatal("unknown relation: %s", anames6[a]);
+	return 0;
+}
+
+static void
+xfol(Link *ctxt, Prog *p, Prog **last)
+{
+	Prog *q;
+	int i;
+	enum as a;
+
+loop:
+	if(p == nil)
+		return;
+	if(p->as == AJMP)
+	if((q = p->pcond) != nil && 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 == nil)
+				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 == nil || q->pcond->mark)
+				continue;
+			if(a == ACALL || a == ALOOP)
+				continue;
+			for(;;) {
+				if(p->as == ANOP) {
+					p = p->link;
+					continue;
+				}
+				q = copyp(ctxt, p);
+				p = p->link;
+				q->mark = 1;
+				(*last)->link = q;
+				*last = q;
+				if(q->as != a || q->pcond == nil || q->pcond->mark)
+					continue;
+
+				q->as = relinv(q->as);
+				p = q->pcond;
+				q->pcond = q->link;
+				q->link = p;
+				xfol(ctxt, q->link, last);
+				p = q->link;
+				if(p->mark)
+					return;
+				goto loop;
+			}
+		} /* */
+		q = ctxt->arch->prg();
+		q->as = AJMP;
+		q->lineno = p->lineno;
+		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 != nil && a != ACALL) {
+		/*
+		 * some kind of conditional branch.
+		 * recurse to follow one path.
+		 * continue loop on the other.
+		 */
+		if((q = brchain(ctxt, p->pcond)) != nil)
+			p->pcond = q;
+		if((q = brchain(ctxt, p->link)) != nil)
+			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(ctxt, p->link, last);
+		if(p->pcond->mark)
+			return;
+		p = p->pcond;
+		goto loop;
+	}
+	p = p->link;
+	goto loop;
+}
+
+static Prog*
+prg(void)
+{
+	Prog *p;
+
+	p = emallocz(sizeof(*p));
+	*p = zprg;
+	return p;
+}
+
+LinkArch linkamd64 = {
+	.name = "amd64",
+	.thechar = '6',
+
+	.addstacksplit = addstacksplit,
+	.assemble = span6,
+	.datasize = datasize,
+	.follow = follow,
+	.iscall = iscall,
+	.isdata = isdata,
+	.prg = prg,
+	.progedit = progedit,
+	.settextflag = settextflag,
+	.symtype = symtype,
+	.textflag = textflag,
+
+	.minlc = 1,
+	.ptrsize = 8,
+	.regsize = 8,
+
+	.D_ADDR = D_ADDR,
+	.D_AUTO = D_AUTO,
+	.D_BRANCH = D_BRANCH,
+	.D_CONST = D_CONST,
+	.D_EXTERN = D_EXTERN,
+	.D_FCONST = D_FCONST,
+	.D_NONE = D_NONE,
+	.D_PARAM = D_PARAM,
+	.D_SCONST = D_SCONST,
+	.D_STATIC = D_STATIC,
+
+	.ACALL = ACALL,
+	.ADATA = ADATA,
+	.AEND = AEND,
+	.AFUNCDATA = AFUNCDATA,
+	.AGLOBL = AGLOBL,
+	.AJMP = AJMP,
+	.ANOP = ANOP,
+	.APCDATA = APCDATA,
+	.ARET = ARET,
+	.ATEXT = ATEXT,
+	.ATYPE = ATYPE,
+	.AUSEFIELD = AUSEFIELD,
+};
+
+LinkArch linkamd64p32 = {
+	.name = "amd64p32",
+	.thechar = '6',
+
+	.addstacksplit = addstacksplit,
+	.assemble = span6,
+	.datasize = datasize,
+	.follow = follow,
+	.iscall = iscall,
+	.isdata = isdata,
+	.prg = prg,
+	.progedit = progedit,
+	.settextflag = settextflag,
+	.symtype = symtype,
+	.textflag = textflag,
+
+	.minlc = 1,
+	.ptrsize = 4,
+	.regsize = 8,
+
+	.D_ADDR = D_ADDR,
+	.D_AUTO = D_AUTO,
+	.D_BRANCH = D_BRANCH,
+	.D_CONST = D_CONST,
+	.D_EXTERN = D_EXTERN,
+	.D_FCONST = D_FCONST,
+	.D_NONE = D_NONE,
+	.D_PARAM = D_PARAM,
+	.D_SCONST = D_SCONST,
+	.D_STATIC = D_STATIC,
+
+	.ACALL = ACALL,
+	.ADATA = ADATA,
+	.AEND = AEND,
+	.AFUNCDATA = AFUNCDATA,
+	.AGLOBL = AGLOBL,
+	.AJMP = AJMP,
+	.ANOP = ANOP,
+	.APCDATA = APCDATA,
+	.ARET = ARET,
+	.ATEXT = ATEXT,
+	.ATYPE = ATYPE,
+	.AUSEFIELD = AUSEFIELD,
+};
diff --git a/src/liblink/obj8.c b/src/liblink/obj8.c
new file mode 100644
index 0000000..72934c1
--- /dev/null
+++ b/src/liblink/obj8.c
@@ -0,0 +1,859 @@
+// 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 at 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 at 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/8l/8.out.h"
+#include "../pkg/runtime/stack.h"
+
+static Prog zprg = {
+	.back = 2,
+	.as = AGOK,
+	.from = {
+		.type = D_NONE,
+		.index = D_NONE,
+		.scale = 1,
+	},
+	.to = {
+		.type = D_NONE,
+		.index = D_NONE,
+		.scale = 1,
+	},
+};
+
+static int
+symtype(Addr *a)
+{
+	int t;
+
+	t = a->type;
+	if(t == D_ADDR)
+		t = a->index;
+	return t;
+}
+
+static int
+isdata(Prog *p)
+{
+	return p->as == ADATA || p->as == AGLOBL;
+}
+
+static int
+iscall(Prog *p)
+{
+	return p->as == ACALL;
+}
+
+static int
+datasize(Prog *p)
+{
+	return p->from.scale;
+}
+
+static int
+textflag(Prog *p)
+{
+	return p->from.scale;
+}
+
+static void
+settextflag(Prog *p, int f)
+{
+	p->from.scale = f;
+}
+
+static int
+canuselocaltls(Link *ctxt)
+{
+	switch(ctxt->headtype) {
+	case Hlinux:
+	case Hnacl:
+	case Hplan9:
+	case Hwindows:
+		return 0;
+	}
+	return 1;
+}
+
+static void
+progedit(Link *ctxt, Prog *p)
+{
+	char literal[64];
+	LSym *s;
+	Prog *q;
+	
+	// See obj6.c for discussion of TLS.
+	if(canuselocaltls(ctxt)) {
+		// Reduce TLS initial exec model to TLS local exec model.
+		// Sequences like
+		//	MOVL TLS, BX
+		//	... off(BX)(TLS*1) ...
+		// become
+		//	NOP
+		//	... off(TLS) ...
+		if(p->as == AMOVL && p->from.type == D_TLS && D_AX <= p->to.type && p->to.type <= D_DI) {
+			p->as = ANOP;
+			p->from.type = D_NONE;
+			p->to.type = D_NONE;
+		}
+		if(p->from.index == D_TLS && D_INDIR+D_AX <= p->from.type && p->from.type <= D_INDIR+D_DI) {
+			p->from.type = D_INDIR+D_TLS;
+			p->from.scale = 0;
+			p->from.index = D_NONE;
+		}
+		if(p->to.index == D_TLS && D_INDIR+D_AX <= p->to.type && p->to.type <= D_INDIR+D_DI) {
+			p->to.type = D_INDIR+D_TLS;
+			p->to.scale = 0;
+			p->to.index = D_NONE;
+		}
+	} else {
+		// As a courtesy to the C compilers, rewrite TLS local exec load as TLS initial exec load.
+		// The instruction
+		//	MOVL off(TLS), BX
+		// becomes the sequence
+		//	MOVL TLS, BX
+		//	MOVL off(BX)(TLS*1), BX
+		// This allows the C compilers to emit references to m and g using the direct off(TLS) form.
+		if(p->as == AMOVL && p->from.type == D_INDIR+D_TLS && D_AX <= p->to.type && p->to.type <= D_DI) {
+			q = appendp(ctxt, p);
+			q->as = p->as;
+			q->from = p->from;
+			q->from.type = D_INDIR + p->to.type;
+			q->from.index = D_TLS;
+			q->from.scale = 2; // TODO: use 1
+			q->to = p->to;
+			p->from.type = D_TLS;
+			p->from.index = D_NONE;
+			p->from.offset = 0;
+		}
+	}
+
+	// TODO: Remove.
+	if(ctxt->headtype == Hplan9) {
+		if(p->from.scale == 1 && p->from.index == D_TLS)
+			p->from.scale = 2;
+		if(p->to.scale == 1 && p->to.index == D_TLS)
+			p->to.scale = 2;
+	}
+
+	// Rewrite CALL/JMP/RET to symbol as D_BRANCH.
+	switch(p->as) {
+	case ACALL:
+	case AJMP:
+	case ARET:
+		if((p->to.type == D_EXTERN || p->to.type == D_STATIC) && p->to.sym != nil)
+			p->to.type = D_BRANCH;
+		break;
+	}
+
+	// Rewrite float constants to values stored in memory.
+	switch(p->as) {
+	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(p->from.type == D_FCONST) {
+			int32 i32;
+			float32 f32;
+			f32 = p->from.u.dval;
+			memmove(&i32, &f32, 4);
+			sprint(literal, "$f32.%08ux", (uint32)i32);
+			s = linklookup(ctxt, literal, 0);
+			if(s->type == 0) {
+				s->type = SRODATA;
+				adduint32(ctxt, s, i32);
+				s->reachable = 0;
+			}
+			p->from.type = D_EXTERN;
+			p->from.sym = s;
+			p->from.offset = 0;
+		}
+		break;
+
+	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(p->from.type == D_FCONST) {
+			int64 i64;
+			memmove(&i64, &p->from.u.dval, 8);
+			sprint(literal, "$f64.%016llux", (uvlong)i64);
+			s = linklookup(ctxt, literal, 0);
+			if(s->type == 0) {
+				s->type = SRODATA;
+				adduint64(ctxt, s, i64);
+				s->reachable = 0;
+			}
+			p->from.type = D_EXTERN;
+			p->from.sym = s;
+			p->from.offset = 0;
+		}
+		break;
+	}
+}
+
+static Prog*
+prg(void)
+{
+	Prog *p;
+
+	p = emallocz(sizeof(*p));
+	*p = zprg;
+	return p;
+}
+
+static Prog*	load_g_cx(Link*, Prog*);
+static Prog*	stacksplit(Link*, Prog*, int32, int, Prog**);
+
+static void
+addstacksplit(Link *ctxt, LSym *cursym)
+{
+	Prog *p, *q;
+	int32 autoffset, deltasp;
+	int a;
+
+	if(ctxt->symmorestack[0] == nil) {
+		ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
+		ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0);
+	}
+
+	if(ctxt->headtype == Hplan9 && ctxt->plan9tos == nil)
+		ctxt->plan9tos = linklookup(ctxt, "_tos", 0);
+
+	ctxt->cursym = cursym;
+
+	if(cursym->text == nil || cursym->text->link == nil)
+		return;
+
+	p = cursym->text;
+	autoffset = p->to.offset;
+	if(autoffset < 0)
+		autoffset = 0;
+	
+	cursym->locals = autoffset;
+	cursym->args = p->to.offset2;
+
+	q = nil;
+
+	if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
+		p = appendp(ctxt, p);
+		p = load_g_cx(ctxt, p); // load g into CX
+	}
+	if(!(cursym->text->from.scale & NOSPLIT))
+		p = stacksplit(ctxt, p, autoffset, !(cursym->text->from.scale&NEEDCTXT), &q); // emit split check
+
+	if(autoffset) {
+		p = appendp(ctxt, 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(ctxt, p);
+		p->as = ANOP;
+		p->spadj = -ctxt->arch->ptrsize;
+		p = appendp(ctxt, p);
+		p->as = ANOP;
+		p->spadj = ctxt->arch->ptrsize;
+	}
+	if(q != nil)
+		q->pcond = p;
+	deltasp = autoffset;
+	
+	if(cursym->text->from.scale & WRAPPER) {
+		// g->panicwrap += autoffset + ctxt->arch->ptrsize;
+		p = appendp(ctxt, p);
+		p->as = AADDL;
+		p->from.type = D_CONST;
+		p->from.offset = autoffset + ctxt->arch->ptrsize;
+		p->to.type = D_INDIR+D_CX;
+		p->to.offset = 2*ctxt->arch->ptrsize;
+	}
+	
+	if(ctxt->debugzerostack && 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(ctxt, p);
+		p->as = AMOVL;
+		p->from.type = D_SP;
+		p->to.type = D_DI;
+		
+		p = appendp(ctxt, p);
+		p->as = AMOVL;
+		p->from.type = D_CONST;
+		p->from.offset = autoffset/4;
+		p->to.type = D_CX;
+		
+		p = appendp(ctxt, p);
+		p->as = AMOVL;
+		p->from.type = D_CONST;
+		p->from.offset = 0;
+		p->to.type = D_AX;
+		
+		p = appendp(ctxt, p);
+		p->as = AREP;
+		
+		p = appendp(ctxt, p);
+		p->as = ASTOSL;
+	}
+	
+	for(; p != nil; 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)
+			ctxt->diag("unbalanced PUSH/POP");
+
+		if(cursym->text->from.scale & WRAPPER) {
+			p = load_g_cx(ctxt, p);
+			p = appendp(ctxt, p);
+			// g->panicwrap -= autoffset + ctxt->arch->ptrsize;
+			p->as = ASUBL;
+			p->from.type = D_CONST;
+			p->from.offset = autoffset + ctxt->arch->ptrsize;
+			p->to.type = D_INDIR+D_CX;
+			p->to.offset = 2*ctxt->arch->ptrsize;
+			p = appendp(ctxt, p);
+			p->as = ARET;
+		}
+
+		if(autoffset) {
+			p->as = AADJSP;
+			p->from.type = D_CONST;
+			p->from.offset = -autoffset;
+			p->spadj = -autoffset;
+			p = appendp(ctxt, 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(Link *ctxt, Prog *p)
+{
+	Prog *next;
+
+	p->as = AMOVL;
+	p->from.type = D_INDIR+D_TLS;
+	p->from.offset = 0;
+	p->to.type = D_CX;
+
+	next = p->link;
+	progedit(ctxt, p);
+	while(p->link != next)
+		p = p->link;
+	
+	if(p->from.index == D_TLS)
+		p->from.scale = 2;
+
+	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(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok)
+{
+	Prog *q, *q1;
+	int arg;
+
+	if(ctxt->debugstack) {
+		// 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(ctxt, p);
+		p->as = ACMPL;
+		p->from.type = D_INDIR+D_CX;
+		p->from.offset = 4;
+		p->to.type = D_SP;
+
+		p = appendp(ctxt, p);
+		p->as = AJCC;
+		p->to.type = D_BRANCH;
+		p->to.offset = 4;
+		q1 = p;
+
+		p = appendp(ctxt, p);
+		p->as = AINT;
+		p->from.type = D_CONST;
+		p->from.offset = 3;
+		
+		p = appendp(ctxt, p);
+		p->as = ANOP;
+		q1->pcond = p;
+	}
+	q1 = nil;
+
+	if(framesize <= StackSmall) {
+		// small stack: SP <= stackguard
+		//	CMPL SP, stackguard
+		p = appendp(ctxt, 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(ctxt, p);
+		p->as = ALEAL;
+		p->from.type = D_INDIR+D_SP;
+		p->from.offset = -(framesize-StackSmall);
+		p->to.type = D_AX;
+
+		p = appendp(ctxt, 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(ctxt, p);
+		p->as = AMOVL;
+		p->from.type = D_INDIR+D_CX;
+		p->from.offset = 0;
+		p->to.type = D_SI;
+
+		p = appendp(ctxt, p);
+		p->as = ACMPL;
+		p->from.type = D_SI;
+		p->to.type = D_CONST;
+		p->to.offset = (uint32)StackPreempt;
+
+		p = appendp(ctxt, p);
+		p->as = AJEQ;
+		p->to.type = D_BRANCH;
+		q1 = p;
+
+		p = appendp(ctxt, p);
+		p->as = ALEAL;
+		p->from.type = D_INDIR+D_SP;
+		p->from.offset = StackGuard;
+		p->to.type = D_AX;
+		
+		p = appendp(ctxt, p);
+		p->as = ASUBL;
+		p->from.type = D_SI;
+		p->from.offset = 0;
+		p->to.type = D_AX;
+		
+		p = appendp(ctxt, p);
+		p->as = ACMPL;
+		p->from.type = D_AX;
+		p->to.type = D_CONST;
+		p->to.offset = framesize+(StackGuard-StackSmall);
+	}		
+			
+	// common
+	p = appendp(ctxt, p);
+	p->as = AJHI;
+	p->to.type = D_BRANCH;
+	p->to.offset = 4;
+	q = p;
+
+	p = appendp(ctxt, 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 + ctxt->cursym->text->to.offset2 + ctxt->arch->ptrsize + framesize + ctxt->arch->ptrsize + StackLimit >= StackMin)
+		p->from.offset = (framesize+7) & ~7LL;
+
+	arg = ctxt->cursym->text->to.offset2;
+	if(arg == 1) // special marker for known 0
+		arg = 0;
+	if(arg&3)
+		ctxt->diag("misaligned argument size in stack split");
+	p = appendp(ctxt, 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(ctxt, p);
+	p->as = ACALL;
+	p->to.type = D_BRANCH;
+	p->to.sym = ctxt->symmorestack[noctxt];
+
+	p = appendp(ctxt, p);
+	p->as = AJMP;
+	p->to.type = D_BRANCH;
+	p->pcond = ctxt->cursym->text->link;
+
+	if(q != nil)
+		q->pcond = p->link;
+	if(q1 != nil)
+		q1->pcond = q->link;
+	
+	*jmpok = q;
+	return p;
+}
+
+static void xfol(Link*, Prog*, Prog**);
+
+static void
+follow(Link *ctxt, LSym *s)
+{
+	Prog *firstp, *lastp;
+
+	ctxt->cursym = s;
+
+	firstp = ctxt->arch->prg();
+	lastp = firstp;
+	xfol(ctxt, s->text, &lastp);
+	lastp->link = nil;
+	s->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 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;
+	}
+	sysfatal("unknown relation: %s", anames8[a]);
+	return 0;
+}
+
+static void
+xfol(Link *ctxt, Prog *p, Prog **last)
+{
+	Prog *q;
+	int i;
+	enum as a;
+
+loop:
+	if(p == nil)
+		return;
+	if(p->as == AJMP)
+	if((q = p->pcond) != nil && 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 == nil)
+				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 == nil || q->pcond->mark)
+				continue;
+			if(a == ACALL || a == ALOOP)
+				continue;
+			for(;;) {
+				if(p->as == ANOP) {
+					p = p->link;
+					continue;
+				}
+				q = copyp(ctxt, p);
+				p = p->link;
+				q->mark = 1;
+				(*last)->link = q;
+				*last = q;
+				if(q->as != a || q->pcond == nil || q->pcond->mark)
+					continue;
+
+				q->as = relinv(q->as);
+				p = q->pcond;
+				q->pcond = q->link;
+				q->link = p;
+				xfol(ctxt, q->link, last);
+				p = q->link;
+				if(p->mark)
+					return;
+				goto loop;
+			}
+		} /* */
+		q = ctxt->arch->prg();
+		q->as = AJMP;
+		q->lineno = p->lineno;
+		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 != nil && a != ACALL) {
+		/*
+		 * some kind of conditional branch.
+		 * recurse to follow one path.
+		 * continue loop on the other.
+		 */
+		if((q = brchain(ctxt, p->pcond)) != nil)
+			p->pcond = q;
+		if((q = brchain(ctxt, p->link)) != nil)
+			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(ctxt, p->link, last);
+		if(p->pcond->mark)
+			return;
+		p = p->pcond;
+		goto loop;
+	}
+	p = p->link;
+	goto loop;
+}
+
+LinkArch link386 = {
+	.name = "386",
+	.thechar = '8',
+
+	.addstacksplit = addstacksplit,
+	.assemble = span8,
+	.datasize = datasize,
+	.follow = follow,
+	.iscall = iscall,
+	.isdata = isdata,
+	.prg = prg,
+	.progedit = progedit,
+	.settextflag = settextflag,
+	.symtype = symtype,
+	.textflag = textflag,
+
+	.minlc = 1,
+	.ptrsize = 4,
+	.regsize = 4,
+
+	.D_ADDR = D_ADDR,
+	.D_AUTO = D_AUTO,
+	.D_BRANCH = D_BRANCH,
+	.D_CONST = D_CONST,
+	.D_EXTERN = D_EXTERN,
+	.D_FCONST = D_FCONST,
+	.D_NONE = D_NONE,
+	.D_PARAM = D_PARAM,
+	.D_SCONST = D_SCONST,
+	.D_STATIC = D_STATIC,
+
+	.ACALL = ACALL,
+	.ADATA = ADATA,
+	.AEND = AEND,
+	.AFUNCDATA = AFUNCDATA,
+	.AGLOBL = AGLOBL,
+	.AJMP = AJMP,
+	.ANOP = ANOP,
+	.APCDATA = APCDATA,
+	.ARET = ARET,
+	.ATEXT = ATEXT,
+	.ATYPE = ATYPE,
+	.AUSEFIELD = AUSEFIELD,
+};
diff --git a/src/liblink/objfile.c b/src/liblink/objfile.c
new file mode 100644
index 0000000..610f879
--- /dev/null
+++ b/src/liblink/objfile.c
@@ -0,0 +1,746 @@
+// 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.
+
+// Writing and reading of Go object files.
+//
+// Originally, Go object files were Plan 9 object files, but no longer.
+// Now they are more like standard object files, in that each symbol is defined
+// by an associated memory image (bytes) and a list of relocations to apply
+// during linking. We do not (yet?) use a standard file format, however.
+// For now, the format is chosen to be as simple as possible to read and write.
+// It may change for reasons of efficiency, or we may even switch to a
+// standard file format if there are compelling benefits to doing so.
+// See golang.org/s/go13linker for more background.
+//
+// The file format is:
+//
+//	- magic header: "\x00\x00go13ld"
+//	- byte 1 - version number
+//	- sequence of strings giving dependencies (imported packages)
+//	- empty string (marks end of sequence)
+//	- sequence of defined symbols
+//	- byte 0xff (marks end of sequence)
+//	- magic footer: "\xff\xffgo13ld"
+//
+// All integers are stored in a zigzag varint format.
+// See golang.org/s/go12symtab for a definition.
+//
+// Data blocks and strings are both stored as an integer
+// followed by that many bytes.
+//
+// A symbol reference is a string name followed by a version.
+// An empty name corresponds to a nil LSym* pointer.
+//
+// Each symbol is laid out as the following fields (taken from LSym*):
+//
+//	- byte 0xfe (sanity check for synchronization)
+//	- type [int]
+//	- name [string]
+//	- version [int]
+//	- dupok [int]
+//	- size [int]
+//	- gotype [symbol reference]
+//	- p [data block]
+//	- nr [int]
+//	- r [nr relocations, sorted by off]
+//
+// If type == STEXT, there are a few more fields:
+//
+//	- args [int]
+//	- locals [int]
+//	- nosplit [int]
+//	- leaf [int]
+//	- nlocal [int]
+//	- local [nlocal automatics]
+//	- pcln [pcln table]
+//
+// Each relocation has the encoding:
+//
+//	- off [int]
+//	- siz [int]
+//	- type [int]
+//	- add [int]
+//	- xadd [int]
+//	- sym [symbol reference]
+//	- xsym [symbol reference]
+//
+// Each local has the encoding:
+//
+//	- asym [symbol reference]
+//	- offset [int]
+//	- type [int]
+//	- gotype [symbol reference]
+//
+// The pcln table has the encoding:
+//
+//	- pcsp [data block]
+//	- pcfile [data block]
+//	- pcline [data block]
+//	- npcdata [int]
+//	- pcdata [npcdata data blocks]
+//	- nfuncdata [int]
+//	- funcdata [nfuncdata symbol references]
+//	- funcdatasym [nfuncdata ints]
+//	- nfile [int]
+//	- file [nfile symbol references]
+//
+// The file layout and meaning of type integers are architecture-independent.
+//
+// TODO(rsc): The file format is good for a first pass but needs work.
+//	- There are SymID in the object file that should really just be strings.
+//	- The actual symbol memory images are interlaced with the symbol
+//	  metadata. They should be separated, to reduce the I/O required to
+//	  load just the metadata.
+//	- The symbol references should be shortened, either with a symbol
+//	  table or by using a simple backward index to an earlier mentioned symbol.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+#include "../cmd/ld/textflag.h"
+
+static void writesym(Link*, Biobuf*, LSym*);
+static void wrint(Biobuf*, int64);
+static void wrstring(Biobuf*, char*);
+static void wrpath(Link *, Biobuf*, char*);
+static void wrdata(Biobuf*, void*, int);
+static void wrsym(Biobuf*, LSym*);
+static void wrpathsym(Link *ctxt, Biobuf *b, LSym *s);
+
+static void readsym(Link*, Biobuf*, char*, char*);
+static int64 rdint(Biobuf*);
+static char *rdstring(Biobuf*);
+static void rddata(Biobuf*, uchar**, int*);
+static LSym *rdsym(Link*, Biobuf*, char*);
+
+// The Go and C compilers, and the assembler, call writeobj to write
+// out a Go object file.  The linker does not call this; the linker
+// does not write out object files.
+void
+writeobj(Link *ctxt, Biobuf *b)
+{
+	int flag;
+	Hist *h;
+	LSym *s, *text, *etext, *curtext, *data, *edata;
+	Plist *pl;
+	Prog *p, *plink;
+	Auto *a;
+
+	// Build list of symbols, and assign instructions to lists.
+	// Ignore ctxt->plist boundaries. There are no guarantees there,
+	// and the C compilers and assemblers just use one big list.
+	text = nil;
+	curtext = nil;
+	data = nil;
+	etext = nil;
+	edata = nil;
+	for(pl = ctxt->plist; pl != nil; pl = pl->link) {
+		for(p = pl->firstpc; p != nil; p = plink) {
+			plink = p->link;
+			p->link = nil;
+
+			if(p->as == ctxt->arch->AEND)
+				continue;
+
+			if(p->as == ctxt->arch->ATYPE) {
+				// Assume each TYPE instruction describes
+				// a different local variable or parameter,
+				// so no dedup.
+				// Using only the TYPE instructions means
+				// that we discard location information about local variables
+				// in C and assembly functions; that information is inferred
+				// from ordinary references, because there are no TYPE
+				// instructions there. Without the type information, gdb can't
+				// use the locations, so we don't bother to save them.
+				// If something else could use them, we could arrange to
+				// preserve them.
+				if(curtext == nil)
+					continue;
+				a = emallocz(sizeof *a);
+				a->asym = p->from.sym;
+				a->aoffset = p->from.offset;
+				a->type = ctxt->arch->symtype(&p->from);
+				a->gotype = p->from.gotype;
+				a->link = curtext->autom;
+				curtext->autom = a;
+				continue;
+			}
+
+			if(p->as == ctxt->arch->AGLOBL) {
+				s = p->from.sym;
+				if(s->seenglobl++)
+					print("duplicate %P\n", p);
+				if(s->onlist)
+					sysfatal("symbol %s listed multiple times", s->name);
+				s->onlist = 1;
+				if(data == nil)
+					data = s;
+				else
+					edata->next = s;
+				s->next = nil;
+				s->size = p->to.offset;
+				if(s->type == 0 || s->type == SXREF)
+					s->type = SBSS;
+				
+				if(ctxt->arch->thechar == '5')
+					flag = p->reg;
+				else
+					flag = p->from.scale;
+					
+				if(flag & DUPOK)
+					s->dupok = 1;
+				if(flag & RODATA)
+					s->type = SRODATA;
+				else if(flag & NOPTR)
+					s->type = SNOPTRBSS;
+				edata = s;
+				continue;
+			}
+
+			if(p->as == ctxt->arch->ADATA) {
+				savedata(ctxt, p->from.sym, p, "<input>");
+				continue;
+			}
+
+			if(p->as == ctxt->arch->ATEXT) {
+				s = p->from.sym;
+				if(s == nil) {
+					// func _() { }
+					curtext = nil;
+					continue;
+				}
+				if(s->text != nil)
+					sysfatal("duplicate TEXT for %s", s->name);
+				if(s->onlist)
+					sysfatal("symbol %s listed multiple times", s->name);
+				s->onlist = 1;
+				if(text == nil)
+					text = s;
+				else
+					etext->next = s;
+				etext = s;
+				if(ctxt->arch->thechar == '5')
+					flag = p->reg;
+				else
+					flag = p->from.scale;
+				if(flag & DUPOK)
+					s->dupok = 1;
+				if(flag & NOSPLIT)
+					s->nosplit = 1;
+				s->next = nil;
+				s->type = STEXT;
+				s->text = p;
+				s->etext = p;
+				curtext = s;
+				continue;
+			}
+			
+			if(curtext == nil)
+				continue;
+			s = curtext;
+			s->etext->link = p;
+			s->etext = p;
+		}
+	}
+
+	// Turn functions into machine code images.
+	for(s = text; s != nil; s = s->next) {
+		mkfwd(s);
+		linkpatch(ctxt, s);
+		ctxt->arch->follow(ctxt, s);
+		ctxt->arch->addstacksplit(ctxt, s);
+		ctxt->arch->assemble(ctxt, s);
+		linkpcln(ctxt, s);
+	}
+
+	// Emit header.
+	Bputc(b, 0);
+	Bputc(b, 0);
+	Bprint(b, "go13ld");
+	Bputc(b, 1); // version
+
+	// Emit autolib.
+	for(h = ctxt->hist; h != nil; h = h->link)
+		if(h->offset < 0)
+			wrstring(b, h->name);
+	wrstring(b, "");
+
+	// Emit symbols.
+	for(s = text; s != nil; s = s->next)
+		writesym(ctxt, b, s);
+	for(s = data; s != nil; s = s->next)
+		writesym(ctxt, b, s);
+
+	// Emit footer.
+	Bputc(b, 0xff);
+	Bputc(b, 0xff);
+	Bprint(b, "go13ld");
+}
+
+static void
+writesym(Link *ctxt, Biobuf *b, LSym *s)
+{
+	Reloc *r;
+	int i, j, c, n;
+	Pcln *pc;
+	Prog *p;
+	Auto *a;
+	char *name;
+
+	if(ctxt->debugasm) {
+		Bprint(ctxt->bso, "%s ", s->name);
+		if(s->version)
+			Bprint(ctxt->bso, "v=%d ", s->version);
+		if(s->type)
+			Bprint(ctxt->bso, "t=%d ", s->type);
+		if(s->dupok)
+			Bprint(ctxt->bso, "dupok ");
+		if(s->nosplit)
+			Bprint(ctxt->bso, "nosplit ");
+		Bprint(ctxt->bso, "size=%lld value=%lld", (vlong)s->size, (vlong)s->value);
+		if(s->type == STEXT) {
+			Bprint(ctxt->bso, " args=%#llux locals=%#llux", (uvlong)s->args, (uvlong)s->locals);
+			if(s->leaf)
+				Bprint(ctxt->bso, " leaf");
+		}
+		Bprint(ctxt->bso, "\n");
+		for(p=s->text; p != nil; p = p->link)
+			Bprint(ctxt->bso, "\t%#06ux %P\n", (int)p->pc, p);
+		for(i=0; i<s->np; ) {
+			Bprint(ctxt->bso, "\t%#06ux", i);
+			for(j=i; j<i+16 && j<s->np; j++)
+				Bprint(ctxt->bso, " %02ux", s->p[j]);
+			for(; j<i+16; j++)
+				Bprint(ctxt->bso, "   ");
+			Bprint(ctxt->bso, "  ");
+			for(j=i; j<i+16 && j<s->np; j++) {
+				c = s->p[j];
+				if(' ' <= c && c <= 0x7e)
+					Bprint(ctxt->bso, "%c", c);
+				else
+					Bprint(ctxt->bso, ".");
+			}
+			Bprint(ctxt->bso, "\n");
+			i += 16;
+		}
+		for(i=0; i<s->nr; i++) {
+			r = &s->r[i];
+			name = "";
+			if(r->sym != nil)
+				name = r->sym->name;
+			Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%lld\n", (int)r->off, r->siz, r->type, name, (vlong)r->add);
+		}
+	}
+
+	Bputc(b, 0xfe);
+	wrint(b, s->type);
+	wrstring(b, s->name);
+	wrint(b, s->version);
+	wrint(b, s->dupok);
+	wrint(b, s->size);
+	wrsym(b, s->gotype);
+	wrdata(b, s->p, s->np);
+
+	wrint(b, s->nr);
+	for(i=0; i<s->nr; i++) {
+		r = &s->r[i];
+		wrint(b, r->off);
+		wrint(b, r->siz);
+		wrint(b, r->type);
+		wrint(b, r->add);
+		wrint(b, r->xadd);
+		wrsym(b, r->sym);
+		wrsym(b, r->xsym);
+	}
+	
+	if(s->type == STEXT) {
+		wrint(b, s->args);
+		wrint(b, s->locals);
+		wrint(b, s->nosplit);
+		wrint(b, s->leaf);
+		n = 0;
+		for(a = s->autom; a != nil; a = a->link)
+			n++;
+		wrint(b, n);
+		for(a = s->autom; a != nil; a = a->link) {
+			wrsym(b, a->asym);
+			wrint(b, a->aoffset);
+			if(a->type == ctxt->arch->D_AUTO)
+				wrint(b, A_AUTO);
+			else if(a->type == ctxt->arch->D_PARAM)
+				wrint(b, A_PARAM);
+			else
+				sysfatal("%s: invalid local variable type %d", s->name, a->type);
+			wrsym(b, a->gotype);
+		}
+
+		pc = s->pcln;
+		wrdata(b, pc->pcsp.p, pc->pcsp.n);
+		wrdata(b, pc->pcfile.p, pc->pcfile.n);
+		wrdata(b, pc->pcline.p, pc->pcline.n);
+		wrint(b, pc->npcdata);
+		for(i=0; i<pc->npcdata; i++)
+			wrdata(b, pc->pcdata[i].p, pc->pcdata[i].n);
+		wrint(b, pc->nfuncdata);
+		for(i=0; i<pc->nfuncdata; i++)
+			wrsym(b, pc->funcdata[i]);
+		for(i=0; i<pc->nfuncdata; i++)
+			wrint(b, pc->funcdataoff[i]);
+		wrint(b, pc->nfile);
+		for(i=0; i<pc->nfile; i++)
+			wrpathsym(ctxt, b, pc->file[i]);
+	}
+}
+
+static void
+wrint(Biobuf *b, int64 sval)
+{
+	uint64 uv, v;
+	uchar buf[10], *p;
+
+	uv = ((uint64)sval<<1) ^ (uint64)(int64)(sval>>63);
+
+	p = buf;
+	for(v = uv; v >= 0x80; v >>= 7)
+		*p++ = v | 0x80;
+	*p++ = v;
+	
+	Bwrite(b, buf, p - buf);
+}
+
+static void
+wrstring(Biobuf *b, char *s)
+{
+	wrdata(b, s, strlen(s));
+}
+
+// wrpath writes a path just like a string, but on windows, it
+// translates '\\' to '/' in the process.
+static void
+wrpath(Link *ctxt, Biobuf *b, char *p)
+{
+	int i, n;
+	if (!ctxt->windows || strchr(p, '\\') == nil) {
+		wrstring(b, p);
+		return;
+	} else {
+		n = strlen(p);
+		wrint(b, n);
+		for (i = 0; i < n; i++)
+			Bputc(b, p[i] == '\\' ? '/' : p[i]);
+	}
+}
+
+static void
+wrdata(Biobuf *b, void *v, int n)
+{
+	wrint(b, n);
+	Bwrite(b, v, n);
+}
+
+static void
+wrpathsym(Link *ctxt, Biobuf *b, LSym *s)
+{
+	if(s == nil) {
+		wrint(b, 0);
+		wrint(b, 0);
+		return;
+	}
+	wrpath(ctxt, b, s->name);
+	wrint(b, s->version);
+}
+
+static void
+wrsym(Biobuf *b, LSym *s)
+{
+	if(s == nil) {
+		wrint(b, 0);
+		wrint(b, 0);
+		return;
+	}
+	wrstring(b, s->name);
+	wrint(b, s->version);
+}
+
+static char startmagic[] = "\x00\x00go13ld";
+static char endmagic[] = "\xff\xffgo13ld";
+
+void
+ldobjfile(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn)
+{
+	int c;
+	uchar buf[8];
+	int64 start;
+	char *lib;
+
+	start = Boffset(f);
+	ctxt->version++;
+	memset(buf, 0, sizeof buf);
+	Bread(f, buf, sizeof buf);
+	if(memcmp(buf, startmagic, sizeof buf) != 0)
+		sysfatal("%s: invalid file start %x %x %x %x %x %x %x %x", pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+	if((c = Bgetc(f)) != 1)
+		sysfatal("%s: invalid file version number %d", pn, c);
+
+	for(;;) {
+		lib = rdstring(f);
+		if(lib[0] == 0)
+			break;
+		addlib(ctxt, pkg, pn, lib);
+	}
+	
+	for(;;) {
+		c = Bgetc(f);
+		Bungetc(f);
+		if(c == 0xff)
+			break;
+		readsym(ctxt, f, pkg, pn);
+	}
+	
+	memset(buf, 0, sizeof buf);
+	Bread(f, buf, sizeof buf);
+	if(memcmp(buf, endmagic, sizeof buf) != 0)
+		sysfatal("%s: invalid file end", pn);
+	
+	if(Boffset(f) != start+len)
+		sysfatal("%s: unexpected end at %lld, want %lld", pn, (vlong)Boffset(f), (vlong)(start+len));
+}
+
+static void
+readsym(Link *ctxt, Biobuf *f, char *pkg, char *pn)
+{
+	int i, j, c, t, v, n, size, dupok;
+	static int ndup;
+	char *name;
+	Reloc *r;
+	LSym *s, *dup;
+	Pcln *pc;
+	Auto *a;
+	
+	if(Bgetc(f) != 0xfe)
+		sysfatal("readsym out of sync");
+	t = rdint(f);
+	name = expandpkg(rdstring(f), pkg);
+	v = rdint(f);
+	if(v != 0 && v != 1)
+		sysfatal("invalid symbol version %d", v);
+	dupok = rdint(f);
+	size = rdint(f);
+	
+	if(v != 0)
+		v = ctxt->version;
+	s = linklookup(ctxt, name, v);
+	dup = nil;
+	if(s->type != 0 && s->type != SXREF) {
+		if(s->type != SBSS && s->type != SNOPTRBSS && !dupok && !s->dupok)
+			sysfatal("duplicate symbol %s (types %d and %d) in %s and %s", s->name, s->type, t, s->file, pn);
+		if(s->np > 0) {
+			dup = s;
+			s = linknewsym(ctxt, ".dup", ndup++); // scratch
+		}
+	}
+	s->file = pkg;
+	s->dupok = dupok;
+	if(t == SXREF)
+		sysfatal("bad sxref");
+	if(t == 0)
+		sysfatal("missing type for %s in %s", name, pn);
+	s->type = t;
+	if(s->size < size)
+		s->size = size;
+	s->gotype = rdsym(ctxt, f, pkg);
+	rddata(f, &s->p, &s->np);
+	s->maxp = s->np;
+	n = rdint(f);
+	if(n > 0) {
+		s->r = emallocz(n * sizeof s->r[0]);
+		s->nr = n;
+		s->maxr = n;
+		for(i=0; i<n; i++) {
+			r = &s->r[i];
+			r->off = rdint(f);
+			r->siz = rdint(f);
+			r->type = rdint(f);
+			r->add = rdint(f);
+			r->xadd = rdint(f);
+			r->sym = rdsym(ctxt, f, pkg);
+			r->xsym = rdsym(ctxt, f, pkg);
+		}
+	}
+	
+	if(s->np > 0 && dup != nil && dup->np > 0 && strncmp(s->name, "gclocals·", 10) == 0) {
+		// content-addressed garbage collection liveness bitmap symbol.
+		// double check for hash collisions.
+		if(s->np != dup->np || memcmp(s->p, dup->p, s->np) != 0)
+			sysfatal("dupok hash collision for %s in %s and %s", s->name, s->file, pn);
+	}
+	
+	if(s->type == STEXT) {
+		s->args = rdint(f);
+		s->locals = rdint(f);
+		s->nosplit = rdint(f);
+		s->leaf = rdint(f);
+		n = rdint(f);
+		for(i=0; i<n; i++) {
+			a = emallocz(sizeof *a);
+			a->asym = rdsym(ctxt, f, pkg);
+			a->aoffset = rdint(f);
+			a->type = rdint(f);
+			a->gotype = rdsym(ctxt, f, pkg);
+			a->link = s->autom;
+			s->autom = a;
+		}
+
+		s->pcln = emallocz(sizeof *s->pcln);
+		pc = s->pcln;
+		rddata(f, &pc->pcsp.p, &pc->pcsp.n);
+		rddata(f, &pc->pcfile.p, &pc->pcfile.n);
+		rddata(f, &pc->pcline.p, &pc->pcline.n);
+		n = rdint(f);
+		pc->pcdata = emallocz(n * sizeof pc->pcdata[0]);
+		pc->npcdata = n;
+		for(i=0; i<n; i++)
+			rddata(f, &pc->pcdata[i].p, &pc->pcdata[i].n);
+		n = rdint(f);
+		pc->funcdata = emallocz(n * sizeof pc->funcdata[0]);
+		pc->funcdataoff = emallocz(n * sizeof pc->funcdataoff[0]);
+		pc->nfuncdata = n;
+		for(i=0; i<n; i++)
+			pc->funcdata[i] = rdsym(ctxt, f, pkg);
+		for(i=0; i<n; i++)
+			pc->funcdataoff[i] = rdint(f);
+		n = rdint(f);
+		pc->file = emallocz(n * sizeof pc->file[0]);
+		pc->nfile = n;
+		for(i=0; i<n; i++)
+			pc->file[i] = rdsym(ctxt, f, pkg);
+
+		if(dup == nil) {
+			if(s->onlist)
+				sysfatal("symbol %s listed multiple times", s->name);
+			s->onlist = 1;
+			if(ctxt->etextp)
+				ctxt->etextp->next = s;
+			else
+				ctxt->textp = s;
+			ctxt->etextp = s;
+		}
+	}
+
+	if(ctxt->debugasm) {
+		Bprint(ctxt->bso, "%s ", s->name);
+		if(s->version)
+			Bprint(ctxt->bso, "v=%d ", s->version);
+		if(s->type)
+			Bprint(ctxt->bso, "t=%d ", s->type);
+		if(s->dupok)
+			Bprint(ctxt->bso, "dupok ");
+		if(s->nosplit)
+			Bprint(ctxt->bso, "nosplit ");
+		Bprint(ctxt->bso, "size=%lld value=%lld", (vlong)s->size, (vlong)s->value);
+		if(s->type == STEXT)
+			Bprint(ctxt->bso, " args=%#llux locals=%#llux", (uvlong)s->args, (uvlong)s->locals);
+		Bprint(ctxt->bso, "\n");
+		for(i=0; i<s->np; ) {
+			Bprint(ctxt->bso, "\t%#06ux", i);
+			for(j=i; j<i+16 && j<s->np; j++)
+				Bprint(ctxt->bso, " %02ux", s->p[j]);
+			for(; j<i+16; j++)
+				Bprint(ctxt->bso, "   ");
+			Bprint(ctxt->bso, "  ");
+			for(j=i; j<i+16 && j<s->np; j++) {
+				c = s->p[j];
+				if(' ' <= c && c <= 0x7e)
+					Bprint(ctxt->bso, "%c", c);
+				else
+					Bprint(ctxt->bso, ".");
+			}
+			Bprint(ctxt->bso, "\n");
+			i += 16;
+		}
+		for(i=0; i<s->nr; i++) {
+			r = &s->r[i];
+			Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%lld\n", (int)r->off, r->siz, r->type, r->sym->name, (vlong)r->add);
+		}
+	}
+}
+
+static int64
+rdint(Biobuf *f)
+{
+	int c;
+	uint64 uv;
+	int shift;
+	
+	uv = 0;
+	for(shift = 0;; shift += 7) {
+		if(shift >= 64)
+			sysfatal("corrupt input");
+		c = Bgetc(f);
+		uv |= (uint64)(c & 0x7F) << shift;
+		if(!(c & 0x80))
+			break;
+	}
+
+	return (int64)(uv>>1) ^ ((int64)((uint64)uv<<63)>>63);
+}
+
+static char*
+rdstring(Biobuf *f)
+{
+	int n;
+	char *p;
+	
+	n = rdint(f);
+	p = emallocz(n+1);
+	Bread(f, p, n);
+	return p;
+}
+
+static void
+rddata(Biobuf *f, uchar **pp, int *np)
+{
+	*np = rdint(f);
+	*pp = emallocz(*np);
+	Bread(f, *pp, *np);
+}
+
+static LSym*
+rdsym(Link *ctxt, Biobuf *f, char *pkg)
+{
+	int n, v;
+	char *p;
+	LSym *s;
+	
+	n = rdint(f);
+	if(n == 0) {
+		rdint(f);
+		return nil;
+	}
+	p = emallocz(n+1);
+	Bread(f, p, n);
+	v = rdint(f);
+	if(v != 0)
+		v = ctxt->version;
+	s = linklookup(ctxt, expandpkg(p, pkg), v);
+	
+	if(v == 0 && s->name[0] == '$' && s->type == 0) {
+		if(strncmp(s->name, "$f32.", 5) == 0) {
+			int32 i32;
+			i32 = strtoul(s->name+5, nil, 16);
+			s->type = SRODATA;
+			adduint32(ctxt, s, i32);
+			s->reachable = 0;
+		} else if(strncmp(s->name, "$f64.", 5) == 0) {
+			int64 i64;
+			i64 = strtoull(s->name+5, nil, 16);
+			s->type = SRODATA;
+			adduint64(ctxt, s, i64);
+			s->reachable = 0;
+		}
+	}
+
+	return s;
+}
diff --git a/src/liblink/pass.c b/src/liblink/pass.c
new file mode 100644
index 0000000..bc8eb43
--- /dev/null
+++ b/src/liblink/pass.c
@@ -0,0 +1,115 @@
+// 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 at 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 at 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+Prog*
+brchain(Link *ctxt, Prog *p)
+{
+	int i;
+
+	for(i=0; i<20; i++) {
+		if(p == nil || p->as != ctxt->arch->AJMP)
+			return p;
+		p = p->pcond;
+	}
+	return nil;
+}
+
+Prog*
+brloop(Link *ctxt, Prog *p)
+{
+	int c;
+	Prog *q;
+
+	c = 0;
+	for(q = p; q != nil; q = q->pcond) {
+		if(q->as != ctxt->arch->AJMP)
+			break;
+		c++;
+		if(c >= 5000)
+			return nil;
+	}
+	return q;
+}
+
+void
+linkpatch(Link *ctxt, LSym *sym)
+{
+	int32 c;
+	Prog *p, *q;
+
+	ctxt->cursym = sym;
+	
+	for(p = sym->text; p != nil; p = p->link) {
+		if(ctxt->arch->progedit)
+			ctxt->arch->progedit(ctxt, p);
+		if(p->to.type != ctxt->arch->D_BRANCH)
+			continue;
+		if(p->to.u.branch != nil) {
+			// TODO: Remove to.u.branch in favor of p->pcond.
+			p->pcond = p->to.u.branch;
+			continue;
+		}
+		if(p->to.sym != nil)
+			continue;
+		c = p->to.offset;
+		for(q = sym->text; q != nil;) {
+			if(c == q->pc)
+				break;
+			if(q->forwd != nil && c >= q->forwd->pc)
+				q = q->forwd;
+			else
+				q = q->link;
+		}
+		if(q == nil) {
+			ctxt->diag("branch out of range (%#ux)\n%P [%s]",
+				c, p, p->to.sym ? p->to.sym->name : "<nil>");
+			p->to.type = ctxt->arch->D_NONE;
+		}
+		p->to.u.branch = q;
+		p->pcond = q;
+	}
+	
+	for(p = sym->text; p != nil; p = p->link) {
+		p->mark = 0;	/* initialization for follow */
+		if(p->pcond != nil) {
+			p->pcond = brloop(ctxt, p->pcond);
+			if(p->pcond != nil)
+			if(p->to.type == ctxt->arch->D_BRANCH)
+				p->to.offset = p->pcond->pc;
+		}
+	}
+}
diff --git a/src/liblink/pcln.c b/src/liblink/pcln.c
new file mode 100644
index 0000000..4b2b855
--- /dev/null
+++ b/src/liblink/pcln.c
@@ -0,0 +1,365 @@
+// 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+static void
+addvarint(Link *ctxt, Pcdata *d, uint32 val)
+{
+	int32 n;
+	uint32 v;
+	uchar *p;
+
+	USED(ctxt);
+
+	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;
+}
+
+// funcpctab writes 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.
+static void
+funcpctab(Link *ctxt, Pcdata *dst, LSym *func, char *desc, int32 (*valfunc)(Link*, LSym*, int32, Prog*, int32, void*), void* arg)
+{
+	int dbg, i;
+	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;
+	//dbg = strcmp(desc, "pctofile") == 0;
+
+	ctxt->debugpcln += dbg;
+
+	dst->n = 0;
+
+	if(ctxt->debugpcln)
+		Bprint(ctxt->bso, "funcpctab %s [valfunc=%s]\n", func->name, desc);
+
+	val = -1;
+	oldval = val;
+	if(func->text == nil) {
+		ctxt->debugpcln -= dbg;
+		return;
+	}
+
+	pc = func->text->pc;
+	
+	if(ctxt->debugpcln)
+		Bprint(ctxt->bso, "%6llux %6d %P\n", pc, val, func->text);
+
+	started = 0;
+	for(p=func->text; p != nil; p = p->link) {
+		// Update val. If it's not changing, keep going.
+		val = valfunc(ctxt, func, val, p, 0, arg);
+		if(val == oldval && started) {
+			val = valfunc(ctxt, func, val, p, 1, arg);
+			if(ctxt->debugpcln)
+				Bprint(ctxt->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(ctxt, func, val, p, 1, arg);
+			if(ctxt->debugpcln)
+				Bprint(ctxt->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(ctxt->debugpcln)
+			Bprint(ctxt->bso, "%6llux %6d %P\n", (vlong)p->pc, val, p);
+
+		if(started) {
+			addvarint(ctxt, dst, (p->pc - pc) / ctxt->arch->minlc);
+			pc = p->pc;
+		}
+		delta = val - oldval;
+		if(delta>>31)
+			delta = 1 | ~(delta<<1);
+		else
+			delta <<= 1;
+		addvarint(ctxt, dst, delta);
+		oldval = val;
+		started = 1;
+		val = valfunc(ctxt, func, val, p, 1, arg);
+	}
+
+	if(started) {
+		if(ctxt->debugpcln)
+			Bprint(ctxt->bso, "%6llux done\n", (vlong)func->text->pc+func->size);
+		addvarint(ctxt, dst, (func->value+func->size - pc) / ctxt->arch->minlc);
+		addvarint(ctxt, dst, 0); // terminator
+	}
+
+	if(ctxt->debugpcln) {
+		Bprint(ctxt->bso, "wrote %d bytes to %p\n", dst->n, dst);
+		for(i=0; i<dst->n; i++)
+			Bprint(ctxt->bso, " %02ux", dst->p[i]);
+		Bprint(ctxt->bso, "\n");
+	}
+
+	ctxt->debugpcln -= 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(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
+{
+	int32 i, l;
+	LSym *f;
+	Pcln *pcln;
+
+	USED(sym);
+
+	if(p->as == ctxt->arch->ATEXT || p->as == ctxt->arch->ANOP || p->as == ctxt->arch->AUSEFIELD || p->lineno == 0 || phase == 1)
+		return oldval;
+	linkgetline(ctxt, p->lineno, &f, &l);
+	if(f == nil) {
+	//	print("getline failed for %s %P\n", ctxt->cursym->name, p);
+		return oldval;
+	}
+	if(arg == nil)
+		return l;
+	pcln = arg;
+	
+	if(f == pcln->lastfile)
+		return pcln->lastindex;
+
+	for(i=0; i<pcln->nfile; i++) {
+		if(pcln->file[i] == f) {
+			pcln->lastfile = f;
+			pcln->lastindex = i;
+			return i;
+		}
+	}
+
+	if(pcln->nfile >= pcln->mfile) {
+		pcln->mfile = (pcln->nfile+1)*2;
+		pcln->file = erealloc(pcln->file, pcln->mfile*sizeof pcln->file[0]);
+	}
+	pcln->file[pcln->nfile++] = f;
+	pcln->lastfile = f;
+	pcln->lastindex = i;
+	return i;
+}
+
+// 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(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *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) {
+		ctxt->diag("overflow in spadj: %d + %d = %d", oldval, p->spadj, oldval + p->spadj);
+		sysfatal("bad code");
+	}
+	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(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
+{
+	USED(sym);
+
+	if(phase == 0 || p->as != ctxt->arch->APCDATA || p->from.offset != (uintptr)arg)
+		return oldval;
+	if((int32)p->to.offset != p->to.offset) {
+		ctxt->diag("overflow in PCDATA instruction: %P", p);
+		sysfatal("bad code");
+	}
+	return p->to.offset;
+}
+
+void
+linkpcln(Link *ctxt, LSym *cursym)
+{
+	Prog *p;
+	Pcln *pcln;
+	int i, npcdata, nfuncdata, n;
+	uint32 *havepc, *havefunc;
+
+	ctxt->cursym = cursym;
+
+	pcln = emallocz(sizeof *pcln);
+	cursym->pcln = pcln;
+
+	npcdata = 0;
+	nfuncdata = 0;
+	for(p = cursym->text; p != nil; p = p->link) {
+		if(p->as == ctxt->arch->APCDATA && p->from.offset >= npcdata)
+			npcdata = p->from.offset+1;
+		if(p->as == ctxt->arch->AFUNCDATA && p->from.offset >= nfuncdata)
+			nfuncdata = p->from.offset+1;
+	}
+
+	pcln->pcdata = emallocz(npcdata*sizeof pcln->pcdata[0]);
+	pcln->npcdata = npcdata;
+	pcln->funcdata = emallocz(nfuncdata*sizeof pcln->funcdata[0]);
+	pcln->funcdataoff = emallocz(nfuncdata*sizeof pcln->funcdataoff[0]);
+	pcln->nfuncdata = nfuncdata;
+
+	funcpctab(ctxt, &pcln->pcsp, cursym, "pctospadj", pctospadj, nil);
+	funcpctab(ctxt, &pcln->pcfile, cursym, "pctofile", pctofileline, pcln);
+	funcpctab(ctxt, &pcln->pcline, cursym, "pctoline", pctofileline, nil);
+	
+	// tabulate which pc and func data we have.
+	n = ((npcdata+31)/32 + (nfuncdata+31)/32)*4;
+	havepc = emallocz(n);
+	havefunc = havepc + (npcdata+31)/32;
+	for(p = cursym->text; p != nil; p = p->link) {
+		if(p->as == ctxt->arch->AFUNCDATA) {
+			if((havefunc[p->from.offset/32]>>(p->from.offset%32))&1)
+				ctxt->diag("multiple definitions for FUNCDATA $%d", p->from.offset);
+			havefunc[p->from.offset/32] |= 1<<(p->from.offset%32);
+		}
+		if(p->as == ctxt->arch->APCDATA)
+			havepc[p->from.offset/32] |= 1<<(p->from.offset%32);
+	}
+	// pcdata.
+	for(i=0; i<npcdata; i++) {
+		if(!(havepc[i/32]>>(i%32))&1) 
+			continue;
+		funcpctab(ctxt, &pcln->pcdata[i], cursym, "pctopcdata", pctopcdata, (void*)(uintptr)i);
+	}
+	free(havepc);
+	
+	// funcdata
+	if(nfuncdata > 0) {
+		for(p = cursym->text; p != nil; p = p->link) {
+			if(p->as == ctxt->arch->AFUNCDATA) {
+				i = p->from.offset;
+				pcln->funcdataoff[i] = p->to.offset;
+				if(p->to.type != ctxt->arch->D_CONST) {
+					// TODO: Dedup.
+					//funcdata_bytes += p->to.sym->size;
+					pcln->funcdata[i] = p->to.sym;
+				}
+			}
+		}
+	}
+}
+
+// iteration over encoded pcdata tables.
+
+static uint32
+getvarint(uchar **pp)
+{
+	uchar *p;
+	int shift;
+	uint32 v;
+
+	v = 0;
+	p = *pp;
+	for(shift = 0;; shift += 7) {
+		v |= (uint32)(*p & 0x7F) << shift;
+		if(!(*p++ & 0x80))
+			break;
+	}
+	*pp = p;
+	return v;
+}
+
+void
+pciternext(Pciter *it)
+{
+	uint32 v;
+	int32 dv;
+
+	it->pc = it->nextpc;
+	if(it->done)
+		return;
+	if(it->p >= it->d.p + it->d.n) {
+		it->done = 1;
+		return;
+	}
+
+	// value delta
+	v = getvarint(&it->p);
+	if(v == 0 && !it->start) {
+		it->done = 1;
+		return;
+	}
+	it->start = 0;
+	dv = (int32)(v>>1) ^ ((int32)(v<<31)>>31);
+	it->value += dv;
+	
+	// pc delta
+	v = getvarint(&it->p);
+	it->nextpc = it->pc + v*it->pcscale;
+}
+
+void
+pciterinit(Link *ctxt, Pciter *it, Pcdata *d)
+{
+	it->d = *d;
+	it->p = it->d.p;
+	it->pc = 0;
+	it->nextpc = 0;
+	it->value = -1;
+	it->start = 1;
+	it->done = 0;
+	it->pcscale = ctxt->arch->minlc;
+	pciternext(it);
+}
diff --git a/src/liblink/sym.c b/src/liblink/sym.c
new file mode 100644
index 0000000..cba50e9
--- /dev/null
+++ b/src/liblink/sym.c
@@ -0,0 +1,271 @@
+// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+static int
+yy_isalpha(int c)
+{
+	return c >= 0 && c <= 0xFF && isalpha(c);
+}
+
+static struct {
+	char *name;
+	int val;
+} headers[] = {
+	"darwin",	Hdarwin,
+	"dragonfly",	Hdragonfly,
+	"elf",		Helf,
+	"freebsd",	Hfreebsd,
+	"linux",	Hlinux,
+	"nacl",		Hnacl,
+	"netbsd",	Hnetbsd,
+	"openbsd",	Hopenbsd,
+	"plan9",	Hplan9,
+	"solaris",	Hsolaris,
+	"windows",	Hwindows,
+	"windowsgui",	Hwindows,
+	0, 0
+};
+
+int
+headtype(char *name)
+{
+	int i;
+
+	for(i=0; headers[i].name; i++)
+		if(strcmp(name, headers[i].name) == 0)
+			return headers[i].val;
+	return -1;
+}
+
+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;
+}
+
+Link*
+linknew(LinkArch *arch)
+{
+	Link *ctxt;
+	char *p;
+	char buf[1024];
+
+	nuxiinit();
+	
+	ctxt = emallocz(sizeof *ctxt);
+	ctxt->arch = arch;
+	ctxt->version = HistVersion;
+	ctxt->goroot = getgoroot();
+	ctxt->goroot_final = getenv("GOROOT_FINAL");
+	if(ctxt->goroot_final != nil && ctxt->goroot_final[0] == '\0')
+		ctxt->goroot_final = nil;
+
+	p = getgoarch();
+	if(strcmp(p, arch->name) != 0)
+		sysfatal("invalid goarch %s (want %s)", p, arch->name);
+	
+	if(getwd(buf, sizeof buf) == 0)
+		strcpy(buf, "/???");
+	if(yy_isalpha(buf[0]) && buf[1] == ':') {
+		// On Windows.
+		ctxt->windows = 1;
+
+		// Canonicalize path by converting \ to / (Windows accepts both).
+		for(p=buf; *p; p++)
+			if(*p == '\\')
+				*p = '/';
+	}
+	ctxt->pathname = strdup(buf);
+	
+	ctxt->headtype = headtype(getgoos());
+	if(ctxt->headtype < 0)
+		sysfatal("unknown goos %s", getgoos());
+	
+	// Record thread-local storage offset.
+	// TODO(rsc): Move tlsoffset back into the linker.
+	switch(ctxt->headtype) {
+	default:
+		sysfatal("unknown thread-local storage offset for %s", headstr(ctxt->headtype));
+	case Hplan9:
+		ctxt->tlsoffset = -2*ctxt->arch->ptrsize;
+		break;
+	case Hwindows:
+		break;
+	case Hlinux:
+	case Hfreebsd:
+	case Hnetbsd:
+	case Hopenbsd:
+	case Hdragonfly:
+	case Hsolaris:
+		/*
+		 * ELF uses TLS offset negative from FS.
+		 * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
+		 * Known to low-level assembly in package runtime and runtime/cgo.
+		 */
+		ctxt->tlsoffset = -2*ctxt->arch->ptrsize;
+		break;
+
+	case Hnacl:
+		switch(ctxt->arch->thechar) {
+		default:
+			sysfatal("unknown thread-local storage offset for nacl/%s", ctxt->arch->name);
+		case '6':
+			ctxt->tlsoffset = 0;
+			break;
+		case '8':
+			ctxt->tlsoffset = -8;
+			break;
+		}
+		break;
+
+	case Hdarwin:
+		/*
+		 * OS X system constants - offset from 0(GS) to our TLS.
+		 * Explained in ../../pkg/runtime/cgo/gcc_darwin_*.c.
+		 */
+		switch(ctxt->arch->thechar) {
+		default:
+			sysfatal("unknown thread-local storage offset for darwin/%s", ctxt->arch->name);
+		case '6':
+			ctxt->tlsoffset = 0x8a0;
+			break;
+		case '8':
+			ctxt->tlsoffset = 0x468;
+			break;
+		}
+		break;
+	}
+	
+	// On arm, record goarm.
+	if(ctxt->arch->thechar == '5') {
+		p = getgoarm();
+		if(p != nil)
+			ctxt->goarm = atoi(p);
+		else
+			ctxt->goarm = 6;
+	}
+
+	return ctxt;
+}
+
+LSym*
+linknewsym(Link *ctxt, char *symb, int v)
+{
+	LSym *s;
+	int l;
+
+	l = strlen(symb) + 1;
+	s = malloc(sizeof(*s));
+	memset(s, 0, sizeof(*s));
+
+	s->dynid = -1;
+	s->plt = -1;
+	s->got = -1;
+	s->name = malloc(l + 1);
+	memmove(s->name, symb, l);
+	s->name[l] = '\0';
+
+	s->type = 0;
+	s->version = v;
+	s->value = 0;
+	s->sig = 0;
+	s->size = 0;
+	ctxt->nsymbol++;
+
+	s->allsym = ctxt->allsym;
+	ctxt->allsym = s;
+
+	return s;
+}
+
+static LSym*
+_lookup(Link *ctxt, char *symb, int v, int creat)
+{
+	LSym *s;
+	char *p;
+	uint32 h;
+	int c;
+
+	h = v;
+	for(p=symb; c = *p; p++)
+		h = h+h+h + c;
+	h &= 0xffffff;
+	h %= LINKHASH;
+	for(s = ctxt->hash[h]; s != nil; s = s->hash)
+		if(s->version == v && strcmp(s->name, symb) == 0)
+			return s;
+	if(!creat)
+		return nil;
+
+	s = linknewsym(ctxt, symb, v);
+	s->extname = s->name;
+	s->hash = ctxt->hash[h];
+	ctxt->hash[h] = s;
+
+	return s;
+}
+
+LSym*
+linklookup(Link *ctxt, char *name, int v)
+{
+	return _lookup(ctxt, name, v, 1);
+}
+
+// read-only lookup
+LSym*
+linkrlookup(Link *ctxt, char *name, int v)
+{
+	return _lookup(ctxt, name, v, 0);
+}
+
+int
+linksymfmt(Fmt *f)
+{
+	LSym *s;
+	
+	s = va_arg(f->args, LSym*);
+	if(s == nil)
+		return fmtstrcpy(f, "<nil>");
+	
+	return fmtstrcpy(f, s->name);
+}
diff --git a/src/libmach/5.c b/src/libmach/5.c
deleted file mode 100644
index 9882c1a..0000000
--- a/src/libmach/5.c
+++ /dev/null
@@ -1,92 +0,0 @@
-// Inferno libmach/5.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/5.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.
-//	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth at 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.
-
-/*
- * arm definition
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include "ureg_arm.h"
-#include <mach.h>
-
-#define	REGOFF(x)	(uintptr) (&((struct Ureg *) 0)->x)
-
-#define SP		REGOFF(r13)
-#define PC		REGOFF(pc)
-
-#define	REGSIZE		sizeof(struct Ureg)
-
-Reglist armreglist[] =
-{
-	{"LINK",	REGOFF(link),		RINT|RRDONLY, 'X'},
-	{"TYPE",	REGOFF(type),		RINT|RRDONLY, 'X'},
-	{"PSR",		REGOFF(psr),		RINT|RRDONLY, 'X'},
-	{"PC",		PC,			RINT, 'X'},
-	{"SP",		SP,			RINT, 'X'},
-	{"R15",		PC,			RINT, 'X'},
-	{"R14",		REGOFF(r14),		RINT, 'X'},
-	{"R13",		REGOFF(r13),		RINT, 'X'},
-	{"R12",		REGOFF(r12),		RINT, 'X'},
-	{"R11",		REGOFF(r11),		RINT, 'X'},
-	{"R10",		REGOFF(r10),		RINT, 'X'},
-	{"R9",		REGOFF(r9),		RINT, 'X'},
-	{"R8",		REGOFF(r8),		RINT, 'X'},
-	{"R7",		REGOFF(r7),		RINT, 'X'},
-	{"R6",		REGOFF(r6),		RINT, 'X'},
-	{"R5",		REGOFF(r5),		RINT, 'X'},
-	{"R4",		REGOFF(r4),		RINT, 'X'},
-	{"R3",		REGOFF(r3),		RINT, 'X'},
-	{"R2",		REGOFF(r2),		RINT, 'X'},
-	{"R1",		REGOFF(r1),		RINT, 'X'},
-	{"R0",		REGOFF(r0),		RINT, 'X'},
-	{  0 }
-};
-
-	/* the machine description */
-Mach marm =
-{
-	"arm",
-	MARM,		/* machine type */
-	armreglist,	/* register set */
-	REGSIZE,	/* register set size */
-	0,		/* fp register set size */
-	"PC",		/* name of PC */
-	"SP",		/* name of SP */
-	"R15",		/* name of link register */
-	"setR12",	/* static base register name */
-	0,		/* static base register value */
-	0x1000,		/* page size */
-	0xC0000000,	/* kernel base */
-	0,		/* kernel text mask */
-	4,		/* quantization of pc */
-	4,		/* szaddr */
-	4,		/* szreg */
-	4,		/* szfloat */
-	8,		/* szdouble */
-};
diff --git a/src/libmach/5db.c b/src/libmach/5db.c
deleted file mode 100644
index ae71dd9..0000000
--- a/src/libmach/5db.c
+++ /dev/null
@@ -1,1095 +0,0 @@
-// Inferno libmach/5db.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/5db.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.
-//	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth at 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.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include "ureg_arm.h"
-#include <mach.h>
-
-static int debug = 0;
-
-#define	BITS(a, b)	((1<<(b+1))-(1<<a))
-
-#define LSR(v, s)	((ulong)(v) >> (s))
-#define ASR(v, s)	((long)(v) >> (s))
-#define ROR(v, s)	(LSR((v), (s)) | (((v) & ((1 << (s))-1)) << (32 - (s))))
-
-
-
-typedef struct	Instr	Instr;
-struct	Instr
-{
-	Map	*map;
-	ulong	w;
-	ulong	addr;
-	uchar	op;			/* super opcode */
-
-	uchar	cond;			/* bits 28-31 */
-	uchar	store;			/* bit 20 */
-
-	uchar	rd;			/* bits 12-15 */
-	uchar	rn;			/* bits 16-19 */
-	uchar	rs;			/* bits 0-11 (shifter operand) */
-
-	long	imm;			/* rotated imm */
-	char*	curr;			/* fill point in buffer */
-	char*	end;			/* end of buffer */
-	char*	err;			/* error message */
-};
-
-typedef struct Opcode Opcode;
-struct Opcode
-{
-	char*	o;
-	void	(*fmt)(Opcode*, Instr*);
-	ulong	(*foll)(Map*, Rgetter, Instr*, ulong);
-	char*	a;
-};
-
-static	void	format(char*, Instr*, char*);
-static	char	FRAMENAME[] = ".frame";
-
-/*
- * Arm-specific debugger interface
- */
-
-extern	char	*armexcep(Map*, Rgetter);
-static	int	armfoll(Map*, uvlong, Rgetter, uvlong*);
-static	int	arminst(Map*, uvlong, char, char*, int);
-static	int	armdas(Map*, uvlong, char*, int);
-static	int	arminstlen(Map*, uvlong);
-
-/*
- *	Debugger interface
- */
-Machdata armmach =
-{
-	{0, 0, 0, 0xD},		/* break point */
-	4,			/* break point size */
-
-	leswab,			/* short to local byte order */
-	leswal,			/* long to local byte order */
-	leswav,			/* long to local byte order */
-	risctrace,		/* C traceback */
-	riscframe,		/* Frame finder */
-	armexcep,			/* print exception */
-	0,			/* breakpoint fixup */
-	0,			/* single precision float printer */
-	0,			/* double precision float printer */
-	armfoll,		/* following addresses */
-	arminst,		/* print instruction */
-	armdas,			/* dissembler */
-	arminstlen,		/* instruction size */
-};
-
-char*
-armexcep(Map *map, Rgetter rget)
-{
-	long c;
-
-	c = (*rget)(map, "TYPE");
-	switch (c&0x1f) {
-	case 0x11:
-		return "Fiq interrupt";
-	case 0x12:
-		return "Mirq interrupt";
-	case 0x13:
-		return "SVC/SWI Exception";
-	case 0x17:
-		return "Prefetch Abort/Data Abort";
-	case 0x18:
-		return "Data Abort";
-	case 0x1b:
-		return "Undefined instruction/Breakpoint";
-	case 0x1f:
-		return "Sys trap";
-	default:
-		return "Undefined trap";
-	}
-}
-
-static
-char*	cond[16] =
-{
-	"EQ",	"NE",	"CS",	"CC",
-	"MI",	"PL",	"VS",	"VC",
-	"HI",	"LS",	"GE",	"LT",
-	"GT",	"LE",	0,	"NV"
-};
-
-static
-char*	shtype[4] =
-{
-	"<<",	">>",	"->",	"@>"
-};
-
-static
-char *hb[4] =
-{
-	"???",	"HU", "B", "H"
-};
-
-static
-char*	addsub[2] =
-{
-	"-",	"+",
-};
-
-int
-armclass(long w)
-{
-	int op;
-
-	op = (w >> 25) & 0x7;
-	switch(op) {
-	case 0:	/* data processing r,r,r */
-		op = ((w >> 4) & 0xf);
-		if(op == 0x9) {
-			op = 48+16;		/* mul */
-			if(w & (1<<24)) {
-				op += 2;
-				if(w & (1<<22))
-					op++;	/* swap */
-				break;
-			}
-			if(w & (1<<21))
-				op++;		/* mla */
-			break;
-		}
-		if ((op & 0x9) == 0x9)		/* ld/st byte/half s/u */
-		{
-			op = (48+16+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
-			break;
-		}
-		op = (w >> 21) & 0xf;
-		if(w & (1<<4))
-			op += 32;
-		else
-		if(w & (31<<7))
-			op += 16;
-		break;
-	case 1:	/* data processing i,r,r */
-		op = (48) + ((w >> 21) & 0xf);
-		break;
-	case 2:	/* load/store byte/word i(r) */
-		op = (48+24) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
-		break;
-	case 3:	/* load/store byte/word (r)(r) */
-		op = (48+24+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
-		break;
-	case 4:	/* block data transfer (r)(r) */
-		op = (48+24+4+4) + ((w >> 20) & 0x1);
-		break;
-	case 5:	/* branch / branch link */
-		op = (48+24+4+4+2) + ((w >> 24) & 0x1);
-		break;
-	case 7:	/* coprocessor crap */
-		op = (48+24+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1);
-		break;
-	default:
-		op = (48+24+4+4+2+2+4);
-		break;
-	}
-	return op;
-}
-
-static int
-decode(Map *map, ulong pc, Instr *i)
-{
-	uint32 w;
-
-	if(get4(map, pc, &w) < 0) {
-		werrstr("can't read instruction: %r");
-		return -1;
-	}
-	i->w = w;
-	i->addr = pc;
-	i->cond = (w >> 28) & 0xF;
-	i->op = armclass(w);
-	i->map = map;
-	return 1;
-}
-
-static void
-bprint(Instr *i, char *fmt, ...)
-{
-	va_list arg;
-
-	va_start(arg, fmt);
-	i->curr = vseprint(i->curr, i->end, fmt, arg);
-	va_end(arg);
-}
-
-static int
-plocal(Instr *i)
-{
-	char *reg;
-	Symbol s;
-	char *fn;
-	int class;
-	int offset;
-
-	if(!findsym(i->addr, CTEXT, &s)) {
-		if(debug)fprint(2,"fn not found @%lux: %r\n", i->addr);
-		return 0;
-	}
-	fn = s.name;
-	if (!findlocal(&s, FRAMENAME, &s)) {
-		if(debug)fprint(2,"%s.%s not found @%s: %r\n", fn, FRAMENAME, s.name);
-			return 0;
-	}
-	if(s.value > i->imm) {
-		class = CAUTO;
-		offset = s.value-i->imm;
-		reg = "(SP)";
-	} else {
-		class = CPARAM;
-		offset = i->imm-s.value-4;
-		reg = "(FP)";
-	}
-	if(!getauto(&s, offset, class, &s)) {
-		if(debug)fprint(2,"%s %s not found @%ux: %r\n", fn,
-			class == CAUTO ? " auto" : "param", offset);
-		return 0;
-	}
-	bprint(i, "%s%c%d%s", s.name, class == CPARAM ? '+' : '-', s.value, reg);
-	return 1;
-}
-
-/*
- * Print value v as name[+offset]
- */
-int
-gsymoff(char *buf, int n, long v, int space)
-{
-	Symbol s;
-	int r;
-	long delta;
-
-	r = delta = 0;		/* to shut compiler up */
-	if (v) {
-		r = findsym(v, space, &s);
-		if (r)
-			delta = v-s.value;
-		if (delta < 0)
-			delta = -delta;
-	}
-	if (v == 0 || r == 0 || delta >= 4096)
-		return snprint(buf, n, "#%lux", v);
-	if (strcmp(s.name, ".string") == 0)
-		return snprint(buf, n, "#%lux", v);
-	if (!delta)
-		return snprint(buf, n, "%s", s.name);
-	if (s.type != 't' && s.type != 'T')
-		return snprint(buf, n, "%s+%llux", s.name, v-s.value);
-	else
-		return snprint(buf, n, "#%lux", v);
-}
-
-static void
-armdps(Opcode *o, Instr *i)
-{
-	i->store = (i->w >> 20) & 1;
-	i->rn = (i->w >> 16) & 0xf;
-	i->rd = (i->w >> 12) & 0xf;
-	i->rs = (i->w >> 0) & 0xf;
-	if(i->rn == 15 && i->rs == 0) {
-		if(i->op == 8) {
-			format("MOVW", i,"CPSR, R%d");
-			return;
-		} else
-		if(i->op == 10) {
-			format("MOVW", i,"SPSR, R%d");
-			return;
-		}
-	} else
-	if(i->rn == 9 && i->rd == 15) {
-		if(i->op == 9) {
-			format("MOVW", i, "R%s, CPSR");
-			return;
-		} else
-		if(i->op == 11) {
-			format("MOVW", i, "R%s, SPSR");
-			return;
-		}
-	}
-	format(o->o, i, o->a);
-}
-
-static void
-armdpi(Opcode *o, Instr *i)
-{
-	ulong v;
-	int c;
-
-	v = (i->w >> 0) & 0xff;
-	c = (i->w >> 8) & 0xf;
-	while(c) {
-		v = (v<<30) | (v>>2);
-		c--;
-	}
-	i->imm = v;
-	i->store = (i->w >> 20) & 1;
-	i->rn = (i->w >> 16) & 0xf;
-	i->rd = (i->w >> 12) & 0xf;
-	i->rs = i->w&0x0f;
-
-		/* RET is encoded as ADD #0,R14,R15 */
-	if((i->w & 0x0fffffff) == 0x028ef000){
-		format("RET%C", i, "");
-		return;
-	}
-	if((i->w & 0x0ff0ffff) == 0x0280f000){
-		format("B%C", i, "0(R%n)");
-		return;
-	}
-	format(o->o, i, o->a);
-}
-
-static void
-armsdti(Opcode *o, Instr *i)
-{
-	ulong v;
-
-	v = i->w & 0xfff;
-	if(!(i->w & (1<<23)))
-		v = -v;
-	i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
-	i->imm = v;
-	i->rn = (i->w >> 16) & 0xf;
-	i->rd = (i->w >> 12) & 0xf;
-		/* RET is encoded as LW.P x,R13,R15 */
-	if ((i->w & 0x0ffff000) == 0x049df000)
-	{
-		format("RET%C%p", i, "%I");
-		return;
-	}
-	format(o->o, i, o->a);
-}
-
-/* arm V4 ld/st halfword, signed byte */
-static void
-armhwby(Opcode *o, Instr *i)
-{
-	i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
-	i->imm = (i->w & 0xf) | ((i->w >> 8) & 0xf);
-	if (!(i->w & (1 << 23)))
-		i->imm = - i->imm;
-	i->rn = (i->w >> 16) & 0xf;
-	i->rd = (i->w >> 12) & 0xf;
-	i->rs = (i->w >> 0) & 0xf;
-	format(o->o, i, o->a);
-}
-
-static void
-armsdts(Opcode *o, Instr *i)
-{
-	i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
-	i->rs = (i->w >> 0) & 0xf;
-	i->rn = (i->w >> 16) & 0xf;
-	i->rd = (i->w >> 12) & 0xf;
-	format(o->o, i, o->a);
-}
-
-static void
-armbdt(Opcode *o, Instr *i)
-{
-	i->store = (i->w >> 21) & 0x3;		/* S & W bits */
-	i->rn = (i->w >> 16) & 0xf;
-	i->imm = i->w & 0xffff;
-	if(i->w == 0xe8fd8000)
-		format("RFE", i, "");
-	else
-		format(o->o, i, o->a);
-}
-
-/*
-static void
-armund(Opcode *o, Instr *i)
-{
-	format(o->o, i, o->a);
-}
-
-static void
-armcdt(Opcode *o, Instr *i)
-{
-	format(o->o, i, o->a);
-}
-*/
-
-static void
-armunk(Opcode *o, Instr *i)
-{
-	format(o->o, i, o->a);
-}
-
-static void
-armb(Opcode *o, Instr *i)
-{
-	ulong v;
-
-	v = i->w & 0xffffff;
-	if(v & 0x800000)
-		v |= ~0xffffff;
-	i->imm = (v<<2) + i->addr + 8;
-	format(o->o, i, o->a);
-}
-
-static void
-armco(Opcode *o, Instr *i)		/* coprocessor instructions */
-{
-	int op, p, cp;
-
-	char buf[1024];
-
-	i->rn = (i->w >> 16) & 0xf;
-	i->rd = (i->w >> 12) & 0xf;
-	i->rs = i->w&0xf;
-	cp = (i->w >> 8) & 0xf;
-	p = (i->w >> 5) & 0x7;
-	if(i->w&(1<<4)) {
-		op = (i->w >> 21) & 0x07;
-		snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
-	} else {
-		op = (i->w >> 20) & 0x0f;
-		snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
-	}
-	format(o->o, i, buf);
-}
-
-static int
-armcondpass(Map *map, Rgetter rget, uchar cond)
-{
-	ulong psr;
-	uchar n;
-	uchar z;
-	uchar c;
-	uchar v;
-
-	psr = rget(map, "PSR");
-	n = (psr >> 31) & 1;
-	z = (psr >> 30) & 1;
-	c = (psr >> 29) & 1;
-	v = (psr >> 28) & 1;
-
-	switch(cond) {
-		case 0:		return z;
-		case 1:		return !z;
-		case 2:		return c;
-		case 3:		return !c;
-		case 4:		return n;
-		case 5:		return !n;
-		case 6:		return v;
-		case 7:		return !v;
-		case 8:		return c && !z;
-		case 9:		return !c || z;
-		case 10:	return n == v;
-		case 11:	return n != v;
-		case 12:	return !z && (n == v);
-		case 13:	return z && (n != v);
-		case 14:	return 1;
-		case 15:	return 0;
-	}
-	return 0;
-}
-
-static ulong
-armshiftval(Map *map, Rgetter rget, Instr *i)
-{
-	if(i->w & (1 << 25)) {				/* immediate */
-		ulong imm = i->w & BITS(0, 7);
-		ulong s = (i->w & BITS(8, 11)) >> 7; /* this contains the *2 */
-		return ROR(imm, s);
-	} else {
-		char buf[8];
-		ulong v;
-		ulong s = (i->w & BITS(7,11)) >> 7;
-
-		sprint(buf, "R%ld", i->w & 0xf);
-		v = rget(map, buf);
-
-		switch((i->w & BITS(4, 6)) >> 4) {
-		case 0:					/* LSLIMM */
-			return v << s;
-		case 1:					/* LSLREG */
-			sprint(buf, "R%lud", s >> 1);
-			s = rget(map, buf) & 0xFF;
-			if(s >= 32) return 0;
-			return v << s;
-		case 2:					/* LSRIMM */
-			return LSR(v, s);
-		case 3:					/* LSRREG */
-			sprint(buf, "R%ld", s >> 1);
-			s = rget(map, buf) & 0xFF;
-			if(s >= 32) return 0;
-			return LSR(v, s);
-		case 4:					/* ASRIMM */
-			if(s == 0) {
-				if((v & (1U<<31)) == 0)
-					return 0;
-				return 0xFFFFFFFF;
-			}
-			return ASR(v, s);
-		case 5:					/* ASRREG */
-			sprint(buf, "R%ld", s >> 1);
-			s = rget(map, buf) & 0xFF;
-			if(s >= 32) {
-				if((v & (1U<<31)) == 0)
-					return 0;
-				return 0xFFFFFFFF;
-			}
-			return ASR(v, s);
-		case 6:					/* RORIMM */
-			if(s == 0) {
-				ulong c = (rget(map, "PSR") >> 29) & 1;
-
-				return (c << 31) | LSR(v, 1);
-			}
-			return ROR(v, s);
-		case 7:					/* RORREG */
-			sprint(buf, "R%ld", (s>>1)&0xF);
-			s = rget(map, buf);
-			if(s == 0 || (s & 0xF) == 0)
-				return v;
-			return ROR(v, s & 0xF);
-		}
-	}
-	return 0;
-}
-
-static int
-nbits(ulong v)
-{
-	int n = 0;
-	int i;
-
-	for(i=0; i < 32 ; i++) {
-		if(v & 1) ++n;
-		v >>= 1;
-	}
-
-	return n;
-}
-
-static ulong
-armmaddr(Map *map, Rgetter rget, Instr *i)
-{
-	ulong v;
-	ulong nb;
-	char buf[8];
-	ulong rn;
-
-	rn = (i->w >> 16) & 0xf;
-	sprint(buf,"R%ld", rn);
-
-	v = rget(map, buf);
-	nb = nbits(i->w & ((1 << 15) - 1));
-
-	switch((i->w >> 23) & 3) {
-		case 0: return (v - (nb*4)) + 4;
-		case 1: return v;
-		case 2: return v - (nb*4);
-		case 3: return v + 4;
-	}
-	return 0;
-}
-
-static ulong
-armaddr(Map *map, Rgetter rget, Instr *i)
-{
-	char buf[8];
-	ulong rn;
-
-	sprint(buf, "R%ld", (i->w >> 16) & 0xf);
-	rn = rget(map, buf);
-
-	if((i->w & (1<<24)) == 0) {			/* POSTIDX */
-		sprint(buf, "R%ld", rn);
-		return rget(map, buf);
-	}
-
-	if((i->w & (1<<25)) == 0) {			/* OFFSET */
-		sprint(buf, "R%ld", rn);
-		if(i->w & (1U<<23))
-			return rget(map, buf) + (i->w & BITS(0,11));
-		return rget(map, buf) - (i->w & BITS(0,11));
-	} else {					/* REGOFF */
-		ulong index = 0;
-		uchar c;
-		uchar rm;
-
-		sprint(buf, "R%ld", i->w & 0xf);
-		rm = rget(map, buf);
-
-		switch((i->w & BITS(5,6)) >> 5) {
-		case 0: index = rm << ((i->w & BITS(7,11)) >> 7);	break;
-		case 1: index = LSR(rm, ((i->w & BITS(7,11)) >> 7));	break;
-		case 2: index = ASR(rm, ((i->w & BITS(7,11)) >> 7));	break;
-		case 3:
-			if((i->w & BITS(7,11)) == 0) {
-				c = (rget(map, "PSR") >> 29) & 1;
-				index = c << 31 | LSR(rm, 1);
-			} else {
-				index = ROR(rm, ((i->w & BITS(7,11)) >> 7));
-			}
-			break;
-		}
-		if(i->w & (1<<23))
-			return rn + index;
-		return rn - index;
-	}
-}
-
-static ulong
-armfadd(Map *map, Rgetter rget, Instr *i, ulong pc)
-{
-	char buf[8];
-	int r;
-
-	r = (i->w >> 12) & 0xf;
-	if(r != 15 || !armcondpass(map, rget, (i->w >> 28) & 0xf))
-		return pc+4;
-
-	r = (i->w >> 16) & 0xf;
-	sprint(buf, "R%d", r);
-
-	return rget(map, buf) + armshiftval(map, rget, i);
-}
-
-static ulong
-armfmovm(Map *map, Rgetter rget, Instr *i, ulong pc)
-{
-	uint32 v;
-	ulong addr;
-
-	v = i->w & 1<<15;
-	if(!v || !armcondpass(map, rget, (i->w>>28)&0xf))
-		return pc+4;
-
-	addr = armmaddr(map, rget, i) + nbits(i->w & BITS(0,15));
-	if(get4(map, addr, &v) < 0) {
-		werrstr("can't read addr: %r");
-		return -1;
-	}
-	return v;
-}
-
-static ulong
-armfbranch(Map *map, Rgetter rget, Instr *i, ulong pc)
-{
-	if(!armcondpass(map, rget, (i->w >> 28) & 0xf))
-		return pc+4;
-
-	return pc + (((signed long)i->w << 8) >> 6) + 8;
-}
-
-static ulong
-armfmov(Map *map, Rgetter rget, Instr *i, ulong pc)
-{
-	ulong rd;
-	uint32 v;
-
-	rd = (i->w >> 12) & 0xf;
-	if(rd != 15 || !armcondpass(map, rget, (i->w>>28)&0xf))
-		return pc+4;
-
-	 /* LDR */
-	/* BUG: Needs LDH/B, too */
-	if(((i->w>>26)&0x3) == 1) {
-		if(get4(map, armaddr(map, rget, i), &v) < 0) {
-			werrstr("can't read instruction: %r");
-			return pc+4;
-		}
-		return v;
-	}
-
-	 /* MOV */
-	return armshiftval(map, rget, i);
-}
-
-static Opcode opcodes[] =
-{
-	"AND%C%S",	armdps, 0,	"R%s,R%n,R%d",
-	"EOR%C%S",	armdps, 0,	"R%s,R%n,R%d",
-	"SUB%C%S",	armdps, 0,	"R%s,R%n,R%d",
-	"RSB%C%S",	armdps, 0,	"R%s,R%n,R%d",
-	"ADD%C%S",	armdps, armfadd,	"R%s,R%n,R%d",
-	"ADC%C%S",	armdps, 0,	"R%s,R%n,R%d",
-	"SBC%C%S",	armdps, 0,	"R%s,R%n,R%d",
-	"RSC%C%S",	armdps, 0,	"R%s,R%n,R%d",
-	"TST%C%S",	armdps, 0,	"R%s,R%n",
-	"TEQ%C%S",	armdps, 0,	"R%s,R%n",
-	"CMP%C%S",	armdps, 0,	"R%s,R%n",
-	"CMN%C%S",	armdps, 0,	"R%s,R%n",
-	"ORR%C%S",	armdps, 0,	"R%s,R%n,R%d",
-	"MOVW%C%S",	armdps, armfmov,	"R%s,R%d",
-	"BIC%C%S",	armdps, 0,	"R%s,R%n,R%d",
-	"MVN%C%S",	armdps, 0,	"R%s,R%d",
-
-/* 16 */
-	"AND%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
-	"EOR%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
-	"SUB%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
-	"RSB%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
-	"ADD%C%S",	armdps, armfadd,	"(R%s%h%m),R%n,R%d",
-	"ADC%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
-	"SBC%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
-	"RSC%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
-	"TST%C%S",	armdps, 0,	"(R%s%h%m),R%n",
-	"TEQ%C%S",	armdps, 0,	"(R%s%h%m),R%n",
-	"CMP%C%S",	armdps, 0,	"(R%s%h%m),R%n",
-	"CMN%C%S",	armdps, 0,	"(R%s%h%m),R%n",
-	"ORR%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
-	"MOVW%C%S",	armdps, armfmov,	"(R%s%h%m),R%d",
-	"BIC%C%S",	armdps, 0,	"(R%s%h%m),R%n,R%d",
-	"MVN%C%S",	armdps, 0,	"(R%s%h%m),R%d",
-
-/* 32 */
-	"AND%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
-	"EOR%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
-	"SUB%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
-	"RSB%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
-	"ADD%C%S",	armdps, armfadd,	"(R%s%hR%M),R%n,R%d",
-	"ADC%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
-	"SBC%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
-	"RSC%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
-	"TST%C%S",	armdps, 0,	"(R%s%hR%M),R%n",
-	"TEQ%C%S",	armdps, 0,	"(R%s%hR%M),R%n",
-	"CMP%C%S",	armdps, 0,	"(R%s%hR%M),R%n",
-	"CMN%C%S",	armdps, 0,	"(R%s%hR%M),R%n",
-	"ORR%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
-	"MOVW%C%S",	armdps, armfmov,	"(R%s%hR%M),R%d",
-	"BIC%C%S",	armdps, 0,	"(R%s%hR%M),R%n,R%d",
-	"MVN%C%S",	armdps, 0,	"(R%s%hR%M),R%d",
-
-/* 48 */
-	"AND%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
-	"EOR%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
-	"SUB%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
-	"RSB%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
-	"ADD%C%S",	armdpi, armfadd,	"$#%i,R%n,R%d",
-	"ADC%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
-	"SBC%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
-	"RSC%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
-	"TST%C%S",	armdpi, 0,	"$#%i,R%n",
-	"TEQ%C%S",	armdpi, 0,	"$#%i,R%n",
-	"CMP%C%S",	armdpi, 0,	"$#%i,R%n",
-	"CMN%C%S",	armdpi, 0,	"$#%i,R%n",
-	"ORR%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
-	"MOVW%C%S",	armdpi, armfmov,	"$#%i,R%d",
-	"BIC%C%S",	armdpi, 0,	"$#%i,R%n,R%d",
-	"MVN%C%S",	armdpi, 0,	"$#%i,R%d",
-
-/* 48+16 */
-	"MUL%C%S",	armdpi, 0,	"R%s,R%M,R%n",
-	"MULA%C%S",	armdpi, 0,	"R%s,R%M,R%n,R%d",
-	"SWPW",		armdpi, 0,	"R%s,(R%n),R%d",
-	"SWPB",		armdpi, 0,	"R%s,(R%n),R%d",
-
-/* 48+16+4 */
-	"MOV%u%C%p",	armhwby, 0,	"R%d,(R%n%UR%M)",
-	"MOV%u%C%p",	armhwby, 0,	"R%d,%I",
-	"MOV%u%C%p",	armhwby, armfmov,	"(R%n%UR%M),R%d",
-	"MOV%u%C%p",	armhwby, armfmov,	"%I,R%d",
-
-/* 48+24 */
-	"MOVW%C%p",	armsdti, 0,	"R%d,%I",
-	"MOVB%C%p",	armsdti, 0,	"R%d,%I",
-	"MOVW%C%p",	armsdti, armfmov,	"%I,R%d",
-	"MOVBU%C%p",	armsdti, armfmov,	"%I,R%d",
-
-	"MOVW%C%p",	armsdts, 0,	"R%d,(R%s%h%m)(R%n)",
-	"MOVB%C%p",	armsdts, 0,	"R%d,(R%s%h%m)(R%n)",
-	"MOVW%C%p",	armsdts, armfmov,	"(R%s%h%m)(R%n),R%d",
-	"MOVBU%C%p",	armsdts, armfmov,	"(R%s%h%m)(R%n),R%d",
-
-	"MOVM%C%P%a",	armbdt, armfmovm,		"[%r],(R%n)",
-	"MOVM%C%P%a",	armbdt, armfmovm,		"(R%n),[%r]",
-
-	"B%C",		armb, armfbranch,		"%b",
-	"BL%C",		armb, armfbranch,		"%b",
-
-	"CDP%C",	armco, 0,		"",
-	"CDP%C",	armco, 0,		"",
-	"MCR%C",	armco, 0,		"",
-	"MRC%C",	armco, 0,		"",
-
-	"UNK",		armunk, 0,	"",
-};
-
-static void
-gaddr(Instr *i)
-{
-	*i->curr++ = '$';
-	i->curr += gsymoff(i->curr, i->end-i->curr, i->imm, CANY);
-}
-
-static	char *mode[] = { 0, "IA", "DB", "IB" };
-static	char *pw[] = { "P", "PW", 0, "W" };
-static	char *sw[] = { 0, "W", "S", "SW" };
-
-static void
-format(char *mnemonic, Instr *i, char *f)
-{
-	int j, k, m, n;
-	int g;
-	char *fmt;
-
-	if(mnemonic)
-		format(0, i, mnemonic);
-	if(f == 0)
-		return;
-	if(mnemonic)
-		if(i->curr < i->end)
-			*i->curr++ = '\t';
-	for ( ; *f && i->curr < i->end; f++) {
-		if(*f != '%') {
-			*i->curr++ = *f;
-			continue;
-		}
-		switch (*++f) {
-
-		case 'C':	/* .CONDITION */
-			if(cond[i->cond])
-				bprint(i, ".%s", cond[i->cond]);
-			break;
-
-		case 'S':	/* .STORE */
-			if(i->store)
-				bprint(i, ".S");
-			break;
-
-		case 'P':	/* P & U bits for block move */
-			n = (i->w >>23) & 0x3;
-			if (mode[n])
-				bprint(i, ".%s", mode[n]);
-			break;
-
-		case 'p':	/* P & W bits for single data xfer*/
-			if (pw[i->store])
-				bprint(i, ".%s", pw[i->store]);
-			break;
-
-		case 'a':	/* S & W bits for single data xfer*/
-			if (sw[i->store])
-				bprint(i, ".%s", sw[i->store]);
-			break;
-
-		case 's':
-			bprint(i, "%d", i->rs & 0xf);
-			break;
-
-		case 'M':
-			bprint(i, "%d", (i->w>>8) & 0xf);
-			break;
-
-		case 'm':
-			bprint(i, "%d", (i->w>>7) & 0x1f);
-			break;
-
-		case 'h':
-			bprint(i, shtype[(i->w>>5) & 0x3]);
-			break;
-
-		case 'u':		/* Signed/unsigned Byte/Halfword */
-			bprint(i, hb[(i->w>>5) & 0x3]);
-			break;
-
-		case 'I':
-			if (i->rn == 13) {
-				if (plocal(i))
-					break;
-			}
-			g = 0;
-			fmt = "#%lx(R%d)";
-			if (i->rn == 15) {
-				/* convert load of offset(PC) to a load immediate */
-				uint32 x;
-				if (get4(i->map, i->addr+i->imm+8, &x) > 0)
-				{
-					i->imm = (int32)x;
-					g = 1;
-					fmt = "";
-				}
-			}
-			if (mach->sb)
-			{
-				if (i->rd == 11) {
-					uint32 nxti;
-
-					if (get4(i->map, i->addr+4, &nxti) > 0) {
-						if ((nxti & 0x0e0f0fff) == 0x060c000b) {
-							i->imm += mach->sb;
-							g = 1;
-							fmt = "-SB";
-						}
-					}
-				}
-				if (i->rn == 12)
-				{
-					i->imm += mach->sb;
-					g = 1;
-					fmt = "-SB(SB)";
-				}
-			}
-			if (g)
-			{
-				gaddr(i);
-				bprint(i, fmt, i->rn);
-			}
-			else
-				bprint(i, fmt, i->imm, i->rn);
-			break;
-		case 'U':		/* Add/subtract from base */
-			bprint(i, addsub[(i->w >> 23) & 1]);
-			break;
-
-		case 'n':
-			bprint(i, "%d", i->rn);
-			break;
-
-		case 'd':
-			bprint(i, "%d", i->rd);
-			break;
-
-		case 'i':
-			bprint(i, "%lux", i->imm);
-			break;
-
-		case 'b':
-			i->curr += symoff(i->curr, i->end-i->curr,
-				i->imm, CTEXT);
-			break;
-
-		case 'g':
-			i->curr += gsymoff(i->curr, i->end-i->curr,
-				i->imm, CANY);
-			break;
-
-		case 'r':
-			n = i->imm&0xffff;
-			j = 0;
-			k = 0;
-			while(n) {
-				m = j;
-				while(n&0x1) {
-					j++;
-					n >>= 1;
-				}
-				if(j != m) {
-					if(k)
-						bprint(i, ",");
-					if(j == m+1)
-						bprint(i, "R%d", m);
-					else
-						bprint(i, "R%d-R%d", m, j-1);
-					k = 1;
-				}
-				j++;
-				n >>= 1;
-			}
-			break;
-
-		case '\0':
-			*i->curr++ = '%';
-			return;
-
-		default:
-			bprint(i, "%%%c", *f);
-			break;
-		}
-	}
-	*i->curr = 0;
-}
-
-static int
-printins(Map *map, ulong pc, char *buf, int n)
-{
-	Instr i;
-
-	i.curr = buf;
-	i.end = buf+n-1;
-	if(decode(map, pc, &i) < 0)
-		return -1;
-
-	(*opcodes[i.op].fmt)(&opcodes[i.op], &i);
-	return 4;
-}
-
-static int
-arminst(Map *map, uvlong pc, char modifier, char *buf, int n)
-{
-	USED(modifier);
-	return printins(map, pc, buf, n);
-}
-
-static int
-armdas(Map *map, uvlong pc, char *buf, int n)
-{
-	Instr i;
-
-	i.curr = buf;
-	i.end = buf+n;
-	if(decode(map, pc, &i) < 0)
-		return -1;
-	if(i.end-i.curr > 8)
-		i.curr = _hexify(buf, i.w, 7);
-	*i.curr = 0;
-	return 4;
-}
-
-static int
-arminstlen(Map *map, uvlong pc)
-{
-	Instr i;
-
-	if(decode(map, pc, &i) < 0)
-		return -1;
-	return 4;
-}
-
-static int
-armfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
-{
-	ulong d;
-	Instr i;
-
-	if(decode(map, pc, &i) < 0)
-		return -1;
-
-	if(opcodes[i.op].foll) {
-		d = (*opcodes[i.op].foll)(map, rget, &i, pc);
-		if(d == -1)
-			return -1;
-	} else
-		d = pc+4;
-
-	foll[0] = d;
-	return 1;
-}
diff --git a/src/libmach/5obj.c b/src/libmach/5obj.c
deleted file mode 100644
index 7fd3459..0000000
--- a/src/libmach/5obj.c
+++ /dev/null
@@ -1,171 +0,0 @@
-// Inferno libmach/5obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/5obj.c
-//
-// 	Copyright © 1994-1999 Lucent Technologies Inc.
-// 	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth at 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.
-
-/*
- * 5obj.c - identify and parse an arm object file
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-#include "../cmd/5l/5.out.h"
-#include "obj.h"
-
-typedef struct Addr	Addr;
-struct Addr
-{
-	char	type;
-	char	sym;
-	char	name;
-	char	gotype;
-};
-static Addr addr(Biobuf*);
-static char type2char(int);
-static void skip(Biobuf*, int);
-
-int
-_is5(char *s)
-{
-	return  s[0] == ANAME				/* ANAME */
-		&& s[1] == D_FILE			/* type */
-		&& s[2] == 1				/* sym */
-		&& s[3] == '<';				/* name of file */
-}
-
-int
-_read5(Biobuf *bp, Prog *p)
-{
-	int as, n;
-	Addr a;
-
-	as = BGETC(bp);			/* as */
-	if(as < 0)
-		return 0;
-	p->kind = aNone;
-	p->sig = 0;
-	if(as == ANAME || as == ASIGNAME){
-		if(as == ASIGNAME){
-			Bread(bp, &p->sig, 4);
-			p->sig = leswal(p->sig);
-		}
-		p->kind = aName;
-		p->type = type2char(BGETC(bp));		/* type */
-		p->sym = BGETC(bp);			/* sym */
-		n = 0;
-		for(;;) {
-			as = BGETC(bp);
-			if(as < 0)
-				return 0;
-			n++;
-			if(as == 0)
-				break;
-		}
-		p->id = malloc(n);
-		if(p->id == 0)
-			return 0;
-		Bseek(bp, -n, 1);
-		if(Bread(bp, p->id, n) != n)
-			return 0;
-		return 1;
-	}
-	if(as == ATEXT)
-		p->kind = aText;
-	else if(as == AGLOBL)
-		p->kind = aData;
-	skip(bp, 6);		/* scond(1), reg(1), lineno(4) */
-	a = addr(bp);
-	addr(bp);
-	if(a.type != D_OREG || a.name != D_STATIC && a.name != D_EXTERN)
-		p->kind = aNone;
-	p->sym = a.sym;
-	return 1;
-}
-
-static Addr
-addr(Biobuf *bp)
-{
-	Addr a;
-	long off;
-
-	a.type = BGETC(bp);	/* a.type */
-	skip(bp,1);		/* reg */
-	a.sym = BGETC(bp);	/* sym index */
-	a.name = BGETC(bp);	/* sym type */
-	a.gotype = BGETC(bp);	/* go type */
-	switch(a.type){
-	default:
-	case D_NONE:
-	case D_REG:
-	case D_FREG:
-	case D_PSR:
-	case D_FPCR:
-		break;
-	case D_REGREG:
-	case D_REGREG2:
-		Bgetc(bp);
-		break;
-	case D_CONST2:
-		Bgetle4(bp); // fall through
-	case D_OREG:
-	case D_CONST:
-	case D_BRANCH:
-	case D_SHIFT:
-		off = BGETLE4(bp);
-		if(off < 0)
-			off = -off;
-		if(a.sym && (a.name==D_PARAM || a.name==D_AUTO))
-			_offset(a.sym, off);
-		break;
-	case D_SCONST:
-		skip(bp, NSNAME);
-		break;
-	case D_FCONST:
-		skip(bp, 8);
-		break;
-	}
-	return a;
-}
-
-static char
-type2char(int t)
-{
-	switch(t){
-	case D_EXTERN:		return 'U';
-	case D_STATIC:		return 'b';
-	case D_AUTO:		return 'a';
-	case D_PARAM:		return 'p';
-	default:		return UNKNOWN;
-	}
-}
-
-static void
-skip(Biobuf *bp, int n)
-{
-	while (n-- > 0)
-		Bgetc(bp);
-}
diff --git a/src/libmach/6.c b/src/libmach/6.c
deleted file mode 100644
index 0f06363..0000000
--- a/src/libmach/6.c
+++ /dev/null
@@ -1,145 +0,0 @@
-// Inferno libmach/6.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/6.c
-//
-// 	Copyright © 1994-1999 Lucent Technologies Inc.
-// 	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth at 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.
-
-/*
- * amd64 definition
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include "ureg_amd64.h"
-#include <mach.h>
-
-#define	REGOFF(x)	offsetof(struct Ureg, x)
-
-#define	REGSIZE		sizeof(struct Ureg)
-#define FP_CTLS(x)	(REGSIZE+2*(x))
-#define FP_CTL(x)	(REGSIZE+4*(x))
-#define FP_REG(x)	(FP_CTL(8)+16*(x))
-#define XM_REG(x)	(FP_CTL(8)+8*16+16*(x))
-
-#define	FPREGSIZE	512	/* TO DO? currently only 0x1A0 used */
-
-Reglist amd64reglist[] = {
-	{"AX",		REGOFF(ax),	RINT, 'Y'},
-	{"BX",		REGOFF(bx),	RINT, 'Y'},
-	{"CX",		REGOFF(cx),	RINT, 'Y'},
-	{"DX",		REGOFF(dx),	RINT, 'Y'},
-	{"SI",		REGOFF(si),	RINT, 'Y'},
-	{"DI",		REGOFF(di),	RINT, 'Y'},
-	{"BP",		REGOFF(bp),	RINT, 'Y'},
-	{"R8",		REGOFF(r8),	RINT, 'Y'},
-	{"R9",		REGOFF(r9),	RINT, 'Y'},
-	{"R10",		REGOFF(r10),	RINT, 'Y'},
-	{"R11",		REGOFF(r11),	RINT, 'Y'},
-	{"R12",		REGOFF(r12),	RINT, 'Y'},
-	{"R13",		REGOFF(r13),	RINT, 'Y'},
-	{"R14",		REGOFF(r14),	RINT, 'Y'},
-	{"R15",		REGOFF(r15),	RINT, 'Y'},
-	{"DS",		REGOFF(ds),	RINT, 'x'},
-	{"ES",		REGOFF(es),	RINT, 'x'},
-	{"FS",		REGOFF(fs),	RINT, 'x'},
-	{"GS",		REGOFF(gs),	RINT, 'x'},
-	{"TYPE",	REGOFF(type), 	RINT, 'Y'},
-	{"TRAP",	REGOFF(type), 	RINT, 'Y'},	/* alias for acid */
-	{"ERROR",	REGOFF(error),	RINT, 'Y'},
-	{"IP",		REGOFF(ip),	RINT, 'Y'},
-	{"PC",		REGOFF(ip),	RINT, 'Y'},	/* alias for acid */
-	{"CS",		REGOFF(cs),	RINT, 'Y'},
-	{"FLAGS",	REGOFF(flags),	RINT, 'Y'},
-	{"SP",		REGOFF(sp),	RINT, 'Y'},
-	{"SS",		REGOFF(ss),	RINT, 'Y'},
-
-	{"FCW",		FP_CTLS(0),	RFLT, 'x'},
-	{"FSW",		FP_CTLS(1),	RFLT, 'x'},
-	{"FTW",		FP_CTLS(2),	RFLT, 'b'},
-	{"FOP",		FP_CTLS(3),	RFLT, 'x'},
-	{"RIP",		FP_CTL(2),	RFLT, 'Y'},
-	{"RDP",		FP_CTL(4),	RFLT, 'Y'},
-	{"MXCSR",	FP_CTL(6),	RFLT, 'X'},
-	{"MXCSRMASK",	FP_CTL(7),	RFLT, 'X'},
-	{"M0",		FP_REG(0),	RFLT, 'F'},	/* assumes double */
-	{"M1",		FP_REG(1),	RFLT, 'F'},
-	{"M2",		FP_REG(2),	RFLT, 'F'},
-	{"M3",		FP_REG(3),	RFLT, 'F'},
-	{"M4",		FP_REG(4),	RFLT, 'F'},
-	{"M5",		FP_REG(5),	RFLT, 'F'},
-	{"M6",		FP_REG(6),	RFLT, 'F'},
-	{"M7",		FP_REG(7),	RFLT, 'F'},
-	{"X0",		XM_REG(0),	RFLT, 'F'},	/* assumes double */
-	{"X1",		XM_REG(1),	RFLT, 'F'},
-	{"X2",		XM_REG(2),	RFLT, 'F'},
-	{"X3",		XM_REG(3),	RFLT, 'F'},
-	{"X4",		XM_REG(4),	RFLT, 'F'},
-	{"X5",		XM_REG(5),	RFLT, 'F'},
-	{"X6",		XM_REG(6),	RFLT, 'F'},
-	{"X7",		XM_REG(7),	RFLT, 'F'},
-	{"X8",		XM_REG(8),	RFLT, 'F'},
-	{"X9",		XM_REG(9),	RFLT, 'F'},
-	{"X10",		XM_REG(10),	RFLT, 'F'},
-	{"X11",		XM_REG(11),	RFLT, 'F'},
-	{"X12",		XM_REG(12),	RFLT, 'F'},
-	{"X13",		XM_REG(13),	RFLT, 'F'},
-	{"X14",		XM_REG(14),	RFLT, 'F'},
-	{"X15",		XM_REG(15),	RFLT, 'F'},
-	{"X16",		XM_REG(16),	RFLT, 'F'},
-/*
-	{"F0",		FP_REG(7),	RFLT, '3'},
-	{"F1",		FP_REG(6),	RFLT, '3'},
-	{"F2",		FP_REG(5),	RFLT, '3'},
-	{"F3",		FP_REG(4),	RFLT, '3'},
-	{"F4",		FP_REG(3),	RFLT, '3'},
-	{"F5",		FP_REG(2),	RFLT, '3'},
-	{"F6",		FP_REG(1),	RFLT, '3'},
-	{"F7",		FP_REG(0),	RFLT, '3'},
-*/
-	{  0 }
-};
-
-Mach mamd64=
-{
-	"amd64",
-	MAMD64,			/* machine type */
-	amd64reglist,		/* register list */
-	REGSIZE,		/* size of registers in bytes */
-	FPREGSIZE,		/* size of fp registers in bytes */
-	"PC",			/* name of PC */
-	"SP",			/* name of SP */
-	0,			/* link register */
-	"setSB",		/* static base register name (bogus anyways) */
-	0,			/* static base register value */
-	0x1000,			/* page size */
-	0xFFFFFFFF80110000ULL,	/* kernel base */
-	0xFFFF800000000000ULL,	/* kernel text mask */
-	0x00007FFFFFFFF000ULL,	/* user stack top */
-	1,			/* quantization of pc */
-	8,			/* szaddr */
-	4,			/* szreg */
-	4,			/* szfloat */
-	8,			/* szdouble */
-};
diff --git a/src/libmach/6obj.c b/src/libmach/6obj.c
deleted file mode 100644
index 1921c9e..0000000
--- a/src/libmach/6obj.c
+++ /dev/null
@@ -1,173 +0,0 @@
-// Inferno libmach/6obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/6obj.c
-//
-// 	Copyright © 1994-1999 Lucent Technologies Inc.
-// 	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth at 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.
-
-/*
- * 6obj.c - identify and parse an amd64 object file
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-#include "../cmd/6l/6.out.h"
-#include "obj.h"
-
-typedef struct Addr	Addr;
-struct Addr
-{
-	char	sym;
-	char	flags;
-	char gotype;
-};
-static	Addr	addr(Biobuf*);
-static	char	type2char(int);
-static	void	skip(Biobuf*, int);
-
-int
-_is6(char *t)
-{
-	uchar *s = (uchar*)t;
-
-	return  s[0] == (ANAME&0xff)			/* also = ANAME */
-		&& s[1] == ((ANAME>>8)&0xff)
-		&& s[2] == D_FILE			/* type */
-		&& s[3] == 1				/* sym */
-		&& s[4] == '<';				/* name of file */
-}
-
-int
-_read6(Biobuf *bp, Prog* p)
-{
-	int as, n, c;
-	Addr a;
-
-	as = BGETC(bp);		/* as(low) */
-	if(as < 0)
-		return 0;
-	c = BGETC(bp);		/* as(high) */
-	if(c < 0)
-		return 0;
-	as |= ((c & 0xff) << 8);
-	p->kind = aNone;
-	p->sig = 0;
-	if(as == ANAME || as == ASIGNAME){
-		if(as == ASIGNAME){
-			Bread(bp, &p->sig, 4);
-			p->sig = leswal(p->sig);
-		}
-		p->kind = aName;
-		p->type = type2char(BGETC(bp));		/* type */
-		p->sym = BGETC(bp);			/* sym */
-		n = 0;
-		for(;;) {
-			as = BGETC(bp);
-			if(as < 0)
-				return 0;
-			n++;
-			if(as == 0)
-				break;
-		}
-		p->id = malloc(n);
-		if(p->id == 0)
-			return 0;
-		Bseek(bp, -n, 1);
-		if(Bread(bp, p->id, n) != n)
-			return 0;
-		return 1;
-	}
-	if(as == ATEXT)
-		p->kind = aText;
-	if(as == AGLOBL)
-		p->kind = aData;
-	skip(bp, 4);		/* lineno(4) */
-	a = addr(bp);
-	addr(bp);
-	if(!(a.flags & T_SYM))
-		p->kind = aNone;
-	p->sym = a.sym;
-	return 1;
-}
-
-static Addr
-addr(Biobuf *bp)
-{
-	Addr a;
-	int t;
-	int32 l;
-	vlong off;
-
-	off = 0;
-	a.sym = -1;
-	a.flags = BGETC(bp);			/* flags */
-	a.gotype = 0;
-	if(a.flags & T_INDEX)
-		skip(bp, 2);
-	if(a.flags & T_OFFSET){
-		l = BGETLE4(bp);
-		off = l;
-		if(a.flags & T_64){
-			l = BGETLE4(bp);
-			off = ((vlong)l << 32) | (off & 0xFFFFFFFF);
-		}
-		if(off < 0)
-			off = -(uvlong)off;
-	}
-	if(a.flags & T_SYM)
-		a.sym = BGETC(bp);
-	if(a.flags & T_FCONST)
-		skip(bp, 8);
-	else
-	if(a.flags & T_SCONST)
-		skip(bp, NSNAME);
-	if(a.flags & T_TYPE) {
-		t = BGETC(bp);
-		if(a.sym > 0 && (t==D_PARAM || t==D_AUTO))
-			_offset(a.sym, off);
-	}
-	if(a.flags & T_GOTYPE)
-		a.gotype = BGETC(bp);
-	return a;
-}
-
-static char
-type2char(int t)
-{
-	switch(t){
-	case D_EXTERN:		return 'U';
-	case D_STATIC:		return 'b';
-	case D_AUTO:		return 'a';
-	case D_PARAM:		return 'p';
-	default:		return UNKNOWN;
-	}
-}
-
-static void
-skip(Biobuf *bp, int n)
-{
-	while (n-- > 0)
-		Bgetc(bp);
-}
diff --git a/src/libmach/8.c b/src/libmach/8.c
deleted file mode 100644
index 34248e6..0000000
--- a/src/libmach/8.c
+++ /dev/null
@@ -1,108 +0,0 @@
-// Inferno libmach/8.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/8.c
-//
-// 	Copyright © 1994-1999 Lucent Technologies Inc.
-// 	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth at 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.
-
-/*
- * 386 definition
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <ureg_x86.h>
-#include <mach.h>
-
-#define	REGOFF(x)	(uintptr)(&((struct Ureg *) 0)->x)
-
-#define PC		REGOFF(pc)
-#define SP		REGOFF(sp)
-#define	AX		REGOFF(ax)
-
-#define	REGSIZE		sizeof(struct Ureg)
-#define FP_CTL(x)	(REGSIZE+4*(x))
-#define FP_REG(x)	(FP_CTL(7)+10*(x))
-#define	FPREGSIZE	(7*4+8*10)
-
-Reglist i386reglist[] = {
-	{"DI",		REGOFF(di),	RINT, 'X'},
-	{"SI",		REGOFF(si),	RINT, 'X'},
-	{"BP",		REGOFF(bp),	RINT, 'X'},
-	{"BX",		REGOFF(bx),	RINT, 'X'},
-	{"DX",		REGOFF(dx),	RINT, 'X'},
-	{"CX",		REGOFF(cx),	RINT, 'X'},
-	{"AX",		REGOFF(ax),	RINT, 'X'},
-	{"GS",		REGOFF(gs),	RINT, 'X'},
-	{"FS",		REGOFF(fs),	RINT, 'X'},
-	{"ES",		REGOFF(es),	RINT, 'X'},
-	{"DS",		REGOFF(ds),	RINT, 'X'},
-	{"TRAP",	REGOFF(trap), 	RINT, 'X'},
-	{"ECODE",	REGOFF(ecode),	RINT, 'X'},
-	{"PC",		PC,		RINT, 'X'},
-	{"CS",		REGOFF(cs),	RINT, 'X'},
-	{"EFLAGS",	REGOFF(flags),	RINT, 'X'},
-	{"SP",		SP,		RINT, 'X'},
-	{"SS",		REGOFF(ss),	RINT, 'X'},
-
-	{"E0",		FP_CTL(0),	RFLT, 'X'},
-	{"E1",		FP_CTL(1),	RFLT, 'X'},
-	{"E2",		FP_CTL(2),	RFLT, 'X'},
-	{"E3",		FP_CTL(3),	RFLT, 'X'},
-	{"E4",		FP_CTL(4),	RFLT, 'X'},
-	{"E5",		FP_CTL(5),	RFLT, 'X'},
-	{"E6",		FP_CTL(6),	RFLT, 'X'},
-	{"F0",		FP_REG(0),	RFLT, '3'},
-	{"F1",		FP_REG(1),	RFLT, '3'},
-	{"F2",		FP_REG(2),	RFLT, '3'},
-	{"F3",		FP_REG(3),	RFLT, '3'},
-	{"F4",		FP_REG(4),	RFLT, '3'},
-	{"F5",		FP_REG(5),	RFLT, '3'},
-	{"F6",		FP_REG(6),	RFLT, '3'},
-	{"F7",		FP_REG(7),	RFLT, '3'},
-	{  0 }
-};
-
-Mach mi386 =
-{
-	"386",
-	MI386,		/* machine type */
-	i386reglist,	/* register list */
-	REGSIZE,	/* size of registers in bytes */
-	FPREGSIZE,	/* size of fp registers in bytes */
-	"PC",		/* name of PC */
-	"SP",		/* name of SP */
-	0,		/* link register */
-	"setSB",	/* static base register name (bogus anyways) */
-	0,		/* static base register value */
-	0x1000,		/* page size */
-	0x80100000ULL,	/* kernel base */
-	0xF0000000ULL,	/* kernel text mask */
-	0xFFFFFFFFULL,	/* user stack top */
-	1,		/* quantization of pc */
-	4,		/* szaddr */
-	4,		/* szreg */
-	4,		/* szfloat */
-	8,		/* szdouble */
-};
diff --git a/src/libmach/8db.c b/src/libmach/8db.c
deleted file mode 100644
index cfc9cb9..0000000
--- a/src/libmach/8db.c
+++ /dev/null
@@ -1,2447 +0,0 @@
-// Inferno libmach/8db.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/8db.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.
-//	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth at 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.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-#define Ureg UregAmd64
-#include <ureg_amd64.h>
-#undef Ureg
-#define Ureg Ureg386
-#include <ureg_x86.h>
-#undef Ureg
-
-typedef struct UregAmd64 UregAmd64;
-typedef struct Ureg386 Ureg386;
-
-/*
- * i386-specific debugger interface
- * also amd64 extensions
- */
-
-static	char	*i386excep(Map*, Rgetter);
-
-static	int	i386trace(Map*, uvlong, uvlong, uvlong, Tracer);
-static	uvlong	i386frame(Map*, uvlong, uvlong, uvlong, uvlong);
-static	int	i386foll(Map*, uvlong, Rgetter, uvlong*);
-static	int	i386inst(Map*, uvlong, char, char*, int);
-static	int	i386das(Map*, uvlong, char*, int);
-static	int	i386instlen(Map*, uvlong);
-
-static	char	STARTSYM[] =	"_main";
-static	char	GOSTARTSYM[] =	"sys·goexit";
-static	char	PROFSYM[] =	"_mainp";
-static	char	FRAMENAME[] =	".frame";
-static	char	LESSSTACK[] = "sys·lessstack";
-static	char	MORESTACK[] = "sys·morestack";
-static char *excname[] =
-{
-[0] =	"divide error",
-[1] =	"debug exception",
-[4] =	"overflow",
-[5] =	"bounds check",
-[6] =	"invalid opcode",
-[7] =	"math coprocessor emulation",
-[8] =	"double fault",
-[9] =	"math coprocessor overrun",
-[10] =	"invalid TSS",
-[11] =	"segment not present",
-[12] =	"stack exception",
-[13] =	"general protection violation",
-[14] =	"page fault",
-[16] =	"math coprocessor error",
-[17] =	"alignment check",
-[18] =	"machine check",
-[19] =	"floating-point exception",
-[24] =	"clock",
-[25] =	"keyboard",
-[27] =	"modem status",
-[28] =	"serial line status",
-[30] =	"floppy disk",
-[36] =	"mouse",
-[37] =	"math coprocessor",
-[38] =	"hard disk",
-[64] =	"system call",
-};
-
-Machdata i386mach =
-{
-	{0xCC, 0, 0, 0},	/* break point: INT 3 */
-	1,			/* break point size */
-
-	leswab,			/* convert short to local byte order */
-	leswal,			/* convert int32 to local byte order */
-	leswav,			/* convert vlong to local byte order */
-	i386trace,		/* C traceback */
-	i386frame,		/* frame finder */
-	i386excep,		/* print exception */
-	0,			/* breakpoint fixup */
-	leieeesftos,		/* single precision float printer */
-	leieeedftos,		/* double precision float printer */
-	i386foll,		/* following addresses */
-	i386inst,		/* print instruction */
-	i386das,		/* dissembler */
-	i386instlen,		/* instruction size calculation */
-};
-
-static char*
-i386excep(Map *map, Rgetter rget)
-{
-	uint32 c;
-	uvlong pc;
-	static char buf[16];
-
-	c = (*rget)(map, "TRAP");
-	if(c > 64 || excname[c] == 0) {
-		if (c == 3) {
-			pc = (*rget)(map, "PC");
-			if (get1(map, pc, (uchar*)buf, machdata->bpsize) > 0)
-			if (memcmp(buf, machdata->bpinst, machdata->bpsize) == 0)
-				return "breakpoint";
-		}
-		snprint(buf, sizeof(buf), "exception %d", c);
-		return buf;
-	} else
-		return excname[c];
-}
-
-static int
-i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
-{
-	int i;
-	uvlong osp, pc1;
-	Symbol s, f, s1;
-	extern Mach mamd64;
-	int isamd64;
-	uvlong g, m, lessstack, morestack, stktop;
-
-	isamd64 = (mach == &mamd64);
-
-	// ../pkg/runtime/runtime.h
-	// G is
-	//	byte* stackguard
-	//	byte* stackbase (= Stktop*)
-	// TODO(rsc): Need some way to get at the g for other threads.
-	// Probably need to pass it into the trace function.
-	g = 0;
-	if(isamd64)
-		geta(map, offsetof(struct UregAmd64, r15), &g);
-	else {
-		// TODO(rsc): How to fetch g on 386?
-	}
-	stktop = 0;
-	if(g != 0)
-		geta(map, g+1*mach->szaddr, &stktop);
-
-	lessstack = 0;
-	if(lookup(0, LESSSTACK, &s))
-		lessstack = s.value;
-	morestack = 0;
-	if(lookup(0, MORESTACK, &s))
-		morestack = s.value;
-
-	USED(link);
-	osp = 0;
-	i = 0;
-
-	for(;;) {
-		if(!findsym(pc, CTEXT, &s)) {
-			// check for closure return sequence
-			uchar buf[8], *p;
-			if(get1(map, pc, buf, 8) < 0)
-				break;
-			// ADDQ $xxx, SP; RET
-			p = buf;
-			if(mach == &mamd64) {
-				if(p[0] != 0x48)
-					break;
-				p++;
-			}
-			if(p[0] != 0x81 || p[1] != 0xc4 || p[6] != 0xc3)
-				break;
-			sp += p[2] | (p[3]<<8) | (p[4]<<16) | (p[5]<<24);
-			if(geta(map, sp, &pc) < 0)
-				break;
-			sp += mach->szaddr;
-			continue;
-		}
-
-		if (osp == sp)
-			break;
-		osp = sp;
-
-		if(strcmp(STARTSYM, s.name) == 0 ||
-		   strcmp(GOSTARTSYM, s.name) == 0 ||
-		   strcmp(PROFSYM, s.name) == 0)
-			break;
-
-		if(s.value == morestack) {
-			// This code is old and won't work anymore.
-			// But no one uses it anyway.
-			// Leave it obviously broken until someone needs it.
-			werrstr("morestack not implemented correctly");
-			return -1;
-			// In the middle of morestack.
-			// Caller is m->morepc.
-			// Caller's caller is in m->morearg.
-			// TODO(rsc): 386
-			geta(map, offsetof(struct UregAmd64, r14), &m);
-
-			pc = 0;
-			sp = 0;
-			pc1 = 0;
-			s1 = s;
-			memset(&s, 0, sizeof s);
-			geta(map, m+1*mach->szaddr, &pc1);	// m->morepc
-			geta(map, m+2*mach->szaddr, &sp);	// m->morebuf.sp
-			geta(map, m+3*mach->szaddr, &pc);	// m->morebuf.pc
-			findsym(pc1, CTEXT, &s);
-			(*trace)(map, pc1, sp-mach->szaddr, &s1);	// morestack symbol; caller's PC/SP
-
-			// caller's caller
-			s1 = s;
-			findsym(pc, CTEXT, &s);
-			(*trace)(map, pc, sp, &s1);		// morestack's caller; caller's caller's PC/SP
-			continue;
-		}
-
-		if(pc == lessstack) {
-			// ../pkg/runtime/runtime.h
-			// Stktop is
-			//	byte* stackguard
-			//	byte* stackbase
-			//	Gobuf gobuf
-			//		byte* sp;
-			//		byte* pc;
-			//		G*	g;
-			if(!isamd64)
-				fprint(2, "warning: cannot unwind stack split on 386\n");
-			if(stktop == 0)
-				break;
-			pc = 0;
-			sp = 0;
-			geta(map, stktop+2*mach->szaddr, &sp);
-			geta(map, stktop+3*mach->szaddr, &pc);
-			geta(map, stktop+1*mach->szaddr, &stktop);
-			(*trace)(map, pc, sp, &s1);
-			continue;
-		}
-
-		s1 = s;
-		pc1 = 0;
-		if(pc != s.value) {	/* not at first instruction */
-			if(findlocal(&s, FRAMENAME, &f) == 0)
-				break;
-			geta(map, sp, &pc1);
-			sp += f.value-mach->szaddr;
-		}
-		if(geta(map, sp, &pc) < 0)
-			break;
-
-		// If PC is not valid, assume we caught the function
-		// before it moved the stack pointer down or perhaps
-		// after it moved the stack pointer back up.
-		// Try the PC we'd have gotten without the stack
-		// pointer adjustment above (pc != s.value).
-		// This only matters for the first frame, and it is only
-		// a heuristic, but it does help.
-		if(!findsym(pc, CTEXT, &s) || strcmp(s.name, "etext") == 0)
-			pc = pc1;
-
-		if(pc == 0)
-			break;
-
-		if(pc != lessstack)
-			(*trace)(map, pc, sp, &s1);
-		sp += mach->szaddr;
-
-		if(++i > 1000)
-			break;
-	}
-	return i;
-}
-
-static uvlong
-i386frame(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link)
-{
-	Symbol s, f;
-
-	USED(link);
-	while (findsym(pc, CTEXT, &s)) {
-		if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
-			break;
-
-		if(pc != s.value) {	/* not first instruction */
-			if(findlocal(&s, FRAMENAME, &f) == 0)
-				break;
-			sp += f.value-mach->szaddr;
-		}
-
-		if (s.value == addr)
-			return sp;
-
-		if (geta(map, sp, &pc) < 0)
-			break;
-		sp += mach->szaddr;
-	}
-	return 0;
-}
-
-	/* I386/486 - Disassembler and related functions */
-
-/*
- *  an instruction
- */
-typedef struct Instr Instr;
-struct	Instr
-{
-	uchar	mem[1+1+1+1+2+1+1+4+4];		/* raw instruction */
-	uvlong	addr;		/* address of start of instruction */
-	int	n;		/* number of bytes in instruction */
-	char	*prefix;	/* instr prefix */
-	char	*segment;	/* segment override */
-	uchar	jumptype;	/* set to the operand type for jump/ret/call */
-	uchar	amd64;
-	uchar	rex;		/* REX prefix (or zero) */
-	char	osize;		/* 'W' or 'L' (or 'Q' on amd64) */
-	char	asize;		/* address size 'W' or 'L' (or 'Q' or amd64) */
-	uchar	mod;		/* bits 6-7 of mod r/m field */
-	uchar	reg;		/* bits 3-5 of mod r/m field */
-	char	ss;		/* bits 6-7 of SIB */
-	schar	index;		/* bits 3-5 of SIB */
-	schar	base;		/* bits 0-2 of SIB */
-	char	rip;		/* RIP-relative in amd64 mode */
-	uchar	opre;		/* f2/f3 could introduce media */
-	short	seg;		/* segment of far address */
-	uint32	disp;		/* displacement */
-	uint32 	imm;		/* immediate */
-	uint32 	imm2;		/* second immediate operand */
-	uvlong	imm64;		/* big immediate */
-	char	*curr;		/* fill level in output buffer */
-	char	*end;		/* end of output buffer */
-	char	*err;		/* error message */
-};
-
-	/* 386 register (ha!) set */
-enum{
-	AX=0,
-	CX,
-	DX,
-	BX,
-	SP,
-	BP,
-	SI,
-	DI,
-
-	/* amd64 */
-	/* be careful: some unix system headers #define R8, R9, etc */
-	AMD64_R8,
-	AMD64_R9,
-	AMD64_R10,
-	AMD64_R11,
-	AMD64_R12,
-	AMD64_R13,
-	AMD64_R14,
-	AMD64_R15
-};
-
-	/* amd64 rex extension byte */
-enum{
-	REXW		= 1<<3,	/* =1, 64-bit operand size */
-	REXR		= 1<<2,	/* extend modrm reg */
-	REXX		= 1<<1,	/* extend sib index */
-	REXB		= 1<<0	/* extend modrm r/m, sib base, or opcode reg */
-};
-
-	/* Operand Format codes */
-/*
-%A	-	address size register modifier (!asize -> 'E')
-%C	-	Control register CR0/CR1/CR2
-%D	-	Debug register DR0/DR1/DR2/DR3/DR6/DR7
-%I	-	second immediate operand
-%O	-	Operand size register modifier (!osize -> 'E')
-%T	-	Test register TR6/TR7
-%S	-	size code ('W' or 'L')
-%W	-	Weird opcode: OSIZE == 'W' => "CBW"; else => "CWDE"
-%d	-	displacement 16-32 bits
-%e	-	effective address - Mod R/M value
-%f	-	floating point register F0-F7 - from Mod R/M register
-%g	-	segment register
-%i	-	immediate operand 8-32 bits
-%p	-	PC-relative - signed displacement in immediate field
-%r	-	Reg from Mod R/M
-%w	-	Weird opcode: OSIZE == 'W' => "CWD"; else => "CDQ"
-*/
-
-typedef struct Optable Optable;
-struct Optable
-{
-	char	operand[2];
-	void	*proto;		/* actually either (char*) or (Optable*) */
-};
-	/* Operand decoding codes */
-enum {
-	Ib = 1,			/* 8-bit immediate - (no sign extension)*/
-	Ibs,			/* 8-bit immediate (sign extended) */
-	Jbs,			/* 8-bit sign-extended immediate in jump or call */
-	Iw,			/* 16-bit immediate -> imm */
-	Iw2,			/* 16-bit immediate -> imm2 */
-	Iwd,			/* Operand-sized immediate (no sign extension)*/
-	Iwdq,			/* Operand-sized immediate, possibly 64 bits */
-	Awd,			/* Address offset */
-	Iwds,			/* Operand-sized immediate (sign extended) */
-	RM,			/* Word or int32 R/M field with register (/r) */
-	RMB,			/* Byte R/M field with register (/r) */
-	RMOP,			/* Word or int32 R/M field with op code (/digit) */
-	RMOPB,			/* Byte R/M field with op code (/digit) */
-	RMR,			/* R/M register only (mod = 11) */
-	RMM,			/* R/M memory only (mod = 0/1/2) */
-	Op_R0,			/* Base reg of Mod R/M is literal 0x00 */
-	Op_R1,			/* Base reg of Mod R/M is literal 0x01 */
-	FRMOP,			/* Floating point R/M field with opcode */
-	FRMEX,			/* Extended floating point R/M field with opcode */
-	JUMP,			/* Jump or Call flag - no operand */
-	RET,			/* Return flag - no operand */
-	OA,			/* literal 0x0a byte */
-	PTR,			/* Seg:Displacement addr (ptr16:16 or ptr16:32) */
-	AUX,			/* Multi-byte op code - Auxiliary table */
-	AUXMM,			/* multi-byte op code - auxiliary table chosen by prefix */
-	PRE,			/* Instr Prefix */
-	OPRE,			/* Instr Prefix or media op extension */
-	SEG,			/* Segment Prefix */
-	OPOVER,			/* Operand size override */
-	ADDOVER,		/* Address size override */
-};
-
-static Optable optab0F00[8]=
-{
-[0x00] =	{ 0,0,		"MOVW	LDT,%e" },
-[0x01] =	{ 0,0,		"MOVW	TR,%e" },
-[0x02] =	{ 0,0,		"MOVW	%e,LDT" },
-[0x03] =	{ 0,0,		"MOVW	%e,TR" },
-[0x04] =	{ 0,0,		"VERR	%e" },
-[0x05] =	{ 0,0,		"VERW	%e" },
-};
-
-static Optable optab0F01[8]=
-{
-[0x00] =	{ 0,0,		"MOVL	GDTR,%e" },
-[0x01] =	{ 0,0,		"MOVL	IDTR,%e" },
-[0x02] =	{ 0,0,		"MOVL	%e,GDTR" },
-[0x03] =	{ 0,0,		"MOVL	%e,IDTR" },
-[0x04] =	{ 0,0,		"MOVW	MSW,%e" },	/* word */
-[0x06] =	{ 0,0,		"MOVW	%e,MSW" },	/* word */
-[0x07] =	{ 0,0,		"INVLPG	%e" },		/* or SWAPGS */
-};
-
-static Optable optab0F01F8[1]=
-{
-[0x00] =	{ 0,0,		"SWAPGS" },
-};
-
-/* 0F71 */
-/* 0F72 */
-/* 0F73 */
-
-static Optable optab0FAE[8]=
-{
-[0x00] =	{ 0,0,		"FXSAVE	%e" },
-[0x01] =	{ 0,0,		"FXRSTOR	%e" },
-[0x02] =	{ 0,0,		"LDMXCSR	%e" },
-[0x03] =	{ 0,0,		"STMXCSR	%e" },
-[0x05] =	{ 0,0,		"LFENCE" },
-[0x06] =	{ 0,0,		"MFENCE" },
-[0x07] =	{ 0,0,		"SFENCE" },
-};
-
-static Optable optab0F18[4]=
-{
-[0x00] =	{ 0,0,		"PREFETCHNTA	%e" },
-[0x01] = 	{ 0,0,		"PREFECTCH0	%e" },
-[0x02] = 	{ 0,0,		"PREFECTCH1	%e" },
-[0x03] = 	{ 0,0,		"PREFECTCH2	%e" },
-};
-
-/* 0F0D */
-
-static Optable optab0FBA[8]=
-{
-[0x04] =	{ Ib,0,		"BT%S	%i,%e" },
-[0x05] =	{ Ib,0,		"BTS%S	%i,%e" },
-[0x06] =	{ Ib,0,		"BTR%S	%i,%e" },
-[0x07] =	{ Ib,0,		"BTC%S	%i,%e" },
-};
-
-static Optable optab0F0F[256]=
-{
-[0x0c] =	{ 0,0,		"PI2FW	%m,%M" },
-[0x0d] =	{ 0,0,		"PI2L	%m,%M" },
-[0x1c] =	{ 0,0,		"PF2IW	%m,%M" },
-[0x1d] =	{ 0,0,		"PF2IL	%m,%M" },
-[0x8a] =	{ 0,0,		"PFNACC	%m,%M" },
-[0x8e] =	{ 0,0,		"PFPNACC	%m,%M" },
-[0x90] =	{ 0,0,		"PFCMPGE	%m,%M" },
-[0x94] =	{ 0,0,		"PFMIN	%m,%M" },
-[0x96] =	{ 0,0,		"PFRCP	%m,%M" },
-[0x97] =	{ 0,0,		"PFRSQRT	%m,%M" },
-[0x9a] =	{ 0,0,		"PFSUB	%m,%M" },
-[0x9e] =	{ 0,0,		"PFADD	%m,%M" },
-[0xa0] =	{ 0,0,		"PFCMPGT	%m,%M" },
-[0xa4] =	{ 0,0,		"PFMAX	%m,%M" },
-[0xa6] =	{ 0,0,		"PFRCPIT1	%m,%M" },
-[0xa7] =	{ 0,0,		"PFRSQIT1	%m,%M" },
-[0xaa] =	{ 0,0,		"PFSUBR	%m,%M" },
-[0xae] =	{ 0,0,		"PFACC	%m,%M" },
-[0xb0] =	{ 0,0,		"PFCMPEQ	%m,%M" },
-[0xb4] =	{ 0,0,		"PFMUL	%m,%M" },
-[0xb6] =	{ 0,0,		"PFRCPI2T	%m,%M" },
-[0xb7] =	{ 0,0,		"PMULHRW	%m,%M" },
-[0xbb] =	{ 0,0,		"PSWAPL	%m,%M" },
-};
-
-static Optable optab0FC7[8]=
-{
-[0x01] =	{ 0,0,		"CMPXCHG8B	%e" },
-};
-
-static Optable optab660F38[256]=
-{
-[0x00] =	{ RM,0,		"PSHUFB	%x,%X" },
-[0xdc] =	{ RM,0,		"AESENC	%x,%X" },
-[0xdb] =	{ RM,0,		"AESIMC	%x,%X," },
-[0xdd] =	{ RM,0,		"AESENCLAST	%x,%X" },
-[0xde] =	{ RM,0,		"AESDEC	%x,%X" },
-[0xdf] =	{ RM,0,		"AESDECLAST	%x,%X" },
-};
-
-static Optable optab660F3A[256]=
-{
-[0x22] =	{ RM,Ib,		"PINSR%S	%i,%e,%X" },
-[0xdf] =	{ RM,Ib,		"AESKEYGENASSIST	%i,%x,%X" },
-};
-
-static Optable optab660F71[8]=
-{
-[0x02] =	{ Ib,0,		"PSRLW	%i,%X" },
-[0x04] =	{ Ib,0,		"PSRAW	%i,%X" },
-[0x06] =	{ Ib,0,		"PSLLW	%i,%X" },
-};
-
-static Optable optab660F72[8]=
-{
-[0x02] =	{ Ib,0,		"PSRLL	%i,%X" },
-[0x04] =	{ Ib,0,		"PSRAL	%i,%X" },
-[0x06] =	{ Ib,0,		"PSLLL	%i,%X" },
-};
-
-static Optable optab660F73[8]=
-{
-[0x02] =	{ Ib,0,		"PSRLQ	%i,%X" },
-[0x03] =	{ Ib,0,		"PSRLO	%i,%X" },
-[0x06] =	{ Ib,0,		"PSLLQ	%i,%X" },
-[0x07] =	{ Ib,0,		"PSLLO	%i,%X" },
-};
-
-static Optable optab660F[256]=
-{
-[0x2B] =	{ RM,0,		"MOVNTPD	%x,%e" },
-[0x2E] =	{ RM,0,		"UCOMISD	%x,%X" },
-[0x2F] =	{ RM,0,		"COMISD	%x,%X" },
-[0x38] =	{ AUX,0,		optab660F38 },
-[0x3A] =	{ AUX,0,		optab660F3A },
-[0x5A] =	{ RM,0,		"CVTPD2PS	%x,%X" },
-[0x5B] =	{ RM,0,		"CVTPS2PL	%x,%X" },
-[0x6A] =	{ RM,0,		"PUNPCKHLQ	%x,%X" },
-[0x6B] =	{ RM,0,		"PACKSSLW	%x,%X" },
-[0x6C] =	{ RM,0,		"PUNPCKLQDQ	%x,%X" },
-[0x6D] =	{ RM,0,		"PUNPCKHQDQ	%x,%X" },
-[0x6E] =	{ RM,0,		"MOV%S	%e,%X" },
-[0x6F] =	{ RM,0,		"MOVO	%x,%X" },		/* MOVDQA */
-[0x70] =	{ RM,Ib,		"PSHUFL	%i,%x,%X" },
-[0x71] =	{ RMOP,0,		optab660F71 },
-[0x72] =	{ RMOP,0,		optab660F72 },
-[0x73] =	{ RMOP,0,		optab660F73 },
-[0x7E] =	{ RM,0,		"MOV%S	%X,%e" },
-[0x7F] =	{ RM,0,		"MOVO	%X,%x" },
-[0xC4] =	{ RM,Ib,		"PINSRW	%i,%e,%X" },
-[0xC5] =	{ RMR,Ib,		"PEXTRW	%i,%X,%e" },
-[0xD4] =	{ RM,0,		"PADDQ	%x,%X" },
-[0xD5] =	{ RM,0,		"PMULLW	%x,%X" },
-[0xD6] =	{ RM,0,		"MOVQ	%X,%x" },
-[0xE6] =	{ RM,0,		"CVTTPD2PL	%x,%X" },
-[0xE7] =	{ RM,0,		"MOVNTO	%X,%e" },
-[0xF7] =	{ RM,0,		"MASKMOVOU	%x,%X" },
-};
-
-static Optable optabF20F38[256]=
-{
-[0xf0] =	{ RM,0,		"CRC32B	%e, %r" },
-[0xf1] =	{ RM,0,		"CRC32%S	%e, %r" },
-};
-
-static Optable optabF20F[256]=
-{
-[0x10] =	{ RM,0,		"MOVSD	%x,%X" },
-[0x11] =	{ RM,0,		"MOVSD	%X,%x" },
-[0x2A] =	{ RM,0,		"CVTS%S2SD	%e,%X" },
-[0x2C] =	{ RM,0,		"CVTTSD2S%S	%x,%r" },
-[0x2D] =	{ RM,0,		"CVTSD2S%S	%x,%r" },
-[0x38] =	{ AUX,0,		optabF20F38 },
-[0x5A] =	{ RM,0,		"CVTSD2SS	%x,%X" },
-[0x6F] =	{ RM,0,		"MOVOU	%x,%X" },
-[0x70] =	{ RM,Ib,		"PSHUFLW	%i,%x,%X" },
-[0x7F] =	{ RM,0,		"MOVOU	%X,%x" },
-[0xD6] =	{ RM,0,		"MOVQOZX	%M,%X" },
-[0xE6] =	{ RM,0,		"CVTPD2PL	%x,%X" },
-};
-
-static Optable optabF30F[256]=
-{
-[0x10] =	{ RM,0,		"MOVSS	%x,%X" },
-[0x11] =	{ RM,0,		"MOVSS	%X,%x" },
-[0x2A] =	{ RM,0,		"CVTS%S2SS	%e,%X" },
-[0x2C] =	{ RM,0,		"CVTTSS2S%S	%x,%r" },
-[0x2D] =	{ RM,0,		"CVTSS2S%S	%x,%r" },
-[0x5A] =	{ RM,0,		"CVTSS2SD	%x,%X" },
-[0x5B] =	{ RM,0,		"CVTTPS2PL	%x,%X" },
-[0x6F] =	{ RM,0,		"MOVOU	%x,%X" },
-[0x70] =	{ RM,Ib,		"PSHUFHW	%i,%x,%X" },
-[0x7E] =	{ RM,0,		"MOVQOZX	%x,%X" },
-[0x7F] =	{ RM,0,		"MOVOU	%X,%x" },
-[0xD6] =	{ RM,0,		"MOVQOZX	%m*,%X" },
-[0xE6] =	{ RM,0,		"CVTPL2PD	%x,%X" },
-};
-
-static Optable optab0F[256]=
-{
-[0x00] =	{ RMOP,0,		optab0F00 },
-[0x01] =	{ RMOP,0,		optab0F01 },
-[0x02] =	{ RM,0,		"LAR	%e,%r" },
-[0x03] =	{ RM,0,		"LSL	%e,%r" },
-[0x05] =	{ 0,0,		"SYSCALL" },
-[0x06] =	{ 0,0,		"CLTS" },
-[0x07] =	{ 0,0,		"SYSRET" },
-[0x08] =	{ 0,0,		"INVD" },
-[0x09] =	{ 0,0,		"WBINVD" },
-[0x0B] =	{ 0,0,		"UD2" },
-[0x0F] =	{ RM,AUX,		optab0F0F },		/* 3DNow! */
-[0x10] =	{ RM,0,		"MOVU%s	%x,%X" },
-[0x11] =	{ RM,0,		"MOVU%s	%X,%x" },
-[0x12] =	{ RM,0,		"MOV[H]L%s	%x,%X" },	/* TO DO: H if source is XMM */
-[0x13] =	{ RM,0,		"MOVL%s	%X,%e" },
-[0x14] =	{ RM,0,		"UNPCKL%s	%x,%X" },
-[0x15] =	{ RM,0,		"UNPCKH%s	%x,%X" },
-[0x16] =	{ RM,0,		"MOV[L]H%s	%x,%X" },	/* TO DO: L if source is XMM */
-[0x17] =	{ RM,0,		"MOVH%s	%X,%x" },
-[0x18] =	{ RMOP,0,		optab0F18 },
-[0x1F] =	{ RM,0,		"NOP%S	%e" },
-[0x20] =	{ RMR,0,		"MOVL	%C,%e" },
-[0x21] =	{ RMR,0,		"MOVL	%D,%e" },
-[0x22] =	{ RMR,0,		"MOVL	%e,%C" },
-[0x23] =	{ RMR,0,		"MOVL	%e,%D" },
-[0x24] =	{ RMR,0,		"MOVL	%T,%e" },
-[0x26] =	{ RMR,0,		"MOVL	%e,%T" },
-[0x28] =	{ RM,0,		"MOVA%s	%x,%X" },
-[0x29] =	{ RM,0,		"MOVA%s	%X,%x" },
-[0x2A] =	{ RM,0,		"CVTPL2%s	%m*,%X" },
-[0x2B] =	{ RM,0,		"MOVNT%s	%X,%e" },
-[0x2C] =	{ RM,0,		"CVTT%s2PL	%x,%M" },
-[0x2D] =	{ RM,0,		"CVT%s2PL	%x,%M" },
-[0x2E] =	{ RM,0,		"UCOMISS	%x,%X" },
-[0x2F] =	{ RM,0,		"COMISS	%x,%X" },
-[0x30] =	{ 0,0,		"WRMSR" },
-[0x31] =	{ 0,0,		"RDTSC" },
-[0x32] =	{ 0,0,		"RDMSR" },
-[0x33] =	{ 0,0,		"RDPMC" },
-[0x42] =	{ RM,0,		"CMOVC	%e,%r" },		/* CF */
-[0x43] =	{ RM,0,		"CMOVNC	%e,%r" },		/* ¬ CF */
-[0x44] =	{ RM,0,		"CMOVZ	%e,%r" },		/* ZF */
-[0x45] =	{ RM,0,		"CMOVNZ	%e,%r" },		/* ¬ ZF */
-[0x46] =	{ RM,0,		"CMOVBE	%e,%r" },		/* CF ∨ ZF */
-[0x47] =	{ RM,0,		"CMOVA	%e,%r" },		/* ¬CF ∧ ¬ZF */
-[0x48] =	{ RM,0,		"CMOVS	%e,%r" },		/* SF */
-[0x49] =	{ RM,0,		"CMOVNS	%e,%r" },		/* ¬ SF */
-[0x4A] =	{ RM,0,		"CMOVP	%e,%r" },		/* PF */
-[0x4B] =	{ RM,0,		"CMOVNP	%e,%r" },		/* ¬ PF */
-[0x4C] =	{ RM,0,		"CMOVLT	%e,%r" },		/* LT ≡ OF ≠ SF */
-[0x4D] =	{ RM,0,		"CMOVGE	%e,%r" },		/* GE ≡ ZF ∨ SF */
-[0x4E] =	{ RM,0,		"CMOVLE	%e,%r" },		/* LE ≡ ZF ∨ LT */
-[0x4F] =	{ RM,0,		"CMOVGT	%e,%r" },		/* GT ≡ ¬ZF ∧ GE */
-[0x50] =	{ RM,0,		"MOVMSK%s	%X,%r" },	/* TO DO: check */
-[0x51] =	{ RM,0,		"SQRT%s	%x,%X" },
-[0x52] =	{ RM,0,		"RSQRT%s	%x,%X" },
-[0x53] =	{ RM,0,		"RCP%s	%x,%X" },
-[0x54] =	{ RM,0,		"AND%s	%x,%X" },
-[0x55] =	{ RM,0,		"ANDN%s	%x,%X" },
-[0x56] =	{ RM,0,		"OR%s	%x,%X" },		/* TO DO: S/D */
-[0x57] =	{ RM,0,		"XOR%s	%x,%X" },		/* S/D */
-[0x58] =	{ RM,0,		"ADD%s	%x,%X" },		/* S/P S/D */
-[0x59] =	{ RM,0,		"MUL%s	%x,%X" },
-[0x5A] =	{ RM,0,		"CVTPS2PD	%x,%X" },
-[0x5B] =	{ RM,0,		"CVTPL2PS	%x,%X" },
-[0x5C] =	{ RM,0,		"SUB%s	%x,%X" },
-[0x5D] =	{ RM,0,		"MIN%s	%x,%X" },
-[0x5E] =	{ RM,0,		"DIV%s	%x,%X" },		/* TO DO: S/P S/D */
-[0x5F] =	{ RM,0,		"MAX%s	%x,%X" },
-[0x60] =	{ RM,0,		"PUNPCKLBW	%m,%M" },
-[0x61] =	{ RM,0,		"PUNPCKLWL	%m,%M" },
-[0x62] =	{ RM,0,		"PUNPCKLLQ	%m,%M" },
-[0x63] =	{ RM,0,		"PACKSSWB	%m,%M" },
-[0x64] =	{ RM,0,		"PCMPGTB	%m,%M" },
-[0x65] =	{ RM,0,		"PCMPGTW	%m,%M" },
-[0x66] =	{ RM,0,		"PCMPGTL	%m,%M" },
-[0x67] =	{ RM,0,		"PACKUSWB	%m,%M" },
-[0x68] =	{ RM,0,		"PUNPCKHBW	%m,%M" },
-[0x69] =	{ RM,0,		"PUNPCKHWL	%m,%M" },
-[0x6A] =	{ RM,0,		"PUNPCKHLQ	%m,%M" },
-[0x6B] =	{ RM,0,		"PACKSSLW	%m,%M" },
-[0x6E] =	{ RM,0,		"MOV%S	%e,%M" },
-[0x6F] =	{ RM,0,		"MOVQ	%m,%M" },
-[0x70] =	{ RM,Ib,		"PSHUFW	%i,%m,%M" },
-[0x74] =	{ RM,0,		"PCMPEQB	%m,%M" },
-[0x75] =	{ RM,0,		"PCMPEQW	%m,%M" },
-[0x76] =	{ RM,0,		"PCMPEQL	%m,%M" },
-[0x77] =	{ 0,0,		"EMMS" },
-[0x7E] =	{ RM,0,		"MOV%S	%M,%e" },
-[0x7F] =	{ RM,0,		"MOVQ	%M,%m" },
-[0xAE] =	{ RMOP,0,		optab0FAE },
-[0xAA] =	{ 0,0,		"RSM" },
-[0xB0] =	{ RM,0,		"CMPXCHGB	%r,%e" },
-[0xB1] =	{ RM,0,		"CMPXCHG%S	%r,%e" },
-[0xC0] =	{ RMB,0,		"XADDB	%r,%e" },
-[0xC1] =	{ RM,0,		"XADD%S	%r,%e" },
-[0xC2] =	{ RM,Ib,		"CMP%s	%x,%X,%#i" },
-[0xC3] =	{ RM,0,		"MOVNTI%S	%r,%e" },
-[0xC6] =	{ RM,Ib,		"SHUF%s	%i,%x,%X" },
-[0xC8] =	{ 0,0,		"BSWAP	AX" },
-[0xC9] =	{ 0,0,		"BSWAP	CX" },
-[0xCA] =	{ 0,0,		"BSWAP	DX" },
-[0xCB] =	{ 0,0,		"BSWAP	BX" },
-[0xCC] =	{ 0,0,		"BSWAP	SP" },
-[0xCD] =	{ 0,0,		"BSWAP	BP" },
-[0xCE] =	{ 0,0,		"BSWAP	SI" },
-[0xCF] =	{ 0,0,		"BSWAP	DI" },
-[0xD1] =	{ RM,0,		"PSRLW	%m,%M" },
-[0xD2] =	{ RM,0,		"PSRLL	%m,%M" },
-[0xD3] =	{ RM,0,		"PSRLQ	%m,%M" },
-[0xD5] =	{ RM,0,		"PMULLW	%m,%M" },
-[0xD6] =	{ RM,0,		"MOVQOZX	%m*,%X" },
-[0xD7] =	{ RM,0,		"PMOVMSKB	%m,%r" },
-[0xD8] =	{ RM,0,		"PSUBUSB	%m,%M" },
-[0xD9] =	{ RM,0,		"PSUBUSW	%m,%M" },
-[0xDA] =	{ RM,0,		"PMINUB	%m,%M" },
-[0xDB] =	{ RM,0,		"PAND	%m,%M" },
-[0xDC] =	{ RM,0,		"PADDUSB	%m,%M" },
-[0xDD] =	{ RM,0,		"PADDUSW	%m,%M" },
-[0xDE] =	{ RM,0,		"PMAXUB	%m,%M" },
-[0xDF] =	{ RM,0,		"PANDN	%m,%M" },
-[0xE0] =	{ RM,0,		"PAVGB	%m,%M" },
-[0xE1] =	{ RM,0,		"PSRAW	%m,%M" },
-[0xE2] =	{ RM,0,		"PSRAL	%m,%M" },
-[0xE3] =	{ RM,0,		"PAVGW	%m,%M" },
-[0xE4] =	{ RM,0,		"PMULHUW	%m,%M" },
-[0xE5] =	{ RM,0,		"PMULHW	%m,%M" },
-[0xE7] =	{ RM,0,		"MOVNTQ	%M,%e" },
-[0xE8] =	{ RM,0,		"PSUBSB	%m,%M" },
-[0xE9] =	{ RM,0,		"PSUBSW	%m,%M" },
-[0xEA] =	{ RM,0,		"PMINSW	%m,%M" },
-[0xEB] =	{ RM,0,		"POR	%m,%M" },
-[0xEC] =	{ RM,0,		"PADDSB	%m,%M" },
-[0xED] =	{ RM,0,		"PADDSW	%m,%M" },
-[0xEE] =	{ RM,0,		"PMAXSW	%m,%M" },
-[0xEF] =	{ RM,0,		"PXOR	%m,%M" },
-[0xF1] =	{ RM,0,		"PSLLW	%m,%M" },
-[0xF2] =	{ RM,0,		"PSLLL	%m,%M" },
-[0xF3] =	{ RM,0,		"PSLLQ	%m,%M" },
-[0xF4] =	{ RM,0,		"PMULULQ	%m,%M" },
-[0xF5] =	{ RM,0,		"PMADDWL	%m,%M" },
-[0xF6] =	{ RM,0,		"PSADBW	%m,%M" },
-[0xF7] =	{ RMR,0,		"MASKMOVQ	%m,%M" },
-[0xF8] =	{ RM,0,		"PSUBB	%m,%M" },
-[0xF9] =	{ RM,0,		"PSUBW	%m,%M" },
-[0xFA] =	{ RM,0,		"PSUBL	%m,%M" },
-[0xFC] =	{ RM,0,		"PADDB	%m,%M" },
-[0xFD] =	{ RM,0,		"PADDW	%m,%M" },
-[0xFE] =	{ RM,0,		"PADDL	%m,%M" },
-
-[0x80] =	{ Iwds,0,		"JOS	%p" },
-[0x81] =	{ Iwds,0,		"JOC	%p" },
-[0x82] =	{ Iwds,0,		"JCS	%p" },
-[0x83] =	{ Iwds,0,		"JCC	%p" },
-[0x84] =	{ Iwds,0,		"JEQ	%p" },
-[0x85] =	{ Iwds,0,		"JNE	%p" },
-[0x86] =	{ Iwds,0,		"JLS	%p" },
-[0x87] =	{ Iwds,0,		"JHI	%p" },
-[0x88] =	{ Iwds,0,		"JMI	%p" },
-[0x89] =	{ Iwds,0,		"JPL	%p" },
-[0x8a] =	{ Iwds,0,		"JPS	%p" },
-[0x8b] =	{ Iwds,0,		"JPC	%p" },
-[0x8c] =	{ Iwds,0,		"JLT	%p" },
-[0x8d] =	{ Iwds,0,		"JGE	%p" },
-[0x8e] =	{ Iwds,0,		"JLE	%p" },
-[0x8f] =	{ Iwds,0,		"JGT	%p" },
-[0x90] =	{ RMB,0,		"SETOS	%e" },
-[0x91] =	{ RMB,0,		"SETOC	%e" },
-[0x92] =	{ RMB,0,		"SETCS	%e" },
-[0x93] =	{ RMB,0,		"SETCC	%e" },
-[0x94] =	{ RMB,0,		"SETEQ	%e" },
-[0x95] =	{ RMB,0,		"SETNE	%e" },
-[0x96] =	{ RMB,0,		"SETLS	%e" },
-[0x97] =	{ RMB,0,		"SETHI	%e" },
-[0x98] =	{ RMB,0,		"SETMI	%e" },
-[0x99] =	{ RMB,0,		"SETPL	%e" },
-[0x9a] =	{ RMB,0,		"SETPS	%e" },
-[0x9b] =	{ RMB,0,		"SETPC	%e" },
-[0x9c] =	{ RMB,0,		"SETLT	%e" },
-[0x9d] =	{ RMB,0,		"SETGE	%e" },
-[0x9e] =	{ RMB,0,		"SETLE	%e" },
-[0x9f] =	{ RMB,0,		"SETGT	%e" },
-[0xa0] =	{ 0,0,		"PUSHL	FS" },
-[0xa1] =	{ 0,0,		"POPL	FS" },
-[0xa2] =	{ 0,0,		"CPUID" },
-[0xa3] =	{ RM,0,		"BT%S	%r,%e" },
-[0xa4] =	{ RM,Ib,		"SHLD%S	%r,%i,%e" },
-[0xa5] =	{ RM,0,		"SHLD%S	%r,CL,%e" },
-[0xa8] =	{ 0,0,		"PUSHL	GS" },
-[0xa9] =	{ 0,0,		"POPL	GS" },
-[0xab] =	{ RM,0,		"BTS%S	%r,%e" },
-[0xac] =	{ RM,Ib,		"SHRD%S	%r,%i,%e" },
-[0xad] =	{ RM,0,		"SHRD%S	%r,CL,%e" },
-[0xaf] =	{ RM,0,		"IMUL%S	%e,%r" },
-[0xb2] =	{ RMM,0,		"LSS	%e,%r" },
-[0xb3] =	{ RM,0,		"BTR%S	%r,%e" },
-[0xb4] =	{ RMM,0,		"LFS	%e,%r" },
-[0xb5] =	{ RMM,0,		"LGS	%e,%r" },
-[0xb6] =	{ RMB,0,		"MOVBZX	%e,%R" },
-[0xb7] =	{ RM,0,		"MOVWZX	%e,%R" },
-[0xba] =	{ RMOP,0,		optab0FBA },
-[0xbb] =	{ RM,0,		"BTC%S	%e,%r" },
-[0xbc] =	{ RM,0,		"BSF%S	%e,%r" },
-[0xbd] =	{ RM,0,		"BSR%S	%e,%r" },
-[0xbe] =	{ RMB,0,		"MOVBSX	%e,%R" },
-[0xbf] =	{ RM,0,		"MOVWSX	%e,%R" },
-[0xc7] =	{ RMOP,0,		optab0FC7 },
-};
-
-static Optable optab80[8]=
-{
-[0x00] =	{ Ib,0,		"ADDB	%i,%e" },
-[0x01] =	{ Ib,0,		"ORB	%i,%e" },
-[0x02] =	{ Ib,0,		"ADCB	%i,%e" },
-[0x03] =	{ Ib,0,		"SBBB	%i,%e" },
-[0x04] =	{ Ib,0,		"ANDB	%i,%e" },
-[0x05] =	{ Ib,0,		"SUBB	%i,%e" },
-[0x06] =	{ Ib,0,		"XORB	%i,%e" },
-[0x07] =	{ Ib,0,		"CMPB	%e,%i" },
-};
-
-static Optable optab81[8]=
-{
-[0x00] =	{ Iwd,0,		"ADD%S	%i,%e" },
-[0x01] =	{ Iwd,0,		"OR%S	%i,%e" },
-[0x02] =	{ Iwd,0,		"ADC%S	%i,%e" },
-[0x03] =	{ Iwd,0,		"SBB%S	%i,%e" },
-[0x04] =	{ Iwd,0,		"AND%S	%i,%e" },
-[0x05] =	{ Iwd,0,		"SUB%S	%i,%e" },
-[0x06] =	{ Iwd,0,		"XOR%S	%i,%e" },
-[0x07] =	{ Iwd,0,		"CMP%S	%e,%i" },
-};
-
-static Optable optab83[8]=
-{
-[0x00] =	{ Ibs,0,		"ADD%S	%i,%e" },
-[0x01] =	{ Ibs,0,		"OR%S	%i,%e" },
-[0x02] =	{ Ibs,0,		"ADC%S	%i,%e" },
-[0x03] =	{ Ibs,0,		"SBB%S	%i,%e" },
-[0x04] =	{ Ibs,0,		"AND%S	%i,%e" },
-[0x05] =	{ Ibs,0,		"SUB%S	%i,%e" },
-[0x06] =	{ Ibs,0,		"XOR%S	%i,%e" },
-[0x07] =	{ Ibs,0,		"CMP%S	%e,%i" },
-};
-
-static Optable optabC0[8] =
-{
-[0x00] =	{ Ib,0,		"ROLB	%i,%e" },
-[0x01] =	{ Ib,0,		"RORB	%i,%e" },
-[0x02] =	{ Ib,0,		"RCLB	%i,%e" },
-[0x03] =	{ Ib,0,		"RCRB	%i,%e" },
-[0x04] =	{ Ib,0,		"SHLB	%i,%e" },
-[0x05] =	{ Ib,0,		"SHRB	%i,%e" },
-[0x07] =	{ Ib,0,		"SARB	%i,%e" },
-};
-
-static Optable optabC1[8] =
-{
-[0x00] =	{ Ib,0,		"ROL%S	%i,%e" },
-[0x01] =	{ Ib,0,		"ROR%S	%i,%e" },
-[0x02] =	{ Ib,0,		"RCL%S	%i,%e" },
-[0x03] =	{ Ib,0,		"RCR%S	%i,%e" },
-[0x04] =	{ Ib,0,		"SHL%S	%i,%e" },
-[0x05] =	{ Ib,0,		"SHR%S	%i,%e" },
-[0x07] =	{ Ib,0,		"SAR%S	%i,%e" },
-};
-
-static Optable optabD0[8] =
-{
-[0x00] =	{ 0,0,		"ROLB	%e" },
-[0x01] =	{ 0,0,		"RORB	%e" },
-[0x02] =	{ 0,0,		"RCLB	%e" },
-[0x03] =	{ 0,0,		"RCRB	%e" },
-[0x04] =	{ 0,0,		"SHLB	%e" },
-[0x05] =	{ 0,0,		"SHRB	%e" },
-[0x07] =	{ 0,0,		"SARB	%e" },
-};
-
-static Optable optabD1[8] =
-{
-[0x00] =	{ 0,0,		"ROL%S	%e" },
-[0x01] =	{ 0,0,		"ROR%S	%e" },
-[0x02] =	{ 0,0,		"RCL%S	%e" },
-[0x03] =	{ 0,0,		"RCR%S	%e" },
-[0x04] =	{ 0,0,		"SHL%S	%e" },
-[0x05] =	{ 0,0,		"SHR%S	%e" },
-[0x07] =	{ 0,0,		"SAR%S	%e" },
-};
-
-static Optable optabD2[8] =
-{
-[0x00] =	{ 0,0,		"ROLB	CL,%e" },
-[0x01] =	{ 0,0,		"RORB	CL,%e" },
-[0x02] =	{ 0,0,		"RCLB	CL,%e" },
-[0x03] =	{ 0,0,		"RCRB	CL,%e" },
-[0x04] =	{ 0,0,		"SHLB	CL,%e" },
-[0x05] =	{ 0,0,		"SHRB	CL,%e" },
-[0x07] =	{ 0,0,		"SARB	CL,%e" },
-};
-
-static Optable optabD3[8] =
-{
-[0x00] =	{ 0,0,		"ROL%S	CL,%e" },
-[0x01] =	{ 0,0,		"ROR%S	CL,%e" },
-[0x02] =	{ 0,0,		"RCL%S	CL,%e" },
-[0x03] =	{ 0,0,		"RCR%S	CL,%e" },
-[0x04] =	{ 0,0,		"SHL%S	CL,%e" },
-[0x05] =	{ 0,0,		"SHR%S	CL,%e" },
-[0x07] =	{ 0,0,		"SAR%S	CL,%e" },
-};
-
-static Optable optabD8[8+8] =
-{
-[0x00] =	{ 0,0,		"FADDF	%e,F0" },
-[0x01] =	{ 0,0,		"FMULF	%e,F0" },
-[0x02] =	{ 0,0,		"FCOMF	%e,F0" },
-[0x03] =	{ 0,0,		"FCOMFP	%e,F0" },
-[0x04] =	{ 0,0,		"FSUBF	%e,F0" },
-[0x05] =	{ 0,0,		"FSUBRF	%e,F0" },
-[0x06] =	{ 0,0,		"FDIVF	%e,F0" },
-[0x07] =	{ 0,0,		"FDIVRF	%e,F0" },
-[0x08] =	{ 0,0,		"FADDD	%f,F0" },
-[0x09] =	{ 0,0,		"FMULD	%f,F0" },
-[0x0a] =	{ 0,0,		"FCOMD	%f,F0" },
-[0x0b] =	{ 0,0,		"FCOMPD	%f,F0" },
-[0x0c] =	{ 0,0,		"FSUBD	%f,F0" },
-[0x0d] =	{ 0,0,		"FSUBRD	%f,F0" },
-[0x0e] =	{ 0,0,		"FDIVD	%f,F0" },
-[0x0f] =	{ 0,0,		"FDIVRD	%f,F0" },
-};
-/*
- *	optabD9 and optabDB use the following encoding:
- *	if (0 <= modrm <= 2) instruction = optabDx[modrm&0x07];
- *	else instruction = optabDx[(modrm&0x3f)+8];
- *
- *	the instructions for MOD == 3, follow the 8 instructions
- *	for the other MOD values stored at the front of the table.
- */
-static Optable optabD9[64+8] =
-{
-[0x00] =	{ 0,0,		"FMOVF	%e,F0" },
-[0x02] =	{ 0,0,		"FMOVF	F0,%e" },
-[0x03] =	{ 0,0,		"FMOVFP	F0,%e" },
-[0x04] =	{ 0,0,		"FLDENV%S	%e" },
-[0x05] =	{ 0,0,		"FLDCW	%e" },
-[0x06] =	{ 0,0,		"FSTENV%S	%e" },
-[0x07] =	{ 0,0,		"FSTCW	%e" },
-[0x08] =	{ 0,0,		"FMOVD	F0,F0" },		/* Mod R/M = 11xx xxxx*/
-[0x09] =	{ 0,0,		"FMOVD	F1,F0" },
-[0x0a] =	{ 0,0,		"FMOVD	F2,F0" },
-[0x0b] =	{ 0,0,		"FMOVD	F3,F0" },
-[0x0c] =	{ 0,0,		"FMOVD	F4,F0" },
-[0x0d] =	{ 0,0,		"FMOVD	F5,F0" },
-[0x0e] =	{ 0,0,		"FMOVD	F6,F0" },
-[0x0f] =	{ 0,0,		"FMOVD	F7,F0" },
-[0x10] =	{ 0,0,		"FXCHD	F0,F0" },
-[0x11] =	{ 0,0,		"FXCHD	F1,F0" },
-[0x12] =	{ 0,0,		"FXCHD	F2,F0" },
-[0x13] =	{ 0,0,		"FXCHD	F3,F0" },
-[0x14] =	{ 0,0,		"FXCHD	F4,F0" },
-[0x15] =	{ 0,0,		"FXCHD	F5,F0" },
-[0x16] =	{ 0,0,		"FXCHD	F6,F0" },
-[0x17] =	{ 0,0,		"FXCHD	F7,F0" },
-[0x18] =	{ 0,0,		"FNOP" },
-[0x28] =	{ 0,0,		"FCHS" },
-[0x29] =	{ 0,0,		"FABS" },
-[0x2c] =	{ 0,0,		"FTST" },
-[0x2d] =	{ 0,0,		"FXAM" },
-[0x30] =	{ 0,0,		"FLD1" },
-[0x31] =	{ 0,0,		"FLDL2T" },
-[0x32] =	{ 0,0,		"FLDL2E" },
-[0x33] =	{ 0,0,		"FLDPI" },
-[0x34] =	{ 0,0,		"FLDLG2" },
-[0x35] =	{ 0,0,		"FLDLN2" },
-[0x36] =	{ 0,0,		"FLDZ" },
-[0x38] =	{ 0,0,		"F2XM1" },
-[0x39] =	{ 0,0,		"FYL2X" },
-[0x3a] =	{ 0,0,		"FPTAN" },
-[0x3b] =	{ 0,0,		"FPATAN" },
-[0x3c] =	{ 0,0,		"FXTRACT" },
-[0x3d] =	{ 0,0,		"FPREM1" },
-[0x3e] =	{ 0,0,		"FDECSTP" },
-[0x3f] =	{ 0,0,		"FNCSTP" },
-[0x40] =	{ 0,0,		"FPREM" },
-[0x41] =	{ 0,0,		"FYL2XP1" },
-[0x42] =	{ 0,0,		"FSQRT" },
-[0x43] =	{ 0,0,		"FSINCOS" },
-[0x44] =	{ 0,0,		"FRNDINT" },
-[0x45] =	{ 0,0,		"FSCALE" },
-[0x46] =	{ 0,0,		"FSIN" },
-[0x47] =	{ 0,0,		"FCOS" },
-};
-
-static Optable optabDA[8+8] =
-{
-[0x00] =	{ 0,0,		"FADDL	%e,F0" },
-[0x01] =	{ 0,0,		"FMULL	%e,F0" },
-[0x02] =	{ 0,0,		"FCOML	%e,F0" },
-[0x03] =	{ 0,0,		"FCOMLP	%e,F0" },
-[0x04] =	{ 0,0,		"FSUBL	%e,F0" },
-[0x05] =	{ 0,0,		"FSUBRL	%e,F0" },
-[0x06] =	{ 0,0,		"FDIVL	%e,F0" },
-[0x07] =	{ 0,0,		"FDIVRL	%e,F0" },
-[0x08] =	{ 0,0,		"FCMOVCS	%f,F0" },
-[0x09] =	{ 0,0,		"FCMOVEQ	%f,F0" },
-[0x0a] =	{ 0,0,		"FCMOVLS	%f,F0" },
-[0x0b] =	{ 0,0,		"FCMOVUN	%f,F0" },
-[0x0d] =	{ Op_R1,0,		"FUCOMPP" },
-};
-
-static Optable optabDB[8+64] =
-{
-[0x00] =	{ 0,0,		"FMOVL	%e,F0" },
-[0x02] =	{ 0,0,		"FMOVL	F0,%e" },
-[0x03] =	{ 0,0,		"FMOVLP	F0,%e" },
-[0x05] =	{ 0,0,		"FMOVX	%e,F0" },
-[0x07] =	{ 0,0,		"FMOVXP	F0,%e" },
-[0x08] =	{ 0,0,		"FCMOVCC	F0,F0" },	/* Mod R/M = 11xx xxxx*/
-[0x09] =	{ 0,0,		"FCMOVCC	F1,F0" },
-[0x0a] =	{ 0,0,		"FCMOVCC	F2,F0" },
-[0x0b] =	{ 0,0,		"FCMOVCC	F3,F0" },
-[0x0c] =	{ 0,0,		"FCMOVCC	F4,F0" },
-[0x0d] =	{ 0,0,		"FCMOVCC	F5,F0" },
-[0x0e] =	{ 0,0,		"FCMOVCC	F6,F0" },
-[0x0f] =	{ 0,0,		"FCMOVCC	F7,F0" },
-[0x10] =	{ 0,0,		"FCMOVNE	F0,F0" },
-[0x11] =	{ 0,0,		"FCMOVNE	F1,F0" },
-[0x12] =	{ 0,0,		"FCMOVNE	F2,F0" },
-[0x13] =	{ 0,0,		"FCMOVNE	F3,F0" },
-[0x14] =	{ 0,0,		"FCMOVNE	F4,F0" },
-[0x15] =	{ 0,0,		"FCMOVNE	F5,F0" },
-[0x16] =	{ 0,0,		"FCMOVNE	F6,F0" },
-[0x17] =	{ 0,0,		"FCMOVNE	F7,F0" },
-[0x18] =	{ 0,0,		"FCMOVHI	F0,F0" },
-[0x19] =	{ 0,0,		"FCMOVHI	F1,F0" },
-[0x1a] =	{ 0,0,		"FCMOVHI	F2,F0" },
-[0x1b] =	{ 0,0,		"FCMOVHI	F3,F0" },
-[0x1c] =	{ 0,0,		"FCMOVHI	F4,F0" },
-[0x1d] =	{ 0,0,		"FCMOVHI	F5,F0" },
-[0x1e] =	{ 0,0,		"FCMOVHI	F6,F0" },
-[0x1f] =	{ 0,0,		"FCMOVHI	F7,F0" },
-[0x20] =	{ 0,0,		"FCMOVNU	F0,F0" },
-[0x21] =	{ 0,0,		"FCMOVNU	F1,F0" },
-[0x22] =	{ 0,0,		"FCMOVNU	F2,F0" },
-[0x23] =	{ 0,0,		"FCMOVNU	F3,F0" },
-[0x24] =	{ 0,0,		"FCMOVNU	F4,F0" },
-[0x25] =	{ 0,0,		"FCMOVNU	F5,F0" },
-[0x26] =	{ 0,0,		"FCMOVNU	F6,F0" },
-[0x27] =	{ 0,0,		"FCMOVNU	F7,F0" },
-[0x2a] =	{ 0,0,		"FCLEX" },
-[0x2b] =	{ 0,0,		"FINIT" },
-[0x30] =	{ 0,0,		"FUCOMI	F0,F0" },
-[0x31] =	{ 0,0,		"FUCOMI	F1,F0" },
-[0x32] =	{ 0,0,		"FUCOMI	F2,F0" },
-[0x33] =	{ 0,0,		"FUCOMI	F3,F0" },
-[0x34] =	{ 0,0,		"FUCOMI	F4,F0" },
-[0x35] =	{ 0,0,		"FUCOMI	F5,F0" },
-[0x36] =	{ 0,0,		"FUCOMI	F6,F0" },
-[0x37] =	{ 0,0,		"FUCOMI	F7,F0" },
-[0x38] =	{ 0,0,		"FCOMI	F0,F0" },
-[0x39] =	{ 0,0,		"FCOMI	F1,F0" },
-[0x3a] =	{ 0,0,		"FCOMI	F2,F0" },
-[0x3b] =	{ 0,0,		"FCOMI	F3,F0" },
-[0x3c] =	{ 0,0,		"FCOMI	F4,F0" },
-[0x3d] =	{ 0,0,		"FCOMI	F5,F0" },
-[0x3e] =	{ 0,0,		"FCOMI	F6,F0" },
-[0x3f] =	{ 0,0,		"FCOMI	F7,F0" },
-};
-
-static Optable optabDC[8+8] =
-{
-[0x00] =	{ 0,0,		"FADDD	%e,F0" },
-[0x01] =	{ 0,0,		"FMULD	%e,F0" },
-[0x02] =	{ 0,0,		"FCOMD	%e,F0" },
-[0x03] =	{ 0,0,		"FCOMDP	%e,F0" },
-[0x04] =	{ 0,0,		"FSUBD	%e,F0" },
-[0x05] =	{ 0,0,		"FSUBRD	%e,F0" },
-[0x06] =	{ 0,0,		"FDIVD	%e,F0" },
-[0x07] =	{ 0,0,		"FDIVRD	%e,F0" },
-[0x08] =	{ 0,0,		"FADDD	F0,%f" },
-[0x09] =	{ 0,0,		"FMULD	F0,%f" },
-[0x0c] =	{ 0,0,		"FSUBRD	F0,%f" },
-[0x0d] =	{ 0,0,		"FSUBD	F0,%f" },
-[0x0e] =	{ 0,0,		"FDIVRD	F0,%f" },
-[0x0f] =	{ 0,0,		"FDIVD	F0,%f" },
-};
-
-static Optable optabDD[8+8] =
-{
-[0x00] =	{ 0,0,		"FMOVD	%e,F0" },
-[0x02] =	{ 0,0,		"FMOVD	F0,%e" },
-[0x03] =	{ 0,0,		"FMOVDP	F0,%e" },
-[0x04] =	{ 0,0,		"FRSTOR%S	%e" },
-[0x06] =	{ 0,0,		"FSAVE%S	%e" },
-[0x07] =	{ 0,0,		"FSTSW	%e" },
-[0x08] =	{ 0,0,		"FFREED	%f" },
-[0x0a] =	{ 0,0,		"FMOVD	%f,F0" },
-[0x0b] =	{ 0,0,		"FMOVDP	%f,F0" },
-[0x0c] =	{ 0,0,		"FUCOMD	%f,F0" },
-[0x0d] =	{ 0,0,		"FUCOMDP	%f,F0" },
-};
-
-static Optable optabDE[8+8] =
-{
-[0x00] =	{ 0,0,		"FADDW	%e,F0" },
-[0x01] =	{ 0,0,		"FMULW	%e,F0" },
-[0x02] =	{ 0,0,		"FCOMW	%e,F0" },
-[0x03] =	{ 0,0,		"FCOMWP	%e,F0" },
-[0x04] =	{ 0,0,		"FSUBW	%e,F0" },
-[0x05] =	{ 0,0,		"FSUBRW	%e,F0" },
-[0x06] =	{ 0,0,		"FDIVW	%e,F0" },
-[0x07] =	{ 0,0,		"FDIVRW	%e,F0" },
-[0x08] =	{ 0,0,		"FADDDP	F0,%f" },
-[0x09] =	{ 0,0,		"FMULDP	F0,%f" },
-[0x0b] =	{ Op_R1,0,		"FCOMPDP" },
-[0x0c] =	{ 0,0,		"FSUBRDP	F0,%f" },
-[0x0d] =	{ 0,0,		"FSUBDP	F0,%f" },
-[0x0e] =	{ 0,0,		"FDIVRDP	F0,%f" },
-[0x0f] =	{ 0,0,		"FDIVDP	F0,%f" },
-};
-
-static Optable optabDF[8+8] =
-{
-[0x00] =	{ 0,0,		"FMOVW	%e,F0" },
-[0x02] =	{ 0,0,		"FMOVW	F0,%e" },
-[0x03] =	{ 0,0,		"FMOVWP	F0,%e" },
-[0x04] =	{ 0,0,		"FBLD	%e" },
-[0x05] =	{ 0,0,		"FMOVL	%e,F0" },
-[0x06] =	{ 0,0,		"FBSTP	%e" },
-[0x07] =	{ 0,0,		"FMOVLP	F0,%e" },
-[0x0c] =	{ Op_R0,0,		"FSTSW	%OAX" },
-[0x0d] =	{ 0,0,		"FUCOMIP	F0,%f" },
-[0x0e] =	{ 0,0,		"FCOMIP	F0,%f" },
-};
-
-static Optable optabF6[8] =
-{
-[0x00] =	{ Ib,0,		"TESTB	%i,%e" },
-[0x02] =	{ 0,0,		"NOTB	%e" },
-[0x03] =	{ 0,0,		"NEGB	%e" },
-[0x04] =	{ 0,0,		"MULB	AL,%e" },
-[0x05] =	{ 0,0,		"IMULB	AL,%e" },
-[0x06] =	{ 0,0,		"DIVB	AL,%e" },
-[0x07] =	{ 0,0,		"IDIVB	AL,%e" },
-};
-
-static Optable optabF7[8] =
-{
-[0x00] =	{ Iwd,0,		"TEST%S	%i,%e" },
-[0x02] =	{ 0,0,		"NOT%S	%e" },
-[0x03] =	{ 0,0,		"NEG%S	%e" },
-[0x04] =	{ 0,0,		"MUL%S	%OAX,%e" },
-[0x05] =	{ 0,0,		"IMUL%S	%OAX,%e" },
-[0x06] =	{ 0,0,		"DIV%S	%OAX,%e" },
-[0x07] =	{ 0,0,		"IDIV%S	%OAX,%e" },
-};
-
-static Optable optabFE[8] =
-{
-[0x00] =	{ 0,0,		"INCB	%e" },
-[0x01] =	{ 0,0,		"DECB	%e" },
-};
-
-static Optable optabFF[8] =
-{
-[0x00] =	{ 0,0,		"INC%S	%e" },
-[0x01] =	{ 0,0,		"DEC%S	%e" },
-[0x02] =	{ JUMP,0,		"CALL*	%e" },
-[0x03] =	{ JUMP,0,		"CALLF*	%e" },
-[0x04] =	{ JUMP,0,		"JMP*	%e" },
-[0x05] =	{ JUMP,0,		"JMPF*	%e" },
-[0x06] =	{ 0,0,		"PUSHL	%e" },
-};
-
-static Optable optable[256+2] =
-{
-[0x00] =	{ RMB,0,		"ADDB	%r,%e" },
-[0x01] =	{ RM,0,		"ADD%S	%r,%e" },
-[0x02] =	{ RMB,0,		"ADDB	%e,%r" },
-[0x03] =	{ RM,0,		"ADD%S	%e,%r" },
-[0x04] =	{ Ib,0,		"ADDB	%i,AL" },
-[0x05] =	{ Iwd,0,		"ADD%S	%i,%OAX" },
-[0x06] =	{ 0,0,		"PUSHL	ES" },
-[0x07] =	{ 0,0,		"POPL	ES" },
-[0x08] =	{ RMB,0,		"ORB	%r,%e" },
-[0x09] =	{ RM,0,		"OR%S	%r,%e" },
-[0x0a] =	{ RMB,0,		"ORB	%e,%r" },
-[0x0b] =	{ RM,0,		"OR%S	%e,%r" },
-[0x0c] =	{ Ib,0,		"ORB	%i,AL" },
-[0x0d] =	{ Iwd,0,		"OR%S	%i,%OAX" },
-[0x0e] =	{ 0,0,		"PUSHL	CS" },
-[0x0f] =	{ AUXMM,0,	optab0F },
-[0x10] =	{ RMB,0,		"ADCB	%r,%e" },
-[0x11] =	{ RM,0,		"ADC%S	%r,%e" },
-[0x12] =	{ RMB,0,		"ADCB	%e,%r" },
-[0x13] =	{ RM,0,		"ADC%S	%e,%r" },
-[0x14] =	{ Ib,0,		"ADCB	%i,AL" },
-[0x15] =	{ Iwd,0,		"ADC%S	%i,%OAX" },
-[0x16] =	{ 0,0,		"PUSHL	SS" },
-[0x17] =	{ 0,0,		"POPL	SS" },
-[0x18] =	{ RMB,0,		"SBBB	%r,%e" },
-[0x19] =	{ RM,0,		"SBB%S	%r,%e" },
-[0x1a] =	{ RMB,0,		"SBBB	%e,%r" },
-[0x1b] =	{ RM,0,		"SBB%S	%e,%r" },
-[0x1c] =	{ Ib,0,		"SBBB	%i,AL" },
-[0x1d] =	{ Iwd,0,		"SBB%S	%i,%OAX" },
-[0x1e] =	{ 0,0,		"PUSHL	DS" },
-[0x1f] =	{ 0,0,		"POPL	DS" },
-[0x20] =	{ RMB,0,		"ANDB	%r,%e" },
-[0x21] =	{ RM,0,		"AND%S	%r,%e" },
-[0x22] =	{ RMB,0,		"ANDB	%e,%r" },
-[0x23] =	{ RM,0,		"AND%S	%e,%r" },
-[0x24] =	{ Ib,0,		"ANDB	%i,AL" },
-[0x25] =	{ Iwd,0,		"AND%S	%i,%OAX" },
-[0x26] =	{ SEG,0,		"ES:" },
-[0x27] =	{ 0,0,		"DAA" },
-[0x28] =	{ RMB,0,		"SUBB	%r,%e" },
-[0x29] =	{ RM,0,		"SUB%S	%r,%e" },
-[0x2a] =	{ RMB,0,		"SUBB	%e,%r" },
-[0x2b] =	{ RM,0,		"SUB%S	%e,%r" },
-[0x2c] =	{ Ib,0,		"SUBB	%i,AL" },
-[0x2d] =	{ Iwd,0,		"SUB%S	%i,%OAX" },
-[0x2e] =	{ SEG,0,		"CS:" },
-[0x2f] =	{ 0,0,		"DAS" },
-[0x30] =	{ RMB,0,		"XORB	%r,%e" },
-[0x31] =	{ RM,0,		"XOR%S	%r,%e" },
-[0x32] =	{ RMB,0,		"XORB	%e,%r" },
-[0x33] =	{ RM,0,		"XOR%S	%e,%r" },
-[0x34] =	{ Ib,0,		"XORB	%i,AL" },
-[0x35] =	{ Iwd,0,		"XOR%S	%i,%OAX" },
-[0x36] =	{ SEG,0,		"SS:" },
-[0x37] =	{ 0,0,		"AAA" },
-[0x38] =	{ RMB,0,		"CMPB	%r,%e" },
-[0x39] =	{ RM,0,		"CMP%S	%r,%e" },
-[0x3a] =	{ RMB,0,		"CMPB	%e,%r" },
-[0x3b] =	{ RM,0,		"CMP%S	%e,%r" },
-[0x3c] =	{ Ib,0,		"CMPB	%i,AL" },
-[0x3d] =	{ Iwd,0,		"CMP%S	%i,%OAX" },
-[0x3e] =	{ SEG,0,		"DS:" },
-[0x3f] =	{ 0,0,		"AAS" },
-[0x40] =	{ 0,0,		"INC%S	%OAX" },
-[0x41] =	{ 0,0,		"INC%S	%OCX" },
-[0x42] =	{ 0,0,		"INC%S	%ODX" },
-[0x43] =	{ 0,0,		"INC%S	%OBX" },
-[0x44] =	{ 0,0,		"INC%S	%OSP" },
-[0x45] =	{ 0,0,		"INC%S	%OBP" },
-[0x46] =	{ 0,0,		"INC%S	%OSI" },
-[0x47] =	{ 0,0,		"INC%S	%ODI" },
-[0x48] =	{ 0,0,		"DEC%S	%OAX" },
-[0x49] =	{ 0,0,		"DEC%S	%OCX" },
-[0x4a] =	{ 0,0,		"DEC%S	%ODX" },
-[0x4b] =	{ 0,0,		"DEC%S	%OBX" },
-[0x4c] =	{ 0,0,		"DEC%S	%OSP" },
-[0x4d] =	{ 0,0,		"DEC%S	%OBP" },
-[0x4e] =	{ 0,0,		"DEC%S	%OSI" },
-[0x4f] =	{ 0,0,		"DEC%S	%ODI" },
-[0x50] =	{ 0,0,		"PUSH%S	%OAX" },
-[0x51] =	{ 0,0,		"PUSH%S	%OCX" },
-[0x52] =	{ 0,0,		"PUSH%S	%ODX" },
-[0x53] =	{ 0,0,		"PUSH%S	%OBX" },
-[0x54] =	{ 0,0,		"PUSH%S	%OSP" },
-[0x55] =	{ 0,0,		"PUSH%S	%OBP" },
-[0x56] =	{ 0,0,		"PUSH%S	%OSI" },
-[0x57] =	{ 0,0,		"PUSH%S	%ODI" },
-[0x58] =	{ 0,0,		"POP%S	%OAX" },
-[0x59] =	{ 0,0,		"POP%S	%OCX" },
-[0x5a] =	{ 0,0,		"POP%S	%ODX" },
-[0x5b] =	{ 0,0,		"POP%S	%OBX" },
-[0x5c] =	{ 0,0,		"POP%S	%OSP" },
-[0x5d] =	{ 0,0,		"POP%S	%OBP" },
-[0x5e] =	{ 0,0,		"POP%S	%OSI" },
-[0x5f] =	{ 0,0,		"POP%S	%ODI" },
-[0x60] =	{ 0,0,		"PUSHA%S" },
-[0x61] =	{ 0,0,		"POPA%S" },
-[0x62] =	{ RMM,0,		"BOUND	%e,%r" },
-[0x63] =	{ RM,0,		"ARPL	%r,%e" },
-[0x64] =	{ SEG,0,		"FS:" },
-[0x65] =	{ SEG,0,		"GS:" },
-[0x66] =	{ OPOVER,0,	"" },
-[0x67] =	{ ADDOVER,0,	"" },
-[0x68] =	{ Iwd,0,		"PUSH%S	%i" },
-[0x69] =	{ RM,Iwd,		"IMUL%S	%e,%i,%r" },
-[0x6a] =	{ Ib,0,		"PUSH%S	%i" },
-[0x6b] =	{ RM,Ibs,		"IMUL%S	%e,%i,%r" },
-[0x6c] =	{ 0,0,		"INSB	DX,(%ODI)" },
-[0x6d] =	{ 0,0,		"INS%S	DX,(%ODI)" },
-[0x6e] =	{ 0,0,		"OUTSB	(%ASI),DX" },
-[0x6f] =	{ 0,0,		"OUTS%S	(%ASI),DX" },
-[0x70] =	{ Jbs,0,		"JOS	%p" },
-[0x71] =	{ Jbs,0,		"JOC	%p" },
-[0x72] =	{ Jbs,0,		"JCS	%p" },
-[0x73] =	{ Jbs,0,		"JCC	%p" },
-[0x74] =	{ Jbs,0,		"JEQ	%p" },
-[0x75] =	{ Jbs,0,		"JNE	%p" },
-[0x76] =	{ Jbs,0,		"JLS	%p" },
-[0x77] =	{ Jbs,0,		"JHI	%p" },
-[0x78] =	{ Jbs,0,		"JMI	%p" },
-[0x79] =	{ Jbs,0,		"JPL	%p" },
-[0x7a] =	{ Jbs,0,		"JPS	%p" },
-[0x7b] =	{ Jbs,0,		"JPC	%p" },
-[0x7c] =	{ Jbs,0,		"JLT	%p" },
-[0x7d] =	{ Jbs,0,		"JGE	%p" },
-[0x7e] =	{ Jbs,0,		"JLE	%p" },
-[0x7f] =	{ Jbs,0,		"JGT	%p" },
-[0x80] =	{ RMOPB,0,	optab80 },
-[0x81] =	{ RMOP,0,		optab81 },
-[0x83] =	{ RMOP,0,		optab83 },
-[0x84] =	{ RMB,0,		"TESTB	%r,%e" },
-[0x85] =	{ RM,0,		"TEST%S	%r,%e" },
-[0x86] =	{ RMB,0,		"XCHGB	%r,%e" },
-[0x87] =	{ RM,0,		"XCHG%S	%r,%e" },
-[0x88] =	{ RMB,0,		"MOVB	%r,%e" },
-[0x89] =	{ RM,0,		"MOV%S	%r,%e" },
-[0x8a] =	{ RMB,0,		"MOVB	%e,%r" },
-[0x8b] =	{ RM,0,		"MOV%S	%e,%r" },
-[0x8c] =	{ RM,0,		"MOVW	%g,%e" },
-[0x8d] =	{ RM,0,		"LEA%S	%e,%r" },
-[0x8e] =	{ RM,0,		"MOVW	%e,%g" },
-[0x8f] =	{ RM,0,		"POP%S	%e" },
-[0x90] =	{ 0,0,		"NOP" },
-[0x91] =	{ 0,0,		"XCHG	%OCX,%OAX" },
-[0x92] =	{ 0,0,		"XCHG	%ODX,%OAX" },
-[0x93] =	{ 0,0,		"XCHG	%OBX,%OAX" },
-[0x94] =	{ 0,0,		"XCHG	%OSP,%OAX" },
-[0x95] =	{ 0,0,		"XCHG	%OBP,%OAX" },
-[0x96] =	{ 0,0,		"XCHG	%OSI,%OAX" },
-[0x97] =	{ 0,0,		"XCHG	%ODI,%OAX" },
-[0x98] =	{ 0,0,		"%W" },			/* miserable CBW or CWDE */
-[0x99] =	{ 0,0,		"%w" },			/* idiotic CWD or CDQ */
-[0x9a] =	{ PTR,0,		"CALL%S	%d" },
-[0x9b] =	{ 0,0,		"WAIT" },
-[0x9c] =	{ 0,0,		"PUSHF" },
-[0x9d] =	{ 0,0,		"POPF" },
-[0x9e] =	{ 0,0,		"SAHF" },
-[0x9f] =	{ 0,0,		"LAHF" },
-[0xa0] =	{ Awd,0,		"MOVB	%i,AL" },
-[0xa1] =	{ Awd,0,		"MOV%S	%i,%OAX" },
-[0xa2] =	{ Awd,0,		"MOVB	AL,%i" },
-[0xa3] =	{ Awd,0,		"MOV%S	%OAX,%i" },
-[0xa4] =	{ 0,0,		"MOVSB	(%ASI),(%ADI)" },
-[0xa5] =	{ 0,0,		"MOVS%S	(%ASI),(%ADI)" },
-[0xa6] =	{ 0,0,		"CMPSB	(%ASI),(%ADI)" },
-[0xa7] =	{ 0,0,		"CMPS%S	(%ASI),(%ADI)" },
-[0xa8] =	{ Ib,0,		"TESTB	%i,AL" },
-[0xa9] =	{ Iwd,0,		"TEST%S	%i,%OAX" },
-[0xaa] =	{ 0,0,		"STOSB	AL,(%ADI)" },
-[0xab] =	{ 0,0,		"STOS%S	%OAX,(%ADI)" },
-[0xac] =	{ 0,0,		"LODSB	(%ASI),AL" },
-[0xad] =	{ 0,0,		"LODS%S	(%ASI),%OAX" },
-[0xae] =	{ 0,0,		"SCASB	(%ADI),AL" },
-[0xaf] =	{ 0,0,		"SCAS%S	(%ADI),%OAX" },
-[0xb0] =	{ Ib,0,		"MOVB	%i,AL" },
-[0xb1] =	{ Ib,0,		"MOVB	%i,CL" },
-[0xb2] =	{ Ib,0,		"MOVB	%i,DL" },
-[0xb3] =	{ Ib,0,		"MOVB	%i,BL" },
-[0xb4] =	{ Ib,0,		"MOVB	%i,AH" },
-[0xb5] =	{ Ib,0,		"MOVB	%i,CH" },
-[0xb6] =	{ Ib,0,		"MOVB	%i,DH" },
-[0xb7] =	{ Ib,0,		"MOVB	%i,BH" },
-[0xb8] =	{ Iwdq,0,		"MOV%S	%i,%OAX" },
-[0xb9] =	{ Iwdq,0,		"MOV%S	%i,%OCX" },
-[0xba] =	{ Iwdq,0,		"MOV%S	%i,%ODX" },
-[0xbb] =	{ Iwdq,0,		"MOV%S	%i,%OBX" },
-[0xbc] =	{ Iwdq,0,		"MOV%S	%i,%OSP" },
-[0xbd] =	{ Iwdq,0,		"MOV%S	%i,%OBP" },
-[0xbe] =	{ Iwdq,0,		"MOV%S	%i,%OSI" },
-[0xbf] =	{ Iwdq,0,		"MOV%S	%i,%ODI" },
-[0xc0] =	{ RMOPB,0,	optabC0 },
-[0xc1] =	{ RMOP,0,		optabC1 },
-[0xc2] =	{ Iw,0,		"RET	%i" },
-[0xc3] =	{ RET,0,		"RET" },
-[0xc4] =	{ RM,0,		"LES	%e,%r" },
-[0xc5] =	{ RM,0,		"LDS	%e,%r" },
-[0xc6] =	{ RMB,Ib,		"MOVB	%i,%e" },
-[0xc7] =	{ RM,Iwd,		"MOV%S	%i,%e" },
-[0xc8] =	{ Iw2,Ib,		"ENTER	%i,%I" },		/* loony ENTER */
-[0xc9] =	{ RET,0,		"LEAVE" },		/* bizarre LEAVE */
-[0xca] =	{ Iw,0,		"RETF	%i" },
-[0xcb] =	{ RET,0,		"RETF" },
-[0xcc] =	{ 0,0,		"INT	3" },
-[0xcd] =	{ Ib,0,		"INTB	%i" },
-[0xce] =	{ 0,0,		"INTO" },
-[0xcf] =	{ 0,0,		"IRET" },
-[0xd0] =	{ RMOPB,0,	optabD0 },
-[0xd1] =	{ RMOP,0,		optabD1 },
-[0xd2] =	{ RMOPB,0,	optabD2 },
-[0xd3] =	{ RMOP,0,		optabD3 },
-[0xd4] =	{ OA,0,		"AAM" },
-[0xd5] =	{ OA,0,		"AAD" },
-[0xd7] =	{ 0,0,		"XLAT" },
-[0xd8] =	{ FRMOP,0,	optabD8 },
-[0xd9] =	{ FRMEX,0,	optabD9 },
-[0xda] =	{ FRMOP,0,	optabDA },
-[0xdb] =	{ FRMEX,0,	optabDB },
-[0xdc] =	{ FRMOP,0,	optabDC },
-[0xdd] =	{ FRMOP,0,	optabDD },
-[0xde] =	{ FRMOP,0,	optabDE },
-[0xdf] =	{ FRMOP,0,	optabDF },
-[0xe0] =	{ Jbs,0,		"LOOPNE	%p" },
-[0xe1] =	{ Jbs,0,		"LOOPE	%p" },
-[0xe2] =	{ Jbs,0,		"LOOP	%p" },
-[0xe3] =	{ Jbs,0,		"JCXZ	%p" },
-[0xe4] =	{ Ib,0,		"INB	%i,AL" },
-[0xe5] =	{ Ib,0,		"IN%S	%i,%OAX" },
-[0xe6] =	{ Ib,0,		"OUTB	AL,%i" },
-[0xe7] =	{ Ib,0,		"OUT%S	%OAX,%i" },
-[0xe8] =	{ Iwds,0,		"CALL	%p" },
-[0xe9] =	{ Iwds,0,		"JMP	%p" },
-[0xea] =	{ PTR,0,		"JMP	%d" },
-[0xeb] =	{ Jbs,0,		"JMP	%p" },
-[0xec] =	{ 0,0,		"INB	DX,AL" },
-[0xed] =	{ 0,0,		"IN%S	DX,%OAX" },
-[0xee] =	{ 0,0,		"OUTB	AL,DX" },
-[0xef] =	{ 0,0,		"OUT%S	%OAX,DX" },
-[0xf0] =	{ PRE,0,		"LOCK" },
-[0xf2] =	{ OPRE,0,		"REPNE" },
-[0xf3] =	{ OPRE,0,		"REP" },
-[0xf4] =	{ 0,0,		"HLT" },
-[0xf5] =	{ 0,0,		"CMC" },
-[0xf6] =	{ RMOPB,0,	optabF6 },
-[0xf7] =	{ RMOP,0,		optabF7 },
-[0xf8] =	{ 0,0,		"CLC" },
-[0xf9] =	{ 0,0,		"STC" },
-[0xfa] =	{ 0,0,		"CLI" },
-[0xfb] =	{ 0,0,		"STI" },
-[0xfc] =	{ 0,0,		"CLD" },
-[0xfd] =	{ 0,0,		"STD" },
-[0xfe] =	{ RMOPB,0,	optabFE },
-[0xff] =	{ RMOP,0,		optabFF },
-[0x100] =	{ RM,0,		"MOVLQSX	%e,%r" },
-[0x101] =	{ RM,0,		"MOVLQZX	%e,%r" },
-};
-
-/*
- *  get a byte of the instruction
- */
-static int
-igetc(Map *map, Instr *ip, uchar *c)
-{
-	if(ip->n+1 > sizeof(ip->mem)){
-		werrstr("instruction too long");
-		return -1;
-	}
-	if (get1(map, ip->addr+ip->n, c, 1) < 0) {
-		werrstr("can't read instruction: %r");
-		return -1;
-	}
-	ip->mem[ip->n++] = *c;
-	return 1;
-}
-
-/*
- *  get two bytes of the instruction
- */
-static int
-igets(Map *map, Instr *ip, ushort *sp)
-{
-	uchar c;
-	ushort s;
-
-	if (igetc(map, ip, &c) < 0)
-		return -1;
-	s = c;
-	if (igetc(map, ip, &c) < 0)
-		return -1;
-	s |= (c<<8);
-	*sp = s;
-	return 1;
-}
-
-/*
- *  get 4 bytes of the instruction
- */
-static int
-igetl(Map *map, Instr *ip, uint32 *lp)
-{
-	ushort s;
-	int32	l;
-
-	if (igets(map, ip, &s) < 0)
-		return -1;
-	l = s;
-	if (igets(map, ip, &s) < 0)
-		return -1;
-	l |= (s<<16);
-	*lp = l;
-	return 1;
-}
-
-/*
- *  get 8 bytes of the instruction
- *
-static int
-igetq(Map *map, Instr *ip, vlong *qp)
-{
-	uint32	l;
-	uvlong q;
-
-	if (igetl(map, ip, &l) < 0)
-		return -1;
-	q = l;
-	if (igetl(map, ip, &l) < 0)
-		return -1;
-	q |= ((uvlong)l<<32);
-	*qp = q;
-	return 1;
-}
- */
-
-static int
-getdisp(Map *map, Instr *ip, int mod, int rm, int code, int pcrel)
-{
-	uchar c;
-	ushort s;
-
-	if (mod > 2)
-		return 1;
-	if (mod == 1) {
-		if (igetc(map, ip, &c) < 0)
-			return -1;
-		if (c&0x80)
-			ip->disp = c|0xffffff00;
-		else
-			ip->disp = c&0xff;
-	} else if (mod == 2 || rm == code) {
-		if (ip->asize == 'E') {
-			if (igetl(map, ip, &ip->disp) < 0)
-				return -1;
-			if (mod == 0)
-				ip->rip = pcrel;
-		} else {
-			if (igets(map, ip, &s) < 0)
-				return -1;
-			if (s&0x8000)
-				ip->disp = s|0xffff0000;
-			else
-				ip->disp = s;
-		}
-		if (mod == 0)
-			ip->base = -1;
-	}
-	return 1;
-}
-
-static int
-modrm(Map *map, Instr *ip, uchar c)
-{
-	uchar rm, mod;
-
-	mod = (c>>6)&3;
-	rm = c&7;
-	ip->mod = mod;
-	ip->base = rm;
-	ip->reg = (c>>3)&7;
-	ip->rip = 0;
-	if (mod == 3)			/* register */
-		return 1;
-	if (ip->asize == 0) {		/* 16-bit mode */
-		switch(rm) {
-		case 0:
-			ip->base = BX; ip->index = SI;
-			break;
-		case 1:
-			ip->base = BX; ip->index = DI;
-			break;
-		case 2:
-			ip->base = BP; ip->index = SI;
-			break;
-		case 3:
-			ip->base = BP; ip->index = DI;
-			break;
-		case 4:
-			ip->base = SI;
-			break;
-		case 5:
-			ip->base = DI;
-			break;
-		case 6:
-			ip->base = BP;
-			break;
-		case 7:
-			ip->base = BX;
-			break;
-		default:
-			break;
-		}
-		return getdisp(map, ip, mod, rm, 6, 0);
-	}
-	if (rm == 4) {	/* scummy sib byte */
-		if (igetc(map, ip, &c) < 0)
-			return -1;
-		ip->ss = (c>>6)&0x03;
-		ip->index = (c>>3)&0x07;
-		if (ip->index == 4)
-			ip->index = -1;
-		ip->base = c&0x07;
-		return getdisp(map, ip, mod, ip->base, 5, 0);
-	}
-	return getdisp(map, ip, mod, rm, 5, ip->amd64);
-}
-
-static Optable *
-mkinstr(Map *map, Instr *ip, uvlong pc)
-{
-	int i, n, norex;
-	uchar c;
-	ushort s;
-	Optable *op, *obase;
-	char buf[128];
-
-	memset(ip, 0, sizeof(*ip));
-	norex = 1;
-	ip->base = -1;
-	ip->index = -1;
-	if(asstype == AI8086)
-		ip->osize = 'W';
-	else {
-		ip->osize = 'L';
-		ip->asize = 'E';
-		ip->amd64 = asstype != AI386;
-		norex = 0;
-	}
-	ip->addr = pc;
-	if (igetc(map, ip, &c) < 0)
-		return 0;
-	obase = optable;
-newop:
-	if(ip->amd64 && !norex){
-		if(c >= 0x40 && c <= 0x4f) {
-			ip->rex = c;
-			if(igetc(map, ip, &c) < 0)
-				return 0;
-		}
-		if(c == 0x63){
-			if(ip->rex&REXW)
-				op = &obase[0x100];	/* MOVLQSX */
-			else
-				op = &obase[0x101];	/* MOVLQZX */
-			goto hack;
-		}
-	}
-	op = &obase[c];
-hack:
-	if (op->proto == 0) {
-badop:
-		n = snprint(buf, sizeof(buf), "opcode: ??");
-		for (i = 0; i < ip->n && n < sizeof(buf)-3; i++, n+=2)
-			_hexify(buf+n, ip->mem[i], 1);
-		strcpy(buf+n, "??");
-		werrstr(buf);
-		return 0;
-	}
-	for(i = 0; i < 2 && op->operand[i]; i++) {
-		switch(op->operand[i]) {
-		case Ib:	/* 8-bit immediate - (no sign extension)*/
-			if (igetc(map, ip, &c) < 0)
-				return 0;
-			ip->imm = c&0xff;
-			ip->imm64 = ip->imm;
-			break;
-		case Jbs:	/* 8-bit jump immediate (sign extended) */
-			if (igetc(map, ip, &c) < 0)
-				return 0;
-			if (c&0x80)
-				ip->imm = c|0xffffff00;
-			else
-				ip->imm = c&0xff;
-			ip->imm64 = (int32)ip->imm;
-			ip->jumptype = Jbs;
-			break;
-		case Ibs:	/* 8-bit immediate (sign extended) */
-			if (igetc(map, ip, &c) < 0)
-				return 0;
-			if (c&0x80)
-				if (ip->osize == 'L')
-					ip->imm = c|0xffffff00;
-				else
-					ip->imm = c|0xff00;
-			else
-				ip->imm = c&0xff;
-			ip->imm64 = (int32)ip->imm;
-			break;
-		case Iw:	/* 16-bit immediate -> imm */
-			if (igets(map, ip, &s) < 0)
-				return 0;
-			ip->imm = s&0xffff;
-			ip->imm64 = ip->imm;
-			ip->jumptype = Iw;
-			break;
-		case Iw2:	/* 16-bit immediate -> in imm2*/
-			if (igets(map, ip, &s) < 0)
-				return 0;
-			ip->imm2 = s&0xffff;
-			break;
-		case Iwd:	/* Operand-sized immediate (no sign extension unless 64 bits)*/
-			if (ip->osize == 'L') {
-				if (igetl(map, ip, &ip->imm) < 0)
-					return 0;
-				ip->imm64 = ip->imm;
-				if(ip->rex&REXW && (ip->imm & (1<<31)) != 0)
-					ip->imm64 |= (vlong)~0 << 32;
-			} else {
-				if (igets(map, ip, &s)< 0)
-					return 0;
-				ip->imm = s&0xffff;
-				ip->imm64 = ip->imm;
-			}
-			break;
-		case Iwdq:	/* Operand-sized immediate, possibly big */
-			if (ip->osize == 'L') {
-				if (igetl(map, ip, &ip->imm) < 0)
-					return 0;
-				ip->imm64 = ip->imm;
-				if (ip->rex & REXW) {
-					uint32 l;
-					if (igetl(map, ip, &l) < 0)
-						return 0;
-					ip->imm64 |= (uvlong)l << 32;
-				}
-			} else {
-				if (igets(map, ip, &s)< 0)
-					return 0;
-				ip->imm = s&0xffff;
-			}
-			break;
-		case Awd:	/* Address-sized immediate (no sign extension)*/
-			if (ip->asize == 'E') {
-				if (igetl(map, ip, &ip->imm) < 0)
-					return 0;
-				/* TO DO: REX */
-			} else {
-				if (igets(map, ip, &s)< 0)
-					return 0;
-				ip->imm = s&0xffff;
-			}
-			break;
-		case Iwds:	/* Operand-sized immediate (sign extended) */
-			if (ip->osize == 'L') {
-				if (igetl(map, ip, &ip->imm) < 0)
-					return 0;
-			} else {
-				if (igets(map, ip, &s)< 0)
-					return 0;
-				if (s&0x8000)
-					ip->imm = s|0xffff0000;
-				else
-					ip->imm = s&0xffff;
-			}
-			ip->jumptype = Iwds;
-			break;
-		case OA:	/* literal 0x0a byte */
-			if (igetc(map, ip, &c) < 0)
-				return 0;
-			if (c != 0x0a)
-				goto badop;
-			break;
-		case Op_R0:	/* base register must be R0 */
-			if (ip->base != 0)
-				goto badop;
-			break;
-		case Op_R1:	/* base register must be R1 */
-			if (ip->base != 1)
-				goto badop;
-			break;
-		case RMB:	/* R/M field with byte register (/r)*/
-			if (igetc(map, ip, &c) < 0)
-				return 0;
-			if (modrm(map, ip, c) < 0)
-				return 0;
-			ip->osize = 'B';
-			break;
-		case RM:	/* R/M field with register (/r) */
-			if (igetc(map, ip, &c) < 0)
-				return 0;
-			if (modrm(map, ip, c) < 0)
-				return 0;
-			break;
-		case RMOPB:	/* R/M field with op code (/digit) */
-			if (igetc(map, ip, &c) < 0)
-				return 0;
-			if (modrm(map, ip, c) < 0)
-				return 0;
-			c = ip->reg;		/* secondary op code */
-			obase = (Optable*)op->proto;
-			ip->osize = 'B';
-			goto newop;
-		case RMOP:	/* R/M field with op code (/digit) */
-			if (igetc(map, ip, &c) < 0)
-				return 0;
-			if (modrm(map, ip, c) < 0)
-				return 0;
-			obase = (Optable*)op->proto;
-			if(ip->amd64 && obase == optab0F01 && c == 0xF8)
-				return optab0F01F8;
-			c = ip->reg;
-			goto newop;
-		case FRMOP:	/* FP R/M field with op code (/digit) */
-			if (igetc(map, ip, &c) < 0)
-				return 0;
-			if (modrm(map, ip, c) < 0)
-				return 0;
-			if ((c&0xc0) == 0xc0)
-				c = ip->reg+8;		/* 16 entry table */
-			else
-				c = ip->reg;
-			obase = (Optable*)op->proto;
-			goto newop;
-		case FRMEX:	/* Extended FP R/M field with op code (/digit) */
-			if (igetc(map, ip, &c) < 0)
-				return 0;
-			if (modrm(map, ip, c) < 0)
-				return 0;
-			if ((c&0xc0) == 0xc0)
-				c = (c&0x3f)+8;		/* 64-entry table */
-			else
-				c = ip->reg;
-			obase = (Optable*)op->proto;
-			goto newop;
-		case RMR:	/* R/M register only (mod = 11) */
-			if (igetc(map, ip, &c) < 0)
-				return 0;
-			if ((c&0xc0) != 0xc0) {
-				werrstr("invalid R/M register: %x", c);
-				return 0;
-			}
-			if (modrm(map, ip, c) < 0)
-				return 0;
-			break;
-		case RMM:	/* R/M register only (mod = 11) */
-			if (igetc(map, ip, &c) < 0)
-				return 0;
-			if ((c&0xc0) == 0xc0) {
-				werrstr("invalid R/M memory mode: %x", c);
-				return 0;
-			}
-			if (modrm(map, ip, c) < 0)
-				return 0;
-			break;
-		case PTR:	/* Seg:Displacement addr (ptr16:16 or ptr16:32) */
-			if (ip->osize == 'L') {
-				if (igetl(map, ip, &ip->disp) < 0)
-					return 0;
-			} else {
-				if (igets(map, ip, &s)< 0)
-					return 0;
-				ip->disp = s&0xffff;
-			}
-			if (igets(map, ip, (ushort*)&ip->seg) < 0)
-				return 0;
-			ip->jumptype = PTR;
-			break;
-		case AUXMM:	/* Multi-byte op code; prefix determines table selection */
-			if (igetc(map, ip, &c) < 0)
-				return 0;
-			obase = (Optable*)op->proto;
-			switch (ip->opre) {
-			case 0x66:
-				op = optab660F;
-				break;
-			case 0xF2:
-				op = optabF20F;
-				ip->prefix = 0; /* discard REPNE */
-				break;
-			case 0xF3:
-				op = optabF30F;
-				ip->prefix = 0; /* discard REP */
-				break;
-			default:
-				op = nil;
-				break;
-			}
-			if(op != nil && op[c].proto != nil)
-				obase = op;
-			/* otherwise the optab entry captures it */
-			goto newop;
-		case AUX:	/* Multi-byte op code - Auxiliary table */
-			obase = (Optable*)op->proto;
-			if (igetc(map, ip, &c) < 0)
-				return 0;
-			goto newop;
-		case OPRE:	/* Instr Prefix or media op */
-			ip->opre = c;
-			/* fall through */
-		case PRE:	/* Instr Prefix */
-			ip->prefix = (char*)op->proto;
-			if (igetc(map, ip, &c) < 0)
-				return 0;
-			goto newop;
-		case SEG:	/* Segment Prefix */
-			ip->segment = (char*)op->proto;
-			if (igetc(map, ip, &c) < 0)
-				return 0;
-			goto newop;
-		case OPOVER:	/* Operand size override */
-			ip->opre = c;
-			ip->osize = 'W';
-			if (igetc(map, ip, &c) < 0)
-				return 0;
-			if (c == 0x0F)
-				ip->osize = 'L';
-			else if (ip->amd64 && (c&0xF0) == 0x40)
-				ip->osize = 'Q';
-			goto newop;
-		case ADDOVER:	/* Address size override */
-			ip->asize = 0;
-			if (igetc(map, ip, &c) < 0)
-				return 0;
-			goto newop;
-		case JUMP:	/* mark instruction as JUMP or RET */
-		case RET:
-			ip->jumptype = op->operand[i];
-			break;
-		default:
-			werrstr("bad operand type %d", op->operand[i]);
-			return 0;
-		}
-	}
-	return op;
-}
-
-#pragma	varargck	argpos	bprint		2
-
-static void
-bprint(Instr *ip, char *fmt, ...)
-{
-	va_list arg;
-
-	va_start(arg, fmt);
-	ip->curr = vseprint(ip->curr, ip->end, fmt, arg);
-	va_end(arg);
-}
-
-/*
- *  if we want to call 16 bit regs AX,BX,CX,...
- *  and 32 bit regs EAX,EBX,ECX,... then
- *  change the defs of ANAME and ONAME to:
- *  #define	ANAME(ip)	((ip->asize == 'E' ? "E" : "")
- *  #define	ONAME(ip)	((ip)->osize == 'L' ? "E" : "")
- */
-#define	ANAME(ip)	""
-#define	ONAME(ip)	""
-
-static char *reg[] =  {
-[AX] =	"AX",
-[CX] =	"CX",
-[DX] =	"DX",
-[BX] =	"BX",
-[SP] =	"SP",
-[BP] =	"BP",
-[SI] =	"SI",
-[DI] =	"DI",
-
-	/* amd64 */
-[AMD64_R8] =	"R8",
-[AMD64_R9] =	"R9",
-[AMD64_R10] =	"R10",
-[AMD64_R11] =	"R11",
-[AMD64_R12] =	"R12",
-[AMD64_R13] =	"R13",
-[AMD64_R14] =	"R14",
-[AMD64_R15] =	"R15",
-};
-
-static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" };
-static char *breg64[] = { "AL", "CL", "DL", "BL", "SPB", "BPB", "SIB", "DIB",
-	"R8B", "R9B", "R10B", "R11B", "R12B", "R13B", "R14B", "R15B" };
-static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" };
-
-static void
-plocal(Instr *ip)
-{
-	int ret;
-	int32 offset;
-	Symbol s;
-	char *reg;
-
-	offset = ip->disp;
-	if (!findsym(ip->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s)) {
-		bprint(ip, "%ux(SP)", offset);
-		return;
-	}
-
-	if (s.value > ip->disp) {
-		ret = getauto(&s, s.value-ip->disp-mach->szaddr, CAUTO, &s);
-		reg = "(SP)";
-	} else {
-		offset -= s.value;
-		ret = getauto(&s, offset, CPARAM, &s);
-		reg = "(FP)";
-	}
-	if (ret)
-		bprint(ip, "%s+", s.name);
-	else
-		offset = ip->disp;
-	bprint(ip, "%ux%s", offset, reg);
-}
-
-static int
-isjmp(Instr *ip)
-{
-	switch(ip->jumptype){
-	case Iwds:
-	case Jbs:
-	case JUMP:
-		return 1;
-	default:
-		return 0;
-	}
-}
-
-/*
- * This is too smart for its own good, but it really is nice
- * to have accurate translations when debugging, and it
- * helps us identify which code is different in binaries that
- * are changed on sources.
- */
-static int
-issymref(Instr *ip, Symbol *s, int32 w, int32 val)
-{
-	Symbol next, tmp;
-	int32 isstring, size;
-
-	if (isjmp(ip))
-		return 1;
-	if (s->class==CTEXT && w==0)
-		return 1;
-	if (s->class==CDATA) {
-		/* use first bss symbol (or "end") rather than edata */
-		if (s->name[0]=='e' && strcmp(s->name, "edata") == 0){
-			if((s ->index >= 0 && globalsym(&tmp, s->index+1) && tmp.value==s->value)
-			|| (s->index > 0 && globalsym(&tmp, s->index-1) && tmp.value==s->value))
-				*s = tmp;
-		}
-		if (w == 0)
-			return 1;
-		for (next=*s; next.value==s->value; next=tmp)
-			if (!globalsym(&tmp, next.index+1))
-				break;
-		size = next.value - s->value;
-		if (w >= size)
-			return 0;
-		if (w > size-w)
-			w = size-w;
-		/* huge distances are usually wrong except in .string */
-		isstring = (s->name[0]=='.' && strcmp(s->name, ".string") == 0);
-		if (w > 8192 && !isstring)
-			return 0;
-		/* medium distances are tricky - look for constants */
-		/* near powers of two */
-		if ((val&(val-1)) == 0 || (val&(val+1)) == 0)
-			return 0;
-		return 1;
-	}
-	return 0;
-}
-
-static void
-immediate(Instr *ip, vlong val)
-{
-	Symbol s;
-	int32 w;
-
-	if (findsym(val, CANY, &s)) {		/* TO DO */
-		w = val - s.value;
-		if (w < 0)
-			w = -w;
-		if (issymref(ip, &s, w, val)) {
-			if (w)
-				bprint(ip, "%s+%#ux(SB)", s.name, w);
-			else
-				bprint(ip, "%s(SB)", s.name);
-			return;
-		}
-/*
-		if (s.class==CDATA && globalsym(&s, s.index+1)) {
-			w = s.value - val;
-			if (w < 0)
-				w = -w;
-			if (w < 4096) {
-				bprint(ip, "%s-%#lux(SB)", s.name, w);
-				return;
-			}
-		}
-*/
-	}
-	if((ip->rex & REXW) == 0)
-		bprint(ip, "%lux", (long)val);
-	else
-		bprint(ip, "%llux", val);
-}
-
-static void
-pea(Instr *ip)
-{
-	int base;
-
-	base = ip->base;
-	if(base >= 0 && (ip->rex & REXB))
-		base += 8;
-
-	if (ip->mod == 3) {
-		if (ip->osize == 'B')
-			bprint(ip, (ip->rex & REXB? breg64: breg)[(uchar)ip->base]);
-		else
-			bprint(ip, "%s%s", ANAME(ip), reg[base]);
-		return;
-	}
-
-	if (ip->segment)
-		bprint(ip, ip->segment);
-	if (ip->asize == 'E' && base == SP)
-		plocal(ip);
-	else {
-		if (ip->base < 0)
-			immediate(ip, ip->disp);
-		else {
-			bprint(ip, "%ux", ip->disp);
-			if(ip->rip)
-				bprint(ip, "(RIP)");
-			bprint(ip,"(%s%s)", ANAME(ip), reg[ip->rex&REXB? ip->base+8: ip->base]);
-		}
-	}
-	if (ip->index >= 0)
-		bprint(ip,"(%s%s*%d)", ANAME(ip), reg[ip->rex&REXX? ip->index+8: ip->index], 1<<ip->ss);
-}
-
-static void
-prinstr(Instr *ip, char *fmt)
-{
-	int sharp;
-	vlong v;
-
-	if (ip->prefix)
-		bprint(ip, "%s ", ip->prefix);
-	for (; *fmt && ip->curr < ip->end; fmt++) {
-		if (*fmt != '%'){
-			*ip->curr++ = *fmt;
-			continue;
-		}
-		sharp = 0;
-		if(*++fmt == '#') {
-			sharp = 1;
-			++fmt;
-		}
-		switch(*fmt){
-		case '%':
-			*ip->curr++ = '%';
-			break;
-		case 'A':
-			bprint(ip, "%s", ANAME(ip));
-			break;
-		case 'C':
-			bprint(ip, "CR%d", ip->reg);
-			break;
-		case 'D':
-			if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7)
-				bprint(ip, "DR%d",ip->reg);
-			else
-				bprint(ip, "???");
-			break;
-		case 'I':
-			bprint(ip, "$");
-			immediate(ip, ip->imm2);
-			break;
-		case 'O':
-			bprint(ip,"%s", ONAME(ip));
-			break;
-		case 'i':
-			if(!sharp)
-				bprint(ip, "$");
-			v = ip->imm;
-			if(ip->rex & REXW)
-				v = ip->imm64;
-			immediate(ip, v);
-			break;
-		case 'R':
-			bprint(ip, "%s%s", ONAME(ip), reg[ip->rex&REXR? ip->reg+8: ip->reg]);
-			break;
-		case 'S':
-			if(ip->osize == 'Q' || ip->osize == 'L' && ip->rex & REXW)
-				bprint(ip, "Q");
-			else
-				bprint(ip, "%c", ip->osize);
-			break;
-		case 's':
-			if(ip->opre == 0 || ip->opre == 0x66)
-				bprint(ip, "P");
-			else
-				bprint(ip, "S");
-			if(ip->opre == 0xf2 || ip->opre == 0x66)
-				bprint(ip, "D");
-			else
-				bprint(ip, "S");
-			break;
-		case 'T':
-			if (ip->reg == 6 || ip->reg == 7)
-				bprint(ip, "TR%d",ip->reg);
-			else
-				bprint(ip, "???");
-			break;
-		case 'W':
-			if (ip->osize == 'Q' || ip->osize == 'L' && ip->rex & REXW)
-				bprint(ip, "CDQE");
-			else if (ip->osize == 'L')
-				bprint(ip,"CWDE");
-			else
-				bprint(ip, "CBW");
-			break;
-		case 'd':
-			bprint(ip,"%ux:%ux", ip->seg, ip->disp);
-			break;
-		case 'm':
-			if (ip->mod == 3 && ip->osize != 'B') {
-				if(fmt[1] != '*'){
-					if(ip->opre != 0) {
-						bprint(ip, "X%d", ip->rex&REXB? ip->base+8: ip->base);
-						break;
-					}
-				} else
-					fmt++;
-				bprint(ip, "M%d", ip->base);
-				break;
-			}
-			pea(ip);
-			break;
-		case 'e':
-			pea(ip);
-			break;
-		case 'f':
-			bprint(ip, "F%d", ip->base);
-			break;
-		case 'g':
-			if (ip->reg < 6)
-				bprint(ip,"%s",sreg[ip->reg]);
-			else
-				bprint(ip,"???");
-			break;
-		case 'p':
-			/*
-			 * signed immediate in the uint32 ip->imm.
-			 */
-			v = (int32)ip->imm;
-			immediate(ip, v+ip->addr+ip->n);
-			break;
-		case 'r':
-			if (ip->osize == 'B')
-				bprint(ip,"%s", (ip->rex? breg64: breg)[ip->rex&REXR? ip->reg+8: ip->reg]);
-			else
-				bprint(ip, reg[ip->rex&REXR? ip->reg+8: ip->reg]);
-			break;
-		case 'w':
-			if (ip->osize == 'Q' || ip->rex & REXW)
-				bprint(ip, "CQO");
-			else if (ip->osize == 'L')
-				bprint(ip,"CDQ");
-			else
-				bprint(ip, "CWD");
-			break;
-		case 'M':
-			if(ip->opre != 0)
-				bprint(ip, "X%d", ip->rex&REXR? ip->reg+8: ip->reg);
-			else
-				bprint(ip, "M%d", ip->reg);
-			break;
-		case 'x':
-			if (ip->mod == 3 && ip->osize != 'B') {
-				bprint(ip, "X%d", ip->rex&REXB? ip->base+8: ip->base);
-				break;
-			}
-			pea(ip);
-			break;
-		case 'X':
-			bprint(ip, "X%d", ip->rex&REXR? ip->reg+8: ip->reg);
-			break;
-		default:
-			bprint(ip, "%%%c", *fmt);
-			break;
-		}
-	}
-	*ip->curr = 0;		/* there's always room for 1 byte */
-}
-
-static int
-i386inst(Map *map, uvlong pc, char modifier, char *buf, int n)
-{
-	Instr instr;
-	Optable *op;
-
-	USED(modifier);
-	op = mkinstr(map, &instr, pc);
-	if (op == 0) {
-		errstr(buf, n);
-		return -1;
-	}
-	instr.curr = buf;
-	instr.end = buf+n-1;
-	prinstr(&instr, op->proto);
-	return instr.n;
-}
-
-static int
-i386das(Map *map, uvlong pc, char *buf, int n)
-{
-	Instr instr;
-	int i;
-
-	if (mkinstr(map, &instr, pc) == 0) {
-		errstr(buf, n);
-		return -1;
-	}
-	for(i = 0; i < instr.n && n > 2; i++) {
-		_hexify(buf, instr.mem[i], 1);
-		buf += 2;
-		n -= 2;
-	}
-	*buf = 0;
-	return instr.n;
-}
-
-static int
-i386instlen(Map *map, uvlong pc)
-{
-	Instr i;
-
-	if (mkinstr(map, &i, pc))
-		return i.n;
-	return -1;
-}
-
-static int
-i386foll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
-{
-	Instr i;
-	Optable *op;
-	ushort s;
-	uvlong l, addr;
-	vlong v;
-	int n;
-
-	op = mkinstr(map, &i, pc);
-	if (!op)
-		return -1;
-
-	n = 0;
-
-	switch(i.jumptype) {
-	case RET:		/* RETURN or LEAVE */
-	case Iw:		/* RETURN */
-		if (strcmp(op->proto, "LEAVE") == 0) {
-			if (geta(map, (*rget)(map, "BP"), &l) < 0)
-				return -1;
-		} else if (geta(map, (*rget)(map, mach->sp), &l) < 0)
-			return -1;
-		foll[0] = l;
-		return 1;
-	case Iwds:		/* pc relative JUMP or CALL*/
-	case Jbs:		/* pc relative JUMP or CALL */
-		v = (int32)i.imm;
-		foll[0] = pc+v+i.n;
-		n = 1;
-		break;
-	case PTR:		/* seg:displacement JUMP or CALL */
-		foll[0] = (i.seg<<4)+i.disp;
-		return 1;
-	case JUMP:		/* JUMP or CALL EA */
-
-		if(i.mod == 3) {
-			foll[0] = (*rget)(map, reg[i.rex&REXB? i.base+8: i.base]);
-			return 1;
-		}
-			/* calculate the effective address */
-		addr = i.disp;
-		if (i.base >= 0) {
-			if (geta(map, (*rget)(map, reg[i.rex&REXB? i.base+8: i.base]), &l) < 0)
-				return -1;
-			addr += l;
-		}
-		if (i.index >= 0) {
-			if (geta(map, (*rget)(map, reg[i.rex&REXX? i.index+8: i.index]), &l) < 0)
-				return -1;
-			addr += l*(1<<i.ss);
-		}
-			/* now retrieve a seg:disp value at that address */
-		if (get2(map, addr, &s) < 0)			/* seg */
-			return -1;
-		foll[0] = s<<4;
-		addr += 2;
-		if (i.asize == 'L') {
-			if (geta(map, addr, &l) < 0)		/* disp32 */
-				return -1;
-			foll[0] += l;
-		} else {					/* disp16 */
-			if (get2(map, addr, &s) < 0)
-				return -1;
-			foll[0] += s;
-		}
-		return 1;
-	default:
-		break;
-	}
-	if (strncmp(op->proto,"JMP", 3) == 0 || strncmp(op->proto,"CALL", 4) == 0)
-		return 1;
-	foll[n++] = pc+i.n;
-	return n;
-}
diff --git a/src/libmach/8obj.c b/src/libmach/8obj.c
deleted file mode 100644
index c44d92c..0000000
--- a/src/libmach/8obj.c
+++ /dev/null
@@ -1,170 +0,0 @@
-// Inferno libmach/8obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/8obj.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.
-//	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth at 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.
-
-/*
- * 8obj.c - identify and parse a 386 object file
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-#include "../cmd/8l/8.out.h"
-#include "obj.h"
-
-typedef struct Addr	Addr;
-struct Addr
-{
-	char	sym;
-	char	flags;
-	char gotype;
-};
-static	Addr	addr(Biobuf*);
-static	char	type2char(int);
-static	void	skip(Biobuf*, int);
-
-int
-_is8(char *t)
-{
-	uchar *s = (uchar*)t;
-
-	return  s[0] == (ANAME&0xff)			/* also = ANAME */
-		&& s[1] == ((ANAME>>8)&0xff)
-		&& s[2] == D_FILE			/* type */
-		&& s[3] == 1				/* sym */
-		&& s[4] == '<';				/* name of file */
-}
-
-int
-_read8(Biobuf *bp, Prog* p)
-{
-	int as, n, c;
-	Addr a;
-
-	as = BGETC(bp);		/* as(low) */
-	if(as < 0)
-		return 0;
-	c = BGETC(bp);		/* as(high) */
-	if(c < 0)
-		return 0;
-	as |= ((c & 0xff) << 8);
-	p->kind = aNone;
-	p->sig = 0;
-	if(as == ANAME || as == ASIGNAME){
-		if(as == ASIGNAME){
-			Bread(bp, &p->sig, 4);
-			p->sig = leswal(p->sig);
-		}
-		p->kind = aName;
-		p->type = type2char(BGETC(bp));		/* type */
-		p->sym = BGETC(bp);			/* sym */
-		n = 0;
-		for(;;) {
-			as = BGETC(bp);
-			if(as < 0)
-				return 0;
-			n++;
-			if(as == 0)
-				break;
-		}
-		p->id = malloc(n);
-		if(p->id == 0)
-			return 0;
-		Bseek(bp, -n, 1);
-		if(Bread(bp, p->id, n) != n)
-			return 0;
-		return 1;
-	}
-	if(as == ATEXT)
-		p->kind = aText;
-	if(as == AGLOBL)
-		p->kind = aData;
-	skip(bp, 4);		/* lineno(4) */
-	a = addr(bp);
-	addr(bp);
-	if(!(a.flags & T_SYM))
-		p->kind = aNone;
-	p->sym = a.sym;
-	return 1;
-}
-
-static Addr
-addr(Biobuf *bp)
-{
-	Addr a;
-	int t;
-	long off;
-
-	off = 0;
-	a.gotype = 0;
-	a.sym = -1;
-	a.flags = BGETC(bp);			/* flags */
-	if(a.flags & T_INDEX)
-		skip(bp, 2);
-	if(a.flags & T_OFFSET){
-		off = BGETLE4(bp);
-		if(off < 0)
-			off = -off;
-	}
-	if(a.flags & T_OFFSET2){
-		Bgetle4(bp);
-	}
-	if(a.flags & T_SYM)
-		a.sym = BGETC(bp);
-	if(a.flags & T_FCONST)
-		skip(bp, 8);
-	else
-	if(a.flags & T_SCONST)
-		skip(bp, NSNAME);
-	if(a.flags & T_TYPE) {
-		t = BGETC(bp);
-		if(a.sym > 0 && (t==D_PARAM || t==D_AUTO))
-			_offset(a.sym, off);
-	}
-	if(a.flags & T_GOTYPE)
-		a.gotype = BGETC(bp);
-	return a;
-}
-
-static char
-type2char(int t)
-{
-	switch(t){
-	case D_EXTERN:		return 'U';
-	case D_STATIC:		return 'b';
-	case D_AUTO:		return 'a';
-	case D_PARAM:		return 'p';
-	default:		return UNKNOWN;
-	}
-}
-
-static void
-skip(Biobuf *bp, int n)
-{
-	while (n-- > 0)
-		Bgetc(bp);
-}
diff --git a/src/libmach/Makefile b/src/libmach/Makefile
deleted file mode 100644
index 62aba5d..0000000
--- a/src/libmach/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/libmach/access.c b/src/libmach/access.c
deleted file mode 100644
index 0ee75d1..0000000
--- a/src/libmach/access.c
+++ /dev/null
@@ -1,241 +0,0 @@
-// Inferno libmach/access.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/access.c
-//
-// 	Copyright © 1994-1999 Lucent Technologies Inc.
-// 	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth at 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.
-
-/*
- * functions to read and write an executable or file image
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-static	int	mget(Map*, uvlong, void*, int);
-static	int	mput(Map*, uvlong, void*, int);
-static	Seg*	reloc(Map*, uvlong, vlong*);
-
-/*
- * routines to get/put various types
- */
-int
-geta(Map *map, uvlong addr, uvlong *x)
-{
-	uint32 l;
-	uvlong vl;
-
-	if (mach->szaddr == 8){
-		if (get8(map, addr, &vl) < 0)
-			return -1;
-		*x = vl;
-		return 1;
-	}
-
-	if (get4(map, addr, &l) < 0)
-		return -1;
-	*x = l;
-
-	return 1;
-}
-
-int
-get8(Map *map, uvlong addr, uvlong *x)
-{
-	if (!map) {
-		werrstr("get8: invalid map");
-		return -1;
-	}
-
-	if (map->nsegs == 1 && map->seg[0].fd < 0) {
-		*x = addr;
-		return 1;
-	}
-	if (mget(map, addr, x, 8) < 0)
-		return -1;
-	*x = machdata->swav(*x);
-	return 1;
-}
-
-int
-get4(Map *map, uvlong addr, uint32 *x)
-{
-	if (!map) {
-		werrstr("get4: invalid map");
-		return -1;
-	}
-
-	if (map->nsegs == 1 && map->seg[0].fd < 0) {
-		*x = addr;
-		return 1;
-	}
-	if (mget(map, addr, x, 4) < 0)
-		return -1;
-	*x = machdata->swal(*x);
-	return 1;
-}
-
-int
-get2(Map *map, uvlong addr, ushort *x)
-{
-	if (!map) {
-		werrstr("get2: invalid map");
-		return -1;
-	}
-
-	if (map->nsegs == 1 && map->seg[0].fd < 0) {
-		*x = addr;
-		return 1;
-	}
-	if (mget(map, addr, x, 2) < 0)
-		return -1;
-	*x = machdata->swab(*x);
-	return 1;
-}
-
-int
-get1(Map *map, uvlong addr, uchar *x, int size)
-{
-	uchar *cp;
-
-	if (!map) {
-		werrstr("get1: invalid map");
-		return -1;
-	}
-
-	if (map->nsegs == 1 && map->seg[0].fd < 0) {
-		cp = (uchar*)&addr;
-		while (cp < (uchar*)(&addr+1) && size-- > 0)
-			*x++ = *cp++;
-		while (size-- > 0)
-			*x++ = 0;
-	} else
-		return mget(map, addr, x, size);
-	return 1;
-}
-
-int
-puta(Map *map, uvlong addr, uvlong v)
-{
-	if (mach->szaddr == 8)
-		return put8(map, addr, v);
-
-	return put4(map, addr, v);
-}
-
-int
-put8(Map *map, uvlong addr, uvlong v)
-{
-	if (!map) {
-		werrstr("put8: invalid map");
-		return -1;
-	}
-	v = machdata->swav(v);
-	return mput(map, addr, &v, 8);
-}
-
-int
-put4(Map *map, uvlong addr, uint32 v)
-{
-	if (!map) {
-		werrstr("put4: invalid map");
-		return -1;
-	}
-	v = machdata->swal(v);
-	return mput(map, addr, &v, 4);
-}
-
-int
-put2(Map *map, uvlong addr, ushort v)
-{
-	if (!map) {
-		werrstr("put2: invalid map");
-		return -1;
-	}
-	v = machdata->swab(v);
-	return mput(map, addr, &v, 2);
-}
-
-int
-put1(Map *map, uvlong addr, uchar *v, int size)
-{
-	if (!map) {
-		werrstr("put1: invalid map");
-		return -1;
-	}
-	return mput(map, addr, v, size);
-}
-
-static int
-mget(Map *map, uvlong addr, void *buf, int size)
-{
-	uvlong off;
-	Seg *s;
-
-	s = reloc(map, addr, (vlong*)&off);
-	if (!s)
-		return -1;
-	if (s->rw == nil) {
-		werrstr("unreadable map");
-		return -1;
-	}
-	return s->rw(map, s, off, buf, size, 1);
-}
-
-static int
-mput(Map *map, uvlong addr, void *buf, int size)
-{
-	vlong off;
-	Seg *s;
-
-	s = reloc(map, addr, &off);
-	if (!s)
-		return -1;
-	if (s->rw == nil) {
-		werrstr("unwritable map");
-		return -1;
-	}
-	return s->rw(map, s, off, buf, size, 0);
-}
-
-/*
- *	convert address to file offset; returns nonzero if ok
- */
-static Seg*
-reloc(Map *map, uvlong addr, vlong *offp)
-{
-	int i;
-
-	for (i = 0; i < map->nsegs; i++) {
-		if (map->seg[i].inuse)
-		if (map->seg[i].b <= addr && addr < map->seg[i].e) {
-			*offp = addr + map->seg[i].f - map->seg[i].b;
-			return &map->seg[i];
-		}
-	}
-	werrstr("can't translate address %llux", addr);
-	return 0;
-}
diff --git a/src/libmach/darwin.c b/src/libmach/darwin.c
deleted file mode 100644
index 807dfa0..0000000
--- a/src/libmach/darwin.c
+++ /dev/null
@@ -1,897 +0,0 @@
-//	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.
-
-#define __DARWIN_UNIX03 0
-
-#include <u.h>
-#include <sys/ptrace.h>
-#include <sys/signal.h>
-#include <mach/mach.h>
-#include <mach/mach_traps.h>
-#include <errno.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-#define Ureg Ureg32
-#include <ureg_x86.h>
-#undef Ureg
-#define Ureg Ureg64
-#include <ureg_amd64.h>
-#undef Ureg
-#undef waitpid	/* want Unix waitpid, not Plan 9 */
-
-typedef struct Ureg32 Ureg32;
-typedef struct Ureg64 Ureg64;
-
-extern mach_port_t mach_reply_port(void);	// should be in system headers, is not
-
-// Mach-error wrapper.
-// Takes a mach return code and converts it into 0 / -1,
-// setting errstr when it returns -1.
-
-static struct {
-	int code;
-	char *name;
-} macherr[] = {
-	KERN_INVALID_ADDRESS,	"invalid address",
-	KERN_PROTECTION_FAILURE,	"protection failure",
-	KERN_NO_SPACE,	"no space",
-	KERN_INVALID_ARGUMENT,	"invalid argument",
-	KERN_FAILURE,	"failure",
-	KERN_RESOURCE_SHORTAGE,	"resource shortage",
-	KERN_NOT_RECEIVER,	"not receiver",
-	KERN_NO_ACCESS,	"no access",
-	KERN_MEMORY_FAILURE,	"memory failure",
-	KERN_MEMORY_ERROR,	"memory error",
-	KERN_ALREADY_IN_SET,	"already in set",
-	KERN_NOT_IN_SET,	"not in set",
-	KERN_NAME_EXISTS,	"name exists",
-	KERN_ABORTED,	"aborted",
-	KERN_INVALID_NAME,	"invalid name",
-	KERN_INVALID_TASK,	"invalid task",
-	KERN_INVALID_RIGHT,	"invalid right",
-	KERN_INVALID_VALUE,	"invalid value",
-	KERN_UREFS_OVERFLOW,	"urefs overflow",
-	KERN_INVALID_CAPABILITY,	"invalid capability",
-	KERN_RIGHT_EXISTS,	"right exists",
-	KERN_INVALID_HOST,	"invalid host",
-	KERN_MEMORY_PRESENT,	"memory present",
-	KERN_MEMORY_DATA_MOVED,	"memory data moved",
-	KERN_MEMORY_RESTART_COPY,	"memory restart copy",
-	KERN_INVALID_PROCESSOR_SET,	"invalid processor set",
-	KERN_POLICY_LIMIT,	"policy limit",
-	KERN_INVALID_POLICY,	"invalid policy",
-	KERN_INVALID_OBJECT,	"invalid object",
-	KERN_ALREADY_WAITING,	"already waiting",
-	KERN_DEFAULT_SET,	"default set",
-	KERN_EXCEPTION_PROTECTED,	"exception protected",
-	KERN_INVALID_LEDGER,	"invalid ledger",
-	KERN_INVALID_MEMORY_CONTROL,	"invalid memory control",
-	KERN_INVALID_SECURITY,	"invalid security",
-	KERN_NOT_DEPRESSED,	"not depressed",
-	KERN_TERMINATED,	"terminated",
-	KERN_LOCK_SET_DESTROYED,	"lock set destroyed",
-	KERN_LOCK_UNSTABLE,	"lock unstable",
-	KERN_LOCK_OWNED,	"lock owned",
-	KERN_LOCK_OWNED_SELF,	"lock owned self",
-	KERN_SEMAPHORE_DESTROYED,	"semaphore destroyed",
-	KERN_RPC_SERVER_TERMINATED,	"rpc server terminated",
-	KERN_RPC_TERMINATE_ORPHAN,	"rpc terminate orphan",
-	KERN_RPC_CONTINUE_ORPHAN,	"rpc continue orphan",
-	KERN_NOT_SUPPORTED,	"not supported",
-	KERN_NODE_DOWN,	"node down",
-	KERN_NOT_WAITING,	"not waiting",
-	KERN_OPERATION_TIMED_OUT,	"operation timed out",
-	KERN_RETURN_MAX,	"return max",
-
-	MACH_SEND_IN_PROGRESS,	"send in progress",
-	MACH_SEND_INVALID_DATA,	"send invalid data",
-	MACH_SEND_INVALID_DEST,	"send invalid dest",
-	MACH_SEND_TIMED_OUT,	"send timed out",
-	MACH_SEND_INTERRUPTED,	"send interrupted",
-	MACH_SEND_MSG_TOO_SMALL,	"send msg too small",
-	MACH_SEND_INVALID_REPLY,	"send invalid reply",
-	MACH_SEND_INVALID_RIGHT,	"send invalid right",
-	MACH_SEND_INVALID_NOTIFY,	"send invalid notify",
-	MACH_SEND_INVALID_MEMORY,	"send invalid memory",
-	MACH_SEND_NO_BUFFER,	"send no buffer",
-	MACH_SEND_TOO_LARGE,	"send too large",
-	MACH_SEND_INVALID_TYPE,	"send invalid type",
-	MACH_SEND_INVALID_HEADER,	"send invalid header",
-	MACH_SEND_INVALID_TRAILER,	"send invalid trailer",
-	MACH_SEND_INVALID_RT_OOL_SIZE,	"send invalid rt ool size",
-	MACH_RCV_IN_PROGRESS,	"rcv in progress",
-	MACH_RCV_INVALID_NAME,	"rcv invalid name",
-	MACH_RCV_TIMED_OUT,	"rcv timed out",
-	MACH_RCV_TOO_LARGE,	"rcv too large",
-	MACH_RCV_INTERRUPTED,	"rcv interrupted",
-	MACH_RCV_PORT_CHANGED,	"rcv port changed",
-	MACH_RCV_INVALID_NOTIFY,	"rcv invalid notify",
-	MACH_RCV_INVALID_DATA,	"rcv invalid data",
-	MACH_RCV_PORT_DIED,	"rcv port died",
-	MACH_RCV_IN_SET,	"rcv in set",
-	MACH_RCV_HEADER_ERROR,	"rcv header error",
-	MACH_RCV_BODY_ERROR,	"rcv body error",
-	MACH_RCV_INVALID_TYPE,	"rcv invalid type",
-	MACH_RCV_SCATTER_SMALL,	"rcv scatter small",
-	MACH_RCV_INVALID_TRAILER,	"rcv invalid trailer",
-	MACH_RCV_IN_PROGRESS_TIMED,	"rcv in progress timed",
-
-	MIG_TYPE_ERROR,	"mig type error",
-	MIG_REPLY_MISMATCH,	"mig reply mismatch",
-	MIG_REMOTE_ERROR,	"mig remote error",
-	MIG_BAD_ID,	"mig bad id",
-	MIG_BAD_ARGUMENTS,	"mig bad arguments",
-	MIG_NO_REPLY,	"mig no reply",
-	MIG_EXCEPTION,	"mig exception",
-	MIG_ARRAY_TOO_LARGE,	"mig array too large",
-	MIG_SERVER_DIED,	"server died",
-	MIG_TRAILER_ERROR,	"trailer has an unknown format",
-};
-
-static int
-me(kern_return_t r)
-{
-	int i;
-
-	if(r == 0)
-		return 0;
-
-	for(i=0; i<nelem(macherr); i++){
-		if(r == macherr[i].code){
-			werrstr("mach: %s", macherr[i].name);
-			return -1;
-		}
-	}
-	werrstr("mach error %#x", r);
-	return -1;
-}
-
-// Plan 9 and Linux do not distinguish between
-// process ids and thread ids, so the interface here doesn't either.
-// Unfortunately, Mach has three kinds of identifiers: process ids,
-// handles to tasks (processes), and handles to threads within a
-// process.  All of them are small integers.
-//
-// To accommodate Mach, we employ a clumsy hack: in this interface,
-// if you pass in a positive number, that's a process id.
-// If you pass in a negative number, that identifies a thread that
-// has been previously returned by procthreadpids (it indexes
-// into the Thread table below).
-
-// Table of threads we have handles for.
-typedef struct Thread Thread;
-struct Thread
-{
-	int pid;
-	mach_port_t task;
-	mach_port_t thread;
-	int stopped;
-	int exc;
-	int code[10];
-	Map *map;
-};
-static Thread thr[1000];
-static int nthr;
-static pthread_mutex_t mu;
-static pthread_cond_t cond;
-static void* excthread(void*);
-static void* waitthread(void*);
-static mach_port_t excport;
-
-enum {
-	ExcMask = EXC_MASK_BAD_ACCESS |
-		EXC_MASK_BAD_INSTRUCTION |
-		EXC_MASK_ARITHMETIC |
-		EXC_MASK_BREAKPOINT |
-		EXC_MASK_SOFTWARE
-};
-
-// Add process pid to the thread table.
-// If it's already there, don't re-add it (unless force != 0).
-static Thread*
-addpid(int pid, int force)
-{
-	int i, j;
-	mach_port_t task;
-	mach_port_t *thread;
-	uint nthread;
-	Thread *ret;
-	static int first = 1;
-
-	if(first){
-		// Allocate a port for exception messages and
-		// send all thread exceptions to that port.
-		// The excthread reads that port and signals
-		// us if we are waiting on that thread.
-		pthread_t p;
-		int err;
-
-		excport = mach_reply_port();
-		pthread_mutex_init(&mu, nil);
-		pthread_cond_init(&cond, nil);
-		err = pthread_create(&p, nil, excthread, nil);
-		if (err != 0) {
-			fprint(2, "pthread_create failed: %s\n", strerror(err));
-			abort();
-		}
-		err = pthread_create(&p, nil, waitthread, (void*)(uintptr)pid);
-		if (err != 0) {
-			fprint(2, "pthread_create failed: %s\n", strerror(err));
-			abort();
-		}
-		first = 0;
-	}
-
-	if(!force){
-		for(i=0; i<nthr; i++)
-			if(thr[i].pid == pid)
-				return &thr[i];
-	}
-	if(me(task_for_pid(mach_task_self(), pid, &task)) < 0)
-		return nil;
-	if(me(task_threads(task, &thread, &nthread)) < 0)
-		return nil;
-	mach_port_insert_right(mach_task_self(), excport, excport, MACH_MSG_TYPE_MAKE_SEND);
-	if(me(task_set_exception_ports(task, ExcMask,
-			excport, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE)) < 0){
-		fprint(2, "warning: cannot set excport: %r\n");
-	}
-	ret = nil;
-	for(j=0; j<nthread; j++){
-		if(force){
-			// If we're forcing a refresh, don't re-add existing threads.
-			for(i=0; i<nthr; i++)
-				if(thr[i].pid == pid && thr[i].thread == thread[j]){
-					if(ret == nil)
-						ret = &thr[i];
-					goto skip;
-				}
-		}
-		if(nthr >= nelem(thr))
-			return nil;
-		// TODO: We probably should save the old thread exception
-		// ports for each bit and then put them back when we exit.
-		// Probably the BSD signal handlers have put stuff there.
-		mach_port_insert_right(mach_task_self(), excport, excport, MACH_MSG_TYPE_MAKE_SEND);
-		if(me(thread_set_exception_ports(thread[j], ExcMask,
-				excport, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE)) < 0){
-			fprint(2, "warning: cannot set excport: %r\n");
-		}
-		thr[nthr].pid = pid;
-		thr[nthr].task = task;
-		thr[nthr].thread = thread[j];
-		if(ret == nil)
-			ret = &thr[nthr];
-		nthr++;
-	skip:;
-	}
-	return ret;
-}
-
-static Thread*
-idtotable(int id)
-{
-	if(id >= 0)
-		return addpid(id, 1);
-
-	id = -(id+1);
-	if(id >= nthr)
-		return nil;
-	return &thr[id];
-}
-
-/*
-static int
-idtopid(int id)
-{
-	Thread *t;
-
-	if((t = idtotable(id)) == nil)
-		return -1;
-	return t->pid;
-}
-*/
-
-static mach_port_t
-idtotask(int id)
-{
-	Thread *t;
-
-	if((t = idtotable(id)) == nil)
-		return -1;
-	return t->task;
-}
-
-static mach_port_t
-idtothread(int id)
-{
-	Thread *t;
-
-	if((t = idtotable(id)) == nil)
-		return -1;
-	return t->thread;
-}
-
-static int machsegrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr);
-static int machregrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr);
-
-Map*
-attachproc(int id, Fhdr *fp)
-{
-	Thread *t;
-	Map *map;
-
-	if((t = idtotable(id)) == nil)
-		return nil;
-	if(t->map)
-		return t->map;
-	map = newmap(0, 4);
-	if(!map)
-		return nil;
-	map->pid = -((t-thr) + 1);
-	if(mach->regsize)
-		setmap(map, -1, 0, mach->regsize, 0, "regs", machregrw);
-	setmap(map, -1, fp->txtaddr, fp->txtaddr+fp->txtsz, fp->txtaddr, "*text", machsegrw);
-	setmap(map, -1, fp->dataddr, mach->utop, fp->dataddr, "*data", machsegrw);
-	t->map = map;
-	return map;
-}
-
-// Return list of ids for threads in id.
-int
-procthreadpids(int id, int *out, int nout)
-{
-	Thread *t;
-	int i, n, pid;
-
-	t = idtotable(id);
-	if(t == nil)
-		return -1;
-	pid = t->pid;
-	addpid(pid, 1);	// force refresh of thread list
-	n = 0;
-	for(i=0; i<nthr; i++) {
-		if(thr[i].pid == pid) {
-			if(n < nout)
-				out[n] = -(i+1);
-			n++;
-		}
-	}
-	return n;
-}
-
-// Detach from proc.
-// TODO(rsc): Perhaps should unsuspend any threads and clean-up the table.
-void
-detachproc(Map *m)
-{
-	free(m);
-}
-
-// Should return array of pending signals (notes)
-// but don't know how to do that on OS X.
-int
-procnotes(int pid, char ***pnotes)
-{
-	USED(pid);
-	*pnotes = 0;
-	return 0;
-}
-
-// There must be a way to do this.  Gdb can do it.
-// But I don't see, in the Apple gdb sources, how.
-char*
-proctextfile(int pid)
-{
-	USED(pid);
-	return nil;
-}
-
-// Read/write from a Mach data segment.
-static int
-machsegrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
-{
-	mach_port_t task;
-	int r;
-
-	USED(seg);
-
-	task = idtotask(map->pid);
-	if(task == -1)
-		return -1;
-
-	if(isr){
-		vm_size_t nn;
-		nn = n;
-		if(me(vm_read_overwrite(task, addr, n, (uintptr)v, &nn)) < 0) {
-			fprint(2, "vm_read_overwrite %#llux %d to %p: %r\n", addr, n, v);
-			return -1;
-		}
-		return nn;
-	}else{
-		r = vm_write(task, addr, (uintptr)v, n);
-		if(r == KERN_INVALID_ADDRESS){
-			// Happens when writing to text segment.
-			// Change protections.
-			if(me(vm_protect(task, addr, n, 0, VM_PROT_WRITE|VM_PROT_READ|VM_PROT_EXECUTE)) < 0){
-				fprint(2, "vm_protect: %s\n", r);
-				return -1;
-			}
-			r = vm_write(task, addr, (uintptr)v, n);
-		}
-		if(r != 0){
-			me(r);
-			return -1;
-		}
-		return n;
-	}
-}
-
-// Convert Ureg offset to x86_thread_state32_t offset.
-static int
-go2darwin32(uvlong addr)
-{
-	switch(addr){
-	case offsetof(Ureg32, ax):
-		return offsetof(x86_thread_state32_t, eax);
-	case offsetof(Ureg32, bx):
-		return offsetof(x86_thread_state32_t, ebx);
-	case offsetof(Ureg32, cx):
-		return offsetof(x86_thread_state32_t, ecx);
-	case offsetof(Ureg32, dx):
-		return offsetof(x86_thread_state32_t, edx);
-	case offsetof(Ureg32, si):
-		return offsetof(x86_thread_state32_t, esi);
-	case offsetof(Ureg32, di):
-		return offsetof(x86_thread_state32_t, edi);
-	case offsetof(Ureg32, bp):
-		return offsetof(x86_thread_state32_t, ebp);
-	case offsetof(Ureg32, fs):
-		return offsetof(x86_thread_state32_t, fs);
-	case offsetof(Ureg32, gs):
-		return offsetof(x86_thread_state32_t, gs);
-	case offsetof(Ureg32, pc):
-		return offsetof(x86_thread_state32_t, eip);
-	case offsetof(Ureg32, cs):
-		return offsetof(x86_thread_state32_t, cs);
-	case offsetof(Ureg32, flags):
-		return offsetof(x86_thread_state32_t, eflags);
-	case offsetof(Ureg32, sp):
-		return offsetof(x86_thread_state32_t, esp);
-	}
-	return -1;
-}
-
-// Convert Ureg offset to x86_thread_state64_t offset.
-static int
-go2darwin64(uvlong addr)
-{
-	switch(addr){
-	case offsetof(Ureg64, ax):
-		return offsetof(x86_thread_state64_t, rax);
-	case offsetof(Ureg64, bx):
-		return offsetof(x86_thread_state64_t, rbx);
-	case offsetof(Ureg64, cx):
-		return offsetof(x86_thread_state64_t, rcx);
-	case offsetof(Ureg64, dx):
-		return offsetof(x86_thread_state64_t, rdx);
-	case offsetof(Ureg64, si):
-		return offsetof(x86_thread_state64_t, rsi);
-	case offsetof(Ureg64, di):
-		return offsetof(x86_thread_state64_t, rdi);
-	case offsetof(Ureg64, bp):
-		return offsetof(x86_thread_state64_t, rbp);
-	case offsetof(Ureg64, r8):
-		return offsetof(x86_thread_state64_t, r8);
-	case offsetof(Ureg64, r9):
-		return offsetof(x86_thread_state64_t, r9);
-	case offsetof(Ureg64, r10):
-		return offsetof(x86_thread_state64_t, r10);
-	case offsetof(Ureg64, r11):
-		return offsetof(x86_thread_state64_t, r11);
-	case offsetof(Ureg64, r12):
-		return offsetof(x86_thread_state64_t, r12);
-	case offsetof(Ureg64, r13):
-		return offsetof(x86_thread_state64_t, r13);
-	case offsetof(Ureg64, r14):
-		return offsetof(x86_thread_state64_t, r14);
-	case offsetof(Ureg64, r15):
-		return offsetof(x86_thread_state64_t, r15);
-	case offsetof(Ureg64, fs):
-		return offsetof(x86_thread_state64_t, fs);
-	case offsetof(Ureg64, gs):
-		return offsetof(x86_thread_state64_t, gs);
-	case offsetof(Ureg64, ip):
-		return offsetof(x86_thread_state64_t, rip);
-	case offsetof(Ureg64, cs):
-		return offsetof(x86_thread_state64_t, cs);
-	case offsetof(Ureg64, flags):
-		return offsetof(x86_thread_state64_t, rflags);
-	case offsetof(Ureg64, sp):
-		return offsetof(x86_thread_state64_t, rsp);
-	}
-	return -1;
-}
-
-extern Mach mi386;
-
-// Read/write from fake register segment.
-static int
-machregrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
-{
-	uint nn, count, state;
-	mach_port_t thread;
-	int reg;
-	char buf[100];
-	union {
-		x86_thread_state64_t reg64;
-		x86_thread_state32_t reg32;
-		uchar p[1];
-	} u;
-	uchar *p;
-
-	USED(seg);
-
-	if(n > 8){
-		werrstr("asked for %d-byte register", n);
-		return -1;
-	}
-
-	thread = idtothread(map->pid);
-	if(thread == -1){
-		werrstr("no such id");
-		return -1;
-	}
-
-	if(mach == &mi386) {
-		count = x86_THREAD_STATE32_COUNT;
-		state = x86_THREAD_STATE32;
-		if((reg = go2darwin32(addr)) < 0 || reg+n > sizeof u){
-			if(isr){
-				memset(v, 0, n);
-				return 0;
-			}
-			werrstr("register %llud not available", addr);
-			return -1;
-		}
-	} else {
-		count = x86_THREAD_STATE64_COUNT;
-		state = x86_THREAD_STATE64;
-		if((reg = go2darwin64(addr)) < 0 || reg+n > sizeof u){
-			if(isr){
-				memset(v, 0, n);
-				return 0;
-			}
-			werrstr("register %llud not available", addr);
-			return -1;
-		}
-	}
-
-	if(!isr && me(thread_suspend(thread)) < 0){
-		werrstr("thread suspend %#x: %r", thread);
-		return -1;
-	}
-	nn = count;
-	if(me(thread_get_state(thread, state, (void*)u.p, &nn)) < 0){
-		if(!isr)
-			thread_resume(thread);
-		rerrstr(buf, sizeof buf);
-		if(strstr(buf, "send invalid dest") != nil) 
-			werrstr("process exited");
-		else
-			werrstr("thread_get_state: %r");
-		return -1;
-	}
-
-	p = u.p+reg;
-	if(isr)
-		memmove(v, p, n);
-	else{
-		memmove(p, v, n);
-		nn = count;
-		if(me(thread_set_state(thread, state, (void*)u.p, nn)) < 0){
-			thread_resume(thread);
-			werrstr("thread_set_state: %r");
-			return -1;
-		}
-
-		if(me(thread_resume(thread)) < 0){
-			werrstr("thread_resume: %r");
-			return -1;
-		}
-	}
-	return 0;
-}
-
-enum
-{
-	FLAGS_TF = 0x100		// x86 single-step processor flag
-};
-
-// Is thread t suspended?
-static int
-threadstopped(Thread *t)
-{
-	struct thread_basic_info info;
-	uint size;
-
-	size = sizeof info;
-	if(me(thread_info(t->thread, THREAD_BASIC_INFO, (thread_info_t)&info, &size)) <  0){
-		fprint(2, "threadstopped thread_info %#x: %r\n");
-		return 1;
-	}
-	return info.suspend_count > 0;
-}
-
-// If thread t is suspended, start it up again.
-// If singlestep is set, only let it execute one instruction.
-static int
-threadstart(Thread *t, int singlestep)
-{
-	int i;
-	uint n;
-	struct thread_basic_info info;
-
-	if(!threadstopped(t))
-		return 0;
-
-	// Set or clear the processor single-step flag, as appropriate.
-	if(mach == &mi386) {
-		x86_thread_state32_t regs;
-		n = x86_THREAD_STATE32_COUNT;
-		if(me(thread_get_state(t->thread, x86_THREAD_STATE32,
-				(thread_state_t)&regs,
-				&n)) < 0)
-			return -1;
-		if(singlestep)
-			regs.eflags |= FLAGS_TF;
-		else
-			regs.eflags &= ~FLAGS_TF;
-		if(me(thread_set_state(t->thread, x86_THREAD_STATE32,
-				(thread_state_t)&regs,
-				x86_THREAD_STATE32_COUNT)) < 0)
-			return -1;
-	} else {
-		x86_thread_state64_t regs;
-		n = x86_THREAD_STATE64_COUNT;
-		if(me(thread_get_state(t->thread, x86_THREAD_STATE64,
-				(thread_state_t)&regs,
-				&n)) < 0)
-			return -1;
-		if(singlestep)
-			regs.rflags |= FLAGS_TF;
-		else
-			regs.rflags &= ~FLAGS_TF;
-		if(me(thread_set_state(t->thread, x86_THREAD_STATE64,
-				(thread_state_t)&regs,
-				x86_THREAD_STATE64_COUNT)) < 0)
-			return -1;
-	}
-
-	// Run.
-	n = sizeof info;
-	if(me(thread_info(t->thread, THREAD_BASIC_INFO, (thread_info_t)&info, &n)) < 0)
-		return -1;
-	for(i=0; i<info.suspend_count; i++)
-		if(me(thread_resume(t->thread)) < 0)
-			return -1;
-	return 0;
-}
-
-// Stop thread t.
-static int
-threadstop(Thread *t)
-{
-	if(threadstopped(t))
-		return 0;
-	if(me(thread_suspend(t->thread)) < 0)
-		return -1;
-	return 0;
-}
-
-// Callback for exc_server below.  Called when a thread we are
-// watching has an exception like hitting a breakpoint.
-kern_return_t
-catch_exception_raise(mach_port_t eport, mach_port_t thread,
-	mach_port_t task, exception_type_t exception,
-	exception_data_t code, mach_msg_type_number_t ncode)
-{
-	Thread *t;
-	int i;
-
-	USED(eport);
-	USED(task);
-
-	t = nil;
-	for(i=0; i<nthr; i++){
-		if(thr[i].thread == thread){
-			t = &thr[i];
-			goto havet;
-		}
-	}
-	if(nthr > 0)
-		addpid(thr[0].pid, 1);
-	for(i=0; i<nthr; i++){
-		if(thr[i].thread == thread){
-			t = &thr[i];
-			goto havet;
-		}
-	}
-	fprint(2, "did not find thread in catch_exception_raise\n");
-	return KERN_SUCCESS;	// let thread continue
-
-havet:
-	t->exc = exception;
-	if(ncode > nelem(t->code))
-		ncode = nelem(t->code);
-	memmove(t->code, code, ncode*sizeof t->code[0]);
-
-	// Suspend thread, so that we can look at it & restart it later.
-	if(me(thread_suspend(thread)) < 0)
-		fprint(2, "catch_exception_raise thread_suspend: %r\n");
-
-	// Synchronize with waitstop below.
-	pthread_mutex_lock(&mu);
-	pthread_cond_broadcast(&cond);
-	pthread_mutex_unlock(&mu);
-
-	return KERN_SUCCESS;
-}
-
-// Exception watching thread, started in addpid above.
-static void*
-excthread(void *v)
-{
-	USED(v);
-	extern boolean_t exc_server(mach_msg_header_t *, mach_msg_header_t *);
-	mach_msg_server(exc_server, 2048, excport, 0);
-	return 0;
-}
-
-// Wait for pid to exit.
-static int exited;
-static void*
-waitthread(void *v)
-{
-	int pid, status;
-
-	pid = (int)(uintptr)v;
-	waitpid(pid, &status, 0);
-	exited = 1;
-	// Synchronize with waitstop below.
-	pthread_mutex_lock(&mu);
-	pthread_cond_broadcast(&cond);
-	pthread_mutex_unlock(&mu);
-	return nil;
-}
-
-// Wait for thread t to stop.
-static int
-waitstop(Thread *t)
-{
-	pthread_mutex_lock(&mu);
-	while(!exited && !threadstopped(t))
-		pthread_cond_wait(&cond, &mu);
-	pthread_mutex_unlock(&mu);
-	return 0;
-}
-
-int
-ctlproc(int id, char *msg)
-{
-	Thread *t;
-	int status;
-
-	// Hang/attached dance is for debugging newly exec'ed programs.
-	// After fork, the child does ctlproc("hang") before exec,
-	// and the parent does ctlproc("attached") and then waitstop.
-	// Using these requires the BSD ptrace interface, unlike everything
-	// else we do, which uses only the Mach interface.  Our goal here
-	// is to do as little as possible using ptrace and then flip over to Mach.
-
-	if(strcmp(msg, "hang") == 0)
-		return ptrace(PT_TRACE_ME, 0, 0, 0);
-
-	if(strcmp(msg, "attached") == 0){
-		// The pid "id" has done a ctlproc "hang" and then
-		// exec, so we should find it stoppped just before exec
-		// of the new program.
-		#undef waitpid
-		if(waitpid(id, &status, WUNTRACED) < 0){
-			fprint(2, "ctlproc attached waitpid: %r\n");
-			return -1;
-		}
-		if(WIFEXITED(status) || !WIFSTOPPED(status)){
-			fprint(2, "ctlproc attached: bad process state\n");
-			return -1;
-		}
-
-		// Find Mach thread for pid and suspend it.
-		t = addpid(id, 1);
-		if(t == nil) {
-			fprint(2, "ctlproc attached: addpid: %r\n");
-			return -1;
-		}
-		if(me(thread_suspend(t->thread)) < 0){
-			fprint(2, "ctlproc attached: thread_suspend: %r\n");
-			return -1;
-		}
-
-		// Let ptrace tell the process to keep going:
-		// then ptrace is out of the way and we're back in Mach land.
-		if(ptrace(PT_CONTINUE, id, (caddr_t)1, 0) < 0) {
-			fprint(2, "ctlproc attached: ptrace continue: %r\n");
-			return -1;
-		}
-		
-		return 0;
-	}
-
-	// All the other control messages require a Thread structure.
-	if((t = idtotable(id)) == nil){
-		werrstr("no such thread");
-		return -1;
-	}
-
-	if(strcmp(msg, "kill") == 0)
-		return ptrace(PT_KILL, t->pid, 0, 0);
-
-	if(strcmp(msg, "start") == 0)
-		return threadstart(t, 0);
-
-	if(strcmp(msg, "stop") == 0)
-		return threadstop(t);
-
-	if(strcmp(msg, "startstop") == 0){
-		if(threadstart(t, 0) < 0)
-			return -1;
-		return waitstop(t);
-	}
-
-	if(strcmp(msg, "step") == 0){
-		if(threadstart(t, 1) < 0)
-			return -1;
-		return waitstop(t);
-	}
-
-	if(strcmp(msg, "waitstop") == 0)
-		return waitstop(t);
-
-	// sysstop not available on OS X
-
-	werrstr("unknown control message");
-	return -1;
-}
-
-char*
-procstatus(int id)
-{
-	Thread *t;
-
-	if((t = idtotable(id)) == nil)
-		return "gone!";
-
-	if(threadstopped(t))
-		return "Stopped";
-
-	return "Running";
-}
-
diff --git a/src/libmach/dragonfly.c b/src/libmach/dragonfly.c
deleted file mode 100644
index 43dd005..0000000
--- a/src/libmach/dragonfly.c
+++ /dev/null
@@ -1,62 +0,0 @@
-// This is stubbed out for the moment. Will revisit when the time comes.
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-int
-ctlproc(int pid, char *msg)
-{
-	USED(pid);
-	USED(msg);
-
-	sysfatal("ctlproc unimplemented in DragonFly");
-	return -1;
-}
-
-char*
-proctextfile(int pid)
-{
-	USED(pid);
-	
-	sysfatal("proctextfile unimplemented in DragonFly");
-	return nil;
-}
-
-char*
-procstatus(int pid)
-{
-	USED(pid);
-
-	sysfatal("procstatus unimplemented in DragonFly");
-	return nil;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
-	USED(pid);
-	USED(fp);
-
-	sysfatal("attachproc unimplemented in DragonFly");
-	return nil;
-}
-
-void
-detachproc(Map *m)
-{
-	USED(m);
-
-	sysfatal("detachproc unimplemented in DragonFly");
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
-	USED(pid);
-	USED(p);
-	USED(np);
-
-	sysfatal("procthreadpids unimplemented in DragonFly");
-	return -1;
-}
diff --git a/src/libmach/elf.h b/src/libmach/elf.h
deleted file mode 100644
index 8dbc983..0000000
--- a/src/libmach/elf.h
+++ /dev/null
@@ -1,182 +0,0 @@
-// Inferno libmach/elf.h
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/elf.h
-//
-// 	Copyright © 1994-1999 Lucent Technologies Inc.
-// 	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth at 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.
-
-/*
- *	Definitions needed for  accessing ELF headers.
- *	32-bit and 64-bit structs differ.
- */
-typedef struct {
-	uchar	ident[16];	/* ident bytes */
-	ushort	type;		/* file type */
-	ushort	machine;	/* target machine */
-	int	version;	/* file version */
-	uint32	elfentry;	/* start address */
-	uint32	phoff;		/* phdr file offset */
-	uint32	shoff;		/* shdr file offset */
-	int	flags;		/* file flags */
-	ushort	ehsize;		/* sizeof ehdr */
-	ushort	phentsize;	/* sizeof phdr */
-	ushort	phnum;		/* number phdrs */
-	ushort	shentsize;	/* sizeof shdr */
-	ushort	shnum;		/* number shdrs */
-	ushort	shstrndx;	/* shdr string index */
-} Ehdr32;
-
-typedef struct {
-	uchar	ident[16];	/* ident bytes */
-	ushort	type;		/* file type */
-	ushort	machine;	/* target machine */
-	int	version;	/* file version */
-	uvlong	elfentry;	/* start address */
-	uvlong	phoff;		/* phdr file offset */
-	uvlong	shoff;		/* shdr file offset */
-	int	flags;		/* file flags */
-	ushort	ehsize;		/* sizeof ehdr */
-	ushort	phentsize;	/* sizeof phdr */
-	ushort	phnum;		/* number phdrs */
-	ushort	shentsize;	/* sizeof shdr */
-	ushort	shnum;		/* number shdrs */
-	ushort	shstrndx;	/* shdr string index */
-} Ehdr64;
-
-typedef struct {
-	int	type;		/* entry type */
-	uint32	offset;		/* file offset */
-	uint32	vaddr;		/* virtual address */
-	uint32	paddr;		/* physical address */
-	int	filesz;		/* file size */
-	uint32	memsz;		/* memory size */
-	int	flags;		/* entry flags */
-	int	align;		/* memory/file alignment */
-} Phdr32;
-
-typedef struct {
-	int	type;		/* entry type */
-	int	flags;		/* entry flags */
-	uvlong	offset;		/* file offset */
-	uvlong	vaddr;		/* virtual address */
-	uvlong	paddr;		/* physical address */
-	uvlong	filesz;		/* file size */
-	uvlong	memsz;		/* memory size */
-	uvlong	align;		/* memory/file alignment */
-} Phdr64;
-
-typedef struct {
-	uint32	name;		/* section name */
-	uint32	type;		/* SHT_... */
-	uint32	flags;		/* SHF_... */
-	uint32	addr;		/* virtual address */
-	uint32	offset;		/* file offset */
-	uint32	size;		/* section size */
-	uint32	link;		/* misc info */
-	uint32	info;		/* misc info */
-	uint32	addralign;	/* memory alignment */
-	uint32	entsize;	/* entry size if table */
-} Shdr32;
-
-typedef struct {
-	uint32	name;		/* section name */
-	uint32	type;		/* SHT_... */
-	uvlong	flags;		/* SHF_... */
-	uvlong	addr;		/* virtual address */
-	uvlong	offset;		/* file offset */
-	uvlong	size;		/* section size */
-	uint32	link;		/* misc info */
-	uint32	info;		/* misc info */
-	uvlong	addralign;	/* memory alignment */
-	uvlong	entsize;	/* entry size if table */
-} Shdr64;
-
-enum {
-	/* Ehdr codes */
-	MAG0 = 0,		/* ident[] indexes */
-	MAG1 = 1,
-	MAG2 = 2,
-	MAG3 = 3,
-	CLASS = 4,
-	DATA = 5,
-	VERSION = 6,
-
-	ELFCLASSNONE = 0,	/* ident[CLASS] */
-	ELFCLASS32 = 1,
-	ELFCLASS64 = 2,
-	ELFCLASSNUM = 3,
-
-	ELFDATANONE = 0,	/* ident[DATA] */
-	ELFDATA2LSB = 1,
-	ELFDATA2MSB = 2,
-	ELFDATANUM = 3,
-
-	NOETYPE = 0,		/* type */
-	REL = 1,
-	EXEC = 2,
-	DYN = 3,
-	CORE = 4,
-
-	NONE = 0,		/* machine */
-	M32 = 1,		/* AT&T WE 32100 */
-	SPARC = 2,		/* Sun SPARC */
-	I386 = 3,		/* Intel 80386 */
-	M68K = 4,		/* Motorola 68000 */
-	M88K = 5,		/* Motorola 88000 */
-	I486 = 6,		/* Intel 80486 */
-	I860 = 7,		/* Intel i860 */
-	MIPS = 8,		/* Mips R2000 */
-	S370 = 9,		/* Amdhal	*/
-	SPARC64 = 18,		/* Sun SPARC v9 */
-	POWER = 20,		/* PowerPC */
-	ARM = 40,			/* ARM */
-	AMD64 = 62,		/* Amd64 */
-
-	NO_VERSION = 0,		/* version, ident[VERSION] */
-	CURRENT = 1,
-
-	/* Phdr Codes */
-	NOPTYPE = 0,		/* type */
-	LOAD = 1,
-	DYNAMIC = 2,
-	INTERP = 3,
-	NOTE = 4,
-	SHLIB = 5,
-	PHDR = 6,
-
-	R = 0x4,		/* flags */
-	W = 0x2,
-	X = 0x1,
-
-	/* Shdr Codes */
-	Progbits = 1,	/* section types */
-	Strtab = 3,
-	Nobits = 8,
-
-	Swrite = 1,	/* section attributes */
-	Salloc = 2,
-	Sexec = 4,
-};
-
-#define	ELF_MAG		((0x7f<<24) | ('E'<<16) | ('L'<<8) | 'F')
diff --git a/src/libmach/executable.c b/src/libmach/executable.c
deleted file mode 100644
index eae1444..0000000
--- a/src/libmach/executable.c
+++ /dev/null
@@ -1,1525 +0,0 @@
-// Inferno libmach/executable.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/executable.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.
-//	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth at 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.
-
-#include	<u.h>
-#include	<libc.h>
-#include	<bio.h>
-#include	<bootexec.h>
-#include	<mach.h>
-#include	"elf.h"
-#include	"macho.h"
-
-/*
- *	All a.out header types.  The dummy entry allows canonical
- *	processing of the union as a sequence of int32s
- */
-
-typedef struct {
-	union{
-		/*struct { */
-			Exec exechdr;		/* a.out.h */
-		/*	uvlong hdr[1];*/
-		/*};*/
-		Ehdr32 elfhdr32;			/* elf.h */
-		Ehdr64 elfhdr64;			/* elf.h */
-		struct mipsexec mips;	/* bootexec.h */
-		struct mips4kexec mipsk4;	/* bootexec.h */
-		struct sparcexec sparc;	/* bootexec.h */
-		struct nextexec next;	/* bootexec.h */
-		Machhdr machhdr;	/* macho.h */
-	} e;
-	int32 dummy;			/* padding to ensure extra int32 */
-} ExecHdr;
-
-static	int	nextboot(int, Fhdr*, ExecHdr*);
-static	int	sparcboot(int, Fhdr*, ExecHdr*);
-static	int	mipsboot(int, Fhdr*, ExecHdr*);
-static	int	mips4kboot(int, Fhdr*, ExecHdr*);
-static	int	common(int, Fhdr*, ExecHdr*);
-static	int	commonllp64(int, Fhdr*, ExecHdr*);
-static	int	adotout(int, Fhdr*, ExecHdr*);
-static	int	elfdotout(int, Fhdr*, ExecHdr*);
-static	int	machdotout(int, Fhdr*, ExecHdr*);
-static	int	armdotout(int, Fhdr*, ExecHdr*);
-static	int	pedotout(int, Fhdr*, ExecHdr*);
-static	void	setsym(Fhdr*, vlong, int32, vlong, int32, vlong, int32);
-static	void	setdata(Fhdr*, uvlong, int32, vlong, int32);
-static	void	settext(Fhdr*, uvlong, uvlong, int32, vlong);
-static	void	hswal(void*, int, uint32(*)(uint32));
-static	uvlong	_round(uvlong, uint32);
-
-/*
- *	definition of per-executable file type structures
- */
-
-typedef struct Exectable{
-	int32	magic;			/* big-endian magic number of file */
-	char	*name;			/* executable identifier */
-	char	*dlmname;		/* dynamically loadable module identifier */
-	uchar	type;			/* Internal code */
-	uchar	_magic;			/* _MAGIC() magic */
-	Mach	*mach;			/* Per-machine data */
-	int32	hsize;			/* header size */
-	uint32	(*swal)(uint32);		/* beswal or leswal */
-	int	(*hparse)(int, Fhdr*, ExecHdr*);
-} ExecTable;
-
-extern	Mach	mmips;
-extern	Mach	mmips2le;
-extern	Mach	mmips2be;
-extern	Mach	msparc;
-extern	Mach	msparc64;
-extern	Mach	m68020;
-extern	Mach	mi386;
-extern	Mach	mamd64;
-extern	Mach	marm;
-extern	Mach	mpower;
-extern	Mach	mpower64;
-extern	Mach	malpha;
-
-/* BUG: FIX THESE WHEN NEEDED */
-Mach	mmips;
-Mach	mmips2le;
-Mach	mmips2be;
-Mach	msparc;
-Mach	msparc64;
-Mach	m68020;
-Mach	mpower;
-Mach	mpower64;
-Mach	malpha;
-
-ExecTable exectab[] =
-{
-	{ V_MAGIC,			/* Mips v.out */
-		"mips plan 9 executable BE",
-		"mips plan 9 dlm BE",
-		FMIPS,
-		1,
-		&mmips,
-		sizeof(Exec),
-		beswal,
-		adotout },
-	{ P_MAGIC,			/* Mips 0.out (r3k le) */
-		"mips plan 9 executable LE",
-		"mips plan 9 dlm LE",
-		FMIPSLE,
-		1,
-		&mmips,
-		sizeof(Exec),
-		beswal,
-		adotout },
-	{ M_MAGIC,			/* Mips 4.out */
-		"mips 4k plan 9 executable BE",
-		"mips 4k plan 9 dlm BE",
-		FMIPS2BE,
-		1,
-		&mmips2be,
-		sizeof(Exec),
-		beswal,
-		adotout },
-	{ N_MAGIC,			/* Mips 0.out */
-		"mips 4k plan 9 executable LE",
-		"mips 4k plan 9 dlm LE",
-		FMIPS2LE,
-		1,
-		&mmips2le,
-		sizeof(Exec),
-		beswal,
-		adotout },
-	{ 0x160<<16,			/* Mips boot image */
-		"mips plan 9 boot image",
-		nil,
-		FMIPSB,
-		0,
-		&mmips,
-		sizeof(struct mipsexec),
-		beswal,
-		mipsboot },
-	{ (0x160<<16)|3,		/* Mips boot image */
-		"mips 4k plan 9 boot image",
-		nil,
-		FMIPSB,
-		0,
-		&mmips2be,
-		sizeof(struct mips4kexec),
-		beswal,
-		mips4kboot },
-	{ K_MAGIC,			/* Sparc k.out */
-		"sparc plan 9 executable",
-		"sparc plan 9 dlm",
-		FSPARC,
-		1,
-		&msparc,
-		sizeof(Exec),
-		beswal,
-		adotout },
-	{ 0x01030107, 			/* Sparc boot image */
-		"sparc plan 9 boot image",
-		nil,
-		FSPARCB,
-		0,
-		&msparc,
-		sizeof(struct sparcexec),
-		beswal,
-		sparcboot },
-	{ U_MAGIC,			/* Sparc64 u.out */
-		"sparc64 plan 9 executable",
-		"sparc64 plan 9 dlm",
-		FSPARC64,
-		1,
-		&msparc64,
-		sizeof(Exec),
-		beswal,
-		adotout },
-	{ A_MAGIC,			/* 68020 2.out & boot image */
-		"68020 plan 9 executable",
-		"68020 plan 9 dlm",
-		F68020,
-		1,
-		&m68020,
-		sizeof(Exec),
-		beswal,
-		common },
-	{ 0xFEEDFACE,			/* Next boot image */
-		"next plan 9 boot image",
-		nil,
-		FNEXTB,
-		0,
-		&m68020,
-		sizeof(struct nextexec),
-		beswal,
-		nextboot },
-	{ I_MAGIC,			/* I386 8.out & boot image */
-		"386 plan 9 executable",
-		"386 plan 9 dlm",
-		FI386,
-		1,
-		&mi386,
-		sizeof(Exec),
-		beswal,
-		common },
-	{ S_MAGIC,			/* amd64 6.out & boot image */
-		"amd64 plan 9 executable",
-		"amd64 plan 9 dlm",
-		FAMD64,
-		1,
-		&mamd64,
-		sizeof(Exec)+8,
-		nil,
-		commonllp64 },
-	{ Q_MAGIC,			/* PowerPC q.out & boot image */
-		"power plan 9 executable",
-		"power plan 9 dlm",
-		FPOWER,
-		1,
-		&mpower,
-		sizeof(Exec),
-		beswal,
-		common },
-	{ T_MAGIC,			/* power64 9.out & boot image */
-		"power64 plan 9 executable",
-		"power64 plan 9 dlm",
-		FPOWER64,
-		1,
-		&mpower64,
-		sizeof(Exec)+8,
-		nil,
-		commonllp64 },
-	{ ELF_MAG,			/* any elf32 or elf64 */
-		"elf executable",
-		nil,
-		FNONE,
-		0,
-		&mi386,
-		sizeof(Ehdr64),
-		nil,
-		elfdotout },
-	{ MACH64_MAG,			/* 64-bit MACH (apple mac) */
-		"mach executable",
-		nil,
-		FAMD64,
-		0,
-		&mamd64,
-		sizeof(Machhdr),
-		nil,
-		machdotout },
-	{ MACH32_MAG,			/* 32-bit MACH (apple mac) */
-		"mach executable",
-		nil,
-		FI386,
-		0,
-		&mi386,
-		sizeof(Machhdr),
-		nil,
-		machdotout },
-	{ E_MAGIC,			/* Arm 5.out and boot image */
-		"arm plan 9 executable",
-		"arm plan 9 dlm",
-		FARM,
-		1,
-		&marm,
-		sizeof(Exec),
-		beswal,
-		common },
-	{ (143<<16)|0413,		/* (Free|Net)BSD Arm */
-		"arm *bsd executable",
-		nil,
-		FARM,
-		0,
-		&marm,
-		sizeof(Exec),
-		leswal,
-		armdotout },
-	{ L_MAGIC,			/* alpha 7.out */
-		"alpha plan 9 executable",
-		"alpha plan 9 dlm",
-		FALPHA,
-		1,
-		&malpha,
-		sizeof(Exec),
-		beswal,
-		common },
-	{ 0x0700e0c3,			/* alpha boot image */
-		"alpha plan 9 boot image",
-		nil,
-		FALPHA,
-		0,
-		&malpha,
-		sizeof(Exec),
-		beswal,
-		common },
-	{ 0x4d5a9000,    /* see dosstub[] in pe.c */
-		"windows PE executable",
-		nil,
-		FWINPE,
-		0,
-		&mi386,
-		sizeof(Exec), /* TODO */
-		nil,
-		pedotout },
-	{ 0 },
-};
-
-Mach	*mach = &mi386;			/* Global current machine table */
-
-static ExecTable*
-couldbe4k(ExecTable *mp)
-{
-	Dir *d;
-	ExecTable *f;
-
-	if((d=dirstat("/proc/1/regs")) == nil)
-		return mp;
-	if(d->length < 32*8){		/* R3000 */
-		free(d);
-		return mp;
-	}
-	free(d);
-	for (f = exectab; f->magic; f++)
-		if(f->magic == M_MAGIC) {
-			f->name = "mips plan 9 executable on mips2 kernel";
-			return f;
-		}
-	return mp;
-}
-
-int
-crackhdr(int fd, Fhdr *fp)
-{
-	ExecTable *mp;
-	ExecHdr d;
-	int nb, ret;
-	uint32 magic;
-
-	fp->type = FNONE;
-	nb = read(fd, (char *)&d.e, sizeof(d.e));
-	if (nb <= 0)
-		return 0;
-
-	ret = 0;
-	magic = beswal(d.e.exechdr.magic);		/* big-endian */
-	for (mp = exectab; mp->magic; mp++) {
-		if (nb < mp->hsize)
-			continue;
-
-		/*
-		 * The magic number has morphed into something
-		 * with fields (the straw was DYN_MAGIC) so now
-		 * a flag is needed in Fhdr to distinguish _MAGIC()
-		 * magic numbers from foreign magic numbers.
-		 *
-		 * This code is creaking a bit and if it has to
-		 * be modified/extended much more it's probably
-		 * time to step back and redo it all.
-		 */
-		if(mp->_magic){
-			if(mp->magic != (magic & ~DYN_MAGIC))
-				continue;
-
-			if(mp->magic == V_MAGIC)
-				mp = couldbe4k(mp);
-
-			if ((magic & DYN_MAGIC) && mp->dlmname != nil)
-				fp->name = mp->dlmname;
-			else
-				fp->name = mp->name;
-		}
-		else{
-			if(mp->magic != magic)
-				continue;
-			fp->name = mp->name;
-		}
-		fp->type = mp->type;
-		fp->hdrsz = mp->hsize;		/* will be zero on bootables */
-		fp->_magic = mp->_magic;
-		fp->magic = magic;
-
-		mach = mp->mach;
-		if(mp->swal != nil)
-			hswal(&d, sizeof(d.e)/sizeof(uint32), mp->swal);
-		ret = mp->hparse(fd, fp, &d);
-		seek(fd, mp->hsize, 0);		/* seek to end of header */
-		break;
-	}
-	if(mp->magic == 0)
-		werrstr("unknown header type");
-	return ret;
-}
-
-/*
- * Convert header to canonical form
- */
-static void
-hswal(void *v, int n, uint32 (*swap)(uint32))
-{
-	uint32 *ulp;
-
-	for(ulp = v; n--; ulp++)
-		*ulp = (*swap)(*ulp);
-}
-
-/*
- *	Crack a normal a.out-type header
- */
-static int
-adotout(int fd, Fhdr *fp, ExecHdr *hp)
-{
-	int32 pgsize;
-
-	USED(fd);
-	pgsize = mach->pgsize;
-	settext(fp, hp->e.exechdr.entry, pgsize+sizeof(Exec),
-			hp->e.exechdr.text, sizeof(Exec));
-	setdata(fp, _round(pgsize+fp->txtsz+sizeof(Exec), pgsize),
-		hp->e.exechdr.data, fp->txtsz+sizeof(Exec), hp->e.exechdr.bss);
-	setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
-	return 1;
-}
-
-static void
-commonboot(Fhdr *fp)
-{
-	if (!(fp->entry & mach->ktmask))
-		return;
-
-	switch(fp->type) {				/* boot image */
-	case F68020:
-		fp->type = F68020B;
-		fp->name = "68020 plan 9 boot image";
-		break;
-	case FI386:
-		fp->type = FI386B;
-		fp->txtaddr = (u32int)fp->entry;
-		fp->name = "386 plan 9 boot image";
-		fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
-		break;
-	case FARM:
-		fp->type = FARMB;
-		fp->txtaddr = (u32int)fp->entry;
-		fp->name = "ARM plan 9 boot image";
-		fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
-		return;
-	case FALPHA:
-		fp->type = FALPHAB;
-		fp->txtaddr = (u32int)fp->entry;
-		fp->name = "alpha plan 9 boot image";
-		fp->dataddr = fp->txtaddr+fp->txtsz;
-		break;
-	case FPOWER:
-		fp->type = FPOWERB;
-		fp->txtaddr = (u32int)fp->entry;
-		fp->name = "power plan 9 boot image";
-		fp->dataddr = fp->txtaddr+fp->txtsz;
-		break;
-	case FAMD64:
-		fp->type = FAMD64B;
-		fp->txtaddr = fp->entry;
-		fp->name = "amd64 plan 9 boot image";
-		fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
-		break;
-	default:
-		return;
-	}
-	fp->hdrsz = 0;			/* header stripped */
-}
-
-/*
- *	_MAGIC() style headers and
- *	alpha plan9-style bootable images for axp "headerless" boot
- *
- */
-static int
-common(int fd, Fhdr *fp, ExecHdr *hp)
-{
-	adotout(fd, fp, hp);
-	if(hp->e.exechdr.magic & DYN_MAGIC) {
-		fp->txtaddr = 0;
-		fp->dataddr = fp->txtsz;
-		return 1;
-	}
-	commonboot(fp);
-	return 1;
-}
-
-static int
-commonllp64(int unused, Fhdr *fp, ExecHdr *hp)
-{
-	int32 pgsize;
-	uvlong entry;
-
-	USED(unused);
-
-	hswal(&hp->e, sizeof(Exec)/sizeof(int32), beswal);
-	if(!(hp->e.exechdr.magic & HDR_MAGIC))
-		return 0;
-
-	/*
-	 * There can be more magic here if the
-	 * header ever needs more expansion.
-	 * For now just catch use of any of the
-	 * unused bits.
-	 */
-	if((hp->e.exechdr.magic & ~DYN_MAGIC)>>16)
-		return 0;
-	union {
-		char *p;
-		uvlong *v;
-	} u;
-	u.p = (char*)&hp->e.exechdr;
-	entry = beswav(*u.v);
-
-	pgsize = mach->pgsize;
-	settext(fp, entry, pgsize+fp->hdrsz, hp->e.exechdr.text, fp->hdrsz);
-	setdata(fp, _round(pgsize+fp->txtsz+fp->hdrsz, pgsize),
-		hp->e.exechdr.data, fp->txtsz+fp->hdrsz, hp->e.exechdr.bss);
-	setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
-
-	if(hp->e.exechdr.magic & DYN_MAGIC) {
-		fp->txtaddr = 0;
-		fp->dataddr = fp->txtsz;
-		return 1;
-	}
-	commonboot(fp);
-	return 1;
-}
-
-/*
- *	mips bootable image.
- */
-static int
-mipsboot(int fd, Fhdr *fp, ExecHdr *hp)
-{
-	USED(fd);
-	USED(fp);
-	USED(hp);
-
-abort();
-#ifdef unused
-	USED(fd);
-	fp->type = FMIPSB;
-	switch(hp->e.exechdr.amagic) {
-	default:
-	case 0407:	/* some kind of mips */
-		settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start,
-			hp->e.tsize, sizeof(struct mipsexec)+4);
-		setdata(fp, (u32int)hp->e.data_start, hp->e.dsize,
-			fp->txtoff+hp->e.tsize, hp->e.bsize);
-		break;
-	case 0413:	/* some kind of mips */
-		settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start,
-			hp->e.tsize, 0);
-		setdata(fp, (u32int)hp->e.data_start, hp->e.dsize,
-			hp->e.tsize, hp->e.bsize);
-		break;
-	}
-	setsym(fp, hp->e.nsyms, 0, hp->e.pcsize, hp->e.symptr);
-	fp->hdrsz = 0;			/* header stripped */
-#endif
-	return 1;
-}
-
-/*
- *	mips4k bootable image.
- */
-static int
-mips4kboot(int fd, Fhdr *fp, ExecHdr *hp)
-{
-	USED(fd);
-	USED(fp);
-	USED(hp);
-
-abort();
-#ifdef unused
-	USED(fd);
-	fp->type = FMIPSB;
-	switch(hp->e.h.amagic) {
-	default:
-	case 0407:	/* some kind of mips */
-		settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start,
-			hp->e.h.tsize, sizeof(struct mips4kexec));
-		setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize,
-			fp->txtoff+hp->e.h.tsize, hp->e.h.bsize);
-		break;
-	case 0413:	/* some kind of mips */
-		settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start,
-			hp->e.h.tsize, 0);
-		setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize,
-			hp->e.h.tsize, hp->e.h.bsize);
-		break;
-	}
-	setsym(fp, hp->e.h.nsyms, 0, hp->e.h.pcsize, hp->e.h.symptr);
-	fp->hdrsz = 0;			/* header stripped */
-#endif
-	return 1;
-}
-
-/*
- *	sparc bootable image
- */
-static int
-sparcboot(int fd, Fhdr *fp, ExecHdr *hp)
-{
-	USED(fd);
-	USED(fp);
-	USED(hp);
-
-abort();
-#ifdef unused
-	USED(fd);
-	fp->type = FSPARCB;
-	settext(fp, hp->e.sentry, hp->e.sentry, hp->e.stext,
-		sizeof(struct sparcexec));
-	setdata(fp, hp->e.sentry+hp->e.stext, hp->e.sdata,
-		fp->txtoff+hp->e.stext, hp->e.sbss);
-	setsym(fp, hp->e.ssyms, 0, hp->e.sdrsize, fp->datoff+hp->e.sdata);
-	fp->hdrsz = 0;			/* header stripped */
-#endif
-	return 1;
-}
-
-/*
- *	next bootable image
- */
-static int
-nextboot(int fd, Fhdr *fp, ExecHdr *hp)
-{
-	USED(fd);
-	USED(fp);
-	USED(hp);
-
-abort();
-#ifdef unused
-	USED(fd);
-	fp->type = FNEXTB;
-	settext(fp, hp->e.textc.vmaddr, hp->e.textc.vmaddr,
-		hp->e.texts.size, hp->e.texts.offset);
-	setdata(fp, hp->e.datac.vmaddr, hp->e.datas.size,
-		hp->e.datas.offset, hp->e.bsss.size);
-	setsym(fp, hp->e.symc.nsyms, hp->e.symc.spoff, hp->e.symc.pcoff,
-		hp->e.symc.symoff);
-	fp->hdrsz = 0;			/* header stripped */
-#endif
-	return 1;
-}
-
-/*
- * Elf32 and Elf64 binaries.
- */
-static int
-elf64dotout(int fd, Fhdr *fp, ExecHdr *hp)
-{
-	uvlong (*swav)(uvlong);
-	uint32 (*swal)(uint32);
-	ushort (*swab)(ushort);
-	Ehdr64 *ep;
-	Phdr64 *ph, *pph;
-	Shdr64 *sh;
-	int i, it, id, is, phsz, shsz;
-
-	/* bitswap the header according to the DATA format */
-	ep = &hp->e.elfhdr64;
-	if(ep->ident[CLASS] != ELFCLASS64) {
-		werrstr("bad ELF class - not 32 bit or 64 bit");
-		return 0;
-	}
-	if(ep->ident[DATA] == ELFDATA2LSB) {
-		swab = leswab;
-		swal = leswal;
-		swav = leswav;
-	} else if(ep->ident[DATA] == ELFDATA2MSB) {
-		swab = beswab;
-		swal = beswal;
-		swav = beswav;
-	} else {
-		werrstr("bad ELF encoding - not big or little endian");
-		return 0;
-	}
-
-	ep->type = swab(ep->type);
-	ep->machine = swab(ep->machine);
-	ep->version = swal(ep->version);
-	ep->elfentry = swal(ep->elfentry);
-	ep->phoff = swav(ep->phoff);
-	ep->shoff = swav(ep->shoff);
-	ep->flags = swav(ep->flags);
-	ep->ehsize = swab(ep->ehsize);
-	ep->phentsize = swab(ep->phentsize);
-	ep->phnum = swab(ep->phnum);
-	ep->shentsize = swab(ep->shentsize);
-	ep->shnum = swab(ep->shnum);
-	ep->shstrndx = swab(ep->shstrndx);
-	if(ep->type != EXEC || ep->version != CURRENT)
-		return 0;
-
-	/* we could definitely support a lot more machines here */
-	fp->magic = ELF_MAG;
-	fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
-	switch(ep->machine) {
-	case AMD64:
-		mach = &mamd64;
-		fp->type = FAMD64;
-		break;
-	default:
-		return 0;
-	}
-
-	if(ep->phentsize != sizeof(Phdr64)) {
-		werrstr("bad ELF header size");
-		return 0;
-	}
-	phsz = sizeof(Phdr64)*ep->phnum;
-	ph = malloc(phsz);
-	if(!ph)
-		return 0;
-	seek(fd, ep->phoff, 0);
-	if(read(fd, ph, phsz) < 0) {
-		free(ph);
-		return 0;
-	}
-	hswal(ph, phsz/sizeof(uint32), swal);
-
-	shsz = sizeof(Shdr64)*ep->shnum;
-	sh = malloc(shsz);
-	if(sh) {
-		seek(fd, ep->shoff, 0);
-		if(read(fd, sh, shsz) < 0) {
-			free(sh);
-			sh = 0;
-		} else
-			hswal(sh, shsz/sizeof(uint32), swal);
-	}
-
-	/* find text, data and symbols and install them */
-	it = id = is = -1;
-	for(i = 0; i < ep->phnum; i++) {
-		if(ph[i].type == LOAD
-		&& (ph[i].flags & (R|X)) == (R|X) && it == -1)
-			it = i;
-		else if(ph[i].type == LOAD
-		&& (ph[i].flags & (R|W)) == (R|W) && id == -1)
-			id = i;
-		else if(ph[i].type == NOPTYPE && is == -1)
-			is = i;
-	}
-	if(it == -1 || id == -1) {
-		/*
-		 * The SPARC64 boot image is something of an ELF hack.
-		 * Text+Data+BSS are represented by ph[0].  Symbols
-		 * are represented by ph[1]:
-		 *
-		 *		filesz, memsz, vaddr, paddr, off
-		 * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff
-		 * ph[1] : symsz, lcsz, 0, 0, symoff
-		 */
-		if(ep->machine == SPARC64 && ep->phnum == 2) {
-			uint32 txtaddr, txtsz, dataddr, bsssz;
-
-			txtaddr = ph[0].vaddr | 0x80000000;
-			txtsz = ph[0].filesz - ph[0].paddr;
-			dataddr = txtaddr + txtsz;
-			bsssz = ph[0].memsz - ph[0].filesz;
-			settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset);
-			setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz);
-			setsym(fp, ph[1].offset, ph[1].filesz, 0, 0, 0, ph[1].memsz);
-			free(ph);
-			return 1;
-		}
-
-		werrstr("No TEXT or DATA sections");
-		free(ph);
-		free(sh);
-		return 0;
-	}
-
-	settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset);
-	pph = ph + id;
-	setdata(fp, pph->vaddr, pph->filesz, pph->offset, pph->memsz - pph->filesz);
-	if(is != -1)
-		setsym(fp, ph[is].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz);
-	else if(sh != 0){
-		char *buf;
-		uvlong symsize = 0;
-		uvlong symoff = 0;
-		uvlong pclnsz = 0;
-		uvlong pclnoff = 0;
-
-		/* load shstrtab names */
-		buf = malloc(sh[ep->shstrndx].size);
-		if (buf == 0)
-			goto done;
-		memset(buf, 0, sh[ep->shstrndx].size);
-		seek(fd, sh[ep->shstrndx].offset, 0);
-		i = read(fd, buf, sh[ep->shstrndx].size);
-		USED(i);	// shut up ubuntu gcc
-
-		for(i = 0; i < ep->shnum; i++) {
-			if (strcmp(&buf[sh[i].name], ".gosymtab") == 0) {
-				symsize = sh[i].size;
-				symoff = sh[i].offset;
-			}
-			if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) {
-				pclnsz = sh[i].size;
-				pclnoff = sh[i].offset;
-			}
-		}
-		setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsz);
-		free(buf);
-	}
-done:
-	free(ph);
-	free(sh);
-	return 1;
-}
-
-static int
-elfdotout(int fd, Fhdr *fp, ExecHdr *hp)
-{
-
-	uint32 (*swal)(uint32);
-	ushort (*swab)(ushort);
-	Ehdr32 *ep;
-	Phdr32 *ph;
-	int i, it, id, is, phsz, shsz;
-	Shdr32 *sh;
-
-	/* bitswap the header according to the DATA format */
-	ep = &hp->e.elfhdr32;
-	if(ep->ident[CLASS] != ELFCLASS32) {
-		return elf64dotout(fd, fp, hp);
-	}
-	if(ep->ident[DATA] == ELFDATA2LSB) {
-		swab = leswab;
-		swal = leswal;
-	} else if(ep->ident[DATA] == ELFDATA2MSB) {
-		swab = beswab;
-		swal = beswal;
-	} else {
-		werrstr("bad ELF encoding - not big or little endian");
-		return 0;
-	}
-
-	ep->type = swab(ep->type);
-	ep->machine = swab(ep->machine);
-	ep->version = swal(ep->version);
-	ep->elfentry = swal(ep->elfentry);
-	ep->phoff = swal(ep->phoff);
-	ep->shoff = swal(ep->shoff);
-	ep->flags = swal(ep->flags);
-	ep->ehsize = swab(ep->ehsize);
-	ep->phentsize = swab(ep->phentsize);
-	ep->phnum = swab(ep->phnum);
-	ep->shentsize = swab(ep->shentsize);
-	ep->shnum = swab(ep->shnum);
-	ep->shstrndx = swab(ep->shstrndx);
-	if(ep->type != EXEC || ep->version != CURRENT)
-		return 0;
-
-	/* we could definitely support a lot more machines here */
-	fp->magic = ELF_MAG;
-	fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
-	switch(ep->machine) {
-	case I386:
-		mach = &mi386;
-		fp->type = FI386;
-		break;
-	case MIPS:
-		mach = &mmips;
-		fp->type = FMIPS;
-		break;
-	case SPARC64:
-		mach = &msparc64;
-		fp->type = FSPARC64;
-		break;
-	case POWER:
-		mach = &mpower;
-		fp->type = FPOWER;
-		break;
-	case ARM:
-		mach = &marm;
-		fp->type = FARM;
-		break;
-	default:
-		return 0;
-	}
-
-	if(ep->phentsize != sizeof(Phdr32)) {
-		werrstr("bad ELF header size");
-		return 0;
-	}
-	phsz = sizeof(Phdr32)*ep->phnum;
-	ph = malloc(phsz);
-	if(!ph)
-		return 0;
-	seek(fd, ep->phoff, 0);
-	if(read(fd, ph, phsz) < 0) {
-		free(ph);
-		return 0;
-	}
-	hswal(ph, phsz/sizeof(uint32), swal);
-
-	shsz = sizeof(Shdr32)*ep->shnum;
-	sh = malloc(shsz);
-	if(sh) {
-		seek(fd, ep->shoff, 0);
-		if(read(fd, sh, shsz) < 0) {
-			free(sh);
-			sh = 0;
-		} else
-			hswal(sh, shsz/sizeof(uint32), swal);
-	}
-
-	/* find text, data and symbols and install them */
-	it = id = is = -1;
-	for(i = 0; i < ep->phnum; i++) {
-		if(ph[i].type == LOAD
-		&& (ph[i].flags & (R|X)) == (R|X) && it == -1)
-			it = i;
-		else if(ph[i].type == LOAD
-		&& (ph[i].flags & (R|W)) == (R|W) && id == -1)
-			id = i;
-		else if(ph[i].type == NOPTYPE && is == -1)
-			is = i;
-	}
-	if(it == -1 || id == -1) {
-		/*
-		 * The SPARC64 boot image is something of an ELF hack.
-		 * Text+Data+BSS are represented by ph[0].  Symbols
-		 * are represented by ph[1]:
-		 *
-		 *		filesz, memsz, vaddr, paddr, off
-		 * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff
-		 * ph[1] : symsz, lcsz, 0, 0, symoff
-		 */
-		if(ep->machine == SPARC64 && ep->phnum == 2) {
-			uint32 txtaddr, txtsz, dataddr, bsssz;
-
-			txtaddr = ph[0].vaddr | 0x80000000;
-			txtsz = ph[0].filesz - ph[0].paddr;
-			dataddr = txtaddr + txtsz;
-			bsssz = ph[0].memsz - ph[0].filesz;
-			settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset);
-			setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz);
-			setsym(fp, ph[1].offset, ph[1].filesz, 0, 0, 0, ph[1].memsz);
-			free(ph);
-			return 1;
-		}
-
-		werrstr("No TEXT or DATA sections");
-		free(sh);
-		free(ph);
-		return 0;
-	}
-
-	settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset);
-	setdata(fp, ph[id].vaddr, ph[id].filesz, ph[id].offset, ph[id].memsz - ph[id].filesz);
-	if(is != -1)
-		setsym(fp, ph[is].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz);
-	else if(sh != 0){
-		char *buf;
-		uvlong symsize = 0;
-		uvlong symoff = 0;
-		uvlong pclnsize = 0;
-		uvlong pclnoff = 0;
-
-		/* load shstrtab names */
-		buf = malloc(sh[ep->shstrndx].size);
-		if (buf == 0)
-			goto done;
-		memset(buf, 0, sh[ep->shstrndx].size);
-		seek(fd, sh[ep->shstrndx].offset, 0);
-		i = read(fd, buf, sh[ep->shstrndx].size);
-		USED(i);	// shut up ubuntu gcc
-
-		for(i = 0; i < ep->shnum; i++) {
-			if (strcmp(&buf[sh[i].name], ".gosymtab") == 0) {
-				symsize = sh[i].size;
-				symoff = sh[i].offset;
-			}
-			if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) {
-				pclnsize = sh[i].size;
-				pclnoff = sh[i].offset;
-			}
-		}
-		setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsize);
-		free(buf);
-	}
-done:
-	free(sh);
-	free(ph);
-	return 1;
-}
-
-static int
-machdotout(int fd, Fhdr *fp, ExecHdr *hp)
-{
-	uvlong (*swav)(uvlong);
-	uint32 (*swal)(uint32);
-	Machhdr *mp;
-	MachCmd **cmd;
-	MachSymSeg *symtab;
-	MachSymSeg *pclntab;
-	MachSeg64 *seg;
-	MachSect64 *sect;
-	MachSeg32 *seg32;
-	MachSect32 *sect32;
-	uvlong textsize, datasize, bsssize;
-	uchar *cmdbuf;
-	uchar *cmdp;
-	int i, j, hdrsize;
-	uint32 textva, textoff, datava, dataoff, symoff, symsize, pclnoff, pclnsize;
-
-	mp = &hp->e.machhdr;
-	if (leswal(mp->filetype) != MACH_EXECUTABLE_TYPE) {
-		werrstr("bad MACH executable type %#ux", leswal(mp->filetype));
-		return 0;
-	}
-
-	swal = leswal;
-	swav = leswav;
-
-	mp->magic = swal(mp->magic);
-	mp->cputype = swal(mp->cputype);
-	mp->cpusubtype = swal(mp->cpusubtype);
-	mp->filetype = swal(mp->filetype);
-	mp->ncmds = swal(mp->ncmds);
-	mp->sizeofcmds = swal(mp->sizeofcmds);
-	mp->flags = swal(mp->flags);
-	mp->reserved = swal(mp->reserved);
-
-	switch(mp->magic) {
-	case 0xFEEDFACE:	// 32-bit mach
-		if (mp->cputype != MACH_CPU_TYPE_X86) {
-			werrstr("bad MACH cpu type - not 386");
-			return 0;
-		}
-		if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86) {
-			werrstr("bad MACH cpu subtype - not 386");
-			return 0;
-		}
-		if (mp->filetype != MACH_EXECUTABLE_TYPE) {
-			werrstr("bad MACH executable type");
-			return 0;
-		}
-		mach = &mi386;
-		fp->type = FI386;
-		hdrsize = 28;
-		break;
-
-	case 0xFEEDFACF:	// 64-bit mach
-		if (mp->cputype != MACH_CPU_TYPE_X86_64) {
-			werrstr("bad MACH cpu type - not amd64");
-			return 0;
-		}
-
-		if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86 && mp->cpusubtype != MACH_CPU_SUBTYPE_X86_64) {
-			werrstr("bad MACH cpu subtype - not amd64");
-			return 0;
-		}
-		mach = &mamd64;
-		fp->type = FAMD64;
-		hdrsize = 32;
-		break;
-
-	default:
-		werrstr("not mach %#ux", mp->magic);
-		return 0;
-	}
-
-	cmdbuf = malloc(mp->sizeofcmds);
-	if(!cmdbuf) {
-		werrstr("out of memory");
-		return 0;
-	}
-	seek(fd, hdrsize, 0);
-	if(read(fd, cmdbuf, mp->sizeofcmds) != mp->sizeofcmds) {
-		free(cmdbuf);
-		return 0;
-	}
-	cmd = malloc(mp->ncmds * sizeof(MachCmd*));
-	if(!cmd) {
-		free(cmdbuf);
-		werrstr("out of memory");
-		return 0;
-	}
-	cmdp = cmdbuf;
-	textva = 0;
-	textoff = 0;
-	dataoff = 0;
-	datava = 0;
-	symtab = 0;
-	pclntab = 0;
-	textsize = 0;
-	datasize = 0;
-	bsssize = 0;
-	symoff = 0;
-	symsize = 0;
-	pclnoff = 0;
-	pclnsize = 0;
-	for (i = 0; i < mp->ncmds; i++) {
-		MachCmd *c;
-
-		cmd[i] = (MachCmd*)cmdp;
-		c = cmd[i];
-		c->type = swal(c->type);
-		c->size = swal(c->size);
-		switch(c->type) {
-		case MACH_SEGMENT_32:
-			if(mp->magic != 0xFEEDFACE) {
-				werrstr("segment 32 in mach 64");
-				goto bad;
-			}
-			seg32 = (MachSeg32*)c;
-			seg32->vmaddr = swav(seg32->vmaddr);
-			seg32->vmsize = swav(seg32->vmsize);
-			seg32->fileoff = swav(seg32->fileoff);
-			seg32->filesize = swav(seg32->filesize);
-			seg32->maxprot = swal(seg32->maxprot);
-			seg32->initprot = swal(seg32->initprot);
-			seg32->nsects = swal(seg32->nsects);
-			seg32->flags = swal(seg32->flags);
-			if (strcmp(seg32->segname, "__TEXT") == 0) {
-				textva = seg32->vmaddr;
-				textoff = seg32->fileoff;
-				textsize = seg32->vmsize;
-				sect32 = (MachSect32*)(cmdp + sizeof(MachSeg32));
-				for(j = 0; j < seg32->nsects; j++, sect32++) {
-					if (strcmp(sect32->sectname, "__gosymtab") == 0) {
-						symoff = swal(sect32->offset);
-						symsize = swal(sect32->size);
-					}
-					if (strcmp(sect32->sectname, "__gopclntab") == 0) {
-						pclnoff = swal(sect32->offset);
-						pclnsize = swal(sect32->size);
-					}
-				}
-			}
-			if (strcmp(seg32->segname, "__DATA") == 0) {
-				datava = seg32->vmaddr;
-				dataoff = seg32->fileoff;
-				datasize = seg32->filesize;
-				bsssize = seg32->vmsize - seg32->filesize;
-			}
-			break;
-
-		case MACH_SEGMENT_64:
-			if(mp->magic != 0xFEEDFACF) {
-				werrstr("segment 32 in mach 64");
-				goto bad;
-			}
-			seg = (MachSeg64*)c;
-			seg->vmaddr = swav(seg->vmaddr);
-			seg->vmsize = swav(seg->vmsize);
-			seg->fileoff = swav(seg->fileoff);
-			seg->filesize = swav(seg->filesize);
-			seg->maxprot = swal(seg->maxprot);
-			seg->initprot = swal(seg->initprot);
-			seg->nsects = swal(seg->nsects);
-			seg->flags = swal(seg->flags);
-			if (strcmp(seg->segname, "__TEXT") == 0) {
-				textva = seg->vmaddr;
-				textoff = seg->fileoff;
-				textsize = seg->vmsize;
-				sect = (MachSect64*)(cmdp + sizeof(MachSeg64));
-				for(j = 0; j < seg->nsects; j++, sect++) {
-					if (strcmp(sect->sectname, "__gosymtab") == 0) {
-						symoff = swal(sect->offset);
-						symsize = swal(sect->size);
-					}
-					if (strcmp(sect->sectname, "__gopclntab") == 0) {
-						pclnoff = swal(sect->offset);
-						pclnsize = swal(sect->size);
-					}
-				}
-			}
-			if (strcmp(seg->segname, "__DATA") == 0) {
-				datava = seg->vmaddr;
-				dataoff = seg->fileoff;
-				datasize = seg->filesize;
-				bsssize = seg->vmsize - seg->filesize;
-			}
-			break;
-		case MACH_UNIXTHREAD:
-			break;
-		case MACH_SYMSEG:
-			if (symtab == 0) {
-				symtab = (MachSymSeg*)c;
-				symoff = swal(symtab->fileoff);
-				symsize = swal(symtab->filesize);
-			} else if (pclntab == 0) {
-				pclntab = (MachSymSeg*)c;
-				pclnoff = swal(pclntab->fileoff);
-				pclnsize = swal(pclntab->filesize);
-			}
-			break;
-		}
-		cmdp += c->size;
-	}
-	if (textva == 0 || datava == 0) {
-		free(cmd);
-		free(cmdbuf);
-		return 0;
-	}
-	/* compute entry by taking address after header - weird - BUG? */
-	settext(fp, textva+sizeof(Machhdr) + mp->sizeofcmds, textva, textsize, textoff);
-	setdata(fp, datava, datasize, dataoff, bsssize);
-	if(symoff > 0)
-		setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsize);
-	free(cmd);
-	free(cmdbuf);
-	return 1;
-bad:
-	free(cmd);
-	free(cmdbuf);
-	return 0;
-}
-
-/*
- * (Free|Net)BSD ARM header.
- */
-static int
-armdotout(int fd, Fhdr *fp, ExecHdr *hp)
-{
-	uvlong kbase;
-
-	USED(fd);
-	settext(fp, hp->e.exechdr.entry, sizeof(Exec), hp->e.exechdr.text, sizeof(Exec));
-	setdata(fp, fp->txtsz, hp->e.exechdr.data, fp->txtsz, hp->e.exechdr.bss);
-	setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
-
-	kbase = 0xF0000000;
-	if ((fp->entry & kbase) == kbase) {		/* Boot image */
-		fp->txtaddr = kbase+sizeof(Exec);
-		fp->name = "ARM *BSD boot image";
-		fp->hdrsz = 0;		/* header stripped */
-		fp->dataddr = kbase+fp->txtsz;
-	}
-	return 1;
-}
-
-/*
- * Structures needed to parse PE image.
- */
-typedef struct {
-	uint16 Machine;
-	uint16 NumberOfSections;
-	uint32 TimeDateStamp;
-	uint32 PointerToSymbolTable;
-	uint32 NumberOfSymbols;
-	uint16 SizeOfOptionalHeader;
-	uint16 Characteristics;
-} IMAGE_FILE_HEADER;
-
-typedef struct {
-	uint8  Name[8];
-	uint32 VirtualSize;
-	uint32 VirtualAddress;
-	uint32 SizeOfRawData;
-	uint32 PointerToRawData;
-	uint32 PointerToRelocations;
-	uint32 PointerToLineNumbers;
-	uint16 NumberOfRelocations;
-	uint16 NumberOfLineNumbers;
-	uint32 Characteristics;
-} IMAGE_SECTION_HEADER;
-
-typedef struct {
-	uint32 VirtualAddress;
-	uint32 Size;
-} IMAGE_DATA_DIRECTORY;
-
-typedef struct {
-	uint16 Magic;
-	uint8  MajorLinkerVersion;
-	uint8  MinorLinkerVersion;
-	uint32 SizeOfCode;
-	uint32 SizeOfInitializedData;
-	uint32 SizeOfUninitializedData;
-	uint32 AddressOfEntryPoint;
-	uint32 BaseOfCode;
-	uint32 BaseOfData;
-	uint32 ImageBase;
-	uint32 SectionAlignment;
-	uint32 FileAlignment;
-	uint16 MajorOperatingSystemVersion;
-	uint16 MinorOperatingSystemVersion;
-	uint16 MajorImageVersion;
-	uint16 MinorImageVersion;
-	uint16 MajorSubsystemVersion;
-	uint16 MinorSubsystemVersion;
-	uint32 Win32VersionValue;
-	uint32 SizeOfImage;
-	uint32 SizeOfHeaders;
-	uint32 CheckSum;
-	uint16 Subsystem;
-	uint16 DllCharacteristics;
-	uint32 SizeOfStackReserve;
-	uint32 SizeOfStackCommit;
-	uint32 SizeOfHeapReserve;
-	uint32 SizeOfHeapCommit;
-	uint32 LoaderFlags;
-	uint32 NumberOfRvaAndSizes;
-	IMAGE_DATA_DIRECTORY DataDirectory[16];
-} IMAGE_OPTIONAL_HEADER;
-
-typedef struct {
-	uint16 Magic;
-	uint8  MajorLinkerVersion;
-	uint8  MinorLinkerVersion;
-	uint32 SizeOfCode;
-	uint32 SizeOfInitializedData;
-	uint32 SizeOfUninitializedData;
-	uint32 AddressOfEntryPoint;
-	uint32 BaseOfCode;
-	uint64 ImageBase;
-	uint32 SectionAlignment;
-	uint32 FileAlignment;
-	uint16 MajorOperatingSystemVersion;
-	uint16 MinorOperatingSystemVersion;
-	uint16 MajorImageVersion;
-	uint16 MinorImageVersion;
-	uint16 MajorSubsystemVersion;
-	uint16 MinorSubsystemVersion;
-	uint32 Win32VersionValue;
-	uint32 SizeOfImage;
-	uint32 SizeOfHeaders;
-	uint32 CheckSum;
-	uint16 Subsystem;
-	uint16 DllCharacteristics;
-	uint64 SizeOfStackReserve;
-	uint64 SizeOfStackCommit;
-	uint64 SizeOfHeapReserve;
-	uint64 SizeOfHeapCommit;
-	uint32 LoaderFlags;
-	uint32 NumberOfRvaAndSizes;
-	IMAGE_DATA_DIRECTORY DataDirectory[16];
-} PE64_IMAGE_OPTIONAL_HEADER;
-
-static int
-match8(void *buf, char *cmp)
-{
-	return strncmp((char*)buf, cmp, 8) == 0;
-}
-
-/*
- * Read from Windows PE/COFF .exe file image.
- */
-static int
-pedotout(int fd, Fhdr *fp, ExecHdr *hp)
-{
-	uint32 start, magic;
-	uint32 symtab, esymtab, pclntab, epclntab;
-	IMAGE_FILE_HEADER fh;
-	IMAGE_SECTION_HEADER sh;
-	IMAGE_OPTIONAL_HEADER oh;
-	PE64_IMAGE_OPTIONAL_HEADER oh64;
-	uint8 sym[18];
-	uint32 *valp, ib, entry;
-	int i, ohoffset;
-
-	USED(hp);
-	seek(fd, 0x3c, 0);
-	if (readn(fd, &start, sizeof(start)) != sizeof(start)) {
-		werrstr("crippled PE MSDOS header");
-		return 0;
-	}
-	start = leswal(start);
-
-	seek(fd, start, 0);
-	if (readn(fd, &magic, sizeof(magic)) != sizeof(magic)) {
-		werrstr("no PE magic number found");
-		return 0;
-	}
-	if (beswal(magic) != 0x50450000) {  /* "PE\0\0" */
-		werrstr("incorrect PE magic number");
-		return 0;
-	}
-
-	if (readn(fd, &fh, sizeof(fh)) != sizeof(fh)) {
-		werrstr("crippled PE File Header");
-		return 0;
-	}
-	if (fh.PointerToSymbolTable == 0) {
-		werrstr("zero pointer to COFF symbol table");
-		return 0;
-	}
-
-	ohoffset = seek(fd, 0, 1);
-	if (readn(fd, &oh, sizeof(oh)) != sizeof(oh)) {
-		werrstr("crippled PE Optional Header");
-		return 0;
-	}
-
-	switch(oh.Magic) {
-	case 0x10b:	// PE32
-		fp->type = FI386;
-		ib = leswal(oh.ImageBase);
-		entry = leswal(oh.AddressOfEntryPoint);
-		break;
-	case 0x20b:	// PE32+
-		fp->type = FAMD64;
-		seek(fd, ohoffset, 0);
-		if (readn(fd, &oh64, sizeof(oh64)) != sizeof(oh64)) {
-			werrstr("crippled PE32+ Optional Header");
-			return 0;
-		}
-		ib = leswal(oh64.ImageBase);
-		entry = leswal(oh64.AddressOfEntryPoint);
-		break;
-	default:
-		werrstr("invalid PE Optional Header magic number");
-		return 0;
-	}
-
-	fp->txtaddr = 0;
-	fp->dataddr = 0;
-	for (i=0; i<leswab(fh.NumberOfSections); i++) {
-		if (readn(fd, &sh, sizeof(sh)) != sizeof(sh)) {
-			werrstr("could not read Section Header %d", i+1);
-			return 0;
-		}
-		if (match8(sh.Name, ".text"))
-			settext(fp, ib+entry, ib+leswal(sh.VirtualAddress), leswal(sh.VirtualSize), leswal(sh.PointerToRawData));
-		if (match8(sh.Name, ".data"))
-			setdata(fp, ib+leswal(sh.VirtualAddress), leswal(sh.SizeOfRawData), leswal(sh.PointerToRawData), leswal(sh.VirtualSize)-leswal(sh.SizeOfRawData));
-	}
-	if (fp->txtaddr==0 || fp->dataddr==0) {
-		werrstr("no .text or .data");
-		return 0;
-	}
-
-	seek(fd, leswal(fh.PointerToSymbolTable), 0);
-	symtab = esymtab = pclntab = epclntab = 0;
-	for (i=0; i<leswal(fh.NumberOfSymbols); i++) {
-		if (readn(fd, sym, sizeof(sym)) != sizeof(sym)) {
-			werrstr("crippled COFF symbol %d", i);
-			return 0;
-		}
-		valp = (uint32 *)&sym[8];
-		if (match8(sym, "symtab"))
-			symtab = leswal(*valp);
-		if (match8(sym, "esymtab"))
-			esymtab = leswal(*valp);
-		if (match8(sym, "pclntab"))
-			pclntab = leswal(*valp);
-		if (match8(sym, "epclntab"))
-			epclntab = leswal(*valp);
-	}
-	if (symtab==0 || esymtab==0 || pclntab==0 || epclntab==0) {
-		werrstr("no symtab or esymtab or pclntab or epclntab in COFF symbol table");
-		return 0;
-	}
-	setsym(fp, symtab, esymtab-symtab, 0, 0, pclntab, epclntab-pclntab);
-
-	return 1;
-}
-
-static void
-settext(Fhdr *fp, uvlong e, uvlong a, int32 s, vlong off)
-{
-	fp->txtaddr = a;
-	fp->entry = e;
-	fp->txtsz = s;
-	fp->txtoff = off;
-}
-
-static void
-setdata(Fhdr *fp, uvlong a, int32 s, vlong off, int32 bss)
-{
-	fp->dataddr = a;
-	fp->datsz = s;
-	fp->datoff = off;
-	fp->bsssz = bss;
-}
-
-static void
-setsym(Fhdr *fp, vlong symoff, int32 symsz, vlong sppcoff, int32 sppcsz, vlong lnpcoff, int32 lnpcsz)
-{
-	fp->symoff = symoff;
-	fp->symsz = symsz;
-	
-	if(sppcoff == 0)
-		sppcoff = symoff+symsz;
-	fp->sppcoff = symoff;
-	fp->sppcsz = sppcsz;
-
-	if(lnpcoff == 0)
-		lnpcoff = sppcoff + sppcsz;
-	fp->lnpcoff = lnpcoff;
-	fp->lnpcsz = lnpcsz;
-}
-
-static uvlong
-_round(uvlong a, uint32 b)
-{
-	uvlong w;
-
-	w = (a/b)*b;
-	if (a!=w)
-		w += b;
-	return(w);
-}
diff --git a/src/libmach/fakeobj.c b/src/libmach/fakeobj.c
deleted file mode 100644
index a4a897c..0000000
--- a/src/libmach/fakeobj.c
+++ /dev/null
@@ -1,29 +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.
-
-/*
- * obj.c
- * routines universal to all object files
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <ar.h>
-#include <mach.h>
-#include "obj.h"
-
-int _is2(char* x) { USED(x); return 0; }
-int _is7(char* x) { USED(x); return 0; }
-int _is9(char* x) { USED(x); return 0; }
-int _isk(char* x) { USED(x); return 0; }
-int _isq(char* x) { USED(x); return 0; }
-int _isv(char* x) { USED(x); return 0; }
-int _isu(char* x) { USED(x); return 0; }
-int _read2(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
-int _read7(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
-int _read9(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
-int _readk(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
-int _readq(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
-int _readv(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
-int _readu(Biobuf* b, Prog* p) { USED(b); USED(p); return 0; }
diff --git a/src/libmach/freebsd.c b/src/libmach/freebsd.c
deleted file mode 100644
index c4e5efd..0000000
--- a/src/libmach/freebsd.c
+++ /dev/null
@@ -1,62 +0,0 @@
-// This is stubbed out for the moment. Will revisit when the time comes.
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-int
-ctlproc(int pid, char *msg)
-{
-	USED(pid);
-	USED(msg);
-
-	sysfatal("ctlproc unimplemented in FreeBSD");
-	return -1;
-}
-
-char*
-proctextfile(int pid)
-{
-	USED(pid);
-	
-	sysfatal("proctextfile unimplemented in FreeBSD");
-	return nil;
-}
-
-char*
-procstatus(int pid)
-{
-	USED(pid);
-
-	sysfatal("procstatus unimplemented in FreeBSD");
-	return nil;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
-	USED(pid);
-	USED(fp);
-
-	sysfatal("attachproc unimplemented in FreeBSD");
-	return nil;
-}
-
-void
-detachproc(Map *m)
-{
-	USED(m);
-
-	sysfatal("detachproc unimplemented in FreeBSD");
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
-	USED(pid);
-	USED(p);
-	USED(np);
-
-	sysfatal("procthreadpids unimplemented in FreeBSD");
-	return -1;
-}
diff --git a/src/libmach/linux.c b/src/libmach/linux.c
deleted file mode 100644
index 2c14326..0000000
--- a/src/libmach/linux.c
+++ /dev/null
@@ -1,1014 +0,0 @@
-// Derived from Plan 9 from User Space src/libmach/Linux.c
-// http://code.swtch.com/plan9port/src/tip/src/libmach/Linux.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.
-//	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth at 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 © 2001-2007 Russ Cox.
-//	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 <u.h>
-#include <sys/syscall.h>	/* for tkill */
-#include <unistd.h>
-#include <dirent.h>
-#include <sys/ptrace.h>
-#include <sys/signal.h>
-#include <sys/wait.h>
-#include <errno.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-#define Ureg Ureg32
-#include <ureg_x86.h>
-#undef Ureg
-#define Ureg Ureg64
-#include <ureg_amd64.h>
-#undef Ureg
-#undef waitpid
-
-// The old glibc used with crosstool compilers on thresher
-// doesn't know these numbers, but the Linux kernel
-// had them as far back as 2.6.0.
-#ifndef WSTOPPED
-#define WSTOPPED 2
-#define WCONTINUED 8
-#define WIFCONTINUED(x) ((x) == 0xffff)
-#endif
-#ifndef PTRACE_SETOPTIONS
-#define PTRACE_SETOPTIONS 0x4200
-#define PTRACE_GETEVENTMSG 0x4201
-#define PTRACE_O_TRACEFORK 0x2
-#define PTRACE_O_TRACEVFORK 0x4
-#define PTRACE_O_TRACECLONE 0x8
-#define PTRACE_O_TRACEEXEC 0x10
-#define PTRACE_O_TRACEVFORKDONE 0x20
-#define PTRACE_O_TRACEEXIT 0x40
-#define PTRACE_EVENT_FORK 0x1
-#define PTRACE_EVENT_VFORK 0x2
-#define PTRACE_EVENT_CLONE 0x3
-#define PTRACE_EVENT_EXEC 0x4
-#define PTRACE_EVENT_VFORK_DONE 0x5
-#define PTRACE_EVENT_EXIT 0x6
-#endif
-
-typedef struct Ureg64 Ureg64;
-
-static Maprw ptracesegrw;
-static Maprw ptraceregrw;
-
-// /usr/include/asm-x86_64/user.h
-struct user_regs_struct {
-	unsigned long r15,r14,r13,r12,rbp,rbx,r11,r10;
-	unsigned long r9,r8,rax,rcx,rdx,rsi,rdi,orig_rax;
-	unsigned long rip,cs,eflags;
-	unsigned long rsp,ss;
-  	unsigned long fs_base, gs_base;
-	unsigned long ds,es,fs,gs;
-};
-
-// Linux gets very upset if a debugger forgets the reported state
-// of a debugged process, so we keep everything we know about
-// a debugged process in the LinuxThread structure.
-//
-// We can poll for state changes by calling waitpid and interpreting
-// the integer status code that comes back.  Wait1 does this.
-//
-// If the process is already running, it is an error to PTRACE_CONT it.
-//
-// If the process is already stopped, it is an error to stop it again.
-//
-// If the process is stopped because of a signal, the debugger must
-// relay the signal to the PTRACE_CONT call, or else the signal is
-// dropped.
-//
-// If the process exits, the debugger should detach so that the real
-// parent can reap the zombie.
-//
-// On first attach, the debugger should set a handful of flags in order
-// to catch future events like fork, clone, exec, etc.
-
-// One for every attached thread.
-typedef struct LinuxThread LinuxThread;
-struct LinuxThread
-{
-	int pid;
-	int tid;
-	int state;
-	int signal;
-	int child;
-	int exitcode;
-};
-
-static int trace = 0;
-
-static LinuxThread **thr;
-static int nthr;
-static int mthr;
-
-static int realpid(int pid);
-
-enum
-{
-	Unknown,
-	Detached,
-	Attached,
-	AttachStop,
-	Stopped,
-	Running,
-	Forking,
-	Vforking,
-	VforkDone,
-	Cloning,
-	Execing,
-	Exiting,
-	Exited,
-	Killed,
-
-	NSTATE,
-};
-
-static char* statestr[NSTATE] = {
-	"Unknown",
-	"Detached",
-	"Attached",
-	"AttachStop",
-	"Stopped",
-	"Running",
-	"Forking",
-	"Vforking",
-	"VforkDone",
-	"Cloning",
-	"Execing",
-	"Exiting",
-	"Exited",
-	"Killed"
-};
-
-static LinuxThread*
-attachthread(int pid, int tid, int *new, int newstate)
-{
-	int i, n, status;
-	LinuxThread **p, *t;
-	uintptr flags;
-
-	if(new)
-		*new = 0;
-
-	for(i=0; i<nthr; i++)
-		if((pid == 0 || thr[i]->pid == pid) && thr[i]->tid == tid) {
-			t = thr[i];
-			goto fixup;
-		}
-
-	if(!new)
-		return nil;
-
-	if(nthr >= mthr) {
-		n = mthr;
-		if(n == 0)
-			n = 64;
-		else
-			n *= 2;
-		p = realloc(thr, n*sizeof thr[0]);
-		if(p == nil)
-			return nil;
-		thr = p;
-		mthr = n;
-	}
-
-	t = malloc(sizeof *t);
-	if(t == nil)
-		return nil;
-	memset(t, 0, sizeof *t);
-
-	thr[nthr++] = t;
-	if(pid == 0 && nthr > 0)
-		pid = thr[0]->pid;
-	t->pid = pid;
-	t->tid = tid;
-	t->state = newstate;
-	if(trace)
-		fprint(2, "new thread %d %d\n", t->pid, t->tid);
-	if(new)
-		*new = 1;
-
-fixup:
-	if(t->state == Detached) {
-		if(ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) {
-			fprint(2, "ptrace ATTACH %d: %r\n", tid);
-			return nil;
-		}
-		t->state = Attached;
-	}
-
-	if(t->state == Attached) {
-		// wait for stop, so we can set options
-		if(waitpid(tid, &status, __WALL|WUNTRACED|WSTOPPED) < 0)
-			return nil;
-		if(!WIFSTOPPED(status)) {
-			fprint(2, "waitpid %d: status=%#x not stopped\n", tid);
-			return nil;
-		}
-		t->state = AttachStop;
-	}
-
-	if(t->state == AttachStop) {
-		// set options so we'll find out about new threads
-		flags = PTRACE_O_TRACEFORK |
-			PTRACE_O_TRACEVFORK |
-			PTRACE_O_TRACECLONE |
-			PTRACE_O_TRACEEXEC |
-			PTRACE_O_TRACEVFORKDONE;
-		if(ptrace(PTRACE_SETOPTIONS, tid, 0, (void*)flags) < 0)	{
-			fprint(2, "ptrace PTRACE_SETOPTIONS %d: %r\n", tid);
-			return nil;
-		}
-		t->state = Stopped;
-	}
-
-	return t;
-}
-
-static LinuxThread*
-findthread(int tid)
-{
-	return attachthread(0, tid, nil, 0);
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
-	int i, n;
-	LinuxThread *t;
-
-	n = 0;
-	for(i=0; i<nthr; i++) {
-		t = thr[i];
-		if(t->pid == pid) {
-			switch(t->state) {
-			case Exited:
-			case Detached:
-			case Killed:
-				break;
-
-			default:
-				if(n < np)
-					p[n] = t->tid;
-				n++;
-				break;
-			}
-		}
-	}
-	return n;
-}
-
-// Execute a single wait and update the corresponding thread.
-static int
-wait1(int nohang)
-{
-	int tid, new, status, event;
-	ulong data;
-	LinuxThread *t;
-	enum
-	{
-		NormalStop = 0x137f
-	};
-
-	if(nohang != 0)
-		nohang = WNOHANG;
-
-	status = 0;
-	tid = waitpid(-1, &status, __WALL|WUNTRACED|WSTOPPED|WCONTINUED|nohang);
-
-	if(tid < 0)
-		return -1;
-	if(tid == 0)
-		return 0;
-
-	if(trace > 0 && status != NormalStop)
-		fprint(2, "TID %d: %#x\n", tid, status);
-
-	t = findthread(tid);
-	if(t == nil) {
-		// Sometimes the kernel tells us about new threads
-		// before we see the parent clone.
-		t = attachthread(0, tid, &new, Stopped);
-		if(t == nil) {
-			fprint(2, "failed to attach to new thread %d\n", tid);
-			return -1;
-		}
-	}
-
-	if(WIFSTOPPED(status)) {
-		t->state = Stopped;
-		t->signal = WSTOPSIG(status);
-		if(trace)
-			fprint(2, "tid %d: stopped %#x%s\n", tid, status,
-				status != NormalStop ? " ***" : "");
-		if(t->signal == SIGTRAP && (event = status>>16) != 0) {	// ptrace event
-			switch(event) {
-			case PTRACE_EVENT_FORK:
-				t->state = Forking;
-				goto child;
-
-			case PTRACE_EVENT_VFORK:
-				t->state = Vforking;
-				goto child;
-
-			case PTRACE_EVENT_CLONE:
-				t->state = Cloning;
-				goto child;
-
-			child:
-				if(ptrace(PTRACE_GETEVENTMSG, t->tid, 0, &data) < 0) {
-					fprint(2, "ptrace GETEVENTMSG tid %d: %r\n", tid);
-					break;
-				}
-				t->child = data;
-				attachthread(t->pid, t->child, &new, Running);
-				break;
-
-			case PTRACE_EVENT_EXEC:
-				t->state = Execing;
-				break;
-
-			case PTRACE_EVENT_VFORK_DONE:
-				t->state = VforkDone;
-				break;
-
-			case PTRACE_EVENT_EXIT:
-				// We won't see this unless we set PTRACE_O_TRACEEXIT.
-				// The debuggers assume that a read or write on a Map
-				// will fail for a thread that has exited.  This event
-				// breaks that assumption.  It's not a big deal: we
-				// only lose the ability to see the register state at
-				// the time of exit.
-				if(trace)
-					fprint(2, "tid %d: exiting %#x\n", tid, status);
-				t->state = Exiting;
-				if(ptrace(PTRACE_GETEVENTMSG, t->tid, 0, &data) < 0) {
-					fprint(2, "ptrace GETEVENTMSG tid %d: %r\n", tid);
-					break;
-				}
-				t->exitcode = data;
-				break;
-			}
-		}
-	}
-	if(WIFCONTINUED(status)) {
-		if(trace)
-			fprint(2, "tid %d: continued %#x\n", tid, status);
-		t->state = Running;
-	}
-	if(WIFEXITED(status)) {
-		if(trace)
-			fprint(2, "tid %d: exited %#x\n", tid, status);
-		t->state = Exited;
-		t->exitcode = WEXITSTATUS(status);
-		t->signal = -1;
-		ptrace(PTRACE_DETACH, t->tid, 0, 0);
-		if(trace)
-			fprint(2, "tid %d: detach exited\n", tid);
-	}
-	if(WIFSIGNALED(status)) {
-		if(trace)
-			fprint(2, "tid %d: signaled %#x\n", tid, status);
-		t->state = Exited;
-		t->signal = WTERMSIG(status);
-		t->exitcode = -1;
-		ptrace(PTRACE_DETACH, t->tid, 0, 0);
-		if(trace)
-			fprint(2, "tid %d: detach signaled\n", tid);
-	}
-	return 1;
-}
-
-static int
-waitstop(LinuxThread *t)
-{
-	while(t->state == Running)
-		if(wait1(0) < 0)
-			return -1;
-	return 0;
-}
-
-// Attach to and stop all threads in process pid.
-// Must stop everyone in order to make sure we set
-// the "tell me about new threads" option in every
-// task.
-int
-attachallthreads(int pid)
-{
-	int tid, foundnew, new;
-	char buf[100];
-	DIR *d;
-	struct dirent *de;
-	LinuxThread *t;
-
-	if(pid == 0) {
-		fprint(2, "attachallthreads(0)\n");
-		return -1;
-	}
-
-	pid = realpid(pid);
-
-	snprint(buf, sizeof buf, "/proc/%d/task", pid);
-	if((d = opendir(buf)) == nil) {
-		fprint(2, "opendir %s: %r\n", buf);
-		return -1;
-	}
-
-	// Loop in case new threads are being created right now.
-	// We stop every thread as we find it, so eventually
-	// this has to stop (or the system runs out of procs).
-	do {
-		foundnew = 0;
-		while((de = readdir(d)) != nil) {
-			tid = atoi(de->d_name);
-			if(tid == 0)
-				continue;
-			t = attachthread(pid, tid, &new, Detached);
-			foundnew |= new;
-			if(t)
-				waitstop(t);
-		}
-		rewinddir(d);
-	} while(foundnew);
-	closedir(d);
-
-	return 0;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
-	Map *map;
-
-	if(pid == 0) {
-		fprint(2, "attachproc(0)\n");
-		return nil;
-	}
-
-	if(findthread(pid) == nil && attachallthreads(pid) < 0)
-		return nil;
-
-	map = newmap(0, 4);
-	if (!map)
-		return 0;
-	map->pid = pid;
-	if(mach->regsize)
-		setmap(map, -1, 0, mach->regsize, 0, "regs", ptraceregrw);
-//	if(mach->fpregsize)
-//		setmap(map, -1, mach->regsize, mach->regsize+mach->fpregsize, 0, "fpregs", ptraceregrw);
-	setmap(map, -1, fp->txtaddr, fp->txtaddr+fp->txtsz, fp->txtaddr, "*text", ptracesegrw);
-	setmap(map, -1, fp->dataddr, mach->utop, fp->dataddr, "*data", ptracesegrw);
-	return map;
-}
-
-void
-detachproc(Map *m)
-{
-	LinuxThread *t;
-
-	t = findthread(m->pid);
-	if(t != nil) {
-		ptrace(PTRACE_DETACH, t->tid, 0, 0);
-		t->state = Detached;
-		if(trace)
-			fprint(2, "tid %d: detachproc\n", t->tid);
-		// TODO(rsc): Reclaim thread structs somehow?
-	}
-	free(m);
-}
-
-/* /proc/pid/stat contains
-	pid
-	command in parens
-	0. state
-	1. ppid
-	2. pgrp
-	3. session
-	4. tty_nr
-	5. tpgid
-	6. flags (math=4, traced=10)
-	7. minflt
-	8. cminflt
-	9. majflt
-	10. cmajflt
-	11. utime
-	12. stime
-	13. cutime
-	14. cstime
-	15. priority
-	16. nice
-	17. 0
-	18. itrealvalue
-	19. starttime
-	20. vsize
-	21. rss
-	22. rlim
-	23. startcode
-	24. endcode
-	25. startstack
-	26. kstkesp
-	27. kstkeip
-	28. pending signal bitmap
-	29. blocked signal bitmap
-	30. ignored signal bitmap
-	31. caught signal bitmap
-	32. wchan
-	33. nswap
-	34. cnswap
-	35. exit_signal
-	36. processor
-*/
-
-static int
-readstat(int pid, char *buf, int nbuf, char **f, int nf)
-{
-	int fd, n;
-	char *p;
-
-	snprint(buf, nbuf, "/proc/%d/stat", pid);
-	if((fd = open(buf, OREAD)) < 0){
-		fprint(2, "open %s: %r\n", buf);
-		return -1;
-	}
-	n = read(fd, buf, nbuf-1);
-	close(fd);
-	if(n <= 0){
-		fprint(2, "read %s: %r\n", buf);
-		return -1;
-	}
-	buf[n] = 0;
-
-	/* command name is in parens, no parens afterward */
-	p = strrchr(buf, ')');
-	if(p == nil || *++p != ' '){
-		fprint(2, "bad format in /proc/%d/stat\n", pid);
-		return -1;
-	}
-	++p;
-
-	nf = tokenize(p, f, nf);
-	if(0) print("code 0x%lux-0x%lux stack 0x%lux kstk 0x%lux keip 0x%lux pending 0x%lux\n",
-		strtoul(f[23], 0, 0), strtoul(f[24], 0, 0), strtoul(f[25], 0, 0),
-		strtoul(f[26], 0, 0), strtoul(f[27], 0, 0), strtoul(f[28], 0, 0));
-
-	return nf;
-}
-
-static char*
-readstatus(int pid, char *buf, int nbuf, char *key)
-{
-	int fd, n;
-	char *p;
-
-	snprint(buf, nbuf, "/proc/%d/status", pid);
-	if((fd = open(buf, OREAD)) < 0){
-		fprint(2, "open %s: %r\n", buf);
-		return nil;
-	}
-	n = read(fd, buf, nbuf-1);
-	close(fd);
-	if(n <= 0){
-		fprint(2, "read %s: %r\n", buf);
-		return nil;
-	}
-	buf[n] = 0;
-	p = strstr(buf, key);
-	if(p)
-		return p+strlen(key);
-	return nil;
-}
-
-int
-procnotes(int pid, char ***pnotes)
-{
-	char buf[1024], *f[40];
-	int i, n, nf;
-	char *s, **notes;
-	ulong sigs;
-	extern char *_p9sigstr(int, char*);
-
-	*pnotes = nil;
-	nf = readstat(pid, buf, sizeof buf, f, nelem(f));
-	if(nf <= 28)
-		return -1;
-
-	sigs = strtoul(f[28], 0, 0) & ~(1<<SIGCONT);
-	if(sigs == 0){
-		*pnotes = nil;
-		return 0;
-	}
-
-	notes = malloc(32*sizeof(char*));
-	if(notes == nil)
-		return -1;
-	memset(notes, 0, 32*sizeof(char*));
-	n = 0;
-	for(i=0; i<32; i++){
-		if((sigs&(1<<i)) == 0)
-			continue;
-		if((s = _p9sigstr(i, nil)) == nil)
-			continue;
-		notes[n++] = s;
-	}
-	*pnotes = notes;
-	return n;
-}
-
-static int
-realpid(int pid)
-{
-	char buf[1024], *p;
-
-	p = readstatus(pid, buf, sizeof buf, "\nTgid:");
-	if(p == nil)
-		return pid;
-	return atoi(p);
-}
-
-int
-ctlproc(int pid, char *msg)
-{
-	int new;
-	LinuxThread *t;
-	uintptr data;
-
-	while(wait1(1) > 0)
-		;
-
-	if(strcmp(msg, "attached") == 0){
-		t = attachthread(pid, pid, &new, Attached);
-		if(t == nil)
-			return -1;
-		return 0;
-	}
-
-	if(strcmp(msg, "hang") == 0){
-		if(pid == getpid())
-			return ptrace(PTRACE_TRACEME, 0, 0, 0);
-		werrstr("can only hang self");
-		return -1;
-	}
-
-	t = findthread(pid);
-	if(t == nil) {
-		werrstr("not attached to pid %d", pid);
-		return -1;
-	}
-	if(t->state == Exited) {
-		werrstr("pid %d has exited", pid);
-		return -1;
-	}
-	if(t->state == Killed) {
-		werrstr("pid %d has been killed", pid);
-		return -1;
-	}
-
-	if(strcmp(msg, "kill") == 0) {
-		if(ptrace(PTRACE_KILL, pid, 0, 0) < 0)
-			return -1;
-		t->state = Killed;
-		return 0;
-	}
-	if(strcmp(msg, "startstop") == 0){
-		if(ctlproc(pid, "start") < 0)
-			return -1;
-		return waitstop(t);
-	}
-	if(strcmp(msg, "sysstop") == 0){
-		if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
-			return -1;
-		t->state = Running;
-		return waitstop(t);
-	}
-	if(strcmp(msg, "stop") == 0){
-		if(trace > 1)
-			fprint(2, "tid %d: tkill stop\n", pid);
-		if(t->state == Stopped)
-			return 0;
-		if(syscall(__NR_tkill, pid, SIGSTOP) < 0)
-			return -1;
-		return waitstop(t);
-	}
-	if(strcmp(msg, "step") == 0){
-		if(t->state == Running) {
-			werrstr("cannot single-step unstopped %d", pid);
-			return -1;
-		}
-		if(ptrace(PTRACE_SINGLESTEP, pid, 0, 0) < 0)
-			return -1;
-		return waitstop(t);
-	}
-	if(strcmp(msg, "start") == 0) {
-		if(t->state == Running)
-			return 0;
-		data = 0;
-		if(t->state == Stopped && t->signal != SIGSTOP && t->signal != SIGTRAP)
-			data = t->signal;
-		if(trace && data)
-			fprint(2, "tid %d: continue %lud\n", pid, (ulong)data);
-		if(ptrace(PTRACE_CONT, pid, 0, (void*)data) < 0)
-			return -1;
-		t->state = Running;
-		return 0;
-	}
-	if(strcmp(msg, "waitstop") == 0) {
-		return waitstop(t);
-	}
-	werrstr("unknown control message '%s'", msg);
-	return -1;
-}
-
-char*
-proctextfile(int pid)
-{
-	static char buf[1024], pbuf[128];
-
-	snprint(pbuf, sizeof pbuf, "/proc/%d/exe", pid);
-	if(readlink(pbuf, buf, sizeof buf) >= 0)
-		return strdup(buf);
-	if(access(pbuf, AEXIST) >= 0)
-		return strdup(pbuf);
-	return nil;
-}
-
-
-static int
-ptracerw(int type, int xtype, int isr, int pid, uvlong addr, void *v, uint n)
-{
-	int i;
-	uintptr u, a;
-	uchar buf[sizeof(uintptr)];
-
-	for(i=0; i<n; i+=sizeof(uintptr)){
-		// Tread carefully here.  On recent versions of glibc,
-		// ptrace is a variadic function which means the third
-		// argument will be pushed onto the stack as a uvlong.
-		// This is fine on amd64 but will not work for 386.
-		// We must convert addr to a uintptr.
-		a = addr+i;
-		if(isr){
-			errno = 0;
-			u = ptrace(type, pid, a, 0);
-			if(errno)
-				goto ptraceerr;
-			if(n-i >= sizeof(uintptr))
-				memmove((char*)v+i, &u, sizeof(uintptr));
-			else{
-				memmove(buf, &u, sizeof u);
-				memmove((char*)v+i, buf, n-i);
-			}
-		}else{
-			if(n-i >= sizeof(uintptr))
-				u = *(uintptr*)((char*)v+i);
-			else{
-				errno = 0;
-				u = ptrace(xtype, pid, a, 0);
-				if(errno)
-					return -1;
-				memmove(buf, &u, sizeof u);
-				memmove(buf, (char*)v+i, n-i);
-				memmove(&u, buf, sizeof u);
-			}
-			if(ptrace(type, pid, a, u) < 0)
-				goto ptraceerr;
-		}
-	}
-	return 0;
-
-ptraceerr:
-	werrstr("ptrace %s addr=%#llux pid=%d: %r", isr ? "read" : "write", addr, pid);
-	return -1;
-}
-
-static int
-ptracesegrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
-{
-	USED(seg);
-
-	return ptracerw(isr ? PTRACE_PEEKDATA : PTRACE_POKEDATA, PTRACE_PEEKDATA,
-		isr, map->pid, addr, v, n);
-}
-
-// If the debugger is compiled as an x86-64 program,
-// then all the ptrace register read/writes are done on
-// a 64-bit register set.  If the target program
-// is a 32-bit program, the debugger is expected to
-// read the bottom half of the relevant registers
-// out of the 64-bit set.
-
-// Linux 32-bit is
-//	BX CX DX SI DI BP AX DS ES FS GS OrigAX IP CS EFLAGS SP SS
-
-// Linux 64-bit is
-//	R15 R14 R13 R12 BP BX R11 R10 R9 R8 AX CX DX SI DI OrigAX IP CS EFLAGS SP SS FSBase GSBase DS ES FS GS
-
-// Go 32-bit is
-//	DI SI BP NSP BX DX CX AX GS FS ES DS TRAP ECODE PC CS EFLAGS SP SS
-
-uint go32tolinux32tab[] = {
-	4, 3, 5, 15, 0, 2, 1, 6, 10, 9, 8, 7, -1, -1, 12, 13, 14, 15, 16
-};
-static int
-go32tolinux32(uvlong addr)
-{
-	int r;
-
-	if(addr%4 || addr/4 >= nelem(go32tolinux32tab))
-		return -1;
-	r = go32tolinux32tab[addr/4];
-	if(r < 0)
-		return -1;
-	return r*4;
-}
-
-uint go32tolinux64tab[] = {
-	14, 13, 4, 19, 5, 12, 11, 10, 26, 25, 24, 23, -1, -1, 16, 17, 18, 19, 20
-};
-static int
-go32tolinux64(uvlong addr)
-{
-	int r;
-
-	if(addr%4 || addr/4 >= nelem(go32tolinux64tab))
-		return -1;
-	r = go32tolinux64tab[addr/4];
-	if(r < 0)
-		return -1;
-	return r*8;
-}
-
-extern Mach mi386;
-extern Mach mamd64;
-
-static int
-go2linux(uvlong addr)
-{
-	if(sizeof(void*) == 4) {
-		if(mach == &mi386)
-			return go32tolinux32(addr);
-		werrstr("unsupported architecture");
-		return -1;
-	}
-
-	if(mach == &mi386)
-		return go32tolinux64(addr);
-	if(mach != &mamd64) {
-		werrstr("unsupported architecture");
-		return -1;
-	}
-
-	switch(addr){
-	case offsetof(Ureg64, ax):
-		return offsetof(struct user_regs_struct, rax);
-	case offsetof(Ureg64, bx):
-		return offsetof(struct user_regs_struct, rbx);
-	case offsetof(Ureg64, cx):
-		return offsetof(struct user_regs_struct, rcx);
-	case offsetof(Ureg64, dx):
-		return offsetof(struct user_regs_struct, rdx);
-	case offsetof(Ureg64, si):
-		return offsetof(struct user_regs_struct, rsi);
-	case offsetof(Ureg64, di):
-		return offsetof(struct user_regs_struct, rdi);
-	case offsetof(Ureg64, bp):
-		return offsetof(struct user_regs_struct, rbp);
-	case offsetof(Ureg64, r8):
-		return offsetof(struct user_regs_struct, r8);
-	case offsetof(Ureg64, r9):
-		return offsetof(struct user_regs_struct, r9);
-	case offsetof(Ureg64, r10):
-		return offsetof(struct user_regs_struct, r10);
-	case offsetof(Ureg64, r11):
-		return offsetof(struct user_regs_struct, r11);
-	case offsetof(Ureg64, r12):
-		return offsetof(struct user_regs_struct, r12);
-	case offsetof(Ureg64, r13):
-		return offsetof(struct user_regs_struct, r13);
-	case offsetof(Ureg64, r14):
-		return offsetof(struct user_regs_struct, r14);
-	case offsetof(Ureg64, r15):
-		return offsetof(struct user_regs_struct, r15);
-	case offsetof(Ureg64, ds):
-		return offsetof(struct user_regs_struct, ds);
-	case offsetof(Ureg64, es):
-		return offsetof(struct user_regs_struct, es);
-	case offsetof(Ureg64, fs):
-		return offsetof(struct user_regs_struct, fs);
-	case offsetof(Ureg64, gs):
-		return offsetof(struct user_regs_struct, gs);
-	case offsetof(Ureg64, ip):
-		return offsetof(struct user_regs_struct, rip);
-	case offsetof(Ureg64, cs):
-		return offsetof(struct user_regs_struct, cs);
-	case offsetof(Ureg64, flags):
-		return offsetof(struct user_regs_struct, eflags);
-	case offsetof(Ureg64, sp):
-		return offsetof(struct user_regs_struct, rsp);
-	case offsetof(Ureg64, ss):
-		return offsetof(struct user_regs_struct, ss);
-	}
-	return -1;
-}
-
-static int
-ptraceregrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
-{
-	int laddr;
-	uvlong u;
-	
-	USED(seg);
-
-	if((laddr = go2linux(addr)) < 0){
-		if(isr){
-			memset(v, 0, n);
-			return 0;
-		}
-		werrstr("register %llud not available", addr);
-		return -1;
-	}
-
-	if(isr){
-		errno = 0;
-		u = ptrace(PTRACE_PEEKUSER, map->pid, laddr, 0);
-		if(errno)
-			goto ptraceerr;
-		switch(n){
-		case 1:
-			*(uint8*)v = u;
-			break;
-		case 2:
-			*(uint16*)v = u;
-			break;
-		case 4:
-			*(uint32*)v = u;
-			break;
-		case 8:
-			*(uint64*)v = u;
-			break;
-		default:
-			werrstr("bad register size");
-			return -1;
-		}
-	}else{
-		switch(n){
-		case 1:
-			u = *(uint8*)v;
-			break;
-		case 2:
-			u = *(uint16*)v;
-			break;
-		case 4:
-			u = *(uint32*)v;
-			break;
-		case 8:
-			u = *(uint64*)v;
-			break;
-		default:
-			werrstr("bad register size");
-			return -1;
-		}
-		if(ptrace(PTRACE_POKEUSER, map->pid, laddr, (void*)(uintptr)u) < 0)
-			goto ptraceerr;
-	}
-	return 0;
-
-ptraceerr:
-	werrstr("ptrace %s register laddr=%d pid=%d n=%d: %r", isr ? "read" : "write", laddr, map->pid, n);
-	return -1;
-}
-
-char*
-procstatus(int pid)
-{
-	LinuxThread *t;
-
-	t = findthread(pid);
-	if(t == nil)
-		return "???";
-
-	return statestr[t->state];
-}
diff --git a/src/libmach/machdata.c b/src/libmach/machdata.c
deleted file mode 100644
index 66c19f9..0000000
--- a/src/libmach/machdata.c
+++ /dev/null
@@ -1,477 +0,0 @@
-// Inferno libmach/machdata.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/machdata.c
-//
-// 	Copyright © 1994-1999 Lucent Technologies Inc.
-// 	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth at 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.
-
-/*
- * Debugger utilities shared by at least two architectures
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-#define STARTSYM	"_main"
-#define PROFSYM		"_mainp"
-#define	FRAMENAME	".frame"
-
-extern	Machdata	mipsmach;
-
-int	asstype = AMIPS;		/* disassembler type */
-Machdata *machdata;		/* machine-dependent functions */
-
-int
-localaddr(Map *map, char *fn, char *var, uvlong *r, Rgetter rget)
-{
-	Symbol s;
-	uvlong fp, pc, sp, link;
-
-	if (!lookup(fn, 0, &s)) {
-		werrstr("function not found");
-		return -1;
-	}
-	pc = rget(map, mach->pc);
-	sp = rget(map, mach->sp);
-	if(mach->link)
-		link = rget(map, mach->link);
-	else
-		link = 0;
-	fp = machdata->findframe(map, s.value, pc, sp, link);
-	if (fp == 0) {
-		werrstr("stack frame not found");
-		return -1;
-	}
-
-	if (!var || !var[0]) {
-		*r = fp;
-		return 1;
-	}
-
-	if (findlocal(&s, var, &s) == 0) {
-		werrstr("local variable not found");
-		return -1;
-	}
-
-	switch (s.class) {
-	case CAUTO:
-		*r = fp - s.value;
-		break;
-	case CPARAM:		/* assume address size is stack width */
-		*r = fp + s.value + mach->szaddr;
-		break;
-	default:
-		werrstr("local variable not found: %d", s.class);
-		return -1;
-	}
-	return 1;
-}
-
-/*
- * Print value v as s.name[+offset] if possible, or just v.
- */
-int
-symoff(char *buf, int n, uvlong v, int space)
-{
-	Symbol s;
-	int r;
-	int32 delta;
-
-	r = delta = 0;		/* to shut compiler up */
-	if (v) {
-		r = findsym(v, space, &s);
-		if (r)
-			delta = v-s.value;
-		if (delta < 0)
-			delta = -delta;
-	}
-	if (v == 0 || r == 0)
-		return snprint(buf, n, "%llux", v);
-	if (s.type != 't' && s.type != 'T' && delta >= 4096)
-		return snprint(buf, n, "%llux", v);
-	else if (delta)
-		return snprint(buf, n, "%s+%#ux", s.name, delta);
-	else
-		return snprint(buf, n, "%s", s.name);
-}
-
-/*
- *	Format floating point registers
- *
- *	Register codes in format field:
- *	'X' - print as 32-bit hexadecimal value
- *	'F' - 64-bit double register when modif == 'F'; else 32-bit single reg
- *	'f' - 32-bit ieee float
- *	'8' - big endian 80-bit ieee extended float
- *	'3' - little endian 80-bit ieee extended float with hole in bytes 8&9
- */
-int
-fpformat(Map *map, Reglist *rp, char *buf, int n, int modif)
-{
-	char reg[12];
-	uint32 r;
-
-	switch(rp->rformat)
-	{
-	case 'X':
-		if (get4(map, rp->roffs, &r) < 0)
-			return -1;
-		snprint(buf, n, "%ux", r);
-		break;
-	case 'F':	/* first reg of double reg pair */
-		if (modif == 'F')
-		if ((rp->rformat=='F') || (((rp+1)->rflags&RFLT) && (rp+1)->rformat == 'f')) {
-			if (get1(map, rp->roffs, (uchar *)reg, 8) < 0)
-				return -1;
-			machdata->dftos(buf, n, reg);
-			if (rp->rformat == 'F')
-				return 1;
-			return 2;
-		}
-			/* treat it like 'f' */
-		if (get1(map, rp->roffs, (uchar *)reg, 4) < 0)
-			return -1;
-		machdata->sftos(buf, n, reg);
-		break;
-	case 'f':	/* 32 bit float */
-		if (get1(map, rp->roffs, (uchar *)reg, 4) < 0)
-			return -1;
-		machdata->sftos(buf, n, reg);
-		break;
-	case '3':	/* little endian ieee 80 with hole in bytes 8&9 */
-		if (get1(map, rp->roffs, (uchar *)reg, 10) < 0)
-			return -1;
-		memmove(reg+10, reg+8, 2);	/* open hole */
-		memset(reg+8, 0, 2);		/* fill it */
-		leieee80ftos(buf, n, reg);
-		break;
-	case '8':	/* big-endian ieee 80 */
-		if (get1(map, rp->roffs, (uchar *)reg, 10) < 0)
-			return -1;
-		beieee80ftos(buf, n, reg);
-		break;
-	default:	/* unknown */
-		break;
-	}
-	return 1;
-}
-
-char *
-_hexify(char *buf, uint32 p, int zeros)
-{
-	uint32 d;
-
-	d = p/16;
-	if(d)
-		buf = _hexify(buf, d, zeros-1);
-	else
-		while(zeros--)
-			*buf++ = '0';
-	*buf++ = "0123456789abcdef"[p&0x0f];
-	return buf;
-}
-
-/*
- * These routines assume that if the number is representable
- * in IEEE floating point, it will be representable in the native
- * double format.  Naive but workable, probably.
- */
-int
-ieeedftos(char *buf, int n, uint32 h, uint32 l)
-{
-	double fr;
-	int exp;
-
-	if (n <= 0)
-		return 0;
-
-
-	if(h & (1L<<31)){
-		*buf++ = '-';
-		h &= ~(1L<<31);
-	}else
-		*buf++ = ' ';
-	n--;
-	if(l == 0 && h == 0)
-		return snprint(buf, n, "0.");
-	exp = (h>>20) & ((1L<<11)-1L);
-	if(exp == 0)
-		return snprint(buf, n, "DeN(%.8ux%.8ux)", h, l);
-	if(exp == ((1L<<11)-1L)){
-		if(l==0 && (h&((1L<<20)-1L)) == 0)
-			return snprint(buf, n, "Inf");
-		else
-			return snprint(buf, n, "NaN(%.8ux%.8ux)", h&((1<<20)-1), l);
-	}
-	exp -= (1L<<10) - 2L;
-	fr = l & ((1L<<16)-1L);
-	fr /= 1L<<16;
-	fr += (l>>16) & ((1L<<16)-1L);
-	fr /= 1L<<16;
-	fr += (h & (1L<<20)-1L) | (1L<<20);
-	fr /= 1L<<21;
-	fr = ldexp(fr, exp);
-	return snprint(buf, n, "%.18g", fr);
-}
-
-int
-ieeesftos(char *buf, int n, uint32 h)
-{
-	double fr;
-	int exp;
-
-	if (n <= 0)
-		return 0;
-
-	if(h & (1L<<31)){
-		*buf++ = '-';
-		h &= ~(1L<<31);
-	}else
-		*buf++ = ' ';
-	n--;
-	if(h == 0)
-		return snprint(buf, n, "0.");
-	exp = (h>>23) & ((1L<<8)-1L);
-	if(exp == 0)
-		return snprint(buf, n, "DeN(%.8ux)", h);
-	if(exp == ((1L<<8)-1L)){
-		if((h&((1L<<23)-1L)) == 0)
-			return snprint(buf, n, "Inf");
-		else
-			return snprint(buf, n, "NaN(%.8lux)", h&((1L<<23)-1L));
-	}
-	exp -= (1L<<7) - 2L;
-	fr = (h & ((1L<<23)-1L)) | (1L<<23);
-	fr /= 1L<<24;
-	fr = ldexp(fr, exp);
-	return snprint(buf, n, "%.9g", fr);
-}
-
-int
-beieeesftos(char *buf, int n, void *s)
-{
-	return ieeesftos(buf, n, beswal(*(uint32*)s));
-}
-
-int
-beieeedftos(char *buf, int n, void *s)
-{
-	return ieeedftos(buf, n, beswal(*(uint32*)s), beswal(((uint32*)(s))[1]));
-}
-
-int
-leieeesftos(char *buf, int n, void *s)
-{
-	return ieeesftos(buf, n, leswal(*(uint32*)s));
-}
-
-int
-leieeedftos(char *buf, int n, void *s)
-{
-	return ieeedftos(buf, n, leswal(((uint32*)(s))[1]), leswal(*(uint32*)s));
-}
-
-/* packed in 12 bytes, with s[2]==s[3]==0; mantissa starts at s[4]*/
-int
-beieee80ftos(char *buf, int n, void *s)
-{
-	uchar *reg = (uchar*)s;
-	int i;
-	uint32 x;
-	uchar ieee[8+8];	/* room for slop */
-	uchar *p, *q;
-
-	memset(ieee, 0, sizeof(ieee));
-	/* sign */
-	if(reg[0] & 0x80)
-		ieee[0] |= 0x80;
-
-	/* exponent */
-	x = ((reg[0]&0x7F)<<8) | reg[1];
-	if(x == 0)		/* number is ±0 */
-		goto done;
-	if(x == 0x7FFF){
-		if(memcmp(reg+4, ieee+1, 8) == 0){ /* infinity */
-			x = 2047;
-		}else{				/* NaN */
-			x = 2047;
-			ieee[7] = 0x1;		/* make sure */
-		}
-		ieee[0] |= x>>4;
-		ieee[1] |= (x&0xF)<<4;
-		goto done;
-	}
-	x -= 0x3FFF;		/* exponent bias */
-	x += 1023;
-	if(x >= (1<<11) || ((reg[4]&0x80)==0 && x!=0))
-		return snprint(buf, n, "not in range");
-	ieee[0] |= x>>4;
-	ieee[1] |= (x&0xF)<<4;
-
-	/* mantissa */
-	p = reg+4;
-	q = ieee+1;
-	for(i=0; i<56; i+=8, p++, q++){	/* move one byte */
-		x = (p[0]&0x7F) << 1;
-		if(p[1] & 0x80)
-			x |= 1;
-		q[0] |= x>>4;
-		q[1] |= (x&0xF)<<4;
-	}
-    done:
-	return beieeedftos(buf, n, (void*)ieee);
-}
-
-int
-leieee80ftos(char *buf, int n, void *s)
-{
-	int i;
-	char *cp;
-	char b[12];
-
-	cp = (char*) s;
-	for(i=0; i<12; i++)
-		b[11-i] = *cp++;
-	return beieee80ftos(buf, n, b);
-}
-
-int
-cisctrace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
-{
-	Symbol s;
-	int found, i;
-	uvlong opc, moved;
-
-	USED(link);
-	i = 0;
-	opc = 0;
-	while(pc && opc != pc) {
-		moved = pc2sp(pc);
-		if (moved == ~0)
-			break;
-		found = findsym(pc, CTEXT, &s);
-		if (!found)
-			break;
-		if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
-			break;
-
-		sp += moved;
-		opc = pc;
-		if (geta(map, sp, &pc) < 0)
-			break;
-		(*trace)(map, pc, sp, &s);
-		sp += mach->szaddr;	/*assumes address size = stack width*/
-		if(++i > 40)
-			break;
-	}
-	return i;
-}
-
-int
-risctrace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
-{
-	int i;
-	Symbol s, f;
-	uvlong oldpc;
-
-	i = 0;
-	while(findsym(pc, CTEXT, &s)) {
-		if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
-			break;
-
-		if(pc == s.value)	/* at first instruction */
-			f.value = 0;
-		else if(findlocal(&s, FRAMENAME, &f) == 0)
-			break;
-
-		oldpc = pc;
-		if(s.type == 'L' || s.type == 'l' || pc <= s.value+mach->pcquant)
-			pc = link;
-		else
-			if (geta(map, sp, &pc) < 0)
-				break;
-
-		if(pc == 0 || (pc == oldpc && f.value == 0))
-			break;
-
-		sp += f.value;
-		(*trace)(map, pc-8, sp, &s);
-
-		if(++i > 40)
-			break;
-	}
-	return i;
-}
-
-uvlong
-ciscframe(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link)
-{
-	Symbol s;
-	uvlong moved;
-
-	USED(link);
-	for(;;) {
-		moved = pc2sp(pc);
-		if (moved  == ~0)
-			break;
-		sp += moved;
-		findsym(pc, CTEXT, &s);
-		if (addr == s.value)
-			return sp;
-		if (geta(map, sp, &pc) < 0)
-			break;
-		sp += mach->szaddr;	/*assumes sizeof(addr) = stack width*/
-	}
-	return 0;
-}
-
-uvlong
-riscframe(Map *map, uvlong addr, uvlong pc, uvlong sp, uvlong link)
-{
-	Symbol s, f;
-
-	while (findsym(pc, CTEXT, &s)) {
-		if(strcmp(STARTSYM, s.name) == 0 || strcmp(PROFSYM, s.name) == 0)
-			break;
-
-		if(pc == s.value)	/* at first instruction */
-			f.value = 0;
-		else
-		if(findlocal(&s, FRAMENAME, &f) == 0)
-			break;
-
-		sp += f.value;
-		if (s.value == addr)
-			return sp;
-
-		if (s.type == 'L' || s.type == 'l' || pc-s.value <= mach->szaddr*2)
-			pc = link;
-		else
-		if (geta(map, sp-f.value, &pc) < 0)
-			break;
-	}
-	return 0;
-}
diff --git a/src/libmach/macho.h b/src/libmach/macho.h
deleted file mode 100644
index 9dfea5a..0000000
--- a/src/libmach/macho.h
+++ /dev/null
@@ -1,100 +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.
-
-/*
- *	Definitions needed for  accessing MACH object headers.
- */
-
-typedef struct {
-	uint32	magic;		/* mach magic number identifier */
-	uint32	cputype;	/* cpu specifier */
-	uint32	cpusubtype;	/* machine specifier */
-	uint32	filetype;	/* type of file */
-	uint32	ncmds;		/* number of load commands */
-	uint32	sizeofcmds;	/* the size of all the load commands */
-	uint32	flags;		/* flags */
-	uint32	reserved;	/* reserved */
-} Machhdr;
-
-typedef struct {
-	uint32	type;	/* type of load command */
-	uint32	size;	/* total size in bytes */
-} MachCmd;
-
-typedef struct  {
-	MachCmd	cmd;
-	char		segname[16];	/* segment name */
-	uint32	vmaddr;		/* memory address of this segment */
-	uint32	vmsize;		/* memory size of this segment */
-	uint32	fileoff;	/* file offset of this segment */
-	uint32	filesize;	/* amount to map from the file */
-	uint32	maxprot;	/* maximum VM protection */
-	uint32	initprot;	/* initial VM protection */
-	uint32	nsects;		/* number of sections in segment */
-	uint32	flags;		/* flags */
-} MachSeg32; /* for 32-bit architectures */
-
-typedef struct  {
-	MachCmd	cmd;
-	char		segname[16];	/* segment name */
-	uvlong	vmaddr;		/* memory address of this segment */
-	uvlong	vmsize;		/* memory size of this segment */
-	uvlong	fileoff;	/* file offset of this segment */
-	uvlong	filesize;	/* amount to map from the file */
-	uint32	maxprot;	/* maximum VM protection */
-	uint32	initprot;	/* initial VM protection */
-	uint32	nsects;		/* number of sections in segment */
-	uint32	flags;		/* flags */
-} MachSeg64; /* for 64-bit architectures */
-
-typedef struct  {
-	MachCmd	cmd;
-	uint32	fileoff;	/* file offset of this segment */
-	uint32	filesize;	/* amount to map from the file */
-} MachSymSeg;
-
-typedef struct  {
-	char		sectname[16];	/* name of this section */
-	char		segname[16];	/* segment this section goes in */
-	uint32	addr;		/* memory address of this section */
-	uint32	size;		/* size in bytes of this section */
-	uint32	offset;		/* file offset of this section */
-	uint32	align;		/* section alignment (power of 2) */
-	uint32	reloff;		/* file offset of relocation entries */
-	uint32	nreloc;		/* number of relocation entries */
-	uint32	flags;		/* flags (section type and attributes)*/
-	uint32	reserved1;	/* reserved (for offset or index) */
-	uint32	reserved2;	/* reserved (for count or sizeof) */
-} MachSect32; /* for 32-bit architectures */
-
-typedef struct  {
-	char		sectname[16];	/* name of this section */
-	char		segname[16];	/* segment this section goes in */
-	uvlong	addr;		/* memory address of this section */
-	uvlong	size;		/* size in bytes of this section */
-	uint32	offset;		/* file offset of this section */
-	uint32	align;		/* section alignment (power of 2) */
-	uint32	reloff;		/* file offset of relocation entries */
-	uint32	nreloc;		/* number of relocation entries */
-	uint32	flags;		/* flags (section type and attributes)*/
-	uint32	reserved1;	/* reserved (for offset or index) */
-	uint32	reserved2;	/* reserved (for count or sizeof) */
-	uint32	reserved3;	/* reserved */
-} MachSect64; /* for 64-bit architectures */
-
-enum {
-	MACH_CPU_TYPE_X86_64 = (1<<24)|7,
-	MACH_CPU_TYPE_X86 = 7,
-	MACH_CPU_SUBTYPE_X86 = 3,
-	MACH_CPU_SUBTYPE_X86_64 = (1<<31)|3,
-	MACH_EXECUTABLE_TYPE = 2,
-	MACH_SEGMENT_32 = 1,	/* 32-bit mapped segment */
-	MACH_SEGMENT_64 = 0x19,	/* 64-bit mapped segment */
-	MACH_SYMSEG = 3,	/* obsolete gdb symtab, reused by go */
-	MACH_UNIXTHREAD = 0x5,	/* thread (for stack) */
-};
-
-
-#define	MACH64_MAG		((0xcf<<24) | (0xfa<<16) | (0xed<<8) | 0xfe)
-#define	MACH32_MAG		((0xce<<24) | (0xfa<<16) | (0xed<<8) | 0xfe)
diff --git a/src/libmach/map.c b/src/libmach/map.c
deleted file mode 100644
index cd5ef09..0000000
--- a/src/libmach/map.c
+++ /dev/null
@@ -1,183 +0,0 @@
-// Derived from Inferno libmach/map.c and
-// Plan 9 from User Space src/libmach/map.c
-//
-// http://code.swtch.com/plan9port/src/tip/src/libmach/map.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/map.c
-//
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.
-//	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth at 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 © 2001-2007 Russ Cox.
-//	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.
-
-/*
- * file map routines
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-Map *
-newmap(Map *map, int n)
-{
-	int size;
-
-	size = sizeof(Map)+(n-1)*sizeof(Seg);
-	if (map == 0)
-		map = malloc(size);
-	else
-		map = realloc(map, size);
-	if (map == 0) {
-		werrstr("out of memory: %r");
-		return 0;
-	}
-	memset(map, 0, size);
-	map->nsegs = n;
-	return map;
-}
-
-int
-setmap(Map *map, int fd, uvlong b, uvlong e, vlong f, char *name, Maprw *rw)
-{
-	int i;
-
-	if (map == 0)
-		return 0;
-	for (i = 0; i < map->nsegs; i++)
-		if (!map->seg[i].inuse)
-			break;
-	if (i >= map->nsegs)
-		return 0;
-	map->seg[i].b = b;
-	map->seg[i].e = e;
-	map->seg[i].f = f;
-	map->seg[i].inuse = 1;
-	map->seg[i].name = name;
-	map->seg[i].fd = fd;
-	map->seg[i].rw = rw;
-	return 1;
-}
-
-/*
-static uvlong
-stacktop(int pid)
-{
-	char buf[64];
-	int fd;
-	int n;
-	char *cp;
-
-	snprint(buf, sizeof(buf), "/proc/%d/segment", pid);
-	fd = open(buf, 0);
-	if (fd < 0)
-		return 0;
-	n = read(fd, buf, sizeof(buf)-1);
-	close(fd);
-	buf[n] = 0;
-	if (strncmp(buf, "Stack", 5))
-		return 0;
-	for (cp = buf+5; *cp && *cp == ' '; cp++)
-		;
-	if (!*cp)
-		return 0;
-	cp = strchr(cp, ' ');
-	if (!cp)
-		return 0;
-	while (*cp && *cp == ' ')
-		cp++;
-	if (!*cp)
-		return 0;
-	return strtoull(cp, 0, 16);
-}
-*/
-
-int
-findseg(Map *map, char *name)
-{
-	int i;
-
-	if (!map)
-		return -1;
-	for (i = 0; i < map->nsegs; i++)
-		if (map->seg[i].inuse && !strcmp(map->seg[i].name, name))
-			return i;
-	return -1;
-}
-
-void
-unusemap(Map *map, int i)
-{
-	if (map != 0 && 0 <= i && i < map->nsegs)
-		map->seg[i].inuse = 0;
-}
-
-int
-fdrw(Map *map, Seg *s, uvlong addr, void *v, uint n, int isread)
-{
-	int tot, m;
-	
-	USED(map);
-
-	for(tot=0; tot<n; tot+=m){
-		if(isread)
-			m = pread(s->fd, (uchar*)v+tot, n-tot, addr+tot);
-		else
-			m = pwrite(s->fd, (uchar*)v+tot, n-tot, addr+tot);
-		if(m == 0){
-			werrstr("short %s", isread ? "read" : "write");
-			return -1;
-		}
-		if(m < 0){
-			werrstr("%s %d at %#llux (+%#llux): %r", isread ? "read" : "write", n, addr, s->f);
-			return -1;
-		}
-	}
-	return 0;
-}
-
-
-Map*
-loadmap(Map *map, int fd, Fhdr *fp)
-{
-	map = newmap(map, 2);
-	if (map == 0)
-		return 0;
-
-	map->seg[0].b = fp->txtaddr;
-	map->seg[0].e = fp->txtaddr+fp->txtsz;
-	map->seg[0].f = fp->txtoff;
-	map->seg[0].fd = fd;
-	map->seg[0].inuse = 1;
-	map->seg[0].name = "text";
-	map->seg[0].rw = fdrw;
-	map->seg[1].b = fp->dataddr;
-	map->seg[1].e = fp->dataddr+fp->datsz;
-	map->seg[1].f = fp->datoff;
-	map->seg[1].fd = fd;
-	map->seg[1].inuse = 1;
-	map->seg[1].name = "data";
-	map->seg[0].rw = fdrw;
-	return map;
-}
diff --git a/src/libmach/netbsd.c b/src/libmach/netbsd.c
deleted file mode 100644
index adeeff3..0000000
--- a/src/libmach/netbsd.c
+++ /dev/null
@@ -1,56 +0,0 @@
-// This is stubbed out for the moment. Will revisit when the time comes.
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-int
-ctlproc(int pid, char *msg)
-{
-	USED(pid);
-	USED(msg);
-	sysfatal("ctlproc unimplemented in NetBSD");
-	return -1;
-}
-
-char*
-proctextfile(int pid)
-{
-	USED(pid);
-	sysfatal("proctextfile unimplemented in NetBSD");
-	return nil;
-}
-
-char*
-procstatus(int pid)
-{
-	USED(pid);
-	sysfatal("procstatus unimplemented in NetBSD");
-	return nil;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
-	USED(pid);
-	USED(fp);
-	sysfatal("attachproc unimplemented in NetBSD");
-	return nil;
-}
-
-void
-detachproc(Map *m)
-{
-	USED(m);
-	sysfatal("detachproc unimplemented in NetBSD");
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
-	USED(pid);
-	USED(p);
-	USED(np);
-	sysfatal("procthreadpids unimplemented in NetBSD");
-	return -1;
-}
diff --git a/src/libmach/obj.c b/src/libmach/obj.c
deleted file mode 100644
index 729a3ea..0000000
--- a/src/libmach/obj.c
+++ /dev/null
@@ -1,393 +0,0 @@
-// Inferno libmach/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/obj.c
-//
-// 	Copyright © 1994-1999 Lucent Technologies Inc.
-// 	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth at 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.
-
-/*
- * obj.c
- * routines universal to all object files
- */
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <ar.h>
-#include <mach.h>
-#include "obj.h"
-
-#define islocal(t)	((t)=='a' || (t)=='p')
-
-enum
-{
-	NNAMES	= 50,
-	MAXIS	= 8,		/* max length to determine if a file is a .? file */
-	MAXOFF	= 0x7fffffff,	/* larger than any possible local offset */
-	NHASH	= 1024,		/* must be power of two */
-	HASHMUL	= 79L,
-};
-
-int	_is2(char*),		/* in [$OS].c */
-	_is5(char*),
-	_is6(char*),
-	_is7(char*),
-	_is8(char*),
-	_is9(char*),
-	_isk(char*),
-	_isq(char*),
-	_isv(char*),
-	_isu(char*),
-	_read2(Biobuf*, Prog*),
-	_read5(Biobuf*, Prog*),
-	_read6(Biobuf*, Prog*),
-	_read7(Biobuf*, Prog*),
-	_read8(Biobuf*, Prog*),
-	_read9(Biobuf*, Prog*),
-	_readk(Biobuf*, Prog*),
-	_readq(Biobuf*, Prog*),
-	_readv(Biobuf*, Prog*),
-	_readu(Biobuf*, Prog*);
-
-typedef struct Obj	Obj;
-typedef struct Symtab	Symtab;
-
-struct	Obj		/* functions to handle each intermediate (.$O) file */
-{
-	char	*name;				/* name of each $O file */
-	int	(*is)(char*);			/* test for each type of $O file */
-	int	(*read)(Biobuf*, Prog*);	/* read for each type of $O file*/
-};
-
-static Obj	obj[] =
-{			/* functions to identify and parse each type of obj */
-	[Obj68020]   = { "68020 .2",	_is2, _read2 },
-	[ObjAmd64]   = { "amd64 .6",	_is6 , _read6 },
-	[ObjArm]     = { "arm .5",	_is5, _read5 },
-	[ObjAlpha]   = { "alpha .7",	_is7, _read7 },
-	[Obj386]     = { "386 .8",	_is8, _read8 },
-	[ObjSparc]   = { "sparc .k",	_isk, _readk },
-	[ObjPower]   = { "power .q",	_isq, _readq },
-	[ObjMips]    = { "mips .v",	_isv, _readv },
-	[ObjSparc64] = { "sparc64 .u",  _isu, _readu },
-	[ObjPower64] = { "power64 .9",	_is9, _read9 },
-	[Maxobjtype] = { 0, 0, 0 }
-};
-
-struct	Symtab
-{
-	struct	Sym 	s;
-	struct	Symtab	*next;
-};
-
-static	Symtab *hash[NHASH];
-static	Sym	*names[NNAMES];	/* working set of active names */
-
-static	int	processprog(Prog*,int);	/* decode each symbol reference */
-static	void	objreset(void);
-static	void	objlookup(int, char *, int, uint);
-static	void 	objupdate(int, int);
-
-static	int	sequence;
-
-int
-objtype(Biobuf *bp, char **name)
-{
-	int i;
-	char buf[MAXIS];
-	int c;
-	char *p;
-
-	/*
-	 * Look for import block.
-	 */
-	p = Brdline(bp, '\n');
-	if(p == nil)
-		return -1;
-	if(Blinelen(bp) < 10 || strncmp(p, "go object ", 10) != 0)
-		return -1;
-	Bseek(bp, -1, 1);
-
-	/*
-	 * Found one.  Skip until "\n!\n"
-	 */
-	for(;;) {
-		if((c = BGETC(bp)) == Beof)
-			return -1;
-		if(c != '\n')
-			continue;
-		c = BGETC(bp);
-		if(c != '!'){
-			Bungetc(bp);
-			continue;
-		}
-		c = BGETC(bp);
-		if(c != '\n'){
-			Bungetc(bp);
-			continue;
-		}
-		break;
-	}
-
-	if(Bread(bp, buf, MAXIS) < MAXIS)
-		return -1;
-	Bseek(bp, -MAXIS, 1);
-	for (i = 0; i < Maxobjtype; i++) {
-		if (obj[i].is && (*obj[i].is)(buf)) {
-			if (name)
-				*name = obj[i].name;
-			return i;
-		}
-	}
-
-	return -1;
-}
-
-int
-isar(Biobuf *bp)
-{
-	int n;
-	char magbuf[SARMAG];
-
-	n = Bread(bp, magbuf, SARMAG);
-	if(n == SARMAG && strncmp(magbuf, ARMAG, SARMAG) == 0)
-		return 1;
-	return 0;
-}
-
-/*
- * determine what kind of object file this is and process it.
- * return whether or not this was a recognized intermediate file.
- */
-int
-readobj(Biobuf *bp, int objtype)
-{
-	Prog p;
-
-	if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0)
-		return 1;
-	objreset();
-	while ((*obj[objtype].read)(bp, &p))
-		if (!processprog(&p, 1))
-			return 0;
-	return 1;
-}
-
-int
-readar(Biobuf *bp, int objtype, vlong end, int doautos)
-{
-	Prog p;
-
-	if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0)
-		return 1;
-	objreset();
-	while ((*obj[objtype].read)(bp, &p) && Boffset(bp) < end)
-		if (!processprog(&p, doautos))
-			return 0;
-	return 1;
-}
-
-/*
- *	decode a symbol reference or definition
- */
-static	int
-processprog(Prog *p, int doautos)
-{
-	if(p->kind == aNone)
-		return 1;
-	if((schar)p->sym < 0 || p->sym >= NNAMES)
-		return 0;
-	switch(p->kind)
-	{
-	case aName:
-		if (!doautos)
-		if(p->type != 'U' && p->type != 'b')
-			break;
-		objlookup(p->sym, p->id, p->type, p->sig);
-		break;
-	case aText:
-		objupdate(p->sym, 'T');
-		break;
-	case aData:
-		objupdate(p->sym, 'D');
-		break;
-	default:
-		break;
-	}
-	return 1;
-}
-
-/*
- * find the entry for s in the symbol array.
- * make a new entry if it is not already there.
- */
-static void
-objlookup(int id, char *name, int type, uint sig)
-{
-	uint32 h;
-	char *cp;
-	Sym *s;
-	Symtab *sp;
-
-	s = names[id];
-	if(s && strcmp(s->name, name) == 0) {
-		s->type = type;
-		s->sig = sig;
-		return;
-	}
-
-	h = *name;
-	for(cp = name+1; *cp; h += *cp++)
-		h *= HASHMUL;
-	h &= NHASH-1;
-	if (type == 'U' || type == 'b' || islocal(type)) {
-		for(sp = hash[h]; sp; sp = sp->next)
-			if(strcmp(sp->s.name, name) == 0) {
-				switch(sp->s.type) {
-				case 'T':
-				case 'D':
-				case 'U':
-					if (type == 'U') {
-						names[id] = &sp->s;
-						return;
-					}
-					break;
-				case 't':
-				case 'd':
-				case 'b':
-					if (type == 'b') {
-						names[id] = &sp->s;
-						return;
-					}
-					break;
-				case 'a':
-				case 'p':
-					if (islocal(type)) {
-						names[id] = &sp->s;
-						return;
-					}
-					break;
-				default:
-					break;
-				}
-			}
-	}
-	sp = malloc(sizeof(Symtab));
-	if(sp == nil)
-		sysfatal("out of memory");
-	sp->s.name = name;
-	sp->s.type = type;
-	sp->s.sig = sig;
-	sp->s.value = islocal(type) ? MAXOFF : 0;
-	sp->s.sequence = sequence++;
-	names[id] = &sp->s;
-	sp->next = hash[h];
-	hash[h] = sp;
-	return;
-}
-/*
- *	traverse the symbol lists
- */
-void
-objtraverse(void (*fn)(Sym*, void*), void *pointer)
-{
-	int i;
-	Symtab *s;
-
-	for(i = 0; i < NHASH; i++)
-		for(s = hash[i]; s; s = s->next)
-			(*fn)(&s->s, pointer);
-}
-
-/*
- * update the offset information for a 'a' or 'p' symbol in an intermediate file
- */
-void
-_offset(int id, vlong off)
-{
-	Sym *s;
-
-	s = names[id];
-	if (s && s->name[0] && islocal(s->type) && s->value > off)
-		s->value = off;
-}
-
-/*
- * update the type of a global text or data symbol
- */
-static void
-objupdate(int id, int type)
-{
-	Sym *s;
-
-	s = names[id];
-	if (s && s->name[0])
-		if (s->type == 'U')
-			s->type = type;
-		else if (s->type == 'b')
-			s->type = tolower(type);
-}
-
-/*
- * look for the next file in an archive
- */
-int
-nextar(Biobuf *bp, int offset, char *buf)
-{
-	struct ar_hdr a;
-	int i, r;
-	int32 arsize;
-
-	if (offset&01)
-		offset++;
-	Bseek(bp, offset, 0);
-	r = Bread(bp, &a, SAR_HDR);
-	if(r != SAR_HDR)
-		return 0;
-	if(strncmp(a.fmag, ARFMAG, sizeof(a.fmag)))
-		return -1;
-	for(i=0; i<sizeof(a.name) && i<SARNAME && a.name[i] != ' '; i++)
-		buf[i] = a.name[i];
-	buf[i] = 0;
-	arsize = strtol(a.size, 0, 0);
-	if (arsize&1)
-		arsize++;
-	return arsize + SAR_HDR;
-}
-
-static void
-objreset(void)
-{
-	int i;
-	Symtab *s, *n;
-
-	for(i = 0; i < NHASH; i++) {
-		for(s = hash[i]; s; s = n) {
-			n = s->next;
-			free(s->s.name);
-			free(s);
-		}
-		hash[i] = 0;
-	}
-	memset(names, 0, sizeof names);
-}
diff --git a/src/libmach/obj.h b/src/libmach/obj.h
deleted file mode 100644
index 35ec413..0000000
--- a/src/libmach/obj.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Inferno libmach/obj.h
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/obj.h
-//
-// 	Copyright © 1994-1999 Lucent Technologies Inc.
-// 	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth at 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.
-
-/*
- * obj.h -- defs for dealing with object files
- */
-
-typedef enum Kind		/* variable defs and references in obj */
-{
-	aNone,			/* we don't care about this prog */
-	aName,			/* introduces a name */
-	aText,			/* starts a function */
-	aData,			/* references to a global object */
-} Kind;
-
-typedef struct	Prog	Prog;
-
-struct Prog		/* info from .$O files */
-{
-	Kind	kind;		/* what kind of symbol */
-	char	type;		/* type of the symbol: ie, 'T', 'a', etc. */
-	char	sym;		/* index of symbol's name */
-	char	*id;		/* name for the symbol, if it introduces one */
-	uint	sig;		/* type signature for symbol */
-};
-
-#define UNKNOWN	'?'
-void		_offset(int, vlong);
diff --git a/src/libmach/openbsd.c b/src/libmach/openbsd.c
deleted file mode 100644
index ace8a22..0000000
--- a/src/libmach/openbsd.c
+++ /dev/null
@@ -1,56 +0,0 @@
-// This is stubbed out for the moment. Will revisit when the time comes.
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-int
-ctlproc(int pid, char *msg)
-{
-	USED(pid);
-	USED(msg);
-	sysfatal("ctlproc unimplemented in OpenBSD");
-	return -1;
-}
-
-char*
-proctextfile(int pid)
-{
-	USED(pid);
-	sysfatal("proctextfile unimplemented in OpenBSD");
-	return nil;
-}
-
-char*
-procstatus(int pid)
-{
-	USED(pid);
-	sysfatal("procstatus unimplemented in OpenBSD");
-	return nil;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
-	USED(pid);
-	USED(fp);
-	sysfatal("attachproc unimplemented in OpenBSD");
-	return nil;
-}
-
-void
-detachproc(Map *m)
-{
-	USED(m);
-	sysfatal("detachproc unimplemented in OpenBSD");
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
-	USED(pid);
-	USED(p);
-	USED(np);
-	sysfatal("procthreadpids unimplemented in OpenBSD");
-	return -1;
-}
diff --git a/src/libmach/plan9.c b/src/libmach/plan9.c
deleted file mode 100644
index 59e2649..0000000
--- a/src/libmach/plan9.c
+++ /dev/null
@@ -1,72 +0,0 @@
-// This is stubbed out for the moment. Will revisit when the time comes.
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-int
-ctlproc(int pid, char *msg)
-{
-	USED(pid);
-	USED(msg);
-
-	sysfatal("ctlproc unimplemented on Plan 9");
-	return -1;
-}
-
-char*
-proctextfile(int pid)
-{
-	USED(pid);
-
-	sysfatal("proctextfile unimplemented on Plan 9");
-	return nil;
-}
-
-char*
-procstatus(int pid)
-{
-	USED(pid);
-
-	sysfatal("procstatus unimplemented on Plan 9");
-	return nil;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
-	USED(pid);
-	USED(fp);
-
-	sysfatal("attachproc unimplemented on Plan 9");
-	return nil;
-}
-
-void
-detachproc(Map *m)
-{
-	USED(m);
-
-	sysfatal("detachproc unimplemented on Plan 9");
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
-	USED(pid);
-	USED(p);
-	USED(np);
-
-	sysfatal("procthreadpids unimplemented on Plan 9");
-	return -1;
-}
-
-int 
-nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
-{
-	USED(rqtp);
-	USED(rmtp);
-
-	sysfatal("nanosleep unimplemented on Plan 9");
-	return -1;
-}
diff --git a/src/libmach/setmach.c b/src/libmach/setmach.c
deleted file mode 100644
index 0fa4d31..0000000
--- a/src/libmach/setmach.c
+++ /dev/null
@@ -1,203 +0,0 @@
-// Inferno libmach/setmach.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/setmach.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.
-//	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth at 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.
-
-#include	<u.h>
-#include	<libc.h>
-#include	<bio.h>
-#include	<mach.h>
-		/* table for selecting machine-dependent parameters */
-
-typedef	struct machtab Machtab;
-
-struct machtab
-{
-	char		*name;			/* machine name */
-	short		type;			/* executable type */
-	short		boottype;		/* bootable type */
-	int		asstype;		/* disassembler code */
-	Mach		*mach;			/* machine description */
-	Machdata	*machdata;		/* machine functions */
-};
-
-/*
-extern	Mach		mmips, msparc, m68020, mi386, mamd64,
-			marm, mmips2be, mmips2le, mpower, mpower64, malpha, msparc64;
-extern	Machdata	mipsmach, sparcmach, m68020mach, i386mach,
-			armmach, mipsmach2le, powermach, alphamach, sparc64mach;
-*/
-extern	Mach		mi386, mamd64, marm;
-extern	Machdata		i386mach, armmach;
-
-/*
- *	machine selection table.  machines with native disassemblers should
- *	follow the plan 9 variant in the table; native modes are selectable
- *	only by name.
- */
-Machtab	machines[] =
-{
-	{	"386",				/*plan 9 386*/
-		FI386,
-		FI386B,
-		AI386,
-		&mi386,
-		&i386mach,	},
-	{	"amd64",			/*amd64*/
-		FAMD64,
-		FAMD64B,
-		AAMD64,
-		&mamd64,
-		&i386mach,	},
-	{	"arm",				/*ARM*/
-		FARM,
-		FARMB,
-		AARM,
-		&marm,
-		&armmach,	},
-#ifdef unused
-	{	"68020",			/*68020*/
-		F68020,
-		F68020B,
-		A68020,
-		&m68020,
-		&m68020mach,	},
-	{	"68020",			/*Next 68040 bootable*/
-		F68020,
-		FNEXTB,
-		A68020,
-		&m68020,
-		&m68020mach,	},
-	{	"mips2LE",			/*plan 9 mips2 little endian*/
-		FMIPS2LE,
-		0,
-		AMIPS,
-		&mmips2le,
-		&mipsmach2le, 	},
-	{	"mips",				/*plan 9 mips*/
-		FMIPS,
-		FMIPSB,
-		AMIPS,
-		&mmips,
-		&mipsmach, 	},
-	{	"mips2",			/*plan 9 mips2*/
-		FMIPS2BE,
-		FMIPSB,
-		AMIPS,
-		&mmips2be,
-		&mipsmach, 	},		/* shares debuggers with native mips */
-	{	"mipsco",			/*native mips - must follow plan 9*/
-		FMIPS,
-		FMIPSB,
-		AMIPSCO,
-		&mmips,
-		&mipsmach,	},
-	{	"sparc",			/*plan 9 sparc */
-		FSPARC,
-		FSPARCB,
-		ASPARC,
-		&msparc,
-		&sparcmach,	},
-	{	"sunsparc",			/*native sparc - must follow plan 9*/
-		FSPARC,
-		FSPARCB,
-		ASUNSPARC,
-		&msparc,
-		&sparcmach,	},
-	{	"86",				/*8086 - a peach of a machine*/
-		FI386,
-		FI386B,
-		AI8086,
-		&mi386,
-		&i386mach,	},
-	{	"power",			/*PowerPC*/
-		FPOWER,
-		FPOWERB,
-		APOWER,
-		&mpower,
-		&powermach,	},
-	{	"power64",			/*PowerPC*/
-		FPOWER64,
-		FPOWER64B,
-		APOWER64,
-		&mpower64,
-		&powermach,	},
-	{	"alpha",			/*Alpha*/
-		FALPHA,
-		FALPHAB,
-		AALPHA,
-		&malpha,
-		&alphamach,	},
-	{	"sparc64",			/*plan 9 sparc64 */
-		FSPARC64,
-		FSPARCB,			/* XXX? */
-		ASPARC64,
-		&msparc64,
-		&sparc64mach,	},
-#endif
-	{	0		},		/*the terminator*/
-};
-
-/*
- *	select a machine by executable file type
- */
-void
-machbytype(int type)
-{
-	Machtab *mp;
-
-	for (mp = machines; mp->name; mp++){
-		if (mp->type == type || mp->boottype == type) {
-			asstype = mp->asstype;
-			machdata = mp->machdata;
-			break;
-		}
-	}
-}
-/*
- *	select a machine by name
- */
-int
-machbyname(char *name)
-{
-	Machtab *mp;
-
-	if (!name) {
-		asstype = AAMD64;
-		machdata = &i386mach;
-		mach = &mamd64;
-		return 1;
-	}
-	for (mp = machines; mp->name; mp++){
-		if (strcmp(mp->name, name) == 0) {
-			asstype = mp->asstype;
-			machdata = mp->machdata;
-			mach = mp->mach;
-			return 1;
-		}
-	}
-	return 0;
-}
diff --git a/src/libmach/swap.c b/src/libmach/swap.c
deleted file mode 100644
index bc296a3..0000000
--- a/src/libmach/swap.c
+++ /dev/null
@@ -1,107 +0,0 @@
-// Inferno libmach/swap.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/swap.c
-//
-// 	Copyright © 1994-1999 Lucent Technologies Inc.
-// 	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth at 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.
-
-#include <u.h>
-
-/*
- * big-endian short
- */
-ushort
-beswab(ushort s)
-{
-	uchar *p;
-
-	p = (uchar*)&s;
-	return (p[0]<<8) | p[1];
-}
-
-/*
- * big-endian int32
- */
-uint32
-beswal(uint32 l)
-{
-	uchar *p;
-
-	p = (uchar*)&l;
-	return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
-}
-
-/*
- * big-endian vlong
- */
-uvlong
-beswav(uvlong v)
-{
-	uchar *p;
-
-	p = (uchar*)&v;
-	return ((uvlong)p[0]<<56) | ((uvlong)p[1]<<48) | ((uvlong)p[2]<<40)
-				  | ((uvlong)p[3]<<32) | ((uvlong)p[4]<<24)
-				  | ((uvlong)p[5]<<16) | ((uvlong)p[6]<<8)
-				  | (uvlong)p[7];
-}
-
-/*
- * little-endian short
- */
-ushort
-leswab(ushort s)
-{
-	uchar *p;
-
-	p = (uchar*)&s;
-	return (p[1]<<8) | p[0];
-}
-
-/*
- * little-endian int32
- */
-uint32
-leswal(uint32 l)
-{
-	uchar *p;
-
-	p = (uchar*)&l;
-	return (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0];
-}
-
-/*
- * little-endian vlong
- */
-uvlong
-leswav(uvlong v)
-{
-	uchar *p;
-
-	p = (uchar*)&v;
-	return ((uvlong)p[7]<<56) | ((uvlong)p[6]<<48) | ((uvlong)p[5]<<40)
-				  | ((uvlong)p[4]<<32) | ((uvlong)p[3]<<24)
-				  | ((uvlong)p[2]<<16) | ((uvlong)p[1]<<8)
-				  | (uvlong)p[0];
-}
diff --git a/src/libmach/sym.c b/src/libmach/sym.c
deleted file mode 100644
index 474cc0c..0000000
--- a/src/libmach/sym.c
+++ /dev/null
@@ -1,1883 +0,0 @@
-// Inferno libmach/sym.c
-// http://code.google.com/p/inferno-os/source/browse/utils/libmach/sym.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.
-//	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth at 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.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-#define	HUGEINT	0x7fffffff
-#define	NNAME	20		/* a relic of the past */
-
-typedef	struct txtsym Txtsym;
-typedef	struct file File;
-typedef	struct hist Hist;
-
-struct txtsym {				/* Text Symbol table */
-	int 	n;			/* number of local vars */
-	Sym	**locals;		/* array of ptrs to autos */
-	Sym	*sym;			/* function symbol entry */
-};
-
-struct hist {				/* Stack of include files & #line directives */
-	char	*name;			/* Assumes names Null terminated in file */
-	int32	line;			/* line # where it was included */
-	int32	offset;			/* line # of #line directive */
-};
-
-struct file {				/* Per input file header to history stack */
-	uvlong	addr;			/* address of first text sym */
-	union {
-		Txtsym	*txt;		/* first text symbol */
-		Sym	*sym;		/* only during initilization */
-	};
-	int	n;			/* size of history stack */
-	Hist	*hist;			/* history stack */
-};
-
-static	int	debug = 0;
-
-static	Sym	**autos;		/* Base of auto variables */
-static	File	*files;			/* Base of file arena */
-static	int	fmaxi;			/* largest file path index */
-static	Sym	**fnames;		/* file names path component table */
-static	Sym	**globals;		/* globals by addr table */
-static	Hist	*hist;			/* base of history stack */
-static	int	isbuilt;		/* internal table init flag */
-static	int32	nauto;			/* number of automatics */
-static	int32	nfiles;			/* number of files */
-static	int32	nglob;			/* number of globals */
-static	int32	nhist;			/* number of history stack entries */
-static	int32	nsym;			/* number of symbols */
-static	int	ntxt;			/* number of text symbols */
-static	uchar	*pcline;		/* start of pc-line state table */
-static	uchar 	*pclineend;		/* end of pc-line table */
-static	uchar	*spoff;			/* start of pc-sp state table */
-static	uchar	*spoffend;		/* end of pc-sp offset table */
-static	Sym	*symbols;		/* symbol table */
-static	Txtsym	*txt;			/* Base of text symbol table */
-static	uvlong	txtstart;		/* start of text segment */
-static	uvlong	txtend;			/* end of text segment */
-static	uvlong	firstinstr;		/* as found from symtab; needed for amd64 */
-
-static void	cleansyms(void);
-static int32	decodename(Biobuf*, Sym*);
-static short	*encfname(char*);
-static int 	fline(char*, int, int32, Hist*, Hist**);
-static void	fillsym(Sym*, Symbol*);
-static int	findglobal(char*, Symbol*);
-static int	findlocvar(Symbol*, char *, Symbol*);
-static int	findtext(char*, Symbol*);
-static int	hcomp(Hist*, short*);
-static int	hline(File*, short*, int32*);
-static void	printhist(char*, Hist*, int);
-static int	buildtbls(void);
-static int	symcomp(const void*, const void*);
-static int	symerrmsg(int, char*);
-static int	txtcomp(const void*, const void*);
-static int	filecomp(const void*, const void*);
-
-/*
- * Go 1.2 pcln table (also contains pcsp).
- */
-#define Go12PclnMagic 0xfffffffb
-#define Go12PclnMagicRev 0xfbffffff
-static int	isgo12pcline(void);
-static uvlong go12pc2sp(uvlong);
-static int32 go12fileline(char*, int, uvlong);
-static void	go12clean(void);
-static uvlong go12file2pc(char*, int);
-
-/*
- *	initialize the symbol tables
- */
-int
-syminit(int fd, Fhdr *fp)
-{
-	Sym *p;
-	int32 i, l, size, symsz;
-	vlong vl;
-	Biobuf b;
-	int svalsz, newformat, shift;
-	uvlong (*swav)(uvlong);
-	uint32 (*swal)(uint32);
-	uchar buf[8], c;
-
-	if(fp->symsz == 0)
-		return 0;
-	if(fp->type == FNONE)
-		return 0;
-
-	swav = beswav;
-	swal = beswal;
-
-	cleansyms();
-	textseg(fp->txtaddr, fp);
-		/* minimum symbol record size = 4+1+2 bytes */
-	symbols = malloc((fp->symsz/(4+1+2)+1)*sizeof(Sym));
-	if(symbols == 0) {
-		werrstr("can't malloc %d bytes", fp->symsz);
-		return -1;
-	}
-	Binit(&b, fd, OREAD);
-	Bseek(&b, fp->symoff, 0);
-	memset(buf, 0, sizeof buf);
-	Bread(&b, buf, sizeof buf);
-	newformat = 0;
-	symsz = fp->symsz;
-	if(memcmp(buf, "\xfd\xff\xff\xff\x00\x00\x00", 7) == 0) {
-		swav = leswav;
-		swal = leswal;
-		newformat = 1;
-	} else if(memcmp(buf, "\xff\xff\xff\xfd\x00\x00\x00", 7) == 0) {
-		newformat = 1;
-	} else if(memcmp(buf, "\xfe\xff\xff\xff\x00\x00", 6) == 0) {
-		// Table format used between Go 1.0 and Go 1.1:
-		// little-endian but otherwise same as the old Go 1.0 table.
-		// Not likely to be seen much in practice, but easy to handle.
-		swav = leswav;
-		swal = leswal;
-		Bseek(&b, fp->symoff+6, 0);
-		symsz -= 6;
-	} else {
-		Bseek(&b, fp->symoff, 0);
-	}
-	svalsz = 0;
-	if(newformat) {
-		svalsz = buf[7];
-		if(svalsz != 4 && svalsz != 8) {
-			werrstr("invalid word size %d bytes", svalsz);
-			return -1;
-		}
-		symsz -= 8;
-	}
-
-	nsym = 0;
-	size = 0;
-	for(p = symbols; size < symsz; p++, nsym++) {
-		if(newformat) {
-			// Go 1.1 format. See comment at top of ../pkg/runtime/symtab.c.
-			if(Bread(&b, &c, 1) != 1)
-				return symerrmsg(1, "symbol");
-			if((c&0x3F) < 26)
-				p->type = (c&0x3F)+ 'A';
-			else
-				p->type = (c&0x3F) - 26 + 'a';
-			size++;
-
-			if(c&0x40) {
-				// Fixed-width address.
-				if(svalsz == 8) {
-					if(Bread(&b, &vl, 8) != 8)
-						return symerrmsg(8, "symbol");
-					p->value = swav(vl);
-				} else {
-					if(Bread(&b, &l, 4) != 4)
-						return symerrmsg(4, "symbol");
-					p->value = (u32int)swal(l);
-				}
-				size += svalsz;
-			} else {
-				// Varint address.
-				shift = 0;
-				p->value = 0;
-				for(;;) {
-					if(Bread(&b, buf, 1) != 1)
-						return symerrmsg(1, "symbol");
-					p->value |= (uint64)(buf[0]&0x7F)<<shift;
-					shift += 7;
-					size++;
-					if((buf[0]&0x80) == 0)
-						break;
-				}
-			}
-			p->gotype = 0;
-			if(c&0x80) {
-				// Has Go type. Fixed-width address.
-				if(svalsz == 8) {
-					if(Bread(&b, &vl, 8) != 8)
-						return symerrmsg(8, "symbol");
-					p->gotype = swav(vl);
-				} else {
-					if(Bread(&b, &l, 4) != 4)
-						return symerrmsg(4, "symbol");
-					p->gotype = (u32int)swal(l);
-				}
-				size += svalsz;
-			}
-			
-			// Name.
-			p->type |= 0x80; // for decodename
-			i = decodename(&b, p);
-			if(i < 0)
-				return -1;
-			size += i;
-		} else {
-			// Go 1.0 format: Plan 9 format + go type symbol.
-			if(fp->_magic && (fp->magic & HDR_MAGIC)){
-				svalsz = 8;
-				if(Bread(&b, &vl, 8) != 8)
-					return symerrmsg(8, "symbol");
-				p->value = swav(vl);
-			}
-			else{
-				svalsz = 4;
-				if(Bread(&b, &l, 4) != 4)
-					return symerrmsg(4, "symbol");
-				p->value = (u32int)swal(l);
-			}
-			if(Bread(&b, &p->type, sizeof(p->type)) != sizeof(p->type))
-				return symerrmsg(sizeof(p->value), "symbol");
-	
-			i = decodename(&b, p);
-			if(i < 0)
-				return -1;
-			size += i+svalsz+sizeof(p->type);
-	
-			if(svalsz == 8){
-				if(Bread(&b, &vl, 8) != 8)
-					return symerrmsg(8, "symbol");
-				p->gotype = swav(vl);
-			}
-			else{
-				if(Bread(&b, &l, 4) != 4)
-					return symerrmsg(4, "symbol");
-				p->gotype = (u32int)swal(l);
-			}
-			size += svalsz;
-		}
-
-		/* count global & auto vars, text symbols, and file names */
-		switch (p->type) {
-		case 'l':
-		case 'L':
-		case 't':
-		case 'T':
-			ntxt++;
-			break;
-		case 'd':
-		case 'D':
-		case 'b':
-		case 'B':
-			nglob++;
-			break;
-		case 'f':
-			if(strcmp(p->name, ".frame") == 0) {
-				p->type = 'm';
-				nauto++;
-			}
-			else if(p->value > fmaxi)
-				fmaxi = p->value;	/* highest path index */
-			break;
-		case 'a':
-		case 'p':
-		case 'm':
-			nauto++;
-			break;
-		case 'z':
-			if(p->value == 1) {		/* one extra per file */
-				nhist++;
-				nfiles++;
-			}
-			nhist++;
-			break;
-		default:
-			break;
-		}
-	}
-	if (debug)
-		print("NG: %d NT: %d NF: %d\n", nglob, ntxt, fmaxi);
-	if (fp->sppcsz) {			/* pc-sp offset table */
-		spoff = (uchar *)malloc(fp->sppcsz);
-		if(spoff == 0) {
-			werrstr("can't malloc %d bytes", fp->sppcsz);
-			return -1;
-		}
-		Bseek(&b, fp->sppcoff, 0);
-		if(Bread(&b, spoff, fp->sppcsz) != fp->sppcsz){
-			spoff = 0;
-			return symerrmsg(fp->sppcsz, "sp-pc");
-		}
-		spoffend = spoff+fp->sppcsz;
-	}
-	if (fp->lnpcsz) {			/* pc-line number table */
-		pcline = (uchar *)malloc(fp->lnpcsz);
-		if(pcline == 0) {
-			werrstr("can't malloc %d bytes", fp->lnpcsz);
-			return -1;
-		}
-		Bseek(&b, fp->lnpcoff, 0);
-		if(Bread(&b, pcline, fp->lnpcsz) != fp->lnpcsz){
-			pcline = 0;
-			return symerrmsg(fp->lnpcsz, "pc-line");
-		}
-		pclineend = pcline+fp->lnpcsz;
-	}
-	return nsym;
-}
-
-static int
-symerrmsg(int n, char *table)
-{
-	werrstr("can't read %d bytes of %s table", n, table);
-	return -1;
-}
-
-static int32
-decodename(Biobuf *bp, Sym *p)
-{
-	char *cp;
-	int c1, c2;
-	int32 n;
-	vlong o;
-
-	if((p->type & 0x80) == 0) {		/* old-style, fixed length names */
-		p->name = malloc(NNAME);
-		if(p->name == 0) {
-			werrstr("can't malloc %d bytes", NNAME);
-			return -1;
-		}
-		if(Bread(bp, p->name, NNAME) != NNAME)
-			return symerrmsg(NNAME, "symbol");
-		Bseek(bp, 3, 1);
-		return NNAME+3;
-	}
-
-	p->type &= ~0x80;
-	if(p->type == 'z' || p->type == 'Z') {
-		o = Bseek(bp, 0, 1);
-		if(BGETC(bp) < 0) {
-			werrstr("can't read symbol name");
-			return -1;
-		}
-		for(;;) {
-			c1 = BGETC(bp);
-			c2 = BGETC(bp);
-			if(c1 < 0 || c2 < 0) {
-				werrstr("can't read symbol name");
-				return -1;
-			}
-			if(c1 == 0 && c2 == 0)
-				break;
-		}
-		n = Bseek(bp, 0, 1)-o;
-		p->name = malloc(n);
-		if(p->name == 0) {
-			werrstr("can't malloc %d bytes", n);
-			return -1;
-		}
-		Bseek(bp, -n, 1);
-		if(Bread(bp, p->name, n) != n) {
-			werrstr("can't read %d bytes of symbol name", n);
-			return -1;
-		}
-	} else {
-		cp = Brdline(bp, '\0');
-		if(cp == 0) {
-			werrstr("can't read symbol name");
-			return -1;
-		}
-		n = Blinelen(bp);
-		p->name = malloc(n);
-		if(p->name == 0) {
-			werrstr("can't malloc %d bytes", n);
-			return -1;
-		}
-		strcpy(p->name, cp);
-	}
-	return n;
-}
-
-/*
- *	free any previously loaded symbol tables
- */
-static void
-cleansyms(void)
-{
-	if(globals)
-		free(globals);
-	globals = 0;
-	nglob = 0;
-	if(txt)
-		free(txt);
-	txt = 0;
-	ntxt = 0;
-	if(fnames)
-		free(fnames);
-	fnames = 0;
-	fmaxi = 0;
-
-	if(files)
-		free(files);
-	files = 0;
-	nfiles = 0;
-	if(hist)
-		free(hist);
-	hist = 0;
-	nhist = 0;
-	if(autos)
-		free(autos);
-	autos = 0;
-	nauto = 0;
-	isbuilt = 0;
-	if(symbols)
-		free(symbols);
-	symbols = 0;
-	nsym = 0;
-	if(spoff)
-		free(spoff);
-	spoff = 0;
-	if(pcline)
-		free(pcline);
-	pcline = 0;
-	go12clean();
-}
-
-/*
- *	delimit the text segment
- */
-void
-textseg(uvlong base, Fhdr *fp)
-{
-	txtstart = base;
-	txtend = base+fp->txtsz;
-}
-
-/*
- *	symbase: return base and size of raw symbol table
- *		(special hack for high access rate operations)
- */
-Sym *
-symbase(int32 *n)
-{
-	*n = nsym;
-	return symbols;
-}
-
-/*
- *	Get the ith symbol table entry
- */
-Sym *
-getsym(int index)
-{
-	if(index >= 0 && index < nsym)
-		return &symbols[index];
-	return 0;
-}
-
-/*
- *	initialize internal symbol tables
- */
-static int
-buildtbls(void)
-{
-	int32 i;
-	int j, nh, ng, nt;
-	File *f;
-	Txtsym *tp;
-	Hist *hp;
-	Sym *p, **ap;
-
-	if(isbuilt)
-		return 1;
-	isbuilt = 1;
-			/* allocate the tables */
-	firstinstr = 0;
-	if(nglob) {
-		globals = malloc(nglob*sizeof(*globals));
-		if(!globals) {
-			werrstr("can't malloc global symbol table");
-			return 0;
-		}
-	}
-	if(ntxt) {
-		txt = malloc(ntxt*sizeof(*txt));
-		if (!txt) {
-			werrstr("can't malloc text symbol table");
-			return 0;
-		}
-	}
-	fnames = malloc((fmaxi+1)*sizeof(*fnames));
-	if (!fnames) {
-		werrstr("can't malloc file name table");
-		return 0;
-	}
-	memset(fnames, 0, (fmaxi+1)*sizeof(*fnames));
-	files = malloc(nfiles*sizeof(*files));
-	if(!files) {
-		werrstr("can't malloc file table");
-		return 0;
-	}
-	hist = malloc(nhist*sizeof(Hist));
-	if(hist == 0) {
-		werrstr("can't malloc history stack");
-		return 0;
-	}
-	autos = malloc(nauto*sizeof(Sym*));
-	if(autos == 0) {
-		werrstr("can't malloc auto symbol table");
-		return 0;
-	}
-		/* load the tables */
-	ng = nt = nh = 0;
-	f = 0;
-	tp = 0;
-	i = nsym;
-	hp = hist;
-	ap = autos;
-	for(p = symbols; i-- > 0; p++) {
-//print("sym %d type %c name %s value %llux\n", p-symbols, p->type, p->name, p->value);
-		switch(p->type) {
-		case 'D':
-		case 'd':
-		case 'B':
-		case 'b':
-			if(debug)
-				print("Global: %s %llux\n", p->name, p->value);
-			globals[ng++] = p;
-			break;
-		case 'z':
-			if(p->value == 1) {		/* New file */
-				if(f) {
-					f->n = nh;
-					f->hist[nh].name = 0;	/* one extra */
-					hp += nh+1;
-					f++;
-				}
-				else
-					f = files;
-				f->hist = hp;
-				f->sym = 0;
-				f->addr = 0;
-				nh = 0;
-			}
-				/* alloc one slot extra as terminator */
-			f->hist[nh].name = p->name;
-			f->hist[nh].line = p->value;
-			f->hist[nh].offset = 0;
-			if(debug)
-				printhist("-> ", &f->hist[nh], 1);
-			nh++;
-			break;
-		case 'Z':
-			if(f && nh > 0)
-				f->hist[nh-1].offset = p->value;
-			break;
-		case 'T':
-		case 't':	/* Text: terminate history if first in file */
-		case 'L':
-		case 'l':
-			tp = &txt[nt++];
-			tp->n = 0;
-			tp->sym = p;
-			tp->locals = ap;
-			if(debug)
-				print("TEXT: %s at %llux\n", p->name, p->value);
-			if (firstinstr == 0 || p->value < firstinstr)
-				firstinstr = p->value;
-			if(f && !f->sym) {			/* first  */
-				f->sym = p;
-				f->addr = p->value;
-			}
-			break;
-		case 'a':
-		case 'p':
-		case 'm':		/* Local Vars */
-			if(!tp)
-				print("Warning: Free floating local var: %s\n",
-					p->name);
-			else {
-				if(debug)
-					print("Local: %s %llux\n", p->name, p->value);
-				tp->locals[tp->n] = p;
-				tp->n++;
-				ap++;
-			}
-			break;
-		case 'f':		/* File names */
-			if(debug)
-				print("Fname: %s\n", p->name);
-			fnames[p->value] = p;
-			break;
-		default:
-			break;
-		}
-	}
-		/* sort global and text tables into ascending address order */
-	qsort(globals, nglob, sizeof(Sym*), symcomp);
-	qsort(txt, ntxt, sizeof(Txtsym), txtcomp);
-	qsort(files, nfiles, sizeof(File), filecomp);
-	tp = txt;
-	for(i = 0, f = files; i < nfiles; i++, f++) {
-		for(j = 0; j < ntxt; j++) {
-			if(f->sym == tp->sym) {
-				if(debug) {
-					print("LINK: %s to at %llux", f->sym->name, f->addr);
-					printhist("... ", f->hist, 1);
-				}
-				f->txt = tp++;
-				break;
-			}
-			if(++tp >= txt+ntxt)	/* wrap around */
-				tp = txt;
-		}
-	}
-	return 1;
-}
-
-/*
- * find symbol function.var by name.
- *	fn != 0 && var != 0	=> look for fn in text, var in data
- *	fn != 0 && var == 0	=> look for fn in text
- *	fn == 0 && var != 0	=> look for var first in text then in data space.
- */
-int
-lookup(char *fn, char *var, Symbol *s)
-{
-	int found;
-
-	if(buildtbls() == 0)
-		return 0;
-	if(fn) {
-		found = findtext(fn, s);
-		if(var == 0)		/* case 2: fn not in text */
-			return found;
-		else if(!found)		/* case 1: fn not found */
-			return 0;
-	} else if(var) {
-		found = findtext(var, s);
-		if(found)
-			return 1;	/* case 3: var found in text */
-	} else return 0;		/* case 4: fn & var == zero */
-
-	if(found)
-		return findlocal(s, var, s);	/* case 1: fn found */
-	return findglobal(var, s);		/* case 3: var not found */
-
-}
-
-/*
- * strcmp, but allow '_' to match center dot (rune 00b7 == bytes c2 b7)
- */
-int
-cdotstrcmp(char *sym, char *user)
-{
-	for (;;) {
-		while (*sym == *user) {
-			if (*sym++ == '\0')
-				return 0;
-			user++;
-		}
-		/* unequal - but maybe '_' matches center dot */
-		if (user[0] == '_' && (sym[0]&0xFF) == 0xc2 && (sym[1]&0xFF) == 0xb7) {
-			/* '_' matches center dot - advance and continue */
-			user++;
-			sym += 2;
-			continue;
-		}
-		break;
-	}
-	return *user - *sym;
-}
-
-/*
- * find a function by name
- */
-static int
-findtext(char *name, Symbol *s)
-{
-	int i;
-
-	for(i = 0; i < ntxt; i++) {
-		if(cdotstrcmp(txt[i].sym->name, name) == 0) {
-			fillsym(txt[i].sym, s);
-			s->handle = (void *) &txt[i];
-			s->index = i;
-			return 1;
-		}
-	}
-	return 0;
-}
-/*
- * find global variable by name
- */
-static int
-findglobal(char *name, Symbol *s)
-{
-	int32 i;
-
-	for(i = 0; i < nglob; i++) {
-		if(cdotstrcmp(globals[i]->name, name) == 0) {
-			fillsym(globals[i], s);
-			s->index = i;
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- *	find the local variable by name within a given function
- */
-int
-findlocal(Symbol *s1, char *name, Symbol *s2)
-{
-	if(s1 == 0)
-		return 0;
-	if(buildtbls() == 0)
-		return 0;
-	return findlocvar(s1, name, s2);
-}
-
-/*
- *	find the local variable by name within a given function
- *		(internal function - does no parameter validation)
- */
-static int
-findlocvar(Symbol *s1, char *name, Symbol *s2)
-{
-	Txtsym *tp;
-	int i;
-
-	tp = (Txtsym *)s1->handle;
-	if(tp && tp->locals) {
-		for(i = 0; i < tp->n; i++)
-			if (cdotstrcmp(tp->locals[i]->name, name) == 0) {
-				fillsym(tp->locals[i], s2);
-				s2->handle = (void *)tp;
-				s2->index = tp->n-1 - i;
-				return 1;
-			}
-	}
-	return 0;
-}
-
-/*
- *	Get ith text symbol
- */
-int
-textsym(Symbol *s, int index)
-{
-
-	if(buildtbls() == 0)
-		return 0;
-	if(index < 0 || index >= ntxt)
-		return 0;
-	fillsym(txt[index].sym, s);
-	s->handle = (void *)&txt[index];
-	s->index = index;
-	return 1;
-}
-
-/*
- *	Get ith file name
- */
-int
-filesym(int index, char *buf, int n)
-{
-	Hist *hp;
-
-	if(buildtbls() == 0)
-		return 0;
-	if(index < 0 || index >= nfiles)
-		return 0;
-	hp = files[index].hist;
-	if(!hp || !hp->name)
-		return 0;
-	return fileelem(fnames, (uchar*)hp->name, buf, n);
-}
-
-/*
- *	Lookup name of local variable located at an offset into the frame.
- *	The type selects either a parameter or automatic.
- */
-int
-getauto(Symbol *s1, int off, int type, Symbol *s2)
-{
-	Txtsym *tp;
-	Sym *p;
-	int i, t;
-
-	if(s1 == 0)
-		return 0;
-	if(type == CPARAM)
-		t = 'p';
-	else if(type == CAUTO)
-		t = 'a';
-	else
-		return 0;
-	if(buildtbls() == 0)
-		return 0;
-	tp = (Txtsym *)s1->handle;
-	if(tp == 0)
-		return 0;
-	for(i = 0; i < tp->n; i++) {
-		p = tp->locals[i];
-		if(p->type == t && p->value == off) {
-			fillsym(p, s2);
-			s2->handle = s1->handle;
-			s2->index = tp->n-1 - i;
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- * Find text symbol containing addr; binary search assumes text array is sorted by addr
- */
-static int
-srchtext(uvlong addr)
-{
-	uvlong val;
-	int top, bot, mid;
-	Sym *sp;
-
-	val = addr;
-	bot = 0;
-	top = ntxt;
-	for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
-		sp = txt[mid].sym;
-		if(val < sp->value)
-			top = mid;
-		else if(mid != ntxt-1 && val >= txt[mid+1].sym->value)
-			bot = mid;
-		else
-			return mid;
-	}
-	return -1;
-}
-
-/*
- * Find data symbol containing addr; binary search assumes data array is sorted by addr
- */
-static int
-srchdata(uvlong addr)
-{
-	uvlong val;
-	int top, bot, mid;
-	Sym *sp;
-
-	bot = 0;
-	top = nglob;
-	val = addr;
-	for(mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
-		sp = globals[mid];
-		if(val < sp->value)
-			top = mid;
-		else if(mid < nglob-1 && val >= globals[mid+1]->value)
-			bot = mid;
-		else
-			return mid;
-	}
-	return -1;
-}
-
-/*
- * Find symbol containing val in specified search space
- * There is a special case when a value falls beyond the end
- * of the text segment; if the search space is CTEXT, that value
- * (usually etext) is returned.  If the search space is CANY, symbols in the
- * data space are searched for a match.
- */
-int
-findsym(uvlong val, int type, Symbol *s)
-{
-	int i;
-
-	if(buildtbls() == 0)
-		return 0;
-
-	if(type == CTEXT || type == CANY) {
-		i = srchtext(val);
-		if(i >= 0) {
-			if(type == CTEXT || i != ntxt-1) {
-				fillsym(txt[i].sym, s);
-				s->handle = (void *) &txt[i];
-				s->index = i;
-				return 1;
-			}
-		}
-	}
-	if(type == CDATA || type == CANY) {
-		i = srchdata(val);
-		if(i >= 0) {
-			fillsym(globals[i], s);
-			s->index = i;
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- *	Find the start and end address of the function containing addr
- */
-int
-fnbound(uvlong addr, uvlong *bounds)
-{
-	int i;
-
-	if(buildtbls() == 0)
-		return 0;
-
-	i = srchtext(addr);
-	if(0 <= i && i < ntxt-1) {
-		bounds[0] = txt[i].sym->value;
-		bounds[1] = txt[i+1].sym->value;
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * get the ith local symbol for a function
- * the input symbol table is reverse ordered, so we reverse
- * accesses here to maintain approx. parameter ordering in a stack trace.
- */
-int
-localsym(Symbol *s, int index)
-{
-	Txtsym *tp;
-
-	if(s == 0 || index < 0)
-		return 0;
-	if(buildtbls() == 0)
-		return 0;
-
-	tp = (Txtsym *)s->handle;
-	if(tp && tp->locals && index < tp->n) {
-		fillsym(tp->locals[tp->n-index-1], s);	/* reverse */
-		s->handle = (void *)tp;
-		s->index = index;
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * get the ith global symbol
- */
-int
-globalsym(Symbol *s, int index)
-{
-	if(s == 0)
-		return 0;
-	if(buildtbls() == 0)
-		return 0;
-
-	if(index >=0 && index < nglob) {
-		fillsym(globals[index], s);
-		s->index = index;
-		return 1;
-	}
-	return 0;
-}
-
-/*
- *	find the pc given a file name and line offset into it.
- */
-uvlong
-file2pc(char *file, int32 line)
-{
-	File *fp;
-	int32 i;
-	uvlong pc, start, end;
-	short *name;
-
-	if(isgo12pcline())
-		return go12file2pc(file, line);
-	if(buildtbls() == 0 || files == 0)
-		return ~(uvlong)0;
-	name = encfname(file);
-	if(name == 0) {			/* encode the file name */
-		werrstr("file %s not found", file);
-		return ~(uvlong)0;
-	}
-		/* find this history stack */
-	for(i = 0, fp = files; i < nfiles; i++, fp++)
-		if (hline(fp, name, &line))
-			break;
-	free(name);
-	if(i >= nfiles) {
-		werrstr("line %d in file %s not found", line, file);
-		return ~(uvlong)0;
-	}
-	start = fp->addr;		/* first text addr this file */
-	if(i < nfiles-1)
-		end = (fp+1)->addr;	/* first text addr next file */
-	else
-		end = 0;		/* last file in load module */
-	/*
-	 * At this point, line contains the offset into the file.
-	 * run the state machine to locate the pc closest to that value.
-	 */
-	if(debug)
-		print("find pc for %d - between: %llux and %llux\n", line, start, end);
-	pc = line2addr(line, start, end);
-	if(pc == ~(uvlong)0) {
-		werrstr("line %d not in file %s", line, file);
-		return ~(uvlong)0;
-	}
-	return pc;
-}
-
-/*
- *	search for a path component index
- */
-static int
-pathcomp(char *s, int n)
-{
-	int i;
-
-	for(i = 0; i <= fmaxi; i++)
-		if(fnames[i] && strncmp(s, fnames[i]->name, n) == 0)
-			return i;
-	return -1;
-}
-
-/*
- *	Encode a char file name as a sequence of short indices
- *	into the file name dictionary.
- */
-static short*
-encfname(char *file)
-{
-	int i, j;
-	char *cp, *cp2;
-	short *dest;
-
-	if(*file == '/')	/* always check first '/' */
-		cp2 = file+1;
-	else {
-		cp2 = strchr(file, '/');
-		if(!cp2)
-			cp2 = strchr(file, 0);
-	}
-	cp = file;
-	dest = 0;
-	for(i = 0; *cp; i++) {
-		j = pathcomp(cp, cp2-cp);
-		if(j < 0)
-			return 0;	/* not found */
-		dest = realloc(dest, (i+1)*sizeof(short));
-		dest[i] = j;
-		cp = cp2;
-		while(*cp == '/')	/* skip embedded '/'s */
-			cp++;
-		cp2 = strchr(cp, '/');
-		if(!cp2)
-			cp2 = strchr(cp, 0);
-	}
-	dest = realloc(dest, (i+1)*sizeof(short));
-	dest[i] = 0;
-	return dest;
-}
-
-/*
- *	Search a history stack for a matching file name accumulating
- *	the size of intervening files in the stack.
- */
-static int
-hline(File *fp, short *name, int32 *line)
-{
-	Hist *hp;
-	int offset, depth;
-	int32 ln;
-
-	for(hp = fp->hist; hp->name; hp++)		/* find name in stack */
-		if(hp->name[1] || hp->name[2]) {
-			if(hcomp(hp, name))
-				break;
-		}
-	if(!hp->name)		/* match not found */
-		return 0;
-	if(debug)
-		printhist("hline found ... ", hp, 1);
-	/*
-	 * unwind the stack until empty or we hit an entry beyond our line
-	 */
-	ln = *line;
-	offset = hp->line-1;
-	depth = 1;
-	for(hp++; depth && hp->name; hp++) {
-		if(debug)
-			printhist("hline inspect ... ", hp, 1);
-		if(hp->name[1] || hp->name[2]) {
-			if(hp->offset){			/* Z record */
-				offset = 0;
-				if(hcomp(hp, name)) {
-					if(*line <= hp->offset)
-						break;
-					ln = *line+hp->line-hp->offset;
-					depth = 1;	/* implicit pop */
-				} else
-					depth = 2;	/* implicit push */
-			} else if(depth == 1 && ln < hp->line-offset)
-					break;		/* Beyond our line */
-			else if(depth++ == 1)		/* push	*/
-				offset -= hp->line;
-		} else if(--depth == 1)		/* pop */
-			offset += hp->line;
-	}
-	*line = ln+offset;
-	return 1;
-}
-
-/*
- *	compare two encoded file names
- */
-static int
-hcomp(Hist *hp, short *sp)
-{
-	uchar *cp;
-	int i, j;
-	short *s;
-
-	cp = (uchar *)hp->name;
-	s = sp;
-	if (*s == 0)
-		return 0;
-	for (i = 1; j = (cp[i]<<8)|cp[i+1]; i += 2) {
-		if(j == 0)
-			break;
-		if(*s == j)
-			s++;
-		else
-			s = sp;
-	}
-	return *s == 0;
-}
-
-/*
- *	Convert a pc to a "file:line {file:line}" string.
- */
-int32
-fileline(char *str, int n, uvlong dot)
-{
-	int32 line, top, bot, mid;
-	File *f;
-
-	if(isgo12pcline())
-		return go12fileline(str, n, dot);
-
-	*str = 0;
-	if(buildtbls() == 0)
-		return 0;
-		/* binary search assumes file list is sorted by addr */
-	bot = 0;
-	top = nfiles;
-	for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
-		f = &files[mid];
-		if(dot < f->addr)
-			top = mid;
-		else if(mid < nfiles-1 && dot >= (f+1)->addr)
-			bot = mid;
-		else {
-			line = pc2line(dot);
-			if(line > 0 && fline(str, n, line, f->hist, 0) >= 0)
-				return 1;
-			break;
-		}
-	}
-	return 0;
-}
-
-/*
- *	Convert a line number within a composite file to relative line
- *	number in a source file.  A composite file is the source
- *	file with included files inserted in line.
- */
-static int
-fline(char *str, int n, int32 line, Hist *base, Hist **ret)
-{
-	Hist *start;			/* start of current level */
-	Hist *h;			/* current entry */
-	int32 delta;			/* sum of size of files this level */
-	int k;
-
-	start = base;
-	h = base;
-	delta = h->line;
-	while(h && h->name && line > h->line) {
-		if(h->name[1] || h->name[2]) {
-			if(h->offset != 0) {	/* #line Directive */
-				delta = h->line-h->offset+1;
-				start = h;
-				base = h++;
-			} else {		/* beginning of File */
-				if(start == base)
-					start = h++;
-				else {
-					k = fline(str, n, line, start, &h);
-					if(k <= 0)
-						return k;
-				}
-			}
-		} else {
-			if(start == base && ret) {	/* end of recursion level */
-				*ret = h;
-				return 1;
-			} else {			/* end of included file */
-				delta += h->line-start->line;
-				h++;
-				start = base;
-			}
-		}
-	}
-	if(!h)
-		return -1;
-	if(start != base)
-		line = line-start->line+1;
-	else
-		line = line-delta+1;
-	if(!h->name)
-		strncpy(str, "<eof>", n);
-	else {
-		k = fileelem(fnames, (uchar*)start->name, str, n);
-		if(k+8 < n)
-			sprint(str+k, ":%d", line);
-	}
-/**********Remove comments for complete back-trace of include sequence
- *	if(start != base) {
- *		k = strlen(str);
- *		if(k+2 < n) {
- *			str[k++] = ' ';
- *			str[k++] = '{';
- *		}
- *		k += fileelem(fnames, (uchar*) base->name, str+k, n-k);
- *		if(k+10 < n)
- *			sprint(str+k, ":%ld}", start->line-delta);
- *	}
- ********************/
-	return 0;
-}
-
-/*
- *	convert an encoded file name to a string.
- */
-int
-fileelem(Sym **fp, uchar *cp, char *buf, int n)
-{
-	int i, j;
-	char *c, *bp, *end;
-
-	bp = buf;
-	end = buf+n-1;
-	for(i = 1; j = (cp[i]<<8)|cp[i+1]; i+=2){
-		c = fp[j]->name;
-		if(bp != buf && bp[-1] != '/' && bp < end)
-			*bp++ = '/';
-		while(bp < end && *c)
-			*bp++ = *c++;
-	}
-	*bp = 0;
-	i =  bp-buf;
-	if(i > 1) {
-		cleanname(buf);
-		i = strlen(buf);
-	}
-	return i;
-}
-
-/*
- *	compare the values of two symbol table entries.
- */
-static int
-symcomp(const void *a, const void *b)
-{
-	int i;
-
-	i = (*(Sym**)a)->value - (*(Sym**)b)->value;
-	if (i)
-		return i;
-	return strcmp((*(Sym**)a)->name, (*(Sym**)b)->name);
-}
-
-/*
- *	compare the values of the symbols referenced by two text table entries
- */
-static int
-txtcomp(const void *a, const void *b)
-{
-	return ((Txtsym*)a)->sym->value - ((Txtsym*)b)->sym->value;
-}
-
-/*
- *	compare the values of the symbols referenced by two file table entries
- */
-static int
-filecomp(const void *a, const void *b)
-{
-	return ((File*)a)->addr - ((File*)b)->addr;
-}
-
-/*
- *	fill an interface Symbol structure from a symbol table entry
- */
-static void
-fillsym(Sym *sp, Symbol *s)
-{
-	s->type = sp->type;
-	s->value = sp->value;
-	s->name = sp->name;
-	s->index = 0;
-	switch(sp->type) {
-	case 'b':
-	case 'B':
-	case 'D':
-	case 'd':
-		s->class = CDATA;
-		break;
-	case 't':
-	case 'T':
-	case 'l':
-	case 'L':
-		s->class = CTEXT;
-		break;
-	case 'a':
-		s->class = CAUTO;
-		break;
-	case 'p':
-		s->class = CPARAM;
-		break;
-	case 'm':
-		s->class = CSTAB;
-		break;
-	default:
-		s->class = CNONE;
-		break;
-	}
-	s->handle = 0;
-}
-
-/*
- *	find the stack frame, given the pc
- */
-uvlong
-pc2sp(uvlong pc)
-{
-	uchar *c, u;
-	uvlong currpc, currsp;
-
-	if(isgo12pcline())
-		return go12pc2sp(pc);
-
-	if(spoff == 0)
-		return ~(uvlong)0;
-	currsp = 0;
-	currpc = txtstart - mach->pcquant;
-
-	if(pc<currpc || pc>txtend)
-		return ~(uvlong)0;
-	for(c = spoff; c < spoffend; c++) {
-		if (currpc >= pc)
-			return currsp;
-		u = *c;
-		if (u == 0) {
-			currsp += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
-			c += 4;
-		}
-		else if (u < 65)
-			currsp += 4*u;
-		else if (u < 129)
-			currsp -= 4*(u-64);
-		else
-			currpc += mach->pcquant*(u-129);
-		currpc += mach->pcquant;
-	}
-	return ~(uvlong)0;
-}
-
-/*
- *	find the source file line number for a given value of the pc
- */
-int32
-pc2line(uvlong pc)
-{
-	uchar *c, u;
-	uvlong currpc;
-	int32 currline;
-
-	if(pcline == 0)
-		return -1;
-	currline = 0;
-	if (firstinstr != 0)
-		currpc = firstinstr-mach->pcquant;
-	else
-		currpc = txtstart-mach->pcquant;
-	if(pc<currpc || pc>txtend)
-		return -1;
-
-	for(c = pcline; c < pclineend && currpc < pc; c++) {
-		u = *c;
-		if(u == 0) {
-			currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
-			c += 4;
-		}
-		else if(u < 65)
-			currline += u;
-		else if(u < 129)
-			currline -= (u-64);
-		else
-			currpc += mach->pcquant*(u-129);
-		currpc += mach->pcquant;
-	}
-	return currline;
-}
-
-/*
- *	find the pc associated with a line number
- *	basepc and endpc are text addresses bounding the search.
- *	if endpc == 0, the end of the table is used (i.e., no upper bound).
- *	usually, basepc and endpc contain the first text address in
- *	a file and the first text address in the following file, respectively.
- */
-uvlong
-line2addr(int32 line, uvlong basepc, uvlong endpc)
-{
-	uchar *c,  u;
-	uvlong currpc, pc;
-	int32 currline;
-	int32 delta, d;
-	int found;
-
-	if(pcline == 0 || line == 0)
-		return ~(uvlong)0;
-
-	currline = 0;
-	currpc = txtstart-mach->pcquant;
-	pc = ~(uvlong)0;
-	found = 0;
-	delta = HUGEINT;
-
-	for(c = pcline; c < pclineend; c++) {
-		if(endpc && currpc >= endpc)	/* end of file of interest */
-			break;
-		if(currpc >= basepc) {		/* proper file */
-			if(currline >= line) {
-				d = currline-line;
-				found = 1;
-			} else
-				d = line-currline;
-			if(d < delta) {
-				delta = d;
-				pc = currpc;
-			}
-		}
-		u = *c;
-		if(u == 0) {
-			currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
-			c += 4;
-		}
-		else if(u < 65)
-			currline += u;
-		else if(u < 129)
-			currline -= (u-64);
-		else
-			currpc += mach->pcquant*(u-129);
-		currpc += mach->pcquant;
-	}
-	if(found)
-		return pc;
-	return ~(uvlong)0;
-}
-
-/*
- *	Print a history stack (debug). if count is 0, prints the whole stack
- */
-static void
-printhist(char *msg, Hist *hp, int count)
-{
-	int i;
-	uchar *cp;
-	char buf[128];
-
-	i = 0;
-	while(hp->name) {
-		if(count && ++i > count)
-			break;
-		print("%s Line: %x (%d)  Offset: %x (%d)  Name: ", msg,
-			hp->line, hp->line, hp->offset, hp->offset);
-		for(cp = (uchar *)hp->name+1; (*cp<<8)|cp[1]; cp += 2) {
-			if (cp != (uchar *)hp->name+1)
-				print("/");
-			print("%x", (*cp<<8)|cp[1]);
-		}
-		fileelem(fnames, (uchar *) hp->name, buf, sizeof(buf));
-		print(" (%s)\n", buf);
-		hp++;
-	}
-}
-
-#ifdef DEBUG
-/*
- *	print the history stack for a file. (debug only)
- *	if (name == 0) => print all history stacks.
- */
-void
-dumphist(char *name)
-{
-	int i;
-	File *f;
-	short *fname;
-
-	if(buildtbls() == 0)
-		return;
-	if(name)
-		fname = encfname(name);
-	for(i = 0, f = files; i < nfiles; i++, f++)
-		if(fname == 0 || hcomp(f->hist, fname))
-			printhist("> ", f->hist, f->n);
-
-	if(fname)
-		free(fname);
-}
-#endif
-
-// Go 1.2 pcln table
-// See golang.org/s/go12symtab.
-
-// Func layout
-#define FuncEntry (0)
-#define FuncName (pcptrsize)
-#define FuncArgs (pcptrsize+4)
-#define FuncFrame (pcptrsize+2*4)
-#define FuncPCSP (pcptrsize+3*4)
-#define FuncPCFile (pcptrsize+4*4)
-#define FuncPCLine (pcptrsize+5*4)
-
-static int32 pcquantum;
-static int32 pcptrsize;
-static uvlong (*pcswav)(uvlong);
-static uint32 (*pcswal)(uint32);
-static uvlong (*pcuintptr)(uchar*);
-static uchar *functab;
-static uint32 nfunctab;
-static uint32 *filetab;
-static uint32 nfiletab;
-
-static uint32
-xswal(uint32 v)
-{
-	return (v>>24) | ((v>>8)&0xFF00) | ((v<<8)&0xFF0000) | v<<24;
-}
-
-static uvlong
-xswav(uvlong v)
-{
-	return (uvlong)xswal(v)<<32 | xswal(v>>32);
-}
-
-static uvlong
-noswav(uvlong v)
-{
-	return v;
-}
-
-static uint32
-noswal(uint32 v)
-{
-	return v;
-}
-
-static uvlong
-readuintptr64(uchar *p)
-{
-	return pcswav(*(uvlong*)p);
-}
-
-static uvlong
-readuintptr32(uchar *p)
-{
-	return pcswal(*(uint32*)p);
-}
-
-static void
-go12clean(void)
-{
-	pcquantum = 0;
-	pcswav = nil;
-	pcswal = nil;
-	functab = nil;
-	nfunctab = 0;
-	filetab = nil;
-	nfiletab = 0;
-}
-
-static void
-go12init(void)
-{
-	uint32 m;
-	uchar *p;
-
-	if(pcquantum != 0)
-		return;
-	pcquantum = -1; // not go 1.2
-	if(pcline == nil || pclineend - pcline < 16 ||
-		pcline[4] != 0 || pcline[5] != 0 ||
-		(pcline[6] != 1 && pcline[6] != 4) ||
-		(pcline[7] != 4 && pcline[7] != 8))
-		return;
-
-	// header is magic, 00 00 pcquantum ptrsize
-	m = *(uint32*)pcline;
-	if(m == Go12PclnMagic) {
-		pcswav = noswav;
-		pcswal = noswal;
-	} else {
-		pcswav = xswav;
-		pcswal = xswal;
-	}
-	pcptrsize = pcline[7];
-	
-	if(pcptrsize == 4)
-		pcuintptr = readuintptr32;
-	else
-		pcuintptr = readuintptr64;
-
-	nfunctab = pcuintptr(pcline+8);
-	functab = pcline + 8 + pcptrsize;
-	
-	// functab is 2*nfunctab pointer-sized values.
-	// The offset to the file table follows.
-	p = functab + nfunctab*2*pcptrsize + pcptrsize;
-	if(p+4 > pclineend)
-		return;
-	filetab = (uint32*)(pcline + pcswal(*(uint32*)p));
-	if((uchar*)filetab+4 > pclineend)
-		return;
-	
-	// File table begins with count.
-	nfiletab = pcswal(filetab[0]);
-	if((uchar*)(filetab + nfiletab) > pclineend)
-		return;
-
-	// Committed.
-	pcquantum = pcline[6];
-}
-
-static int
-isgo12pcline(void)
-{
-	go12init();
-	return pcquantum > 0;
-}
-
-static uchar*
-go12findfunc(uvlong pc)
-{
-	uchar *f, *fm;
-	int32 nf, m;
-
-	if(pc < pcuintptr(functab) || pc >= pcuintptr(functab+2*nfunctab*pcptrsize))
-		return nil;
-
-	// binary search to find func with entry <= addr.
-	f = functab;
-	nf = nfunctab;
-	while(nf > 0) {
-		m = nf/2;
-		fm = f + 2*pcptrsize*m;
-		if(pcuintptr(fm) <= pc && pc < pcuintptr(fm+2*pcptrsize)) {
-			f = pcline + pcuintptr(fm+pcptrsize);
-			if(f >= pclineend)
-				return nil;
-			return f;
-		} else if(pc < pcuintptr(fm))
-			nf = m;
-		else {
-			f += (m+1)*2*pcptrsize;
-			nf -= m+1;
-		}
-	}
-	return nil;
-}
-
-static uint32
-readvarint(uchar **pp)
-{
-	uchar *p;
-	uint32 v;
-	int32 shift;
-	
-	v = 0;
-	p = *pp;
-	for(shift = 0;; shift += 7) {
-		v |= (*p & 0x7F) << shift;
-		if(!(*p++ & 0x80))
-			break;
-	}
-	*pp = p;
-	return v;
-}
-
-static char*
-pcstring(uint32 off)
-{
-	if(off == 0 || off >= pclineend - pcline ||
-	   memchr(pcline + off, '\0', pclineend - (pcline + off)) == nil)
-		return "?";
-	return (char*)pcline+off;
-}
-
-
-static int
-step(uchar **pp, uvlong *pc, int32 *value, int first)
-{
-	uint32 uvdelta, pcdelta;
-	int32 vdelta;
-
-	uvdelta = readvarint(pp);
-	if(uvdelta == 0 && !first)
-		return 0;
-	if(uvdelta&1)
-		uvdelta = ~(uvdelta>>1);
-	else
-		uvdelta >>= 1;
-	vdelta = (int32)uvdelta;
-	pcdelta = readvarint(pp) * pcquantum;
-	*value += vdelta;
-	*pc += pcdelta;
-	return 1;
-}
-
-static int32
-pcvalue(uint32 off, uvlong entry, uvlong targetpc)
-{
-	uvlong pc;
-	int32 val;
-	uchar *p;
-	
-	val = -1;
-	pc = entry;
-	if(off == 0 || off >= pclineend - pcline)
-		return -1;	
-	p = pcline + off;
-	while(step(&p, &pc, &val, pc == entry)) {
-		if(targetpc < pc)
-			return val;
-	}
-	return -1;
-}
-
-static uvlong
-go12pc2sp(uvlong pc)
-{
-	uchar *f;
-	uint32 off;
-	uvlong entry;
-	int32 sp;
-
-	f = go12findfunc(pc);
-	if(f == nil)
-		return ~(uvlong)0;
-	entry = pcuintptr(f+FuncEntry);
-	off = pcswal(*(uint32*)(f+FuncPCSP));
-	sp = pcvalue(off, entry, pc);
-	if(sp < 0)
-		return ~(uvlong)0;
-	return sp;
-}
-
-static int32
-go12fileline(char *str, int n, uvlong pc)
-{
-	uchar *f;
-	uint32 fileoff, lineoff;
-	uvlong entry;
-	int lno, fno;
-
-	f = go12findfunc(pc);
-	if(f == nil)
-		return 0;
-	entry = pcuintptr(f+FuncEntry);
-	fileoff = pcswal(*(uint32*)(f+FuncPCFile));
-	lineoff = pcswal(*(uint32*)(f+FuncPCLine));
-	lno = pcvalue(lineoff, entry, pc);
-	fno = pcvalue(fileoff, entry, pc);
-	if(lno < 0 || fno <= 0 || fno >= nfiletab) {
-		return 0;
-	}
-	snprint(str, n, "%s:%d", pcstring(pcswal(filetab[fno])), lno);
-	return 1;
-}
-
-static uvlong
-go12file2pc(char *file, int line)
-{
-	int fno;
-	int32 i, fval, lval;
-	uchar *func, *fp, *lp;
-	uvlong fpc, lpc, fstartpc, lstartpc, entry;
-
-	// Map file to file number.
-	// NOTE(rsc): Could introduce a hash table for repeated
-	// lookups if anyone ever calls this.
-	for(fno=1; fno<nfiletab; fno++)
-		if(strcmp(pcstring(pcswal(filetab[fno])), file) == 0)
-			goto havefile;
-	werrstr("cannot find file");
-	return ~(uvlong)0;
-
-havefile:
-	// Consider each func.
-	// Run file number program to find file match,
-	// then run line number program to find line match.
-	// Most file number programs are tiny, and most will
-	// not mention the file number, so this should be fairly
-	// quick.
-	for(i=0; i<nfunctab; i++) {
-		func = pcline + pcuintptr(functab+i*2*pcptrsize+pcptrsize);
-		entry = pcuintptr(func+FuncEntry);
-		fp = pcline + pcswal(*(uint32*)(func+FuncPCFile));
-		lp = pcline + pcswal(*(uint32*)(func+FuncPCLine));
-		fval = lval = -1;
-		fpc = lpc = entry;
-		fstartpc = fpc;
-		while(step(&fp, &fpc, &fval, fpc==entry)) {
-			if(fval == fno && fstartpc < fpc) {
-				lstartpc = lpc;
-				while(lpc < fpc && step(&lp, &lpc, &lval, lpc==entry)) {
-					if(lval == line) {
-						if(fstartpc <= lstartpc) {
-							return lstartpc;
-						}
-						if(fstartpc < lpc) {
-							return fstartpc;
-						}
-					}
-					lstartpc = lpc;
-				}
-			}
-			fstartpc = fpc;
-		}
-	}
-	werrstr("cannot find line in file");
-	return ~(uvlong)0;
-}
diff --git a/src/libmach/windows.c b/src/libmach/windows.c
deleted file mode 100644
index 9ffc3af..0000000
--- a/src/libmach/windows.c
+++ /dev/null
@@ -1,87 +0,0 @@
-// This is stubbed out for the moment. Will revisit when the time comes.
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <mach.h>
-
-int
-ctlproc(int pid, char *msg)
-{
-	USED(pid);
-	USED(msg);
-	sysfatal("ctlproc unimplemented in Windows");
-	return -1;
-}
-
-char*
-proctextfile(int pid)
-{
-	USED(pid);
-	sysfatal("proctextfile unimplemented in Windows");
-	return nil;
-}
-
-char*
-procstatus(int pid)
-{
-	USED(pid);
-	sysfatal("procstatus unimplemented in Windows");
-	return nil;
-}
-
-Map*
-attachproc(int pid, Fhdr *fp)
-{
-	USED(pid);
-	USED(fp);
-	sysfatal("attachproc unimplemented in Windows");
-	return nil;
-}
-
-void
-detachproc(Map *m)
-{
-	USED(m);
-	sysfatal("detachproc unimplemented in Windows");
-}
-
-int
-procthreadpids(int pid, int *p, int np)
-{
-	USED(pid);
-	USED(p);
-	USED(np);
-	sysfatal("procthreadpids unimplemented in Windows");
-	return -1;
-}
-
-int 
-pread(int fd, void *buf, int count, int offset)
-{
-	int oldoffset, n;
-	
-	oldoffset = seek(fd, offset, 0);
-	n = read(fd, buf, count);
-	seek(fd, oldoffset, 0);
-	return n;
-}
-
-int 
-pwrite(int fd, void *buf, int count, int offset)
-{
-	USED(fd);
-	USED(buf);
-	USED(count);
-	USED(offset);
-	sysfatal("pwrite unimplemented in Windows");
-	return -1;
-}
-
-int 
-nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
-{
-	USED(rqtp);
-	USED(rmtp);
-	sysfatal("nanosleep unimplemented in Windows");
-	return -1;
-}
diff --git a/src/make.bash b/src/make.bash
index 877d1e5..d7b63ff 100755
--- a/src/make.bash
+++ b/src/make.bash
@@ -35,10 +35,15 @@
 # controls the default behavior of the linker's -linkmode option.  The
 # default value depends on the system.
 #
-# CC: Command line to run to get at host C compiler.
+# CC: Command line to run to compile C code for GOHOSTARCH.
 # Default is "gcc". Also supported: "clang".
-# CXX: Command line to run to get at host C++ compiler, only recorded
-# for cgo use. Default is "g++". Also supported: "clang++".
+#
+# CC_FOR_TARGET: Command line to run to compile C code for GOARCH.
+# This is used by cgo.  Default is CC.
+#
+# CXX_FOR_TARGET: Command line to run to compile C++ code for GOARCH.
+# This is used by cgo. Default is CXX, or, if that is not set, 
+# "g++" or "clang++".
 #
 # GO_DISTFLAGS: extra flags to provide to "dist bootstrap". Use "-s"
 # to build a statically linked toolchain.
@@ -120,6 +125,10 @@ if [ "$(uname)" == "Darwin" ]; then
 	# golang.org/issue/5261
 	mflag="$mflag -mmacosx-version-min=10.6"
 fi
+# if gcc does not exist and $CC is not set, try clang if available.
+if [ -z "$CC" -a -z "$(type -t gcc)" -a -n "$(type -t clang)" ]; then
+	export CC=clang CXX=clang++
+fi
 ${CC:-gcc} $mflag -O2 -Wall -Werror -o cmd/dist/dist -Icmd/dist "$DEFGOROOT" cmd/dist/*.c
 
 # -e doesn't propagate out of eval, so check success by hand.
@@ -144,6 +153,7 @@ echo "# Building compilers and Go bootstrap tool for host, $GOHOSTOS/$GOHOSTARCH
 buildall="-a"
 if [ "$1" = "--no-clean" ]; then
 	buildall=""
+	shift
 fi
 ./cmd/dist/dist bootstrap $buildall $GO_DISTFLAGS -v # builds go_bootstrap
 # Delay move of dist tool to now, because bootstrap may clear tool directory.
@@ -153,13 +163,15 @@ echo
 
 if [ "$GOHOSTARCH" != "$GOARCH" -o "$GOHOSTOS" != "$GOOS" ]; then
 	echo "# Building packages and commands for host, $GOHOSTOS/$GOHOSTARCH."
-	GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \
+	# CC_FOR_TARGET is recorded as the default compiler for the go tool. When building for the host, however,
+	# use the host compiler, CC, from `cmd/dist/dist env` instead.
+	CC=$CC GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \
 		"$GOTOOLDIR"/go_bootstrap install -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
 	echo
 fi
 
 echo "# Building packages and commands for $GOOS/$GOARCH."
-"$GOTOOLDIR"/go_bootstrap install $GO_FLAGS -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
+CC=$CC_FOR_TARGET "$GOTOOLDIR"/go_bootstrap install $GO_FLAGS -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
 echo
 
 rm -f "$GOTOOLDIR"/go_bootstrap
diff --git a/src/make.rc b/src/make.rc
index 222bb8a..ab152c0 100755
--- a/src/make.rc
+++ b/src/make.rc
@@ -36,6 +36,9 @@ if(! test -f run.rc){
 	exit wrongdir
 }
 
+# Generate libc_plan9.h.
+../include/plan9/mklibc.rc > ../include/plan9/libc_plan9.h
+
 # Clean old generated file that will cause problems in the build.
 rm -f ./pkg/runtime/runtime_defs.go
 
diff --git a/src/nacltest.bash b/src/nacltest.bash
new file mode 100755
index 0000000..33fc8c1
--- /dev/null
+++ b/src/nacltest.bash
@@ -0,0 +1,56 @@
+#!/bin/bash
+# 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.
+
+# For testing Native Client on builders or locally.
+# Builds a test file system and embeds it into package syscall
+# in every generated binary.
+#
+# Assumes that sel_ldr binaries and go_nacl_$GOARCH_exec scripts are in $PATH;
+# see ../misc/nacl/README.
+
+set -e
+ulimit -c 0
+
+# Check GOARCH.
+naclGOARCH=${GOARCH:-386}
+case "$naclGOARCH" in
+amd64p32)
+	if ! which sel_ldr_x86_64 >/dev/null; then
+		echo 'cannot find sel_ldr_x86_64' 1>&2
+		exit 1
+	fi
+	;;
+386)
+	if ! which sel_ldr_x86_32 >/dev/null; then
+		echo 'cannot find sel_ldr_x86_32' 1>&2
+		exit 1
+	fi
+	;;
+*)
+	echo 'unsupported $GOARCH for nacl: '"$naclGOARCH" 1>&2
+	exit 1
+esac
+
+if ! which go_nacl_${naclGOARCH}_exec >/dev/null; then
+	echo "cannot find go_nacl_${naclGOARCH}_exec, see ../misc/nacl/README." 1>&2
+	exit 1
+fi
+
+# Run host build to get toolchain for running zip generator.
+unset GOOS GOARCH
+if [ ! -f make.bash ]; then
+	echo 'nacl.bash must be run from $GOROOT/src' 1>&2
+	exit 1
+fi
+GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH ./make.bash
+
+# Build zip file embedded in package syscall.
+gobin=${GOBIN:-$(pwd)/../bin}
+rm -f pkg/syscall/fstest_nacl.go
+GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH $gobin/go run ../misc/nacl/mkzip.go -p syscall -r .. ../misc/nacl/testzip.proto pkg/syscall/fstest_nacl.go
+
+# Run standard build and tests.
+export PATH=$(pwd)/../misc/nacl:$PATH
+GOOS=nacl GOARCH=$naclGOARCH ./all.bash --no-clean
diff --git a/src/pkg/archive/tar/common.go b/src/pkg/archive/tar/common.go
index 1b961e3..e363aa7 100644
--- a/src/pkg/archive/tar/common.go
+++ b/src/pkg/archive/tar/common.go
@@ -38,6 +38,7 @@ const (
 	TypeXGlobalHeader = 'g'    // global extended header
 	TypeGNULongName   = 'L'    // Next file has a long name
 	TypeGNULongLink   = 'K'    // Next file symlinks to a file w/ a long name
+	TypeGNUSparse     = 'S'    // sparse file
 )
 
 // A Header represents a single header in a tar archive.
@@ -57,6 +58,7 @@ type Header struct {
 	Devminor   int64     // minor number of character or block device
 	AccessTime time.Time // access time
 	ChangeTime time.Time // status change time
+	Xattrs     map[string]string
 }
 
 // File name constants from the tar spec.
@@ -189,6 +191,7 @@ const (
 	paxSize     = "size"
 	paxUid      = "uid"
 	paxUname    = "uname"
+	paxXattr    = "SCHILY.xattr."
 	paxNone     = ""
 )
 
diff --git a/src/pkg/archive/tar/reader.go b/src/pkg/archive/tar/reader.go
index b2d62f3..920a9b0 100644
--- a/src/pkg/archive/tar/reader.go
+++ b/src/pkg/archive/tar/reader.go
@@ -29,12 +29,57 @@ const maxNanoSecondIntSize = 9
 // The Next method advances to the next file in the archive (including the first),
 // and then it can be treated as an io.Reader to access the file's data.
 type Reader struct {
-	r   io.Reader
-	err error
-	nb  int64 // number of unread bytes for current file entry
-	pad int64 // amount of padding (ignored) after current file entry
+	r    io.Reader
+	err  error
+	pad  int64          // amount of padding (ignored) after current file entry
+	curr numBytesReader // reader for current file entry
 }
 
+// A numBytesReader is an io.Reader with a numBytes method, returning the number
+// of bytes remaining in the underlying encoded data.
+type numBytesReader interface {
+	io.Reader
+	numBytes() int64
+}
+
+// A regFileReader is a numBytesReader for reading file data from a tar archive.
+type regFileReader struct {
+	r  io.Reader // underlying reader
+	nb int64     // number of unread bytes for current file entry
+}
+
+// A sparseFileReader is a numBytesReader for reading sparse file data from a tar archive.
+type sparseFileReader struct {
+	rfr *regFileReader // reads the sparse-encoded file data
+	sp  []sparseEntry  // the sparse map for the file
+	pos int64          // keeps track of file position
+	tot int64          // total size of the file
+}
+
+// Keywords for GNU sparse files in a PAX extended header
+const (
+	paxGNUSparseNumBlocks = "GNU.sparse.numblocks"
+	paxGNUSparseOffset    = "GNU.sparse.offset"
+	paxGNUSparseNumBytes  = "GNU.sparse.numbytes"
+	paxGNUSparseMap       = "GNU.sparse.map"
+	paxGNUSparseName      = "GNU.sparse.name"
+	paxGNUSparseMajor     = "GNU.sparse.major"
+	paxGNUSparseMinor     = "GNU.sparse.minor"
+	paxGNUSparseSize      = "GNU.sparse.size"
+	paxGNUSparseRealSize  = "GNU.sparse.realsize"
+)
+
+// Keywords for old GNU sparse headers
+const (
+	oldGNUSparseMainHeaderOffset               = 386
+	oldGNUSparseMainHeaderIsExtendedOffset     = 482
+	oldGNUSparseMainHeaderNumEntries           = 4
+	oldGNUSparseExtendedHeaderIsExtendedOffset = 504
+	oldGNUSparseExtendedHeaderNumEntries       = 21
+	oldGNUSparseOffsetSize                     = 12
+	oldGNUSparseNumBytesSize                   = 12
+)
+
 // NewReader creates a new Reader reading from r.
 func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
 
@@ -64,6 +109,18 @@ func (tr *Reader) Next() (*Header, error) {
 		tr.skipUnread()
 		hdr = tr.readHeader()
 		mergePAX(hdr, headers)
+
+		// Check for a PAX format sparse file
+		sp, err := tr.checkForGNUSparsePAXHeaders(hdr, headers)
+		if err != nil {
+			tr.err = err
+			return nil, err
+		}
+		if sp != nil {
+			// Current file is a PAX format GNU sparse file.
+			// Set the current file reader to a sparse file reader.
+			tr.curr = &sparseFileReader{rfr: tr.curr.(*regFileReader), sp: sp, tot: hdr.Size}
+		}
 		return hdr, nil
 	case TypeGNULongName:
 		// We have a GNU long name header. Its contents are the real file name.
@@ -87,6 +144,67 @@ func (tr *Reader) Next() (*Header, error) {
 	return hdr, tr.err
 }
 
+// checkForGNUSparsePAXHeaders checks the PAX headers for GNU sparse headers. If they are found, then
+// this function reads the sparse map and returns it. Unknown sparse formats are ignored, causing the file to
+// be treated as a regular file.
+func (tr *Reader) checkForGNUSparsePAXHeaders(hdr *Header, headers map[string]string) ([]sparseEntry, error) {
+	var sparseFormat string
+
+	// Check for sparse format indicators
+	major, majorOk := headers[paxGNUSparseMajor]
+	minor, minorOk := headers[paxGNUSparseMinor]
+	sparseName, sparseNameOk := headers[paxGNUSparseName]
+	_, sparseMapOk := headers[paxGNUSparseMap]
+	sparseSize, sparseSizeOk := headers[paxGNUSparseSize]
+	sparseRealSize, sparseRealSizeOk := headers[paxGNUSparseRealSize]
+
+	// Identify which, if any, sparse format applies from which PAX headers are set
+	if majorOk && minorOk {
+		sparseFormat = major + "." + minor
+	} else if sparseNameOk && sparseMapOk {
+		sparseFormat = "0.1"
+	} else if sparseSizeOk {
+		sparseFormat = "0.0"
+	} else {
+		// Not a PAX format GNU sparse file.
+		return nil, nil
+	}
+
+	// Check for unknown sparse format
+	if sparseFormat != "0.0" && sparseFormat != "0.1" && sparseFormat != "1.0" {
+		return nil, nil
+	}
+
+	// Update hdr from GNU sparse PAX headers
+	if sparseNameOk {
+		hdr.Name = sparseName
+	}
+	if sparseSizeOk {
+		realSize, err := strconv.ParseInt(sparseSize, 10, 0)
+		if err != nil {
+			return nil, ErrHeader
+		}
+		hdr.Size = realSize
+	} else if sparseRealSizeOk {
+		realSize, err := strconv.ParseInt(sparseRealSize, 10, 0)
+		if err != nil {
+			return nil, ErrHeader
+		}
+		hdr.Size = realSize
+	}
+
+	// Set up the sparse map, according to the particular sparse format in use
+	var sp []sparseEntry
+	var err error
+	switch sparseFormat {
+	case "0.0", "0.1":
+		sp, err = readGNUSparseMap0x1(headers)
+	case "1.0":
+		sp, err = readGNUSparseMap1x0(tr.curr)
+	}
+	return sp, err
+}
+
 // mergePAX merges well known headers according to PAX standard.
 // In general headers with the same name as those found
 // in the header struct overwrite those found in the header
@@ -139,8 +257,14 @@ func mergePAX(hdr *Header, headers map[string]string) error {
 				return err
 			}
 			hdr.Size = int64(size)
+		default:
+			if strings.HasPrefix(k, paxXattr) {
+				if hdr.Xattrs == nil {
+					hdr.Xattrs = make(map[string]string)
+				}
+				hdr.Xattrs[k[len(paxXattr):]] = v
+			}
 		}
-
 	}
 	return nil
 }
@@ -188,6 +312,11 @@ func parsePAX(r io.Reader) (map[string]string, error) {
 	if err != nil {
 		return nil, err
 	}
+
+	// For GNU PAX sparse format 0.0 support.
+	// This function transforms the sparse format 0.0 headers into sparse format 0.1 headers.
+	var sparseMap bytes.Buffer
+
 	headers := make(map[string]string)
 	// Each record is constructed as
 	//     "%d %s=%s\n", length, keyword, value
@@ -205,7 +334,7 @@ func parsePAX(r io.Reader) (map[string]string, error) {
 			return nil, ErrHeader
 		}
 		// Extract everything between the decimal and the n -1 on the
-		// beginning to to eat the ' ', -1 on the end to skip the newline.
+		// beginning to eat the ' ', -1 on the end to skip the newline.
 		var record []byte
 		record, buf = buf[sp+1:n-1], buf[n:]
 		// The first equals is guaranteed to mark the end of the key.
@@ -215,7 +344,21 @@ func parsePAX(r io.Reader) (map[string]string, error) {
 			return nil, ErrHeader
 		}
 		key, value := record[:eq], record[eq+1:]
-		headers[string(key)] = string(value)
+
+		keyStr := string(key)
+		if keyStr == paxGNUSparseOffset || keyStr == paxGNUSparseNumBytes {
+			// GNU sparse format 0.0 special key. Write to sparseMap instead of using the headers map.
+			sparseMap.Write(value)
+			sparseMap.Write([]byte{','})
+		} else {
+			// Normal key. Set the value in the headers map.
+			headers[keyStr] = string(value)
+		}
+	}
+	if sparseMap.Len() != 0 {
+		// Add sparse info to headers, chopping off the extra comma
+		sparseMap.Truncate(sparseMap.Len() - 1)
+		headers[paxGNUSparseMap] = sparseMap.String()
 	}
 	return headers, nil
 }
@@ -262,8 +405,8 @@ func (tr *Reader) octal(b []byte) int64 {
 
 // skipUnread skips any unread bytes in the existing file entry, as well as any alignment padding.
 func (tr *Reader) skipUnread() {
-	nr := tr.nb + tr.pad // number of bytes to skip
-	tr.nb, tr.pad = 0, 0
+	nr := tr.numBytes() + tr.pad // number of bytes to skip
+	tr.curr, tr.pad = nil, 0
 	if sr, ok := tr.r.(io.Seeker); ok {
 		if _, err := sr.Seek(nr, os.SEEK_CUR); err == nil {
 			return
@@ -325,14 +468,14 @@ func (tr *Reader) readHeader() *Header {
 	// so its magic bytes, like the rest of the block, are NULs.
 	magic := string(s.next(8)) // contains version field as well.
 	var format string
-	switch magic {
-	case "ustar\x0000": // POSIX tar (1003.1-1988)
+	switch {
+	case magic[:6] == "ustar\x00": // POSIX tar (1003.1-1988)
 		if string(header[508:512]) == "tar\x00" {
 			format = "star"
 		} else {
 			format = "posix"
 		}
-	case "ustar  \x00": // old GNU tar
+	case magic == "ustar  \x00": // old GNU tar
 		format = "gnu"
 	}
 
@@ -367,30 +510,308 @@ func (tr *Reader) readHeader() *Header {
 
 	// Maximum value of hdr.Size is 64 GB (12 octal digits),
 	// so there's no risk of int64 overflowing.
-	tr.nb = int64(hdr.Size)
-	tr.pad = -tr.nb & (blockSize - 1) // blockSize is a power of two
+	nb := int64(hdr.Size)
+	tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
+
+	// Set the current file reader.
+	tr.curr = &regFileReader{r: tr.r, nb: nb}
+
+	// Check for old GNU sparse format entry.
+	if hdr.Typeflag == TypeGNUSparse {
+		// Get the real size of the file.
+		hdr.Size = tr.octal(header[483:495])
+
+		// Read the sparse map.
+		sp := tr.readOldGNUSparseMap(header)
+		if tr.err != nil {
+			return nil
+		}
+		// Current file is a GNU sparse file. Update the current file reader.
+		tr.curr = &sparseFileReader{rfr: tr.curr.(*regFileReader), sp: sp, tot: hdr.Size}
+	}
 
 	return hdr
 }
 
+// A sparseEntry holds a single entry in a sparse file's sparse map.
+// A sparse entry indicates the offset and size in a sparse file of a
+// block of data.
+type sparseEntry struct {
+	offset   int64
+	numBytes int64
+}
+
+// readOldGNUSparseMap reads the sparse map as stored in the old GNU sparse format.
+// The sparse map is stored in the tar header if it's small enough. If it's larger than four entries,
+// then one or more extension headers are used to store the rest of the sparse map.
+func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
+	isExtended := header[oldGNUSparseMainHeaderIsExtendedOffset] != 0
+	spCap := oldGNUSparseMainHeaderNumEntries
+	if isExtended {
+		spCap += oldGNUSparseExtendedHeaderNumEntries
+	}
+	sp := make([]sparseEntry, 0, spCap)
+	s := slicer(header[oldGNUSparseMainHeaderOffset:])
+
+	// Read the four entries from the main tar header
+	for i := 0; i < oldGNUSparseMainHeaderNumEntries; i++ {
+		offset := tr.octal(s.next(oldGNUSparseOffsetSize))
+		numBytes := tr.octal(s.next(oldGNUSparseNumBytesSize))
+		if tr.err != nil {
+			tr.err = ErrHeader
+			return nil
+		}
+		if offset == 0 && numBytes == 0 {
+			break
+		}
+		sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
+	}
+
+	for isExtended {
+		// There are more entries. Read an extension header and parse its entries.
+		sparseHeader := make([]byte, blockSize)
+		if _, tr.err = io.ReadFull(tr.r, sparseHeader); tr.err != nil {
+			return nil
+		}
+		isExtended = sparseHeader[oldGNUSparseExtendedHeaderIsExtendedOffset] != 0
+		s = slicer(sparseHeader)
+		for i := 0; i < oldGNUSparseExtendedHeaderNumEntries; i++ {
+			offset := tr.octal(s.next(oldGNUSparseOffsetSize))
+			numBytes := tr.octal(s.next(oldGNUSparseNumBytesSize))
+			if tr.err != nil {
+				tr.err = ErrHeader
+				return nil
+			}
+			if offset == 0 && numBytes == 0 {
+				break
+			}
+			sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
+		}
+	}
+	return sp
+}
+
+// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format version 1.0.
+// The sparse map is stored just before the file data and padded out to the nearest block boundary.
+func readGNUSparseMap1x0(r io.Reader) ([]sparseEntry, error) {
+	buf := make([]byte, 2*blockSize)
+	sparseHeader := buf[:blockSize]
+
+	// readDecimal is a helper function to read a decimal integer from the sparse map
+	// while making sure to read from the file in blocks of size blockSize
+	readDecimal := func() (int64, error) {
+		// Look for newline
+		nl := bytes.IndexByte(sparseHeader, '\n')
+		if nl == -1 {
+			if len(sparseHeader) >= blockSize {
+				// This is an error
+				return 0, ErrHeader
+			}
+			oldLen := len(sparseHeader)
+			newLen := oldLen + blockSize
+			if cap(sparseHeader) < newLen {
+				// There's more header, but we need to make room for the next block
+				copy(buf, sparseHeader)
+				sparseHeader = buf[:newLen]
+			} else {
+				// There's more header, and we can just reslice
+				sparseHeader = sparseHeader[:newLen]
+			}
+
+			// Now that sparseHeader is large enough, read next block
+			if _, err := io.ReadFull(r, sparseHeader[oldLen:newLen]); err != nil {
+				return 0, err
+			}
+
+			// Look for a newline in the new data
+			nl = bytes.IndexByte(sparseHeader[oldLen:newLen], '\n')
+			if nl == -1 {
+				// This is an error
+				return 0, ErrHeader
+			}
+			nl += oldLen // We want the position from the beginning
+		}
+		// Now that we've found a newline, read a number
+		n, err := strconv.ParseInt(string(sparseHeader[:nl]), 10, 0)
+		if err != nil {
+			return 0, ErrHeader
+		}
+
+		// Update sparseHeader to consume this number
+		sparseHeader = sparseHeader[nl+1:]
+		return n, nil
+	}
+
+	// Read the first block
+	if _, err := io.ReadFull(r, sparseHeader); err != nil {
+		return nil, err
+	}
+
+	// The first line contains the number of entries
+	numEntries, err := readDecimal()
+	if err != nil {
+		return nil, err
+	}
+
+	// Read all the entries
+	sp := make([]sparseEntry, 0, numEntries)
+	for i := int64(0); i < numEntries; i++ {
+		// Read the offset
+		offset, err := readDecimal()
+		if err != nil {
+			return nil, err
+		}
+		// Read numBytes
+		numBytes, err := readDecimal()
+		if err != nil {
+			return nil, err
+		}
+
+		sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
+	}
+
+	return sp, nil
+}
+
+// readGNUSparseMap0x1 reads the sparse map as stored in GNU's PAX sparse format version 0.1.
+// The sparse map is stored in the PAX headers.
+func readGNUSparseMap0x1(headers map[string]string) ([]sparseEntry, error) {
+	// Get number of entries
+	numEntriesStr, ok := headers[paxGNUSparseNumBlocks]
+	if !ok {
+		return nil, ErrHeader
+	}
+	numEntries, err := strconv.ParseInt(numEntriesStr, 10, 0)
+	if err != nil {
+		return nil, ErrHeader
+	}
+
+	sparseMap := strings.Split(headers[paxGNUSparseMap], ",")
+
+	// There should be two numbers in sparseMap for each entry
+	if int64(len(sparseMap)) != 2*numEntries {
+		return nil, ErrHeader
+	}
+
+	// Loop through the entries in the sparse map
+	sp := make([]sparseEntry, 0, numEntries)
+	for i := int64(0); i < numEntries; i++ {
+		offset, err := strconv.ParseInt(sparseMap[2*i], 10, 0)
+		if err != nil {
+			return nil, ErrHeader
+		}
+		numBytes, err := strconv.ParseInt(sparseMap[2*i+1], 10, 0)
+		if err != nil {
+			return nil, ErrHeader
+		}
+		sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
+	}
+
+	return sp, nil
+}
+
+// numBytes returns the number of bytes left to read in the current file's entry
+// in the tar archive, or 0 if there is no current file.
+func (tr *Reader) numBytes() int64 {
+	if tr.curr == nil {
+		// No current file, so no bytes
+		return 0
+	}
+	return tr.curr.numBytes()
+}
+
 // Read reads from the current entry in the tar archive.
 // It returns 0, io.EOF when it reaches the end of that entry,
 // until Next is called to advance to the next entry.
 func (tr *Reader) Read(b []byte) (n int, err error) {
-	if tr.nb == 0 {
-		// file consumed
+	if tr.curr == nil {
 		return 0, io.EOF
 	}
+	n, err = tr.curr.Read(b)
+	if err != nil && err != io.EOF {
+		tr.err = err
+	}
+	return
+}
 
-	if int64(len(b)) > tr.nb {
-		b = b[0:tr.nb]
+func (rfr *regFileReader) Read(b []byte) (n int, err error) {
+	if rfr.nb == 0 {
+		// file consumed
+		return 0, io.EOF
 	}
-	n, err = tr.r.Read(b)
-	tr.nb -= int64(n)
+	if int64(len(b)) > rfr.nb {
+		b = b[0:rfr.nb]
+	}
+	n, err = rfr.r.Read(b)
+	rfr.nb -= int64(n)
 
-	if err == io.EOF && tr.nb > 0 {
+	if err == io.EOF && rfr.nb > 0 {
 		err = io.ErrUnexpectedEOF
 	}
-	tr.err = err
 	return
 }
+
+// numBytes returns the number of bytes left to read in the file's data in the tar archive.
+func (rfr *regFileReader) numBytes() int64 {
+	return rfr.nb
+}
+
+// readHole reads a sparse file hole ending at offset toOffset
+func (sfr *sparseFileReader) readHole(b []byte, toOffset int64) int {
+	n64 := toOffset - sfr.pos
+	if n64 > int64(len(b)) {
+		n64 = int64(len(b))
+	}
+	n := int(n64)
+	for i := 0; i < n; i++ {
+		b[i] = 0
+	}
+	sfr.pos += n64
+	return n
+}
+
+// Read reads the sparse file data in expanded form.
+func (sfr *sparseFileReader) Read(b []byte) (n int, err error) {
+	if len(sfr.sp) == 0 {
+		// No more data fragments to read from.
+		if sfr.pos < sfr.tot {
+			// We're in the last hole
+			n = sfr.readHole(b, sfr.tot)
+			return
+		}
+		// Otherwise, we're at the end of the file
+		return 0, io.EOF
+	}
+	if sfr.pos < sfr.sp[0].offset {
+		// We're in a hole
+		n = sfr.readHole(b, sfr.sp[0].offset)
+		return
+	}
+
+	// We're not in a hole, so we'll read from the next data fragment
+	posInFragment := sfr.pos - sfr.sp[0].offset
+	bytesLeft := sfr.sp[0].numBytes - posInFragment
+	if int64(len(b)) > bytesLeft {
+		b = b[0:bytesLeft]
+	}
+
+	n, err = sfr.rfr.Read(b)
+	sfr.pos += int64(n)
+
+	if int64(n) == bytesLeft {
+		// We're done with this fragment
+		sfr.sp = sfr.sp[1:]
+	}
+
+	if err == io.EOF && sfr.pos < sfr.tot {
+		// We reached the end of the last fragment's data, but there's a final hole
+		err = nil
+	}
+	return
+}
+
+// numBytes returns the number of bytes left to read in the sparse file's
+// sparse-encoded data in the tar archive.
+func (sfr *sparseFileReader) numBytes() int64 {
+	return sfr.rfr.nb
+}
diff --git a/src/pkg/archive/tar/reader_test.go b/src/pkg/archive/tar/reader_test.go
index 1285616..9601ffe 100644
--- a/src/pkg/archive/tar/reader_test.go
+++ b/src/pkg/archive/tar/reader_test.go
@@ -9,6 +9,7 @@ import (
 	"crypto/md5"
 	"fmt"
 	"io"
+	"io/ioutil"
 	"os"
 	"reflect"
 	"strings"
@@ -54,8 +55,92 @@ var gnuTarTest = &untarTest{
 	},
 }
 
+var sparseTarTest = &untarTest{
+	file: "testdata/sparse-formats.tar",
+	headers: []*Header{
+		{
+			Name:     "sparse-gnu",
+			Mode:     420,
+			Uid:      1000,
+			Gid:      1000,
+			Size:     200,
+			ModTime:  time.Unix(1392395740, 0),
+			Typeflag: 0x53,
+			Linkname: "",
+			Uname:    "david",
+			Gname:    "david",
+			Devmajor: 0,
+			Devminor: 0,
+		},
+		{
+			Name:     "sparse-posix-0.0",
+			Mode:     420,
+			Uid:      1000,
+			Gid:      1000,
+			Size:     200,
+			ModTime:  time.Unix(1392342187, 0),
+			Typeflag: 0x30,
+			Linkname: "",
+			Uname:    "david",
+			Gname:    "david",
+			Devmajor: 0,
+			Devminor: 0,
+		},
+		{
+			Name:     "sparse-posix-0.1",
+			Mode:     420,
+			Uid:      1000,
+			Gid:      1000,
+			Size:     200,
+			ModTime:  time.Unix(1392340456, 0),
+			Typeflag: 0x30,
+			Linkname: "",
+			Uname:    "david",
+			Gname:    "david",
+			Devmajor: 0,
+			Devminor: 0,
+		},
+		{
+			Name:     "sparse-posix-1.0",
+			Mode:     420,
+			Uid:      1000,
+			Gid:      1000,
+			Size:     200,
+			ModTime:  time.Unix(1392337404, 0),
+			Typeflag: 0x30,
+			Linkname: "",
+			Uname:    "david",
+			Gname:    "david",
+			Devmajor: 0,
+			Devminor: 0,
+		},
+		{
+			Name:     "end",
+			Mode:     420,
+			Uid:      1000,
+			Gid:      1000,
+			Size:     4,
+			ModTime:  time.Unix(1392398319, 0),
+			Typeflag: 0x30,
+			Linkname: "",
+			Uname:    "david",
+			Gname:    "david",
+			Devmajor: 0,
+			Devminor: 0,
+		},
+	},
+	cksums: []string{
+		"6f53234398c2449fe67c1812d993012f",
+		"6f53234398c2449fe67c1812d993012f",
+		"6f53234398c2449fe67c1812d993012f",
+		"6f53234398c2449fe67c1812d993012f",
+		"b0061974914468de549a2af8ced10316",
+	},
+}
+
 var untarTests = []*untarTest{
 	gnuTarTest,
+	sparseTarTest,
 	{
 		file: "testdata/star.tar",
 		headers: []*Header{
@@ -161,6 +246,46 @@ var untarTests = []*untarTest{
 			},
 		},
 	},
+	{
+		file: "testdata/xattrs.tar",
+		headers: []*Header{
+			{
+				Name:       "small.txt",
+				Mode:       0644,
+				Uid:        1000,
+				Gid:        10,
+				Size:       5,
+				ModTime:    time.Unix(1386065770, 448252320),
+				Typeflag:   '0',
+				Uname:      "alex",
+				Gname:      "wheel",
+				AccessTime: time.Unix(1389782991, 419875220),
+				ChangeTime: time.Unix(1389782956, 794414986),
+				Xattrs: map[string]string{
+					"user.key":  "value",
+					"user.key2": "value2",
+					// Interestingly, selinux encodes the terminating null inside the xattr
+					"security.selinux": "unconfined_u:object_r:default_t:s0\x00",
+				},
+			},
+			{
+				Name:       "small2.txt",
+				Mode:       0644,
+				Uid:        1000,
+				Gid:        10,
+				Size:       11,
+				ModTime:    time.Unix(1386065770, 449252304),
+				Typeflag:   '0',
+				Uname:      "alex",
+				Gname:      "wheel",
+				AccessTime: time.Unix(1389782991, 419875220),
+				ChangeTime: time.Unix(1386065770, 449252304),
+				Xattrs: map[string]string{
+					"security.selinux": "unconfined_u:object_r:default_t:s0\x00",
+				},
+			},
+		},
+	},
 }
 
 func TestReader(t *testing.T) {
@@ -180,7 +305,7 @@ testLoop:
 				f.Close()
 				continue testLoop
 			}
-			if *hdr != *header {
+			if !reflect.DeepEqual(*hdr, *header) {
 				t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v",
 					i, j, *hdr, *header)
 			}
@@ -253,7 +378,7 @@ func TestIncrementalRead(t *testing.T) {
 		}
 
 		// check the header
-		if *hdr != *headers[nread] {
+		if !reflect.DeepEqual(*hdr, *headers[nread]) {
 			t.Errorf("Incorrect header:\nhave %+v\nwant %+v",
 				*hdr, headers[nread])
 		}
@@ -321,7 +446,7 @@ func TestParsePAXHeader(t *testing.T) {
 		{"mtime", "mtime=1350244992.023960108", "30 mtime=1350244992.023960108\n"}}
 	for _, test := range paxTests {
 		key, expected, raw := test[0], test[1], test[2]
-		reader := bytes.NewBuffer([]byte(raw))
+		reader := bytes.NewReader([]byte(raw))
 		headers, err := parsePAX(reader)
 		if err != nil {
 			t.Errorf("Couldn't parse correctly formatted headers: %v", err)
@@ -337,7 +462,7 @@ func TestParsePAXHeader(t *testing.T) {
 			t.Error("Buffer wasn't consumed")
 		}
 	}
-	badHeader := bytes.NewBuffer([]byte("3 somelongkey="))
+	badHeader := bytes.NewReader([]byte("3 somelongkey="))
 	if _, err := parsePAX(badHeader); err != ErrHeader {
 		t.Fatal("Unexpected success when parsing bad header")
 	}
@@ -346,7 +471,7 @@ func TestParsePAXHeader(t *testing.T) {
 func TestParsePAXTime(t *testing.T) {
 	// Some valid PAX time values
 	timestamps := map[string]time.Time{
-		"1350244992.023960108":  time.Unix(1350244992, 23960108), // The commoon case
+		"1350244992.023960108":  time.Unix(1350244992, 23960108), // The common case
 		"1350244992.02396010":   time.Unix(1350244992, 23960100), // Lower precision value
 		"1350244992.0239601089": time.Unix(1350244992, 23960108), // Higher precision value
 		"1350244992":            time.Unix(1350244992, 0),        // Low precision value
@@ -383,3 +508,236 @@ func TestMergePAX(t *testing.T) {
 		t.Errorf("incorrect merge: got %+v, want %+v", hdr, want)
 	}
 }
+
+func TestSparseEndToEnd(t *testing.T) {
+	test := sparseTarTest
+	f, err := os.Open(test.file)
+	if err != nil {
+		t.Fatalf("Unexpected error: %v", err)
+	}
+	defer f.Close()
+
+	tr := NewReader(f)
+
+	headers := test.headers
+	cksums := test.cksums
+	nread := 0
+
+	// loop over all files
+	for ; ; nread++ {
+		hdr, err := tr.Next()
+		if hdr == nil || err == io.EOF {
+			break
+		}
+
+		// check the header
+		if !reflect.DeepEqual(*hdr, *headers[nread]) {
+			t.Errorf("Incorrect header:\nhave %+v\nwant %+v",
+				*hdr, headers[nread])
+		}
+
+		// read and checksum the file data
+		h := md5.New()
+		_, err = io.Copy(h, tr)
+		if err != nil {
+			t.Fatalf("Unexpected error: %v", err)
+		}
+
+		// verify checksum
+		have := fmt.Sprintf("%x", h.Sum(nil))
+		want := cksums[nread]
+		if want != have {
+			t.Errorf("Bad checksum on file %s:\nhave %+v\nwant %+v", hdr.Name, have, want)
+		}
+	}
+	if nread != len(headers) {
+		t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(headers), nread)
+	}
+}
+
+type sparseFileReadTest struct {
+	sparseData []byte
+	sparseMap  []sparseEntry
+	realSize   int64
+	expected   []byte
+}
+
+var sparseFileReadTests = []sparseFileReadTest{
+	{
+		sparseData: []byte("abcde"),
+		sparseMap: []sparseEntry{
+			{offset: 0, numBytes: 2},
+			{offset: 5, numBytes: 3},
+		},
+		realSize: 8,
+		expected: []byte("ab\x00\x00\x00cde"),
+	},
+	{
+		sparseData: []byte("abcde"),
+		sparseMap: []sparseEntry{
+			{offset: 0, numBytes: 2},
+			{offset: 5, numBytes: 3},
+		},
+		realSize: 10,
+		expected: []byte("ab\x00\x00\x00cde\x00\x00"),
+	},
+	{
+		sparseData: []byte("abcde"),
+		sparseMap: []sparseEntry{
+			{offset: 1, numBytes: 3},
+			{offset: 6, numBytes: 2},
+		},
+		realSize: 8,
+		expected: []byte("\x00abc\x00\x00de"),
+	},
+	{
+		sparseData: []byte("abcde"),
+		sparseMap: []sparseEntry{
+			{offset: 1, numBytes: 3},
+			{offset: 6, numBytes: 2},
+		},
+		realSize: 10,
+		expected: []byte("\x00abc\x00\x00de\x00\x00"),
+	},
+	{
+		sparseData: []byte(""),
+		sparseMap:  nil,
+		realSize:   2,
+		expected:   []byte("\x00\x00"),
+	},
+}
+
+func TestSparseFileReader(t *testing.T) {
+	for i, test := range sparseFileReadTests {
+		r := bytes.NewReader(test.sparseData)
+		nb := int64(r.Len())
+		sfr := &sparseFileReader{
+			rfr: &regFileReader{r: r, nb: nb},
+			sp:  test.sparseMap,
+			pos: 0,
+			tot: test.realSize,
+		}
+		if sfr.numBytes() != nb {
+			t.Errorf("test %d: Before reading, sfr.numBytes() = %d, want %d", i, sfr.numBytes(), nb)
+		}
+		buf, err := ioutil.ReadAll(sfr)
+		if err != nil {
+			t.Errorf("test %d: Unexpected error: %v", i, err)
+		}
+		if e := test.expected; !bytes.Equal(buf, e) {
+			t.Errorf("test %d: Contents = %v, want %v", i, buf, e)
+		}
+		if sfr.numBytes() != 0 {
+			t.Errorf("test %d: After draining the reader, numBytes() was nonzero", i)
+		}
+	}
+}
+
+func TestSparseIncrementalRead(t *testing.T) {
+	sparseMap := []sparseEntry{{10, 2}}
+	sparseData := []byte("Go")
+	expected := "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Go\x00\x00\x00\x00\x00\x00\x00\x00"
+
+	r := bytes.NewReader(sparseData)
+	nb := int64(r.Len())
+	sfr := &sparseFileReader{
+		rfr: &regFileReader{r: r, nb: nb},
+		sp:  sparseMap,
+		pos: 0,
+		tot: int64(len(expected)),
+	}
+
+	// We'll read the data 6 bytes at a time, with a hole of size 10 at
+	// the beginning and one of size 8 at the end.
+	var outputBuf bytes.Buffer
+	buf := make([]byte, 6)
+	for {
+		n, err := sfr.Read(buf)
+		if err == io.EOF {
+			break
+		}
+		if err != nil {
+			t.Errorf("Read: unexpected error %v\n", err)
+		}
+		if n > 0 {
+			_, err := outputBuf.Write(buf[:n])
+			if err != nil {
+				t.Errorf("Write: unexpected error %v\n", err)
+			}
+		}
+	}
+	got := outputBuf.String()
+	if got != expected {
+		t.Errorf("Contents = %v, want %v", got, expected)
+	}
+}
+
+func TestReadGNUSparseMap0x1(t *testing.T) {
+	headers := map[string]string{
+		paxGNUSparseNumBlocks: "4",
+		paxGNUSparseMap:       "0,5,10,5,20,5,30,5",
+	}
+	expected := []sparseEntry{
+		{offset: 0, numBytes: 5},
+		{offset: 10, numBytes: 5},
+		{offset: 20, numBytes: 5},
+		{offset: 30, numBytes: 5},
+	}
+
+	sp, err := readGNUSparseMap0x1(headers)
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+	if !reflect.DeepEqual(sp, expected) {
+		t.Errorf("Incorrect sparse map: got %v, wanted %v", sp, expected)
+	}
+}
+
+func TestReadGNUSparseMap1x0(t *testing.T) {
+	// This test uses lots of holes so the sparse header takes up more than two blocks
+	numEntries := 100
+	expected := make([]sparseEntry, 0, numEntries)
+	sparseMap := new(bytes.Buffer)
+
+	fmt.Fprintf(sparseMap, "%d\n", numEntries)
+	for i := 0; i < numEntries; i++ {
+		offset := int64(2048 * i)
+		numBytes := int64(1024)
+		expected = append(expected, sparseEntry{offset: offset, numBytes: numBytes})
+		fmt.Fprintf(sparseMap, "%d\n%d\n", offset, numBytes)
+	}
+
+	// Make the header the smallest multiple of blockSize that fits the sparseMap
+	headerBlocks := (sparseMap.Len() + blockSize - 1) / blockSize
+	bufLen := blockSize * headerBlocks
+	buf := make([]byte, bufLen)
+	copy(buf, sparseMap.Bytes())
+
+	// Get an reader to read the sparse map
+	r := bytes.NewReader(buf)
+
+	// Read the sparse map
+	sp, err := readGNUSparseMap1x0(r)
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+	if !reflect.DeepEqual(sp, expected) {
+		t.Errorf("Incorrect sparse map: got %v, wanted %v", sp, expected)
+	}
+}
+
+func TestUninitializedRead(t *testing.T) {
+	test := gnuTarTest
+	f, err := os.Open(test.file)
+	if err != nil {
+		t.Fatalf("Unexpected error: %v", err)
+	}
+	defer f.Close()
+
+	tr := NewReader(f)
+	_, err = tr.Read([]byte{})
+	if err == nil || err != io.EOF {
+		t.Errorf("Unexpected error: %v, wanted %v", err, io.EOF)
+	}
+
+}
diff --git a/src/pkg/archive/tar/stat_atim.go b/src/pkg/archive/tar/stat_atim.go
index 6029b08..cf9cc79 100644
--- a/src/pkg/archive/tar/stat_atim.go
+++ b/src/pkg/archive/tar/stat_atim.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 linux openbsd
+// +build linux dragonfly openbsd solaris
 
 package tar
 
diff --git a/src/pkg/archive/tar/stat_unix.go b/src/pkg/archive/tar/stat_unix.go
index 92bc924..cb843db 100644
--- a/src/pkg/archive/tar/stat_unix.go
+++ b/src/pkg/archive/tar/stat_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 linux darwin freebsd openbsd netbsd
+// +build linux darwin dragonfly freebsd openbsd netbsd solaris
 
 package tar
 
diff --git a/src/pkg/archive/tar/tar_test.go b/src/pkg/archive/tar/tar_test.go
index 616a9cc..ed333f3 100644
--- a/src/pkg/archive/tar/tar_test.go
+++ b/src/pkg/archive/tar/tar_test.go
@@ -36,6 +36,10 @@ func TestFileInfoHeader(t *testing.T) {
 	if g, e := h.ModTime, fi.ModTime(); !g.Equal(e) {
 		t.Errorf("ModTime = %v; want %v", g, e)
 	}
+	// FileInfoHeader should error when passing nil FileInfo
+	if _, err := FileInfoHeader(nil, ""); err == nil {
+		t.Fatalf("Expected error when passing nil to FileInfoHeader")
+	}
 }
 
 func TestFileInfoHeaderDir(t *testing.T) {
diff --git a/src/pkg/archive/tar/testdata/sparse-formats.tar b/src/pkg/archive/tar/testdata/sparse-formats.tar
new file mode 100644
index 0000000..8bd4e74
Binary files /dev/null and b/src/pkg/archive/tar/testdata/sparse-formats.tar differ
diff --git a/src/pkg/archive/tar/testdata/writer-big-long.tar b/src/pkg/archive/tar/testdata/writer-big-long.tar
new file mode 100644
index 0000000..5960ee8
Binary files /dev/null and b/src/pkg/archive/tar/testdata/writer-big-long.tar differ
diff --git a/src/pkg/archive/tar/testdata/xattrs.tar b/src/pkg/archive/tar/testdata/xattrs.tar
new file mode 100644
index 0000000..9701950
Binary files /dev/null and b/src/pkg/archive/tar/testdata/xattrs.tar differ
diff --git a/src/pkg/archive/tar/writer.go b/src/pkg/archive/tar/writer.go
index 549f146..6eff6f6 100644
--- a/src/pkg/archive/tar/writer.go
+++ b/src/pkg/archive/tar/writer.go
@@ -218,8 +218,8 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
 				tw.cString(prefixHeaderBytes, prefix, false, paxNone, nil)
 
 				// Use the ustar magic if we used ustar long names.
-				if len(prefix) > 0 {
-					copy(header[257:265], []byte("ustar\000"))
+				if len(prefix) > 0 && !tw.usedBinary {
+					copy(header[257:265], []byte("ustar\x00"))
 				}
 			}
 		}
@@ -236,6 +236,12 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
 		return tw.err
 	}
 
+	if allowPax {
+		for k, v := range hdr.Xattrs {
+			paxHeaders[paxXattr+k] = v
+		}
+	}
+
 	if len(paxHeaders) > 0 {
 		if !allowPax {
 			return errInvalidHeader
diff --git a/src/pkg/archive/tar/writer_test.go b/src/pkg/archive/tar/writer_test.go
index 30ebf97..512fab1 100644
--- a/src/pkg/archive/tar/writer_test.go
+++ b/src/pkg/archive/tar/writer_test.go
@@ -10,6 +10,7 @@ import (
 	"io"
 	"io/ioutil"
 	"os"
+	"reflect"
 	"strings"
 	"testing"
 	"testing/iotest"
@@ -102,6 +103,29 @@ var writerTests = []*writerTest{
 			},
 		},
 	},
+	// The truncated test file was produced using these commands:
+	//   dd if=/dev/zero bs=1048576 count=16384 > (longname/)*15 /16gig.txt
+	//   tar -b 1 -c -f- (longname/)*15 /16gig.txt | dd bs=512 count=8 > writer-big-long.tar
+	{
+		file: "testdata/writer-big-long.tar",
+		entries: []*writerTestEntry{
+			{
+				header: &Header{
+					Name:     strings.Repeat("longname/", 15) + "16gig.txt",
+					Mode:     0644,
+					Uid:      1000,
+					Gid:      1000,
+					Size:     16 << 30,
+					ModTime:  time.Unix(1399583047, 0),
+					Typeflag: '0',
+					Uname:    "guillaume",
+					Gname:    "guillaume",
+				},
+				// fake contents
+				contents: strings.Repeat("\x00", 4<<10),
+			},
+		},
+	},
 	// This file was produced using gnu tar 1.17
 	// gnutar  -b 4 --format=ustar (longname/)*15 + file.txt
 	{
@@ -338,6 +362,45 @@ func TestPaxNonAscii(t *testing.T) {
 	}
 }
 
+func TestPaxXattrs(t *testing.T) {
+	xattrs := map[string]string{
+		"user.key": "value",
+	}
+
+	// Create an archive with an xattr
+	fileinfo, err := os.Stat("testdata/small.txt")
+	if err != nil {
+		t.Fatal(err)
+	}
+	hdr, err := FileInfoHeader(fileinfo, "")
+	if err != nil {
+		t.Fatalf("os.Stat: %v", err)
+	}
+	contents := "Kilts"
+	hdr.Xattrs = xattrs
+	var buf bytes.Buffer
+	writer := NewWriter(&buf)
+	if err := writer.WriteHeader(hdr); err != nil {
+		t.Fatal(err)
+	}
+	if _, err = writer.Write([]byte(contents)); err != nil {
+		t.Fatal(err)
+	}
+	if err := writer.Close(); err != nil {
+		t.Fatal(err)
+	}
+	// Test that we can get the xattrs back out of the archive.
+	reader := NewReader(&buf)
+	hdr, err = reader.Next()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !reflect.DeepEqual(hdr.Xattrs, xattrs) {
+		t.Fatalf("xattrs did not survive round trip: got %+v, want %+v",
+			hdr.Xattrs, xattrs)
+	}
+}
+
 func TestPAXHeader(t *testing.T) {
 	medName := strings.Repeat("CD", 50)
 	longName := strings.Repeat("AB", 100)
diff --git a/src/pkg/archive/zip/reader.go b/src/pkg/archive/zip/reader.go
index 1167373..80ee030 100644
--- a/src/pkg/archive/zip/reader.go
+++ b/src/pkg/archive/zip/reader.go
@@ -253,7 +253,7 @@ func readDirectoryHeader(f *File, r io.Reader) error {
 			}
 			if tag == zip64ExtraId {
 				// update directory values from the zip64 extra block
-				eb := readBuf(b)
+				eb := readBuf(b[:size])
 				if len(eb) >= 8 {
 					f.UncompressedSize64 = eb.uint64()
 				}
diff --git a/src/pkg/archive/zip/reader_test.go b/src/pkg/archive/zip/reader_test.go
index 78875ec..5652f3a 100644
--- a/src/pkg/archive/zip/reader_test.go
+++ b/src/pkg/archive/zip/reader_test.go
@@ -235,6 +235,18 @@ var tests = []ZipTest{
 			},
 		},
 	},
+	// Another zip64 file with different Extras fields. (golang.org/issue/7069)
+	{
+		Name: "zip64-2.zip",
+		File: []ZipTestFile{
+			{
+				Name:    "README",
+				Content: []byte("This small file is in ZIP64 format.\n"),
+				Mtime:   "08-10-12 14:33:32",
+				Mode:    0644,
+			},
+		},
+	},
 }
 
 var crossPlatform = []ZipTestFile{
@@ -343,19 +355,13 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) {
 
 	testFileMode(t, zt.Name, f, ft.Mode)
 
-	size0 := f.UncompressedSize
-
 	var b bytes.Buffer
 	r, err := f.Open()
 	if err != nil {
-		t.Error(err)
+		t.Errorf("%s: %v", zt.Name, err)
 		return
 	}
 
-	if size1 := f.UncompressedSize; size0 != size1 {
-		t.Errorf("file %q changed f.UncompressedSize from %d to %d", f.Name, size0, size1)
-	}
-
 	_, err = io.Copy(&b, r)
 	if err != ft.ContentErr {
 		t.Errorf("%s: copying contents: %v (want %v)", zt.Name, err, ft.ContentErr)
@@ -365,6 +371,14 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) {
 	}
 	r.Close()
 
+	size := uint64(f.UncompressedSize)
+	if size == uint32max {
+		size = f.UncompressedSize64
+	}
+	if g := uint64(b.Len()); g != size {
+		t.Errorf("%v: read %v bytes but f.UncompressedSize == %v", f.Name, g, size)
+	}
+
 	var c []byte
 	if ft.Content != nil {
 		c = ft.Content
diff --git a/src/pkg/archive/zip/register.go b/src/pkg/archive/zip/register.go
index c046f08..4211ec7 100644
--- a/src/pkg/archive/zip/register.go
+++ b/src/pkg/archive/zip/register.go
@@ -6,6 +6,7 @@ package zip
 
 import (
 	"compress/flate"
+	"errors"
 	"io"
 	"io/ioutil"
 	"sync"
@@ -21,12 +22,50 @@ type Compressor func(io.Writer) (io.WriteCloser, error)
 // when they're finished reading.
 type Decompressor func(io.Reader) io.ReadCloser
 
+var flateWriterPool sync.Pool
+
+func newFlateWriter(w io.Writer) io.WriteCloser {
+	fw, ok := flateWriterPool.Get().(*flate.Writer)
+	if ok {
+		fw.Reset(w)
+	} else {
+		fw, _ = flate.NewWriter(w, 5)
+	}
+	return &pooledFlateWriter{fw: fw}
+}
+
+type pooledFlateWriter struct {
+	mu sync.Mutex // guards Close and Write
+	fw *flate.Writer
+}
+
+func (w *pooledFlateWriter) Write(p []byte) (n int, err error) {
+	w.mu.Lock()
+	defer w.mu.Unlock()
+	if w.fw == nil {
+		return 0, errors.New("Write after Close")
+	}
+	return w.fw.Write(p)
+}
+
+func (w *pooledFlateWriter) Close() error {
+	w.mu.Lock()
+	defer w.mu.Unlock()
+	var err error
+	if w.fw != nil {
+		err = w.fw.Close()
+		flateWriterPool.Put(w.fw)
+		w.fw = nil
+	}
+	return err
+}
+
 var (
 	mu sync.RWMutex // guards compressor and decompressor maps
 
 	compressors = map[uint16]Compressor{
 		Store:   func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil },
-		Deflate: func(w io.Writer) (io.WriteCloser, error) { return flate.NewWriter(w, 5) },
+		Deflate: func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil },
 	}
 
 	decompressors = map[uint16]Decompressor{
diff --git a/src/pkg/archive/zip/struct.go b/src/pkg/archive/zip/struct.go
index 65e5238..cb28e83 100644
--- a/src/pkg/archive/zip/struct.go
+++ b/src/pkg/archive/zip/struct.go
@@ -174,13 +174,13 @@ func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) {
 	return
 }
 
-// ModTime returns the modification time.
+// ModTime returns the modification time in UTC.
 // The resolution is 2s.
 func (h *FileHeader) ModTime() time.Time {
 	return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
 }
 
-// SetModTime sets the ModifiedTime and ModifiedDate fields to the given time.
+// SetModTime sets the ModifiedTime and ModifiedDate fields to the given time in UTC.
 // The resolution is 2s.
 func (h *FileHeader) SetModTime(t time.Time) {
 	h.ModifiedDate, h.ModifiedTime = timeToMsDosTime(t)
diff --git a/src/pkg/archive/zip/testdata/zip64-2.zip b/src/pkg/archive/zip/testdata/zip64-2.zip
new file mode 100644
index 0000000..f844e35
Binary files /dev/null and b/src/pkg/archive/zip/testdata/zip64-2.zip differ
diff --git a/src/pkg/archive/zip/writer_test.go b/src/pkg/archive/zip/writer_test.go
index 8b1c4df..4bfa870 100644
--- a/src/pkg/archive/zip/writer_test.go
+++ b/src/pkg/archive/zip/writer_test.go
@@ -125,3 +125,21 @@ func testReadFile(t *testing.T, f *File, wt *WriteTest) {
 		t.Errorf("File contents %q, want %q", b, wt.Data)
 	}
 }
+
+func BenchmarkCompressedZipGarbage(b *testing.B) {
+	b.ReportAllocs()
+	var buf bytes.Buffer
+	bigBuf := bytes.Repeat([]byte("a"), 1<<20)
+	for i := 0; i < b.N; i++ {
+		buf.Reset()
+		zw := NewWriter(&buf)
+		for j := 0; j < 3; j++ {
+			w, _ := zw.CreateHeader(&FileHeader{
+				Name:   "foo",
+				Method: Deflate,
+			})
+			w.Write(bigBuf)
+		}
+		zw.Close()
+	}
+}
diff --git a/src/pkg/bufio/bufio.go b/src/pkg/bufio/bufio.go
index d1ff3c9..61ef261 100644
--- a/src/pkg/bufio/bufio.go
+++ b/src/pkg/bufio/bufio.go
@@ -38,6 +38,7 @@ type Reader struct {
 }
 
 const minReadBufferSize = 16
+const maxConsecutiveEmptyReads = 100
 
 // NewReaderSize returns a new Reader whose buffer has at least the specified
 // size. If the argument io.Reader is already a Reader with large enough
@@ -87,15 +88,26 @@ func (b *Reader) fill() {
 		b.r = 0
 	}
 
-	// Read new data.
-	n, err := b.rd.Read(b.buf[b.w:])
-	if n < 0 {
-		panic(errNegativeRead)
+	if b.w >= len(b.buf) {
+		panic("bufio: tried to fill full buffer")
 	}
-	b.w += n
-	if err != nil {
-		b.err = err
+
+	// Read new data: try a limited number of times.
+	for i := maxConsecutiveEmptyReads; i > 0; i-- {
+		n, err := b.rd.Read(b.buf[b.w:])
+		if n < 0 {
+			panic(errNegativeRead)
+		}
+		b.w += n
+		if err != nil {
+			b.err = err
+			return
+		}
+		if n > 0 {
+			return
+		}
 	}
+	b.err = io.ErrNoProgress
 }
 
 func (b *Reader) readErr() error {
@@ -115,8 +127,9 @@ func (b *Reader) Peek(n int) ([]byte, error) {
 	if n > len(b.buf) {
 		return nil, ErrBufferFull
 	}
+	// 0 <= n <= len(b.buf)
 	for b.w-b.r < n && b.err == nil {
-		b.fill()
+		b.fill() // b.w-b.r < len(b.buf) => buffer is not full
 	}
 	m := b.w - b.r
 	if m > n {
@@ -142,7 +155,7 @@ func (b *Reader) Read(p []byte) (n int, err error) {
 	if n == 0 {
 		return 0, b.readErr()
 	}
-	if b.w == b.r {
+	if b.r == b.w {
 		if b.err != nil {
 			return 0, b.readErr()
 		}
@@ -150,13 +163,16 @@ func (b *Reader) Read(p []byte) (n int, err error) {
 			// Large read, empty buffer.
 			// Read directly into p to avoid copy.
 			n, b.err = b.rd.Read(p)
+			if n < 0 {
+				panic(errNegativeRead)
+			}
 			if n > 0 {
 				b.lastByte = int(p[n-1])
 				b.lastRuneSize = -1
 			}
 			return n, b.readErr()
 		}
-		b.fill()
+		b.fill() // buffer is empty
 		if b.w == b.r {
 			return 0, b.readErr()
 		}
@@ -176,11 +192,11 @@ func (b *Reader) Read(p []byte) (n int, err error) {
 // If no byte is available, returns an error.
 func (b *Reader) ReadByte() (c byte, err error) {
 	b.lastRuneSize = -1
-	for b.w == b.r {
+	for b.r == b.w {
 		if b.err != nil {
 			return 0, b.readErr()
 		}
-		b.fill()
+		b.fill() // buffer is empty
 	}
 	c = b.buf[b.r]
 	b.r++
@@ -190,19 +206,19 @@ func (b *Reader) ReadByte() (c byte, err error) {
 
 // UnreadByte unreads the last byte.  Only the most recently read byte can be unread.
 func (b *Reader) UnreadByte() error {
-	b.lastRuneSize = -1
-	if b.r == b.w && b.lastByte >= 0 {
-		b.w = 1
-		b.r = 0
-		b.buf[0] = byte(b.lastByte)
-		b.lastByte = -1
-		return nil
-	}
-	if b.r <= 0 {
+	if b.lastByte < 0 || b.r == 0 && b.w > 0 {
 		return ErrInvalidUnreadByte
 	}
-	b.r--
+	// b.r > 0 || b.w == 0
+	if b.r > 0 {
+		b.r--
+	} else {
+		// b.r == 0 && b.w == 0
+		b.w = 1
+	}
+	b.buf[b.r] = byte(b.lastByte)
 	b.lastByte = -1
+	b.lastRuneSize = -1
 	return nil
 }
 
@@ -210,8 +226,8 @@ func (b *Reader) UnreadByte() error {
 // rune and its size in bytes. If the encoded rune is invalid, it consumes one byte
 // and returns unicode.ReplacementChar (U+FFFD) with a size of 1.
 func (b *Reader) ReadRune() (r rune, size int, err error) {
-	for b.r+utf8.UTFMax > b.w && !utf8.FullRune(b.buf[b.r:b.w]) && b.err == nil {
-		b.fill()
+	for b.r+utf8.UTFMax > b.w && !utf8.FullRune(b.buf[b.r:b.w]) && b.err == nil && b.w-b.r < len(b.buf) {
+		b.fill() // b.w-b.r < len(buf) => buffer is not full
 	}
 	b.lastRuneSize = -1
 	if b.r == b.w {
@@ -232,7 +248,7 @@ func (b *Reader) ReadRune() (r rune, size int, err error) {
 // regard it is stricter than UnreadByte, which will unread the last byte
 // from any read operation.)
 func (b *Reader) UnreadRune() error {
-	if b.lastRuneSize < 0 || b.r == 0 {
+	if b.lastRuneSize < 0 || b.r < b.lastRuneSize {
 		return ErrInvalidUnreadRune
 	}
 	b.r -= b.lastRuneSize
@@ -255,37 +271,39 @@ func (b *Reader) Buffered() int { return b.w - b.r }
 // ReadBytes or ReadString instead.
 // ReadSlice returns err != nil if and only if line does not end in delim.
 func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
-	// Look in buffer.
-	if i := bytes.IndexByte(b.buf[b.r:b.w], delim); i >= 0 {
-		line1 := b.buf[b.r : b.r+i+1]
-		b.r += i + 1
-		return line1, nil
-	}
-
-	// Read more into buffer, until buffer fills or we find delim.
 	for {
-		if b.err != nil {
-			line := b.buf[b.r:b.w]
-			b.r = b.w
-			return line, b.readErr()
+		// Search buffer.
+		if i := bytes.IndexByte(b.buf[b.r:b.w], delim); i >= 0 {
+			line = b.buf[b.r : b.r+i+1]
+			b.r += i + 1
+			break
 		}
 
-		n := b.Buffered()
-		b.fill()
-
-		// Search new part of buffer
-		if i := bytes.IndexByte(b.buf[n:b.w], delim); i >= 0 {
-			line := b.buf[0 : n+i+1]
-			b.r = n + i + 1
-			return line, nil
+		// Pending error?
+		if b.err != nil {
+			line = b.buf[b.r:b.w]
+			b.r = b.w
+			err = b.readErr()
+			break
 		}
 
-		// Buffer is full?
-		if b.Buffered() >= len(b.buf) {
+		// Buffer full?
+		if n := b.Buffered(); n >= len(b.buf) {
 			b.r = b.w
-			return b.buf, ErrBufferFull
+			line = b.buf
+			err = ErrBufferFull
+			break
 		}
+
+		b.fill() // buffer is not full
 	}
+
+	// Handle last byte, if any.
+	if i := len(line) - 1; i >= 0 {
+		b.lastByte = int(line[i])
+	}
+
+	return
 }
 
 // ReadLine is a low-level line-reading primitive. Most callers should use
@@ -301,6 +319,9 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
 //
 // The text returned from ReadLine does not include the line end ("\r\n" or "\n").
 // No indication or error is given if the input ends without a final line end.
+// Calling UnreadByte after ReadLine will always unread the last byte read
+// (possibly a character belonging to the line end) even if that byte is not
+// part of the line returned by ReadLine.
 func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) {
 	line, err = b.ReadSlice('\n')
 	if err == ErrBufferFull {
@@ -410,12 +431,24 @@ func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
 		return n, err
 	}
 
-	for b.fill(); b.r < b.w; b.fill() {
+	if w, ok := w.(io.ReaderFrom); ok {
+		m, err := w.ReadFrom(b.rd)
+		n += m
+		return n, err
+	}
+
+	if b.w-b.r < len(b.buf) {
+		b.fill() // buffer not full
+	}
+
+	for b.r < b.w {
+		// b.r < b.w => buffer is not empty
 		m, err := b.writeBuf(w)
 		n += m
 		if err != nil {
 			return n, err
 		}
+		b.fill() // buffer is empty
 	}
 
 	if b.err == io.EOF {
@@ -428,6 +461,9 @@ func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
 // writeBuf writes the Reader's buffer to the writer.
 func (b *Reader) writeBuf(w io.Writer) (int64, error) {
 	n, err := w.Write(b.buf[b.r:b.w])
+	if n < b.r-b.w {
+		panic(errors.New("bufio: writer did not write all data"))
+	}
 	b.r += n
 	return int64(n), err
 }
@@ -619,9 +655,16 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
 				return n, err1
 			}
 		}
-		m, err = r.Read(b.buf[b.n:])
-		if m == 0 {
-			break
+		nr := 0
+		for nr < maxConsecutiveEmptyReads {
+			m, err = r.Read(b.buf[b.n:])
+			if m != 0 || err != nil {
+				break
+			}
+			nr++
+		}
+		if nr == maxConsecutiveEmptyReads {
+			return n, io.ErrNoProgress
 		}
 		b.n += m
 		n += int64(m)
diff --git a/src/pkg/bufio/bufio_test.go b/src/pkg/bufio/bufio_test.go
index 41bd3d4..76d3c8e 100644
--- a/src/pkg/bufio/bufio_test.go
+++ b/src/pkg/bufio/bufio_test.go
@@ -14,6 +14,7 @@ import (
 	"strings"
 	"testing"
 	"testing/iotest"
+	"time"
 	"unicode/utf8"
 )
 
@@ -65,12 +66,12 @@ func readBytes(buf *Reader) string {
 
 func TestReaderSimple(t *testing.T) {
 	data := "hello world"
-	b := NewReader(bytes.NewBufferString(data))
+	b := NewReader(strings.NewReader(data))
 	if s := readBytes(b); s != "hello world" {
 		t.Errorf("simple hello world test failed: got %q", s)
 	}
 
-	b = NewReader(newRot13Reader(bytes.NewBufferString(data)))
+	b = NewReader(newRot13Reader(strings.NewReader(data)))
 	if s := readBytes(b); s != "uryyb jbeyq" {
 		t.Errorf("rot13 hello world test failed: got %q", s)
 	}
@@ -139,7 +140,7 @@ var bufreaders = []bufReader{
 const minReadBufferSize = 16
 
 var bufsizes = []int{
-	minReadBufferSize, 23, 32, 46, 64, 93, 128, 1024, 4096,
+	0, minReadBufferSize, 23, 32, 46, 64, 93, 128, 1024, 4096,
 }
 
 func TestReader(t *testing.T) {
@@ -161,7 +162,7 @@ func TestReader(t *testing.T) {
 					readmaker := readMakers[i]
 					bufreader := bufreaders[j]
 					bufsize := bufsizes[k]
-					read := readmaker.fn(bytes.NewBufferString(text))
+					read := readmaker.fn(strings.NewReader(text))
 					buf := NewReaderSize(read, bufsize)
 					s := bufreader.fn(buf)
 					if s != text {
@@ -174,6 +175,34 @@ func TestReader(t *testing.T) {
 	}
 }
 
+type zeroReader struct{}
+
+func (zeroReader) Read(p []byte) (int, error) {
+	return 0, nil
+}
+
+func TestZeroReader(t *testing.T) {
+	var z zeroReader
+	r := NewReader(z)
+
+	c := make(chan error)
+	go func() {
+		_, err := r.ReadByte()
+		c <- err
+	}()
+
+	select {
+	case err := <-c:
+		if err == nil {
+			t.Error("error expected")
+		} else if err != io.ErrNoProgress {
+			t.Error("unexpected error:", err)
+		}
+	case <-time.After(time.Second):
+		t.Error("test timed out (endless loop in ReadByte?)")
+	}
+}
+
 // A StringReader delivers its data one string segment at a time via Read.
 type StringReader struct {
 	data []string
@@ -228,34 +257,150 @@ func TestReadRune(t *testing.T) {
 }
 
 func TestUnreadRune(t *testing.T) {
-	got := ""
 	segments := []string{"Hello, world:", "日本語"}
-	data := strings.Join(segments, "")
 	r := NewReader(&StringReader{data: segments})
+	got := ""
+	want := strings.Join(segments, "")
 	// Normal execution.
 	for {
 		r1, _, err := r.ReadRune()
 		if err != nil {
 			if err != io.EOF {
-				t.Error("unexpected EOF")
+				t.Error("unexpected error on ReadRune:", err)
 			}
 			break
 		}
 		got += string(r1)
-		// Put it back and read it again
+		// Put it back and read it again.
 		if err = r.UnreadRune(); err != nil {
-			t.Error("unexpected error on UnreadRune:", err)
+			t.Fatal("unexpected error on UnreadRune:", err)
 		}
 		r2, _, err := r.ReadRune()
 		if err != nil {
-			t.Error("unexpected error reading after unreading:", err)
+			t.Fatal("unexpected error reading after unreading:", err)
 		}
 		if r1 != r2 {
-			t.Errorf("incorrect rune after unread: got %c wanted %c", r1, r2)
+			t.Fatalf("incorrect rune after unread: got %c, want %c", r1, r2)
+		}
+	}
+	if got != want {
+		t.Errorf("got %q, want %q", got, want)
+	}
+}
+
+func TestUnreadByte(t *testing.T) {
+	segments := []string{"Hello, ", "world"}
+	r := NewReader(&StringReader{data: segments})
+	got := ""
+	want := strings.Join(segments, "")
+	// Normal execution.
+	for {
+		b1, err := r.ReadByte()
+		if err != nil {
+			if err != io.EOF {
+				t.Error("unexpected error on ReadByte:", err)
+			}
+			break
+		}
+		got += string(b1)
+		// Put it back and read it again.
+		if err = r.UnreadByte(); err != nil {
+			t.Fatal("unexpected error on UnreadByte:", err)
 		}
+		b2, err := r.ReadByte()
+		if err != nil {
+			t.Fatal("unexpected error reading after unreading:", err)
+		}
+		if b1 != b2 {
+			t.Fatalf("incorrect byte after unread: got %q, want %q", b1, b2)
+		}
+	}
+	if got != want {
+		t.Errorf("got %q, want %q", got, want)
 	}
-	if got != data {
-		t.Errorf("want=%q got=%q", data, got)
+}
+
+func TestUnreadByteMultiple(t *testing.T) {
+	segments := []string{"Hello, ", "world"}
+	data := strings.Join(segments, "")
+	for n := 0; n <= len(data); n++ {
+		r := NewReader(&StringReader{data: segments})
+		// Read n bytes.
+		for i := 0; i < n; i++ {
+			b, err := r.ReadByte()
+			if err != nil {
+				t.Fatalf("n = %d: unexpected error on ReadByte: %v", n, err)
+			}
+			if b != data[i] {
+				t.Fatalf("n = %d: incorrect byte returned from ReadByte: got %q, want %q", n, b, data[i])
+			}
+		}
+		// Unread one byte if there is one.
+		if n > 0 {
+			if err := r.UnreadByte(); err != nil {
+				t.Errorf("n = %d: unexpected error on UnreadByte: %v", n, err)
+			}
+		}
+		// Test that we cannot unread any further.
+		if err := r.UnreadByte(); err == nil {
+			t.Errorf("n = %d: expected error on UnreadByte", n)
+		}
+	}
+}
+
+func TestUnreadByteOthers(t *testing.T) {
+	// A list of readers to use in conjunction with UnreadByte.
+	var readers = []func(*Reader, byte) ([]byte, error){
+		(*Reader).ReadBytes,
+		(*Reader).ReadSlice,
+		func(r *Reader, delim byte) ([]byte, error) {
+			data, err := r.ReadString(delim)
+			return []byte(data), err
+		},
+		// ReadLine doesn't fit the data/pattern easily
+		// so we leave it out. It should be covered via
+		// the ReadSlice test since ReadLine simply calls
+		// ReadSlice, and it's that function that handles
+		// the last byte.
+	}
+
+	// Try all readers with UnreadByte.
+	for rno, read := range readers {
+		// Some input data that is longer than the minimum reader buffer size.
+		const n = 10
+		var buf bytes.Buffer
+		for i := 0; i < n; i++ {
+			buf.WriteString("abcdefg")
+		}
+
+		r := NewReaderSize(&buf, minReadBufferSize)
+		readTo := func(delim byte, want string) {
+			data, err := read(r, delim)
+			if err != nil {
+				t.Fatalf("#%d: unexpected error reading to %c: %v", rno, delim, err)
+			}
+			if got := string(data); got != want {
+				t.Fatalf("#%d: got %q, want %q", rno, got, want)
+			}
+		}
+
+		// Read the data with occasional UnreadByte calls.
+		for i := 0; i < n; i++ {
+			readTo('d', "abcd")
+			for j := 0; j < 3; j++ {
+				if err := r.UnreadByte(); err != nil {
+					t.Fatalf("#%d: unexpected error on UnreadByte: %v", rno, err)
+				}
+				readTo('d', "d")
+			}
+			readTo('g', "efg")
+		}
+
+		// All data should have been read.
+		_, err := r.ReadByte()
+		if err != io.EOF {
+			t.Errorf("#%d: got error %v; want EOF", rno, err)
+		}
 	}
 }
 
@@ -447,7 +592,7 @@ func TestWriteErrors(t *testing.T) {
 
 func TestNewReaderSizeIdempotent(t *testing.T) {
 	const BufSize = 1000
-	b := NewReaderSize(bytes.NewBufferString("hello world"), BufSize)
+	b := NewReaderSize(strings.NewReader("hello world"), BufSize)
 	// Does it recognize itself?
 	b1 := NewReaderSize(b, BufSize)
 	if b1 != b {
@@ -516,6 +661,9 @@ func TestPeek(t *testing.T) {
 	if s, err := buf.Peek(4); string(s) != "abcd" || err != nil {
 		t.Fatalf("want %q got %q, err=%v", "abcd", string(s), err)
 	}
+	if _, err := buf.Peek(-1); err != ErrNegativeCount {
+		t.Fatalf("want ErrNegativeCount got %v", err)
+	}
 	if _, err := buf.Peek(32); err != ErrBufferFull {
 		t.Fatalf("want ErrBufFull got %v", err)
 	}
@@ -642,7 +790,7 @@ func TestLineTooLong(t *testing.T) {
 	for i := 0; i < minReadBufferSize*5/2; i++ {
 		data = append(data, '0'+byte(i%10))
 	}
-	buf := bytes.NewBuffer(data)
+	buf := bytes.NewReader(data)
 	l := NewReaderSize(buf, minReadBufferSize)
 	line, isPrefix, err := l.ReadLine()
 	if !isPrefix || !bytes.Equal(line, data[:minReadBufferSize]) || err != nil {
@@ -667,7 +815,7 @@ func TestLineTooLong(t *testing.T) {
 func TestReadAfterLines(t *testing.T) {
 	line1 := "this is line1"
 	restData := "this is line2\nthis is line 3\n"
-	inbuf := bytes.NewBuffer([]byte(line1 + "\n" + restData))
+	inbuf := bytes.NewReader([]byte(line1 + "\n" + restData))
 	outbuf := new(bytes.Buffer)
 	maxLineLength := len(line1) + len(restData)/2
 	l := NewReaderSize(inbuf, maxLineLength)
@@ -693,7 +841,7 @@ func TestReadEmptyBuffer(t *testing.T) {
 }
 
 func TestLinesAfterRead(t *testing.T) {
-	l := NewReaderSize(bytes.NewBuffer([]byte("foo")), minReadBufferSize)
+	l := NewReaderSize(bytes.NewReader([]byte("foo")), minReadBufferSize)
 	_, err := ioutil.ReadAll(l)
 	if err != nil {
 		t.Error(err)
@@ -783,7 +931,7 @@ func createTestInput(n int) []byte {
 
 func TestReaderWriteTo(t *testing.T) {
 	input := createTestInput(8192)
-	r := NewReader(onlyReader{bytes.NewBuffer(input)})
+	r := NewReader(onlyReader{bytes.NewReader(input)})
 	w := new(bytes.Buffer)
 	if n, err := r.WriteTo(w); err != nil || n != int64(len(input)) {
 		t.Fatalf("r.WriteTo(w) = %d, %v, want %d, nil", n, err, len(input))
@@ -842,7 +990,7 @@ func TestWriterReadFrom(t *testing.T) {
 			input := createTestInput(8192)
 			b := new(bytes.Buffer)
 			w := NewWriter(wfunc(b))
-			r := rfunc(bytes.NewBuffer(input))
+			r := rfunc(bytes.NewReader(input))
 			if n, err := w.ReadFrom(r); err != nil || n != int64(len(input)) {
 				t.Errorf("ws[%d],rs[%d]: w.ReadFrom(r) = %d, %v, want %d, nil", wi, ri, n, err, len(input))
 				continue
@@ -1021,7 +1169,61 @@ func TestWriterReadFromWhileFull(t *testing.T) {
 	// Use ReadFrom to read in some data.
 	n2, err := w.ReadFrom(strings.NewReader("abcdef"))
 	if n2 != 6 || err != nil {
-		t.Fatalf("ReadFrom returned (%v, %v), want (6, nil)", n, err)
+		t.Fatalf("ReadFrom returned (%v, %v), want (6, nil)", n2, err)
+	}
+}
+
+type emptyThenNonEmptyReader struct {
+	r io.Reader
+	n int
+}
+
+func (r *emptyThenNonEmptyReader) Read(p []byte) (int, error) {
+	if r.n <= 0 {
+		return r.r.Read(p)
+	}
+	r.n--
+	return 0, nil
+}
+
+// Test for golang.org/issue/7611
+func TestWriterReadFromUntilEOF(t *testing.T) {
+	buf := new(bytes.Buffer)
+	w := NewWriterSize(buf, 5)
+
+	// Partially fill buffer
+	n, err := w.Write([]byte("0123"))
+	if n != 4 || err != nil {
+		t.Fatalf("Write returned (%v, %v), want (4, nil)", n, err)
+	}
+
+	// Use ReadFrom to read in some data.
+	r := &emptyThenNonEmptyReader{r: strings.NewReader("abcd"), n: 3}
+	n2, err := w.ReadFrom(r)
+	if n2 != 4 || err != nil {
+		t.Fatalf("ReadFrom returned (%v, %v), want (4, nil)", n2, err)
+	}
+	w.Flush()
+	if got, want := string(buf.Bytes()), "0123abcd"; got != want {
+		t.Fatalf("buf.Bytes() returned %q, want %q", got, want)
+	}
+}
+
+func TestWriterReadFromErrNoProgress(t *testing.T) {
+	buf := new(bytes.Buffer)
+	w := NewWriterSize(buf, 5)
+
+	// Partially fill buffer
+	n, err := w.Write([]byte("0123"))
+	if n != 4 || err != nil {
+		t.Fatalf("Write returned (%v, %v), want (4, nil)", n, err)
+	}
+
+	// Use ReadFrom to read in some data.
+	r := &emptyThenNonEmptyReader{r: strings.NewReader("abcd"), n: 100}
+	n2, err := w.ReadFrom(r)
+	if n2 != 0 || err != io.ErrNoProgress {
+		t.Fatalf("buf.Bytes() returned (%v, %v), want (0, io.ErrNoProgress)", n2, err)
 	}
 }
 
@@ -1059,81 +1261,114 @@ func TestWriterReset(t *testing.T) {
 
 // An onlyReader only implements io.Reader, no matter what other methods the underlying implementation may have.
 type onlyReader struct {
-	r io.Reader
-}
-
-func (r onlyReader) Read(b []byte) (int, error) {
-	return r.r.Read(b)
+	io.Reader
 }
 
 // An onlyWriter only implements io.Writer, no matter what other methods the underlying implementation may have.
 type onlyWriter struct {
-	w io.Writer
-}
-
-func (w onlyWriter) Write(b []byte) (int, error) {
-	return w.w.Write(b)
+	io.Writer
 }
 
 func BenchmarkReaderCopyOptimal(b *testing.B) {
 	// Optimal case is where the underlying reader implements io.WriterTo
+	srcBuf := bytes.NewBuffer(make([]byte, 8192))
+	src := NewReader(srcBuf)
+	dstBuf := new(bytes.Buffer)
+	dst := onlyWriter{dstBuf}
 	for i := 0; i < b.N; i++ {
-		b.StopTimer()
-		src := NewReader(bytes.NewBuffer(make([]byte, 8192)))
-		dst := onlyWriter{new(bytes.Buffer)}
-		b.StartTimer()
+		srcBuf.Reset()
+		src.Reset(srcBuf)
+		dstBuf.Reset()
 		io.Copy(dst, src)
 	}
 }
 
 func BenchmarkReaderCopyUnoptimal(b *testing.B) {
 	// Unoptimal case is where the underlying reader doesn't implement io.WriterTo
+	srcBuf := bytes.NewBuffer(make([]byte, 8192))
+	src := NewReader(onlyReader{srcBuf})
+	dstBuf := new(bytes.Buffer)
+	dst := onlyWriter{dstBuf}
 	for i := 0; i < b.N; i++ {
-		b.StopTimer()
-		src := NewReader(onlyReader{bytes.NewBuffer(make([]byte, 8192))})
-		dst := onlyWriter{new(bytes.Buffer)}
-		b.StartTimer()
+		srcBuf.Reset()
+		src.Reset(onlyReader{srcBuf})
+		dstBuf.Reset()
 		io.Copy(dst, src)
 	}
 }
 
 func BenchmarkReaderCopyNoWriteTo(b *testing.B) {
+	srcBuf := bytes.NewBuffer(make([]byte, 8192))
+	srcReader := NewReader(srcBuf)
+	src := onlyReader{srcReader}
+	dstBuf := new(bytes.Buffer)
+	dst := onlyWriter{dstBuf}
 	for i := 0; i < b.N; i++ {
-		b.StopTimer()
-		src := onlyReader{NewReader(bytes.NewBuffer(make([]byte, 8192)))}
-		dst := onlyWriter{new(bytes.Buffer)}
-		b.StartTimer()
+		srcBuf.Reset()
+		srcReader.Reset(srcBuf)
+		dstBuf.Reset()
 		io.Copy(dst, src)
 	}
 }
 
+func BenchmarkReaderWriteToOptimal(b *testing.B) {
+	const bufSize = 16 << 10
+	buf := make([]byte, bufSize)
+	r := bytes.NewReader(buf)
+	srcReader := NewReaderSize(onlyReader{r}, 1<<10)
+	if _, ok := ioutil.Discard.(io.ReaderFrom); !ok {
+		b.Fatal("ioutil.Discard doesn't support ReaderFrom")
+	}
+	for i := 0; i < b.N; i++ {
+		r.Seek(0, 0)
+		srcReader.Reset(onlyReader{r})
+		n, err := srcReader.WriteTo(ioutil.Discard)
+		if err != nil {
+			b.Fatal(err)
+		}
+		if n != bufSize {
+			b.Fatalf("n = %d; want %d", n, bufSize)
+		}
+	}
+}
+
 func BenchmarkWriterCopyOptimal(b *testing.B) {
 	// Optimal case is where the underlying writer implements io.ReaderFrom
+	srcBuf := bytes.NewBuffer(make([]byte, 8192))
+	src := onlyReader{srcBuf}
+	dstBuf := new(bytes.Buffer)
+	dst := NewWriter(dstBuf)
 	for i := 0; i < b.N; i++ {
-		b.StopTimer()
-		src := onlyReader{bytes.NewBuffer(make([]byte, 8192))}
-		dst := NewWriter(new(bytes.Buffer))
-		b.StartTimer()
+		srcBuf.Reset()
+		dstBuf.Reset()
+		dst.Reset(dstBuf)
 		io.Copy(dst, src)
 	}
 }
 
 func BenchmarkWriterCopyUnoptimal(b *testing.B) {
+	srcBuf := bytes.NewBuffer(make([]byte, 8192))
+	src := onlyReader{srcBuf}
+	dstBuf := new(bytes.Buffer)
+	dst := NewWriter(onlyWriter{dstBuf})
 	for i := 0; i < b.N; i++ {
-		b.StopTimer()
-		src := onlyReader{bytes.NewBuffer(make([]byte, 8192))}
-		dst := NewWriter(onlyWriter{new(bytes.Buffer)})
-		b.StartTimer()
+		srcBuf.Reset()
+		dstBuf.Reset()
+		dst.Reset(onlyWriter{dstBuf})
 		io.Copy(dst, src)
 	}
 }
 
 func BenchmarkWriterCopyNoReadFrom(b *testing.B) {
+	srcBuf := bytes.NewBuffer(make([]byte, 8192))
+	src := onlyReader{srcBuf}
+	dstBuf := new(bytes.Buffer)
+	dstWriter := NewWriter(dstBuf)
+	dst := onlyWriter{dstWriter}
 	for i := 0; i < b.N; i++ {
-		b.StopTimer()
-		src := onlyReader{bytes.NewBuffer(make([]byte, 8192))}
-		dst := onlyWriter{NewWriter(new(bytes.Buffer))}
-		b.StartTimer()
+		srcBuf.Reset()
+		dstBuf.Reset()
+		dstWriter.Reset(dstBuf)
 		io.Copy(dst, src)
 	}
 }
diff --git a/src/pkg/bufio/scan.go b/src/pkg/bufio/scan.go
index 423505f..715ce07 100644
--- a/src/pkg/bufio/scan.go
+++ b/src/pkg/bufio/scan.go
@@ -135,7 +135,7 @@ func (s *Scanner) Scan() bool {
 		}
 		// Must read more data.
 		// First, shift data to beginning of buffer if there's lots of empty space
-		// or space is neded.
+		// or space is needed.
 		if s.start > 0 && (s.end == len(s.buf) || s.start > len(s.buf)/2) {
 			copy(s.buf, s.buf[s.start:s.end])
 			s.end -= s.start
@@ -172,7 +172,7 @@ func (s *Scanner) Scan() bool {
 				break
 			}
 			loop++
-			if loop > 100 {
+			if loop > maxConsecutiveEmptyReads {
 				s.setErr(io.ErrNoProgress)
 				break
 			}
@@ -306,7 +306,7 @@ func isSpace(r rune) bool {
 		return true
 	}
 	switch r {
-	case '\u1680', '\u180e', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000':
+	case '\u1680', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000':
 		return true
 	}
 	return false
diff --git a/src/pkg/bufio/scan_test.go b/src/pkg/bufio/scan_test.go
index c1483b2..0db7cad 100644
--- a/src/pkg/bufio/scan_test.go
+++ b/src/pkg/bufio/scan_test.go
@@ -38,7 +38,7 @@ var scanTests = []string{
 
 func TestScanByte(t *testing.T) {
 	for n, test := range scanTests {
-		buf := bytes.NewBufferString(test)
+		buf := strings.NewReader(test)
 		s := NewScanner(buf)
 		s.Split(ScanBytes)
 		var i int
@@ -60,7 +60,7 @@ func TestScanByte(t *testing.T) {
 // Test that the rune splitter returns same sequence of runes (not bytes) as for range string.
 func TestScanRune(t *testing.T) {
 	for n, test := range scanTests {
-		buf := bytes.NewBufferString(test)
+		buf := strings.NewReader(test)
 		s := NewScanner(buf)
 		s.Split(ScanRunes)
 		var i, runeCount int
@@ -104,7 +104,7 @@ var wordScanTests = []string{
 // Test that the word splitter returns the same data as strings.Fields.
 func TestScanWords(t *testing.T) {
 	for n, test := range wordScanTests {
-		buf := bytes.NewBufferString(test)
+		buf := strings.NewReader(test)
 		s := NewScanner(buf)
 		s.Split(ScanWords)
 		words := strings.Fields(test)
@@ -135,7 +135,7 @@ func TestScanWords(t *testing.T) {
 // reads in Scanner.Scan.
 type slowReader struct {
 	max int
-	buf *bytes.Buffer
+	buf io.Reader
 }
 
 func (sr *slowReader) Read(p []byte) (n int, err error) {
@@ -248,7 +248,7 @@ func TestScanLineTooLong(t *testing.T) {
 
 // Test that the line splitter handles a final line without a newline.
 func testNoNewline(text string, lines []string, t *testing.T) {
-	buf := bytes.NewBufferString(text)
+	buf := strings.NewReader(text)
 	s := NewScanner(&slowReader{7, buf})
 	s.Split(ScanLines)
 	for lineNum := 0; s.Scan(); lineNum++ {
@@ -277,7 +277,7 @@ func TestScanLineNoNewline(t *testing.T) {
 	testNoNewline(text, lines, t)
 }
 
-// Test that the line splitter handles a final line with a carriage return but nonewline.
+// Test that the line splitter handles a final line with a carriage return but no newline.
 func TestScanLineReturnButNoNewline(t *testing.T) {
 	const text = "abcdefghijklmn\nopqrstuvwxyz\r"
 	lines := []string{
@@ -328,7 +328,7 @@ func TestSplitError(t *testing.T) {
 	}
 	// Read the data.
 	const text = "abcdefghijklmnopqrstuvwxyz"
-	buf := bytes.NewBufferString(text)
+	buf := strings.NewReader(text)
 	s := NewScanner(&slowReader{1, buf})
 	s.Split(errorSplit)
 	var i int
diff --git a/src/pkg/bytes/bytes.go b/src/pkg/bytes/bytes.go
index 01a5d9a..0c53e4c 100644
--- a/src/pkg/bytes/bytes.go
+++ b/src/pkg/bytes/bytes.go
@@ -265,8 +265,8 @@ func Fields(s []byte) [][]byte {
 
 // FieldsFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
 // It splits the slice s at each run of code points c satisfying f(c) and
-// returns a slice of subslices of s.  If no code points in s satisfy f(c), an
-// empty slice is returned.
+// returns a slice of subslices of s.  If all code points in s satisfy f(c), or
+// len(s) == 0, an empty slice is returned.
 func FieldsFunc(s []byte, f func(rune) bool) [][]byte {
 	n := 0
 	inField := false
@@ -356,7 +356,11 @@ func Map(mapping func(r rune) rune, s []byte) []byte {
 		}
 		r = mapping(r)
 		if r >= 0 {
-			if nbytes+utf8.RuneLen(r) > maxbytes {
+			rl := utf8.RuneLen(r)
+			if rl < 0 {
+				rl = len(string(utf8.RuneError))
+			}
+			if nbytes+rl > maxbytes {
 				// Grow the buffer.
 				maxbytes = maxbytes*2 + utf8.UTFMax
 				nb := make([]byte, maxbytes)
diff --git a/src/pkg/bytes/bytes_test.go b/src/pkg/bytes/bytes_test.go
index ab5da4f..394dd7a 100644
--- a/src/pkg/bytes/bytes_test.go
+++ b/src/pkg/bytes/bytes_test.go
@@ -785,6 +785,16 @@ func TestMap(t *testing.T) {
 	if string(m) != expect {
 		t.Errorf("drop: expected %q got %q", expect, m)
 	}
+
+	// 6. Invalid rune
+	invalidRune := func(r rune) rune {
+		return utf8.MaxRune + 1
+	}
+	m = Map(invalidRune, []byte("x"))
+	expect = "\uFFFD"
+	if string(m) != expect {
+		t.Errorf("invalidRune: expected %q got %q", expect, m)
+	}
 }
 
 func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) }
@@ -1073,6 +1083,8 @@ var TitleTests = []TitleTest{
 	{"123a456", "123a456"},
 	{"double-blind", "Double-Blind"},
 	{"ÿøû", "Ÿøû"},
+	{"with_underscore", "With_underscore"},
+	{"unicode \xe2\x80\xa8 line separator", "Unicode \xe2\x80\xa8 Line Separator"},
 }
 
 func TestTitle(t *testing.T) {
@@ -1132,7 +1144,7 @@ func TestEqualFold(t *testing.T) {
 func TestBufferGrowNegative(t *testing.T) {
 	defer func() {
 		if err := recover(); err == nil {
-			t.Fatal("Grow(-1) should have paniced")
+			t.Fatal("Grow(-1) should have panicked")
 		}
 	}()
 	var b Buffer
@@ -1142,7 +1154,7 @@ func TestBufferGrowNegative(t *testing.T) {
 func TestBufferTruncateNegative(t *testing.T) {
 	defer func() {
 		if err := recover(); err == nil {
-			t.Fatal("Truncate(-1) should have paniced")
+			t.Fatal("Truncate(-1) should have panicked")
 		}
 	}()
 	var b Buffer
@@ -1152,7 +1164,7 @@ func TestBufferTruncateNegative(t *testing.T) {
 func TestBufferTruncateOutOfRange(t *testing.T) {
 	defer func() {
 		if err := recover(); err == nil {
-			t.Fatal("Truncate(20) should have paniced")
+			t.Fatal("Truncate(20) should have panicked")
 		}
 	}()
 	var b Buffer
@@ -1160,6 +1172,24 @@ func TestBufferTruncateOutOfRange(t *testing.T) {
 	b.Truncate(20)
 }
 
+var containsTests = []struct {
+	b, subslice []byte
+	want        bool
+}{
+	{[]byte("hello"), []byte("hel"), true},
+	{[]byte("日本語"), []byte("日本"), true},
+	{[]byte("hello"), []byte("Hello, world"), false},
+	{[]byte("東京"), []byte("京東"), false},
+}
+
+func TestContains(t *testing.T) {
+	for _, tt := range containsTests {
+		if got := Contains(tt.b, tt.subslice); got != tt.want {
+			t.Errorf("Contains(%q, %q) = %v, want %v", tt.b, tt.subslice, got, tt.want)
+		}
+	}
+}
+
 var makeFieldsInput = func() []byte {
 	x := make([]byte, 1<<20)
 	// Input is ~10% space, ~10% 2-byte UTF-8, rest ASCII non-space.
diff --git a/src/pkg/bytes/compare_test.go b/src/pkg/bytes/compare_test.go
index 0a36f5a..6352237 100644
--- a/src/pkg/bytes/compare_test.go
+++ b/src/pkg/bytes/compare_test.go
@@ -1,3 +1,7 @@
+// 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 bytes_test
 
 import (
diff --git a/src/pkg/bytes/reader.go b/src/pkg/bytes/reader.go
index 77511b9..d2d40fa 100644
--- a/src/pkg/bytes/reader.go
+++ b/src/pkg/bytes/reader.go
@@ -16,40 +16,41 @@ import (
 // Unlike a Buffer, a Reader is read-only and supports seeking.
 type Reader struct {
 	s        []byte
-	i        int // current reading index
-	prevRune int // index of previous rune; or < 0
+	i        int64 // current reading index
+	prevRune int   // index of previous rune; or < 0
 }
 
 // Len returns the number of bytes of the unread portion of the
 // slice.
 func (r *Reader) Len() int {
-	if r.i >= len(r.s) {
+	if r.i >= int64(len(r.s)) {
 		return 0
 	}
-	return len(r.s) - r.i
+	return int(int64(len(r.s)) - r.i)
 }
 
 func (r *Reader) Read(b []byte) (n int, err error) {
 	if len(b) == 0 {
 		return 0, nil
 	}
-	if r.i >= len(r.s) {
+	if r.i >= int64(len(r.s)) {
 		return 0, io.EOF
 	}
-	n = copy(b, r.s[r.i:])
-	r.i += n
 	r.prevRune = -1
+	n = copy(b, r.s[r.i:])
+	r.i += int64(n)
 	return
 }
 
 func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
+	// cannot modify state - see io.ReaderAt
 	if off < 0 {
-		return 0, errors.New("bytes: invalid offset")
+		return 0, errors.New("bytes.Reader.ReadAt: negative offset")
 	}
 	if off >= int64(len(r.s)) {
 		return 0, io.EOF
 	}
-	n = copy(b, r.s[int(off):])
+	n = copy(b, r.s[off:])
 	if n < len(b) {
 		err = io.EOF
 	}
@@ -57,49 +58,51 @@ func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
 }
 
 func (r *Reader) ReadByte() (b byte, err error) {
-	if r.i >= len(r.s) {
+	r.prevRune = -1
+	if r.i >= int64(len(r.s)) {
 		return 0, io.EOF
 	}
 	b = r.s[r.i]
 	r.i++
-	r.prevRune = -1
 	return
 }
 
 func (r *Reader) UnreadByte() error {
+	r.prevRune = -1
 	if r.i <= 0 {
-		return errors.New("bytes.Reader: at beginning of slice")
+		return errors.New("bytes.Reader.UnreadByte: at beginning of slice")
 	}
 	r.i--
-	r.prevRune = -1
 	return nil
 }
 
 func (r *Reader) ReadRune() (ch rune, size int, err error) {
-	if r.i >= len(r.s) {
+	if r.i >= int64(len(r.s)) {
+		r.prevRune = -1
 		return 0, 0, io.EOF
 	}
-	r.prevRune = r.i
+	r.prevRune = int(r.i)
 	if c := r.s[r.i]; c < utf8.RuneSelf {
 		r.i++
 		return rune(c), 1, nil
 	}
 	ch, size = utf8.DecodeRune(r.s[r.i:])
-	r.i += size
+	r.i += int64(size)
 	return
 }
 
 func (r *Reader) UnreadRune() error {
 	if r.prevRune < 0 {
-		return errors.New("bytes.Reader: previous operation was not ReadRune")
+		return errors.New("bytes.Reader.UnreadRune: previous operation was not ReadRune")
 	}
-	r.i = r.prevRune
+	r.i = int64(r.prevRune)
 	r.prevRune = -1
 	return nil
 }
 
 // Seek implements the io.Seeker interface.
 func (r *Reader) Seek(offset int64, whence int) (int64, error) {
+	r.prevRune = -1
 	var abs int64
 	switch whence {
 	case 0:
@@ -109,22 +112,19 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) {
 	case 2:
 		abs = int64(len(r.s)) + offset
 	default:
-		return 0, errors.New("bytes: invalid whence")
+		return 0, errors.New("bytes.Reader.Seek: invalid whence")
 	}
 	if abs < 0 {
-		return 0, errors.New("bytes: negative position")
-	}
-	if abs >= 1<<31 {
-		return 0, errors.New("bytes: position out of range")
+		return 0, errors.New("bytes.Reader.Seek: negative position")
 	}
-	r.i = int(abs)
+	r.i = abs
 	return abs, nil
 }
 
 // WriteTo implements the io.WriterTo interface.
 func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
 	r.prevRune = -1
-	if r.i >= len(r.s) {
+	if r.i >= int64(len(r.s)) {
 		return 0, nil
 	}
 	b := r.s[r.i:]
@@ -132,7 +132,7 @@ func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
 	if m > len(b) {
 		panic("bytes.Reader.WriteTo: invalid Write count")
 	}
-	r.i += m
+	r.i += int64(m)
 	n = int64(m)
 	if m != len(b) && err == nil {
 		err = io.ErrShortWrite
diff --git a/src/pkg/bytes/reader_test.go b/src/pkg/bytes/reader_test.go
index 19f014d..d3dce53 100644
--- a/src/pkg/bytes/reader_test.go
+++ b/src/pkg/bytes/reader_test.go
@@ -10,6 +10,7 @@ import (
 	"io"
 	"io/ioutil"
 	"os"
+	"sync"
 	"testing"
 )
 
@@ -26,9 +27,9 @@ func TestReader(t *testing.T) {
 		{seek: os.SEEK_SET, off: 0, n: 20, want: "0123456789"},
 		{seek: os.SEEK_SET, off: 1, n: 1, want: "1"},
 		{seek: os.SEEK_CUR, off: 1, wantpos: 3, n: 2, want: "34"},
-		{seek: os.SEEK_SET, off: -1, seekerr: "bytes: negative position"},
-		{seek: os.SEEK_SET, off: 1<<31 - 1},
-		{seek: os.SEEK_CUR, off: 1, seekerr: "bytes: position out of range"},
+		{seek: os.SEEK_SET, off: -1, seekerr: "bytes.Reader.Seek: negative position"},
+		{seek: os.SEEK_SET, off: 1 << 33, wantpos: 1 << 33},
+		{seek: os.SEEK_CUR, off: 1, wantpos: 1<<33 + 1},
 		{seek: os.SEEK_SET, n: 5, want: "01234"},
 		{seek: os.SEEK_CUR, n: 5, want: "56789"},
 		{seek: os.SEEK_END, off: -1, n: 1, wantpos: 9, want: "9"},
@@ -60,6 +61,16 @@ func TestReader(t *testing.T) {
 	}
 }
 
+func TestReadAfterBigSeek(t *testing.T) {
+	r := NewReader([]byte("0123456789"))
+	if _, err := r.Seek(1<<31+5, os.SEEK_SET); err != nil {
+		t.Fatal(err)
+	}
+	if n, err := r.Read(make([]byte, 10)); n != 0 || err != io.EOF {
+		t.Errorf("Read = %d, %v; want 0, EOF", n, err)
+	}
+}
+
 func TestReaderAt(t *testing.T) {
 	r := NewReader([]byte("0123456789"))
 	tests := []struct {
@@ -73,7 +84,7 @@ func TestReaderAt(t *testing.T) {
 		{1, 9, "123456789", nil},
 		{11, 10, "", io.EOF},
 		{0, 0, "", nil},
-		{-1, 0, "", "bytes: invalid offset"},
+		{-1, 0, "", "bytes.Reader.ReadAt: negative offset"},
 	}
 	for i, tt := range tests {
 		b := make([]byte, tt.n)
@@ -88,6 +99,43 @@ func TestReaderAt(t *testing.T) {
 	}
 }
 
+func TestReaderAtConcurrent(t *testing.T) {
+	// Test for the race detector, to verify ReadAt doesn't mutate
+	// any state.
+	r := NewReader([]byte("0123456789"))
+	var wg sync.WaitGroup
+	for i := 0; i < 5; i++ {
+		wg.Add(1)
+		go func(i int) {
+			defer wg.Done()
+			var buf [1]byte
+			r.ReadAt(buf[:], int64(i))
+		}(i)
+	}
+	wg.Wait()
+}
+
+func TestEmptyReaderConcurrent(t *testing.T) {
+	// Test for the race detector, to verify a Read that doesn't yield any bytes
+	// is okay to use from multiple goroutines. This was our historic behavior.
+	// See golang.org/issue/7856
+	r := NewReader([]byte{})
+	var wg sync.WaitGroup
+	for i := 0; i < 5; i++ {
+		wg.Add(2)
+		go func() {
+			defer wg.Done()
+			var buf [1]byte
+			r.Read(buf[:])
+		}()
+		go func() {
+			defer wg.Done()
+			r.Read(nil)
+		}()
+	}
+	wg.Wait()
+}
+
 func TestReaderWriteTo(t *testing.T) {
 	for i := 0; i < 30; i += 3 {
 		var l int
@@ -133,6 +181,32 @@ func TestReaderLen(t *testing.T) {
 	}
 }
 
+var UnreadRuneErrorTests = []struct {
+	name string
+	f    func(*Reader)
+}{
+	{"Read", func(r *Reader) { r.Read([]byte{0}) }},
+	{"ReadByte", func(r *Reader) { r.ReadByte() }},
+	{"UnreadRune", func(r *Reader) { r.UnreadRune() }},
+	{"Seek", func(r *Reader) { r.Seek(0, 1) }},
+	{"WriteTo", func(r *Reader) { r.WriteTo(&Buffer{}) }},
+}
+
+func TestUnreadRuneError(t *testing.T) {
+	for _, tt := range UnreadRuneErrorTests {
+		reader := NewReader([]byte("0123456789"))
+		if _, _, err := reader.ReadRune(); err != nil {
+			// should not happen
+			t.Fatal(err)
+		}
+		tt.f(reader)
+		err := reader.UnreadRune()
+		if err == nil {
+			t.Errorf("Unreading after %s: expected error", tt.name)
+		}
+	}
+}
+
 func TestReaderDoubleUnreadRune(t *testing.T) {
 	buf := NewBuffer([]byte("groucho"))
 	if _, _, err := buf.ReadRune(); err != nil {
diff --git a/src/pkg/compress/bzip2/bzip2_test.go b/src/pkg/compress/bzip2/bzip2_test.go
index ada1f9a..727249d 100644
--- a/src/pkg/compress/bzip2/bzip2_test.go
+++ b/src/pkg/compress/bzip2/bzip2_test.go
@@ -14,7 +14,7 @@ import (
 )
 
 func TestBitReader(t *testing.T) {
-	buf := bytes.NewBuffer([]byte{0xaa})
+	buf := bytes.NewReader([]byte{0xaa})
 	br := newBitReader(buf)
 	if n := br.ReadBits(1); n != 1 {
 		t.Errorf("read 1 wrong")
@@ -31,7 +31,7 @@ func TestBitReader(t *testing.T) {
 }
 
 func TestBitReaderLarge(t *testing.T) {
-	buf := bytes.NewBuffer([]byte{0x12, 0x34, 0x56, 0x78})
+	buf := bytes.NewReader([]byte{0x12, 0x34, 0x56, 0x78})
 	br := newBitReader(buf)
 	if n := br.ReadBits(32); n != 0x12345678 {
 		t.Errorf("got: %x want: %x", n, 0x12345678)
@@ -43,7 +43,7 @@ func readerFromHex(s string) io.Reader {
 	if err != nil {
 		panic("readerFromHex: bad input")
 	}
-	return bytes.NewBuffer(data)
+	return bytes.NewReader(data)
 }
 
 func decompressHex(s string) (out []byte, err error) {
@@ -177,7 +177,7 @@ const (
 
 var testfiles = []string{
 	// Digits is the digits of the irrational number e. Its decimal representation
-	// does not repeat, but there are only 10 posible digits, so it should be
+	// does not repeat, but there are only 10 possible digits, so it should be
 	// reasonably compressible.
 	digits: "testdata/e.txt.bz2",
 	// Twain is Project Gutenberg's edition of Mark Twain's classic English novel.
@@ -191,7 +191,7 @@ func benchmarkDecode(b *testing.B, testfile int) {
 	}
 	b.SetBytes(int64(len(compressed)))
 	for i := 0; i < b.N; i++ {
-		r := bytes.NewBuffer(compressed)
+		r := bytes.NewReader(compressed)
 		io.Copy(ioutil.Discard, NewReader(r))
 	}
 }
@@ -201,7 +201,7 @@ func BenchmarkDecodeTwain(b *testing.B)  { benchmarkDecode(b, twain) }
 
 func TestBufferOverrun(t *testing.T) {
 	// Tests https://code.google.com/p/go/issues/detail?id=5747.
-	buffer := bytes.NewBuffer([]byte(bufferOverrunBase64))
+	buffer := bytes.NewReader([]byte(bufferOverrunBase64))
 	decoder := base64.NewDecoder(base64.StdEncoding, buffer)
 	decompressor := NewReader(decoder)
 	// This shouldn't panic.
diff --git a/src/pkg/compress/bzip2/huffman.go b/src/pkg/compress/bzip2/huffman.go
index 8f6b0c9..75a6223 100644
--- a/src/pkg/compress/bzip2/huffman.go
+++ b/src/pkg/compress/bzip2/huffman.go
@@ -190,7 +190,37 @@ func buildHuffmanNode(t *huffmanTree, codes []huffmanCode, level uint32) (nodeIn
 	right := codes[firstRightIndex:]
 
 	if len(left) == 0 || len(right) == 0 {
-		return 0, StructuralError("superfluous level in Huffman tree")
+		// There is a superfluous level in the Huffman tree indicating
+		// a bug in the encoder. However, this bug has been observed in
+		// the wild so we handle it.
+
+		// If this function was called recursively then we know that
+		// len(codes) >= 2 because, otherwise, we would have hit the
+		// "leaf node" case, below, and not recursed.
+		//
+		// However, for the initial call it's possible that len(codes)
+		// is zero or one. Both cases are invalid because a zero length
+		// tree cannot encode anything and a length-1 tree can only
+		// encode EOF and so is superfluous. We reject both.
+		if len(codes) < 2 {
+			return 0, StructuralError("empty Huffman tree")
+		}
+
+		// In this case the recursion doesn't always reduce the length
+		// of codes so we need to ensure termination via another
+		// mechanism.
+		if level == 31 {
+			// Since len(codes) >= 2 the only way that the values
+			// can match at all 32 bits is if they are equal, which
+			// is invalid. This ensures that we never enter
+			// infinite recursion.
+			return 0, StructuralError("equal symbols in Huffman tree")
+		}
+
+		if len(left) == 0 {
+			return buildHuffmanNode(t, right, level+1)
+		}
+		return buildHuffmanNode(t, left, level+1)
 	}
 
 	nodeIndex = uint16(t.nextNode)
diff --git a/src/pkg/compress/flate/fixedhuff.go b/src/pkg/compress/flate/fixedhuff.go
index 41a6b25..9be3d53 100644
--- a/src/pkg/compress/flate/fixedhuff.go
+++ b/src/pkg/compress/flate/fixedhuff.go
@@ -1,3 +1,7 @@
+// 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 flate
 
 // autogenerated by gen.go, DO NOT EDIT
diff --git a/src/pkg/compress/flate/flate_test.go b/src/pkg/compress/flate/flate_test.go
index 57fea5a..0687663 100644
--- a/src/pkg/compress/flate/flate_test.go
+++ b/src/pkg/compress/flate/flate_test.go
@@ -14,7 +14,7 @@ import (
 )
 
 func TestUncompressedSource(t *testing.T) {
-	decoder := NewReader(bytes.NewBuffer([]byte{0x01, 0x01, 0x00, 0xfe, 0xff, 0x11}))
+	decoder := NewReader(bytes.NewReader([]byte{0x01, 0x01, 0x00, 0xfe, 0xff, 0x11}))
 	output := make([]byte, 1)
 	n, error := decoder.Read(output)
 	if n != 1 || error != nil {
diff --git a/src/pkg/compress/flate/inflate.go b/src/pkg/compress/flate/inflate.go
index 3eb3b2b..ce4923e 100644
--- a/src/pkg/compress/flate/inflate.go
+++ b/src/pkg/compress/flate/inflate.go
@@ -54,7 +54,7 @@ func (e *WriteError) Error() string {
 	return "flate: write error at offset " + strconv.FormatInt(e.Offset, 10) + ": " + e.Err.Error()
 }
 
-// Note that much of the implemenation of huffmanDecoder is also copied
+// Note that much of the implementation of huffmanDecoder is also copied
 // into gen.go (in package main) for the purpose of precomputing the
 // fixed huffman tables so they can be included statically.
 
@@ -180,7 +180,7 @@ func (h *huffmanDecoder) init(bits []int) bool {
 // the NewReader will introduce its own buffering.
 type Reader interface {
 	io.Reader
-	ReadByte() (c byte, err error)
+	io.ByteReader
 }
 
 // Decompress state.
diff --git a/src/pkg/compress/flate/reader_test.go b/src/pkg/compress/flate/reader_test.go
index 2a8ebbc..a62ef74 100644
--- a/src/pkg/compress/flate/reader_test.go
+++ b/src/pkg/compress/flate/reader_test.go
@@ -29,7 +29,7 @@ const (
 
 var testfiles = []string{
 	// Digits is the digits of the irrational number e. Its decimal representation
-	// does not repeat, but there are only 10 posible digits, so it should be
+	// does not repeat, but there are only 10 possible digits, so it should be
 	// reasonably compressible.
 	digits: "../testdata/e.txt",
 	// Twain is Project Gutenberg's edition of Mark Twain's classic English novel.
diff --git a/src/pkg/compress/gzip/gunzip.go b/src/pkg/compress/gzip/gunzip.go
index 1fb9b09..4f398b1 100644
--- a/src/pkg/compress/gzip/gunzip.go
+++ b/src/pkg/compress/gzip/gunzip.go
@@ -89,6 +89,21 @@ func NewReader(r io.Reader) (*Reader, error) {
 	return z, nil
 }
 
+// Reset discards the Reader z's state and makes it equivalent to the
+// result of its original state from NewReader, but reading from r instead.
+// This permits reusing a Reader rather than allocating a new one.
+func (z *Reader) Reset(r io.Reader) error {
+	z.r = makeReader(r)
+	if z.digest == nil {
+		z.digest = crc32.NewIEEE()
+	} else {
+		z.digest.Reset()
+	}
+	z.size = 0
+	z.err = nil
+	return z.readHeader(true)
+}
+
 // GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950).
 func get4(p []byte) uint32 {
 	return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
diff --git a/src/pkg/compress/gzip/gunzip_test.go b/src/pkg/compress/gzip/gunzip_test.go
index 572fb58..2471038 100644
--- a/src/pkg/compress/gzip/gunzip_test.go
+++ b/src/pkg/compress/gzip/gunzip_test.go
@@ -284,7 +284,7 @@ var gunzipTests = []gunzipTest{
 func TestDecompressor(t *testing.T) {
 	b := new(bytes.Buffer)
 	for _, tt := range gunzipTests {
-		in := bytes.NewBuffer(tt.gzip)
+		in := bytes.NewReader(tt.gzip)
 		gzip, err := NewReader(in)
 		if err != nil {
 			t.Errorf("%s: NewReader: %s", tt.name, err)
@@ -303,6 +303,26 @@ func TestDecompressor(t *testing.T) {
 		if s != tt.raw {
 			t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.name, n, s, len(tt.raw), tt.raw)
 		}
+
+		// Test Reader Reset.
+		in = bytes.NewReader(tt.gzip)
+		err = gzip.Reset(in)
+		if err != nil {
+			t.Errorf("%s: Reset: %s", tt.name, err)
+			continue
+		}
+		if tt.name != gzip.Name {
+			t.Errorf("%s: got name %s", tt.name, gzip.Name)
+		}
+		b.Reset()
+		n, err = io.Copy(b, gzip)
+		if err != tt.err {
+			t.Errorf("%s: io.Copy: %v want %v", tt.name, err, tt.err)
+		}
+		s = b.String()
+		if s != tt.raw {
+			t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.name, n, s, len(tt.raw), tt.raw)
+		}
 	}
 }
 
@@ -333,3 +353,17 @@ func TestIssue6550(t *testing.T) {
 		// ok
 	}
 }
+
+func TestInitialReset(t *testing.T) {
+	var r Reader
+	if err := r.Reset(bytes.NewReader(gunzipTests[1].gzip)); err != nil {
+		t.Error(err)
+	}
+	var buf bytes.Buffer
+	if _, err := io.Copy(&buf, &r); err != nil {
+		t.Error(err)
+	}
+	if s := buf.String(); s != gunzipTests[1].raw {
+		t.Errorf("got %q want %q", s, gunzipTests[1].raw)
+	}
+}
diff --git a/src/pkg/compress/gzip/gzip.go b/src/pkg/compress/gzip/gzip.go
index fe32d68..3a0bf54 100644
--- a/src/pkg/compress/gzip/gzip.go
+++ b/src/pkg/compress/gzip/gzip.go
@@ -22,8 +22,8 @@ const (
 	DefaultCompression = flate.DefaultCompression
 )
 
-// A Writer is an io.WriteCloser that satisfies writes by compressing data written
-// to its wrapped io.Writer.
+// A Writer is an io.WriteCloser.
+// Writes to a Writer are compressed and written to w.
 type Writer struct {
 	Header
 	w           io.Writer
@@ -37,8 +37,8 @@ type Writer struct {
 	err         error
 }
 
-// NewWriter creates a new Writer that satisfies writes by compressing data
-// written to w.
+// NewWriter returns a new Writer.
+// Writes to the returned writer are compressed and written to w.
 //
 // It is the caller's responsibility to call Close on the WriteCloser when done.
 // Writes may be buffered and not flushed until Close.
diff --git a/src/pkg/compress/gzip/gzip_test.go b/src/pkg/compress/gzip/gzip_test.go
index 119be2e..09271b2 100644
--- a/src/pkg/compress/gzip/gzip_test.go
+++ b/src/pkg/compress/gzip/gzip_test.go
@@ -85,7 +85,7 @@ func TestRoundTrip(t *testing.T) {
 func TestLatin1(t *testing.T) {
 	latin1 := []byte{0xc4, 'u', 0xdf, 'e', 'r', 'u', 'n', 'g', 0}
 	utf8 := "Äußerung"
-	z := Reader{r: bufio.NewReader(bytes.NewBuffer(latin1))}
+	z := Reader{r: bufio.NewReader(bytes.NewReader(latin1))}
 	s, err := z.readString()
 	if err != nil {
 		t.Fatalf("readString: %v", err)
diff --git a/src/pkg/compress/lzw/reader.go b/src/pkg/compress/lzw/reader.go
index efbc758..ef59699 100644
--- a/src/pkg/compress/lzw/reader.go
+++ b/src/pkg/compress/lzw/reader.go
@@ -216,8 +216,8 @@ func (d *decoder) Close() error {
 	return nil
 }
 
-// NewReader creates a new io.ReadCloser that satisfies reads by decompressing
-// the data read from r.
+// NewReader creates a new io.ReadCloser.
+// Reads from the returned io.ReadCloser read and decompress data from r.
 // It is the caller's responsibility to call Close on the ReadCloser when
 // finished reading.
 // The number of bits to use for literal codes, litWidth, must be in the
diff --git a/src/pkg/compress/lzw/reader_test.go b/src/pkg/compress/lzw/reader_test.go
index 6f155b1..9006c91 100644
--- a/src/pkg/compress/lzw/reader_test.go
+++ b/src/pkg/compress/lzw/reader_test.go
@@ -127,7 +127,7 @@ func benchmarkDecoder(b *testing.B, n int) {
 		if len(buf0) > n-i {
 			buf0 = buf0[:n-i]
 		}
-		io.Copy(w, bytes.NewBuffer(buf0))
+		w.Write(buf0)
 	}
 	w.Close()
 	buf1 := compressed.Bytes()
@@ -135,7 +135,7 @@ func benchmarkDecoder(b *testing.B, n int) {
 	runtime.GC()
 	b.StartTimer()
 	for i := 0; i < b.N; i++ {
-		io.Copy(ioutil.Discard, NewReader(bytes.NewBuffer(buf1), LSB, 8))
+		io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1), LSB, 8))
 	}
 }
 
diff --git a/src/pkg/compress/lzw/writer.go b/src/pkg/compress/lzw/writer.go
index b206918..961b25f 100644
--- a/src/pkg/compress/lzw/writer.go
+++ b/src/pkg/compress/lzw/writer.go
@@ -225,8 +225,8 @@ func (e *encoder) Close() error {
 	return e.w.Flush()
 }
 
-// NewWriter creates a new io.WriteCloser that satisfies writes by compressing
-// the data and writing it to w.
+// NewWriter creates a new io.WriteCloser.
+// Writes to the returned io.WriteCloser are compressed and written to w.
 // It is the caller's responsibility to call Close on the WriteCloser when
 // finished writing.
 // The number of bits to use for literal codes, litWidth, must be in the
diff --git a/src/pkg/compress/zlib/example_test.go b/src/pkg/compress/zlib/example_test.go
index b934ffa..7040889 100644
--- a/src/pkg/compress/zlib/example_test.go
+++ b/src/pkg/compress/zlib/example_test.go
@@ -25,7 +25,7 @@ func ExampleNewWriter() {
 func ExampleNewReader() {
 	buff := []byte{120, 156, 202, 72, 205, 201, 201, 215, 81, 40, 207,
 		47, 202, 73, 225, 2, 4, 0, 0, 255, 255, 33, 231, 4, 147}
-	b := bytes.NewBuffer(buff)
+	b := bytes.NewReader(buff)
 
 	r, err := zlib.NewReader(b)
 	if err != nil {
diff --git a/src/pkg/compress/zlib/reader.go b/src/pkg/compress/zlib/reader.go
index d54746f..9e1aafd 100644
--- a/src/pkg/compress/zlib/reader.go
+++ b/src/pkg/compress/zlib/reader.go
@@ -51,7 +51,8 @@ type reader struct {
 	scratch      [4]byte
 }
 
-// NewReader creates a new io.ReadCloser that satisfies reads by decompressing data read from r.
+// NewReader creates a new io.ReadCloser.
+// Reads from the returned io.ReadCloser read and decompress data from r.
 // The implementation buffers input and may read more data than necessary from r.
 // It is the caller's responsibility to call Close on the ReadCloser when done.
 func NewReader(r io.Reader) (io.ReadCloser, error) {
diff --git a/src/pkg/compress/zlib/reader_test.go b/src/pkg/compress/zlib/reader_test.go
index 3b02a08..218ccba 100644
--- a/src/pkg/compress/zlib/reader_test.go
+++ b/src/pkg/compress/zlib/reader_test.go
@@ -102,7 +102,7 @@ var zlibTests = []zlibTest{
 func TestDecompressor(t *testing.T) {
 	b := new(bytes.Buffer)
 	for _, tt := range zlibTests {
-		in := bytes.NewBuffer(tt.compressed)
+		in := bytes.NewReader(tt.compressed)
 		zlib, err := NewReaderDict(in, tt.dict)
 		if err != nil {
 			if err != tt.err {
diff --git a/src/pkg/compress/zlib/writer.go b/src/pkg/compress/zlib/writer.go
index 99ff654..fac7e15 100644
--- a/src/pkg/compress/zlib/writer.go
+++ b/src/pkg/compress/zlib/writer.go
@@ -34,8 +34,8 @@ type Writer struct {
 	wroteHeader bool
 }
 
-// NewWriter creates a new Writer that satisfies writes by compressing data
-// written to w.
+// NewWriter creates a new Writer.
+// Writes to the returned Writer are compressed and written to w.
 //
 // It is the caller's responsibility to call Close on the WriteCloser when done.
 // Writes may be buffered and not flushed until Close.
diff --git a/src/pkg/compress/zlib/writer_test.go b/src/pkg/compress/zlib/writer_test.go
index cf9c832..71ba81a 100644
--- a/src/pkg/compress/zlib/writer_test.go
+++ b/src/pkg/compress/zlib/writer_test.go
@@ -120,7 +120,7 @@ func testFileLevelDictReset(t *testing.T, fn string, level int, dict []byte) {
 	}
 	out := buf.String()
 
-	// Reset and comprses again.
+	// Reset and compress again.
 	buf2 := new(bytes.Buffer)
 	zlibw.Reset(buf2)
 	_, err = zlibw.Write(b0)
diff --git a/src/pkg/container/heap/example_pq_test.go b/src/pkg/container/heap/example_pq_test.go
index 8cbeb8d..7017095 100644
--- a/src/pkg/container/heap/example_pq_test.go
+++ b/src/pkg/container/heap/example_pq_test.go
@@ -52,13 +52,12 @@ func (pq *PriorityQueue) Pop() interface{} {
 
 // update modifies the priority and value of an Item in the queue.
 func (pq *PriorityQueue) update(item *Item, value string, priority int) {
-	heap.Remove(pq, item.index)
 	item.value = value
 	item.priority = priority
-	heap.Push(pq, item)
+	heap.Fix(pq, item.index)
 }
 
-// This example inserts some items into a PriorityQueue, manipulates an item,
+// This example creates a PriorityQueue with some items, adds and manipulates an item,
 // and then removes the items in priority order.
 func Example_priorityQueue() {
 	// Some items and their priorities.
@@ -66,28 +65,31 @@ func Example_priorityQueue() {
 		"banana": 3, "apple": 2, "pear": 4,
 	}
 
-	// Create a priority queue and put the items in it.
-	pq := &PriorityQueue{}
-	heap.Init(pq)
+	// Create a priority queue, put the items in it, and
+	// establish the priority queue (heap) invariants.
+	pq := make(PriorityQueue, len(items))
+	i := 0
 	for value, priority := range items {
-		item := &Item{
+		pq[i] = &Item{
 			value:    value,
 			priority: priority,
+			index:    i,
 		}
-		heap.Push(pq, item)
+		i++
 	}
+	heap.Init(&pq)
 
 	// Insert a new item and then modify its priority.
 	item := &Item{
 		value:    "orange",
 		priority: 1,
 	}
-	heap.Push(pq, item)
+	heap.Push(&pq, item)
 	pq.update(item, item.value, 5)
 
 	// Take the items out; they arrive in decreasing priority order.
 	for pq.Len() > 0 {
-		item := heap.Pop(pq).(*Item)
+		item := heap.Pop(&pq).(*Item)
 		fmt.Printf("%.2d:%s ", item.priority, item.value)
 	}
 	// Output:
diff --git a/src/pkg/container/heap/heap.go b/src/pkg/container/heap/heap.go
index 52c8507..c467a11 100644
--- a/src/pkg/container/heap/heap.go
+++ b/src/pkg/container/heap/heap.go
@@ -22,7 +22,7 @@ import "sort"
 // min-heap with the following invariants (established after
 // Init has been called or if the data is empty or sorted):
 //
-//	!h.Less(j, i) for 0 <= i < h.Len() and j = 2*i+1 or 2*i+2 and j < h.Len()
+//	!h.Less(j, i) for 0 <= i < h.Len() and 2*i+1 <= j <= 2*i+2 and j < h.Len()
 //
 // Note that Push and Pop in this interface are for package heap's
 // implementation to call.  To add and remove things from the heap,
@@ -78,7 +78,7 @@ func Remove(h Interface, i int) interface{} {
 	return h.Pop()
 }
 
-// Fix reestablishes the heap ordering after the element at index i has changed its value.
+// Fix re-establishes the heap ordering after the element at index i has changed its value.
 // Changing the value of the element at index i and then calling Fix is equivalent to,
 // but less expensive than, calling Remove(h, i) followed by a Push of the new value.
 // The complexity is O(log(n)) where n = h.Len().
diff --git a/src/pkg/container/list/example_test.go b/src/pkg/container/list/example_test.go
index 7361212..3621784 100644
--- a/src/pkg/container/list/example_test.go
+++ b/src/pkg/container/list/example_test.go
@@ -17,7 +17,7 @@ func Example() {
 	l.InsertBefore(3, e4)
 	l.InsertAfter(2, e1)
 
-	// Iterate through list and and print its contents.
+	// Iterate through list and print its contents.
 	for e := l.Front(); e != nil; e = e.Next() {
 		fmt.Println(e.Value)
 	}
diff --git a/src/pkg/container/list/list.go b/src/pkg/container/list/list.go
index ed2d15a..0256768 100644
--- a/src/pkg/container/list/list.go
+++ b/src/pkg/container/list/list.go
@@ -65,7 +65,7 @@ func New() *List { return new(List).Init() }
 // The complexity is O(1).
 func (l *List) Len() int { return l.len }
 
-// Front returns the first element of list l or nil
+// Front returns the first element of list l or nil.
 func (l *List) Front() *Element {
 	if l.len == 0 {
 		return nil
@@ -180,18 +180,18 @@ func (l *List) MoveToBack(e *Element) {
 }
 
 // MoveBefore moves element e to its new position before mark.
-// If e is not an element of l, or e == mark, the list is not modified.
+// If e or mark is not an element of l, or e == mark, the list is not modified.
 func (l *List) MoveBefore(e, mark *Element) {
-	if e.list != l || e == mark {
+	if e.list != l || e == mark || mark.list != l {
 		return
 	}
 	l.insert(l.remove(e), mark.prev)
 }
 
 // MoveAfter moves element e to its new position after mark.
-// If e is not an element of l, or e == mark, the list is not modified.
+// If e or mark is not an element of l, or e == mark, the list is not modified.
 func (l *List) MoveAfter(e, mark *Element) {
-	if e.list != l || e == mark {
+	if e.list != l || e == mark || mark.list != l {
 		return
 	}
 	l.insert(l.remove(e), mark)
diff --git a/src/pkg/container/list/list_test.go b/src/pkg/container/list/list_test.go
index ee52afe..4d8bfc2 100644
--- a/src/pkg/container/list/list_test.go
+++ b/src/pkg/container/list/list_test.go
@@ -285,3 +285,59 @@ func TestMove(t *testing.T) {
 	checkListPointers(t, l, []*Element{e1, e3, e2, e4})
 	e1, e2, e3, e4 = e1, e3, e2, e4
 }
+
+// Test PushFront, PushBack, PushFrontList, PushBackList with uninitialized List
+func TestZeroList(t *testing.T) {
+	var l1 = new(List)
+	l1.PushFront(1)
+	checkList(t, l1, []interface{}{1})
+
+	var l2 = new(List)
+	l2.PushBack(1)
+	checkList(t, l2, []interface{}{1})
+
+	var l3 = new(List)
+	l3.PushFrontList(l1)
+	checkList(t, l3, []interface{}{1})
+
+	var l4 = new(List)
+	l4.PushBackList(l2)
+	checkList(t, l4, []interface{}{1})
+}
+
+// Test that a list l is not modified when calling InsertBefore with a mark that is not an element of l.
+func TestInsertBeforeUnknownMark(t *testing.T) {
+	var l List
+	l.PushBack(1)
+	l.PushBack(2)
+	l.PushBack(3)
+	l.InsertBefore(1, new(Element))
+	checkList(t, &l, []interface{}{1, 2, 3})
+}
+
+// Test that a list l is not modified when calling InsertAfter with a mark that is not an element of l.
+func TestInsertAfterUnknownMark(t *testing.T) {
+	var l List
+	l.PushBack(1)
+	l.PushBack(2)
+	l.PushBack(3)
+	l.InsertAfter(1, new(Element))
+	checkList(t, &l, []interface{}{1, 2, 3})
+}
+
+// Test that a list l is not modified when calling MoveAfter or MoveBefore with a mark that is not an element of l.
+func TestMoveUnkownMark(t *testing.T) {
+	var l1 List
+	e1 := l1.PushBack(1)
+
+	var l2 List
+	e2 := l2.PushBack(2)
+
+	l1.MoveAfter(e1, e2)
+	checkList(t, &l1, []interface{}{1})
+	checkList(t, &l2, []interface{}{2})
+
+	l1.MoveBefore(e1, e2)
+	checkList(t, &l1, []interface{}{1})
+	checkList(t, &l2, []interface{}{2})
+}
diff --git a/src/pkg/container/ring/ring_test.go b/src/pkg/container/ring/ring_test.go
index 099d92b..552f0e2 100644
--- a/src/pkg/container/ring/ring_test.go
+++ b/src/pkg/container/ring/ring_test.go
@@ -218,3 +218,11 @@ func TestLinkUnlink(t *testing.T) {
 		}
 	}
 }
+
+// Test that calling Move() on an empty Ring initializes it.
+func TestMoveEmptyRing(t *testing.T) {
+	var r Ring
+
+	r.Move(1)
+	verify(t, &r, 1, 0)
+}
diff --git a/src/pkg/crypto/aes/aes_test.go b/src/pkg/crypto/aes/aes_test.go
index 6261dd0..3631809 100644
--- a/src/pkg/crypto/aes/aes_test.go
+++ b/src/pkg/crypto/aes/aes_test.go
@@ -354,6 +354,34 @@ func TestCipherDecrypt(t *testing.T) {
 	}
 }
 
+// Test short input/output.
+// Assembly used to not notice.
+// See issue 7928.
+func TestShortBlocks(t *testing.T) {
+	bytes := func(n int) []byte { return make([]byte, n) }
+
+	c, _ := NewCipher(bytes(16))
+
+	mustPanic(t, "crypto/aes: input not full block", func() { c.Encrypt(bytes(1), bytes(1)) })
+	mustPanic(t, "crypto/aes: input not full block", func() { c.Decrypt(bytes(1), bytes(1)) })
+	mustPanic(t, "crypto/aes: input not full block", func() { c.Encrypt(bytes(100), bytes(1)) })
+	mustPanic(t, "crypto/aes: input not full block", func() { c.Decrypt(bytes(100), bytes(1)) })
+	mustPanic(t, "crypto/aes: output not full block", func() { c.Encrypt(bytes(1), bytes(100)) })
+	mustPanic(t, "crypto/aes: output not full block", func() { c.Decrypt(bytes(1), bytes(100)) })
+}
+
+func mustPanic(t *testing.T, msg string, f func()) {
+	defer func() {
+		err := recover()
+		if err == nil {
+			t.Errorf("function did not panic, wanted %q", msg)
+		} else if err != msg {
+			t.Errorf("got panic %v, wanted %q", err, msg)
+		}
+	}()
+	f()
+}
+
 func BenchmarkEncrypt(b *testing.B) {
 	tt := encryptTests[0]
 	c, err := NewCipher(tt.key)
diff --git a/src/pkg/crypto/aes/cipher.go b/src/pkg/crypto/aes/cipher.go
index d931134..2c6bb0a 100644
--- a/src/pkg/crypto/aes/cipher.go
+++ b/src/pkg/crypto/aes/cipher.go
@@ -46,9 +46,21 @@ func NewCipher(key []byte) (cipher.Block, error) {
 func (c *aesCipher) BlockSize() int { return BlockSize }
 
 func (c *aesCipher) Encrypt(dst, src []byte) {
+	if len(src) < BlockSize {
+		panic("crypto/aes: input not full block")
+	}
+	if len(dst) < BlockSize {
+		panic("crypto/aes: output not full block")
+	}
 	encryptBlock(c.enc, dst, src)
 }
 
 func (c *aesCipher) Decrypt(dst, src []byte) {
+	if len(src) < BlockSize {
+		panic("crypto/aes: input not full block")
+	}
+	if len(dst) < BlockSize {
+		panic("crypto/aes: output not full block")
+	}
 	decryptBlock(c.dec, dst, src)
 }
diff --git a/src/pkg/crypto/aes/cipher_asm.go b/src/pkg/crypto/aes/cipher_asm.go
index 21369fc..964eaaa 100644
--- a/src/pkg/crypto/aes/cipher_asm.go
+++ b/src/pkg/crypto/aes/cipher_asm.go
@@ -21,6 +21,7 @@ func encryptBlock(xk []uint32, dst, src []byte) {
 		encryptBlockGo(xk, dst, src)
 	}
 }
+
 func decryptBlock(xk []uint32, dst, src []byte) {
 	if useAsm {
 		decryptBlockAsm(len(xk)/4-1, &xk[0], &dst[0], &src[0])
@@ -28,6 +29,7 @@ func decryptBlock(xk []uint32, dst, src []byte) {
 		decryptBlockGo(xk, dst, src)
 	}
 }
+
 func expandKey(key []byte, enc, dec []uint32) {
 	if useAsm {
 		rounds := 10
diff --git a/src/pkg/crypto/cipher/benchmark_test.go b/src/pkg/crypto/cipher/benchmark_test.go
new file mode 100644
index 0000000..027b248
--- /dev/null
+++ b/src/pkg/crypto/cipher/benchmark_test.go
@@ -0,0 +1,139 @@
+// 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 cipher_test
+
+import (
+	"crypto/aes"
+	"crypto/cipher"
+	"testing"
+)
+
+func BenchmarkAESGCMSeal1K(b *testing.B) {
+	buf := make([]byte, 1024)
+	b.SetBytes(int64(len(buf)))
+
+	var key [16]byte
+	var nonce [12]byte
+	aes, _ := aes.NewCipher(key[:])
+	aesgcm, _ := cipher.NewGCM(aes)
+	var out []byte
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		out = aesgcm.Seal(out[:0], nonce[:], buf, nonce[:])
+	}
+}
+
+func BenchmarkAESGCMOpen1K(b *testing.B) {
+	buf := make([]byte, 1024)
+	b.SetBytes(int64(len(buf)))
+
+	var key [16]byte
+	var nonce [12]byte
+	aes, _ := aes.NewCipher(key[:])
+	aesgcm, _ := cipher.NewGCM(aes)
+	var out []byte
+	out = aesgcm.Seal(out[:0], nonce[:], buf, nonce[:])
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		_, err := aesgcm.Open(buf[:0], nonce[:], out, nonce[:])
+		if err != nil {
+			b.Errorf("Open: %v", err)
+		}
+	}
+}
+
+// If we test exactly 1K blocks, we would generate exact multiples of
+// the cipher's block size, and the cipher stream fragments would
+// always be wordsize aligned, whereas non-aligned is a more typical
+// use-case.
+const almost1K = 1024 - 5
+
+func BenchmarkAESCFBEncrypt1K(b *testing.B) {
+	buf := make([]byte, almost1K)
+	b.SetBytes(int64(len(buf)))
+
+	var key [16]byte
+	var iv [16]byte
+	aes, _ := aes.NewCipher(key[:])
+	ctr := cipher.NewCFBEncrypter(aes, iv[:])
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		ctr.XORKeyStream(buf, buf)
+	}
+}
+
+func BenchmarkAESCFBDecrypt1K(b *testing.B) {
+	buf := make([]byte, almost1K)
+	b.SetBytes(int64(len(buf)))
+
+	var key [16]byte
+	var iv [16]byte
+	aes, _ := aes.NewCipher(key[:])
+	ctr := cipher.NewCFBDecrypter(aes, iv[:])
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		ctr.XORKeyStream(buf, buf)
+	}
+}
+
+func BenchmarkAESOFB1K(b *testing.B) {
+	buf := make([]byte, almost1K)
+	b.SetBytes(int64(len(buf)))
+
+	var key [16]byte
+	var iv [16]byte
+	aes, _ := aes.NewCipher(key[:])
+	ctr := cipher.NewOFB(aes, iv[:])
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		ctr.XORKeyStream(buf, buf)
+	}
+}
+
+func BenchmarkAESCTR1K(b *testing.B) {
+	buf := make([]byte, almost1K)
+	b.SetBytes(int64(len(buf)))
+
+	var key [16]byte
+	var iv [16]byte
+	aes, _ := aes.NewCipher(key[:])
+	ctr := cipher.NewCTR(aes, iv[:])
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		ctr.XORKeyStream(buf, buf)
+	}
+}
+
+func BenchmarkAESCBCEncrypt1K(b *testing.B) {
+	buf := make([]byte, 1024)
+	b.SetBytes(int64(len(buf)))
+
+	var key [16]byte
+	var iv [16]byte
+	aes, _ := aes.NewCipher(key[:])
+	cbc := cipher.NewCBCEncrypter(aes, iv[:])
+	for i := 0; i < b.N; i++ {
+		cbc.CryptBlocks(buf, buf)
+	}
+}
+
+func BenchmarkAESCBCDecrypt1K(b *testing.B) {
+	buf := make([]byte, 1024)
+	b.SetBytes(int64(len(buf)))
+
+	var key [16]byte
+	var iv [16]byte
+	aes, _ := aes.NewCipher(key[:])
+	cbc := cipher.NewCBCDecrypter(aes, iv[:])
+	for i := 0; i < b.N; i++ {
+		cbc.CryptBlocks(buf, buf)
+	}
+}
diff --git a/src/pkg/crypto/cipher/cbc.go b/src/pkg/crypto/cipher/cbc.go
index 4189677..241e122 100644
--- a/src/pkg/crypto/cipher/cbc.go
+++ b/src/pkg/crypto/cipher/cbc.go
@@ -48,17 +48,22 @@ func (x *cbcEncrypter) CryptBlocks(dst, src []byte) {
 	if len(dst) < len(src) {
 		panic("crypto/cipher: output smaller than input")
 	}
+
+	iv := x.iv
+
 	for len(src) > 0 {
-		for i := 0; i < x.blockSize; i++ {
-			x.iv[i] ^= src[i]
-		}
-		x.b.Encrypt(x.iv, x.iv)
-		for i := 0; i < x.blockSize; i++ {
-			dst[i] = x.iv[i]
-		}
+		// Write the xor to dst, then encrypt in place.
+		xorBytes(dst[:x.blockSize], src[:x.blockSize], iv)
+		x.b.Encrypt(dst[:x.blockSize], dst[:x.blockSize])
+
+		// Move to the next block with this block as the next iv.
+		iv = dst[:x.blockSize]
 		src = src[x.blockSize:]
 		dst = dst[x.blockSize:]
 	}
+
+	// Save the iv for the next CryptBlocks call.
+	copy(x.iv, iv)
 }
 
 func (x *cbcEncrypter) SetIV(iv []byte) {
@@ -89,17 +94,35 @@ func (x *cbcDecrypter) CryptBlocks(dst, src []byte) {
 	if len(dst) < len(src) {
 		panic("crypto/cipher: output smaller than input")
 	}
-	for len(src) > 0 {
-		x.b.Decrypt(x.tmp, src[:x.blockSize])
-		for i := 0; i < x.blockSize; i++ {
-			x.tmp[i] ^= x.iv[i]
-			x.iv[i] = src[i]
-			dst[i] = x.tmp[i]
-		}
+	if len(src) == 0 {
+		return
+	}
 
-		src = src[x.blockSize:]
-		dst = dst[x.blockSize:]
+	// For each block, we need to xor the decrypted data with the previous block's ciphertext (the iv).
+	// To avoid making a copy each time, we loop over the blocks BACKWARDS.
+	end := len(src)
+	start := end - x.blockSize
+	prev := start - x.blockSize
+
+	// Copy the last block of ciphertext in preparation as the new iv.
+	copy(x.tmp, src[start:end])
+
+	// Loop over all but the first block.
+	for start > 0 {
+		x.b.Decrypt(dst[start:end], src[start:end])
+		xorBytes(dst[start:end], dst[start:end], src[prev:start])
+
+		end = start
+		start = prev
+		prev -= x.blockSize
 	}
+
+	// The first block is special because it uses the saved iv.
+	x.b.Decrypt(dst[start:end], src[start:end])
+	xorBytes(dst[start:end], dst[start:end], x.iv)
+
+	// Set the new iv to the first block we copied earlier.
+	x.iv, x.tmp = x.tmp, x.iv
 }
 
 func (x *cbcDecrypter) SetIV(iv []byte) {
diff --git a/src/pkg/crypto/cipher/cbc_aes_test.go b/src/pkg/crypto/cipher/cbc_aes_test.go
index cee3a78..bf9e7ad 100644
--- a/src/pkg/crypto/cipher/cbc_aes_test.go
+++ b/src/pkg/crypto/cipher/cbc_aes_test.go
@@ -63,28 +63,42 @@ var cbcAESTests = []struct {
 	},
 }
 
-func TestCBC_AES(t *testing.T) {
-	for _, tt := range cbcAESTests {
-		test := tt.name
-
-		c, err := aes.NewCipher(tt.key)
+func TestCBCEncrypterAES(t *testing.T) {
+	for _, test := range cbcAESTests {
+		c, err := aes.NewCipher(test.key)
 		if err != nil {
-			t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+			t.Errorf("%s: NewCipher(%d bytes) = %s", test.name, len(test.key), err)
 			continue
 		}
 
-		encrypter := cipher.NewCBCEncrypter(c, tt.iv)
-		d := make([]byte, len(tt.in))
-		encrypter.CryptBlocks(d, tt.in)
-		if !bytes.Equal(tt.out, d) {
-			t.Errorf("%s: CBCEncrypter\nhave %x\nwant %x", test, d, tt.out)
+		encrypter := cipher.NewCBCEncrypter(c, test.iv)
+
+		data := make([]byte, len(test.in))
+		copy(data, test.in)
+
+		encrypter.CryptBlocks(data, data)
+		if !bytes.Equal(test.out, data) {
+			t.Errorf("%s: CBCEncrypter\nhave %x\nwant %x", test.name, data, test.out)
 		}
+	}
+}
+
+func TestCBCDecrypterAES(t *testing.T) {
+	for _, test := range cbcAESTests {
+		c, err := aes.NewCipher(test.key)
+		if err != nil {
+			t.Errorf("%s: NewCipher(%d bytes) = %s", test.name, len(test.key), err)
+			continue
+		}
+
+		decrypter := cipher.NewCBCDecrypter(c, test.iv)
+
+		data := make([]byte, len(test.out))
+		copy(data, test.out)
 
-		decrypter := cipher.NewCBCDecrypter(c, tt.iv)
-		p := make([]byte, len(d))
-		decrypter.CryptBlocks(p, d)
-		if !bytes.Equal(tt.in, p) {
-			t.Errorf("%s: CBCDecrypter\nhave %x\nwant %x", test, d, tt.in)
+		decrypter.CryptBlocks(data, data)
+		if !bytes.Equal(test.in, data) {
+			t.Errorf("%s: CBCDecrypter\nhave %x\nwant %x", test.name, data, test.in)
 		}
 	}
 }
diff --git a/src/pkg/crypto/cipher/cfb.go b/src/pkg/crypto/cipher/cfb.go
index 99006b5..9b4eebf 100644
--- a/src/pkg/crypto/cipher/cfb.go
+++ b/src/pkg/crypto/cipher/cfb.go
@@ -8,18 +8,41 @@ package cipher
 
 type cfb struct {
 	b       Block
+	next    []byte
 	out     []byte
 	outUsed int
+
 	decrypt bool
 }
 
+func (x *cfb) XORKeyStream(dst, src []byte) {
+	for len(src) > 0 {
+		if x.outUsed == len(x.out) {
+			x.b.Encrypt(x.out, x.next)
+			x.outUsed = 0
+		}
+
+		if x.decrypt {
+			// We can precompute a larger segment of the
+			// keystream on decryption. This will allow
+			// larger batches for xor, and we should be
+			// able to match CTR/OFB performance.
+			copy(x.next[x.outUsed:], src)
+		}
+		n := xorBytes(dst, src, x.out[x.outUsed:])
+		if !x.decrypt {
+			copy(x.next[x.outUsed:], dst)
+		}
+		dst = dst[n:]
+		src = src[n:]
+		x.outUsed += n
+	}
+}
+
 // NewCFBEncrypter returns a Stream which encrypts with cipher feedback mode,
 // using the given Block. The iv must be the same length as the Block's block
 // size.
 func NewCFBEncrypter(block Block, iv []byte) Stream {
-	if len(iv) != block.BlockSize() {
-		panic("cipher.NewCBFEncrypter: IV length must equal block size")
-	}
 	return newCFB(block, iv, false)
 }
 
@@ -27,44 +50,23 @@ func NewCFBEncrypter(block Block, iv []byte) Stream {
 // using the given Block. The iv must be the same length as the Block's block
 // size.
 func NewCFBDecrypter(block Block, iv []byte) Stream {
-	if len(iv) != block.BlockSize() {
-		panic("cipher.NewCBFEncrypter: IV length must equal block size")
-	}
 	return newCFB(block, iv, true)
 }
 
 func newCFB(block Block, iv []byte, decrypt bool) Stream {
 	blockSize := block.BlockSize()
 	if len(iv) != blockSize {
-		return nil
+		// stack trace will indicate whether it was de or encryption
+		panic("cipher.newCFB: IV length must equal block size")
 	}
-
 	x := &cfb{
 		b:       block,
 		out:     make([]byte, blockSize),
-		outUsed: 0,
+		next:    make([]byte, blockSize),
+		outUsed: blockSize,
 		decrypt: decrypt,
 	}
-	block.Encrypt(x.out, iv)
+	copy(x.next, iv)
 
 	return x
 }
-
-func (x *cfb) XORKeyStream(dst, src []byte) {
-	for i := 0; i < len(src); i++ {
-		if x.outUsed == len(x.out) {
-			x.b.Encrypt(x.out, x.out)
-			x.outUsed = 0
-		}
-
-		if x.decrypt {
-			t := src[i]
-			dst[i] = src[i] ^ x.out[x.outUsed]
-			x.out[x.outUsed] = t
-		} else {
-			x.out[x.outUsed] ^= src[i]
-			dst[i] = x.out[x.outUsed]
-		}
-		x.outUsed++
-	}
-}
diff --git a/src/pkg/crypto/cipher/cfb_test.go b/src/pkg/crypto/cipher/cfb_test.go
index f704b33..ec708ab 100644
--- a/src/pkg/crypto/cipher/cfb_test.go
+++ b/src/pkg/crypto/cipher/cfb_test.go
@@ -19,16 +19,18 @@ func TestCFB(t *testing.T) {
 		return
 	}
 
-	plaintext := []byte("this is the plaintext")
+	plaintext := []byte("this is the plaintext. this is the plaintext.")
 	iv := make([]byte, block.BlockSize())
 	rand.Reader.Read(iv)
 	cfb := cipher.NewCFBEncrypter(block, iv)
 	ciphertext := make([]byte, len(plaintext))
-	cfb.XORKeyStream(ciphertext, plaintext)
+	copy(ciphertext, plaintext)
+	cfb.XORKeyStream(ciphertext, ciphertext)
 
 	cfbdec := cipher.NewCFBDecrypter(block, iv)
 	plaintextCopy := make([]byte, len(plaintext))
-	cfbdec.XORKeyStream(plaintextCopy, ciphertext)
+	copy(plaintextCopy, ciphertext)
+	cfbdec.XORKeyStream(plaintextCopy, plaintextCopy)
 
 	if !bytes.Equal(plaintextCopy, plaintext) {
 		t.Errorf("got: %x, want: %x", plaintextCopy, plaintext)
diff --git a/src/pkg/crypto/cipher/cipher.go b/src/pkg/crypto/cipher/cipher.go
index 1ffaa8c..67afdb1 100644
--- a/src/pkg/crypto/cipher/cipher.go
+++ b/src/pkg/crypto/cipher/cipher.go
@@ -46,16 +46,6 @@ type BlockMode interface {
 
 // Utility routines
 
-func shift1(dst, src []byte) byte {
-	var b byte
-	for i := len(src) - 1; i >= 0; i-- {
-		bb := src[i] >> 7
-		dst[i] = src[i]<<1 | b
-		b = bb
-	}
-	return b
-}
-
 func dup(p []byte) []byte {
 	q := make([]byte, len(p))
 	copy(q, p)
diff --git a/src/pkg/crypto/cipher/ctr.go b/src/pkg/crypto/cipher/ctr.go
index d9ee9d8..70ac40f 100644
--- a/src/pkg/crypto/cipher/ctr.go
+++ b/src/pkg/crypto/cipher/ctr.go
@@ -19,37 +19,58 @@ type ctr struct {
 	outUsed int
 }
 
+const streamBufferSize = 512
+
 // NewCTR returns a Stream which encrypts/decrypts using the given Block in
 // counter mode. The length of iv must be the same as the Block's block size.
 func NewCTR(block Block, iv []byte) Stream {
 	if len(iv) != block.BlockSize() {
 		panic("cipher.NewCTR: IV length must equal block size")
 	}
-
+	bufSize := streamBufferSize
+	if bufSize < block.BlockSize() {
+		bufSize = block.BlockSize()
+	}
 	return &ctr{
 		b:       block,
 		ctr:     dup(iv),
-		out:     make([]byte, len(iv)),
-		outUsed: len(iv),
+		out:     make([]byte, 0, bufSize),
+		outUsed: 0,
 	}
 }
 
-func (x *ctr) XORKeyStream(dst, src []byte) {
-	for i := 0; i < len(src); i++ {
-		if x.outUsed == len(x.ctr) {
-			x.b.Encrypt(x.out, x.ctr)
-			x.outUsed = 0
-
-			// Increment counter
-			for i := len(x.ctr) - 1; i >= 0; i-- {
-				x.ctr[i]++
-				if x.ctr[i] != 0 {
-					break
-				}
+func (x *ctr) refill() {
+	remain := len(x.out) - x.outUsed
+	if remain > x.outUsed {
+		return
+	}
+	copy(x.out, x.out[x.outUsed:])
+	x.out = x.out[:cap(x.out)]
+	bs := x.b.BlockSize()
+	for remain < len(x.out)-bs {
+		x.b.Encrypt(x.out[remain:], x.ctr)
+		remain += bs
+
+		// Increment counter
+		for i := len(x.ctr) - 1; i >= 0; i-- {
+			x.ctr[i]++
+			if x.ctr[i] != 0 {
+				break
 			}
 		}
+	}
+	x.out = x.out[:remain]
+	x.outUsed = 0
+}
 
-		dst[i] = src[i] ^ x.out[x.outUsed]
-		x.outUsed++
+func (x *ctr) XORKeyStream(dst, src []byte) {
+	for len(src) > 0 {
+		if x.outUsed >= len(x.out)-x.b.BlockSize() {
+			x.refill()
+		}
+		n := xorBytes(dst, src, x.out[x.outUsed:])
+		dst = dst[n:]
+		src = src[n:]
+		x.outUsed += n
 	}
 }
diff --git a/src/pkg/crypto/cipher/gcm.go b/src/pkg/crypto/cipher/gcm.go
index 2bcb469..bdafd85 100644
--- a/src/pkg/crypto/cipher/gcm.go
+++ b/src/pkg/crypto/cipher/gcm.go
@@ -30,9 +30,9 @@ type AEAD interface {
 
 	// Open decrypts and authenticates ciphertext, authenticates the
 	// additional data and, if successful, appends the resulting plaintext
-	// to dst, returning the updated slice and true. On error, nil and
-	// false is returned. The nonce must be NonceSize() bytes long and both
-	// it and the additional data must match the value passed to Seal.
+	// to dst, returning the updated slice. The nonce must be NonceSize()
+	// bytes long and both it and the additional data must match the
+	// value passed to Seal.
 	//
 	// The ciphertext and dst may alias exactly or not at all.
 	Open(dst, nonce, ciphertext, data []byte) ([]byte, error)
@@ -258,11 +258,11 @@ func (g *gcm) update(y *gcmFieldElement, data []byte) {
 // gcmInc32 treats the final four bytes of counterBlock as a big-endian value
 // and increments it.
 func gcmInc32(counterBlock *[16]byte) {
-	c := 1
 	for i := gcmBlockSize - 1; i >= gcmBlockSize-4; i-- {
-		c += int(counterBlock[i])
-		counterBlock[i] = byte(c)
-		c >>= 8
+		counterBlock[i]++
+		if counterBlock[i] != 0 {
+			break
+		}
 	}
 }
 
@@ -289,9 +289,7 @@ func (g *gcm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) {
 		g.cipher.Encrypt(mask[:], counter[:])
 		gcmInc32(counter)
 
-		for i := range mask {
-			out[i] = in[i] ^ mask[i]
-		}
+		xorWords(out, in, mask[:])
 		out = out[gcmBlockSize:]
 		in = in[gcmBlockSize:]
 	}
@@ -299,10 +297,7 @@ func (g *gcm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) {
 	if len(in) > 0 {
 		g.cipher.Encrypt(mask[:], counter[:])
 		gcmInc32(counter)
-
-		for i := range in {
-			out[i] = in[i] ^ mask[i]
-		}
+		xorBytes(out, in, mask[:])
 	}
 }
 
@@ -321,9 +316,7 @@ func (g *gcm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize]
 	putUint64(out, y.low)
 	putUint64(out[8:], y.high)
 
-	for i := range tagMask {
-		out[i] ^= tagMask[i]
-	}
+	xorWords(out, out, tagMask[:])
 }
 
 func getUint64(data []byte) uint64 {
diff --git a/src/pkg/crypto/cipher/gcm_test.go b/src/pkg/crypto/cipher/gcm_test.go
index 02d4215..0c502ce 100644
--- a/src/pkg/crypto/cipher/gcm_test.go
+++ b/src/pkg/crypto/cipher/gcm_test.go
@@ -157,19 +157,3 @@ func TestAESGCM(t *testing.T) {
 		ct[0] ^= 0x80
 	}
 }
-
-func BenchmarkAESGCM(b *testing.B) {
-	buf := make([]byte, 1024)
-	b.SetBytes(int64(len(buf)))
-
-	var key [16]byte
-	var nonce [12]byte
-	aes, _ := aes.NewCipher(key[:])
-	aesgcm, _ := cipher.NewGCM(aes)
-	var out []byte
-
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		out = aesgcm.Seal(out[:0], nonce[:], buf, nonce[:])
-	}
-}
diff --git a/src/pkg/crypto/cipher/ofb.go b/src/pkg/crypto/cipher/ofb.go
index 85e5f02..e86ebcb 100644
--- a/src/pkg/crypto/cipher/ofb.go
+++ b/src/pkg/crypto/cipher/ofb.go
@@ -8,6 +8,7 @@ package cipher
 
 type ofb struct {
 	b       Block
+	cipher  []byte
 	out     []byte
 	outUsed int
 }
@@ -20,25 +21,46 @@ func NewOFB(b Block, iv []byte) Stream {
 	if len(iv) != blockSize {
 		return nil
 	}
-
+	bufSize := streamBufferSize
+	if bufSize < blockSize {
+		bufSize = blockSize
+	}
 	x := &ofb{
 		b:       b,
-		out:     make([]byte, blockSize),
+		cipher:  make([]byte, blockSize),
+		out:     make([]byte, 0, bufSize),
 		outUsed: 0,
 	}
-	b.Encrypt(x.out, iv)
 
+	copy(x.cipher, iv)
 	return x
 }
 
+func (x *ofb) refill() {
+	bs := x.b.BlockSize()
+	remain := len(x.out) - x.outUsed
+	if remain > x.outUsed {
+		return
+	}
+	copy(x.out, x.out[x.outUsed:])
+	x.out = x.out[:cap(x.out)]
+	for remain < len(x.out)-bs {
+		x.b.Encrypt(x.cipher, x.cipher)
+		copy(x.out[remain:], x.cipher)
+		remain += bs
+	}
+	x.out = x.out[:remain]
+	x.outUsed = 0
+}
+
 func (x *ofb) XORKeyStream(dst, src []byte) {
-	for i, s := range src {
-		if x.outUsed == len(x.out) {
-			x.b.Encrypt(x.out, x.out)
-			x.outUsed = 0
+	for len(src) > 0 {
+		if x.outUsed >= len(x.out)-x.b.BlockSize() {
+			x.refill()
 		}
-
-		dst[i] = s ^ x.out[x.outUsed]
-		x.outUsed++
+		n := xorBytes(dst, src, x.out[x.outUsed:])
+		dst = dst[n:]
+		src = src[n:]
+		x.outUsed += n
 	}
 }
diff --git a/src/pkg/crypto/cipher/xor.go b/src/pkg/crypto/cipher/xor.go
new file mode 100644
index 0000000..f88dc89
--- /dev/null
+++ b/src/pkg/crypto/cipher/xor.go
@@ -0,0 +1,84 @@
+// 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 cipher
+
+import (
+	"runtime"
+	"unsafe"
+)
+
+const wordSize = int(unsafe.Sizeof(uintptr(0)))
+const supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "amd64"
+
+// fastXORBytes xors in bulk. It only works on architectures that
+// support unaligned read/writes.
+func fastXORBytes(dst, a, b []byte) int {
+	n := len(a)
+	if len(b) < n {
+		n = len(b)
+	}
+
+	w := n / wordSize
+	if w > 0 {
+		dw := *(*[]uintptr)(unsafe.Pointer(&dst))
+		aw := *(*[]uintptr)(unsafe.Pointer(&a))
+		bw := *(*[]uintptr)(unsafe.Pointer(&b))
+		for i := 0; i < w; i++ {
+			dw[i] = aw[i] ^ bw[i]
+		}
+	}
+
+	for i := (n - n%wordSize); i < n; i++ {
+		dst[i] = a[i] ^ b[i]
+	}
+
+	return n
+}
+
+func safeXORBytes(dst, a, b []byte) int {
+	n := len(a)
+	if len(b) < n {
+		n = len(b)
+	}
+	for i := 0; i < n; i++ {
+		dst[i] = a[i] ^ b[i]
+	}
+	return n
+}
+
+// xorBytes xors the bytes in a and b. The destination is assumed to have enough
+// space. Returns the number of bytes xor'd.
+func xorBytes(dst, a, b []byte) int {
+	if supportsUnaligned {
+		return fastXORBytes(dst, a, b)
+	} else {
+		// TODO(hanwen): if (dst, a, b) have common alignment
+		// we could still try fastXORBytes. It is not clear
+		// how often this happens, and it's only worth it if
+		// the block encryption itself is hardware
+		// accelerated.
+		return safeXORBytes(dst, a, b)
+	}
+}
+
+// fastXORWords XORs multiples of 4 or 8 bytes (depending on architecture.)
+// The arguments are assumed to be of equal length.
+func fastXORWords(dst, a, b []byte) {
+	dw := *(*[]uintptr)(unsafe.Pointer(&dst))
+	aw := *(*[]uintptr)(unsafe.Pointer(&a))
+	bw := *(*[]uintptr)(unsafe.Pointer(&b))
+	n := len(b) / wordSize
+	for i := 0; i < n; i++ {
+		dw[i] = aw[i] ^ bw[i]
+	}
+}
+
+func xorWords(dst, a, b []byte) {
+	if supportsUnaligned {
+		fastXORWords(dst, a, b)
+	} else {
+		safeXORBytes(dst, a, b)
+	}
+}
diff --git a/src/pkg/crypto/cipher/xor_test.go b/src/pkg/crypto/cipher/xor_test.go
new file mode 100644
index 0000000..cc1c9d7
--- /dev/null
+++ b/src/pkg/crypto/cipher/xor_test.go
@@ -0,0 +1,28 @@
+// 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 cipher
+
+import (
+	"bytes"
+	"testing"
+)
+
+func TestXOR(t *testing.T) {
+	for alignP := 0; alignP < 2; alignP++ {
+		for alignQ := 0; alignQ < 2; alignQ++ {
+			for alignD := 0; alignD < 2; alignD++ {
+				p := make([]byte, 1024)[alignP:]
+				q := make([]byte, 1024)[alignQ:]
+				d1 := make([]byte, 1024+alignD)[alignD:]
+				d2 := make([]byte, 1024+alignD)[alignD:]
+				xorBytes(d1, p, q)
+				safeXORBytes(d2, p, q)
+				if bytes.Compare(d1, d2) != 0 {
+					t.Error("not equal")
+				}
+			}
+		}
+	}
+}
diff --git a/src/pkg/crypto/dsa/dsa.go b/src/pkg/crypto/dsa/dsa.go
index 5a2a657..b7565a6 100644
--- a/src/pkg/crypto/dsa/dsa.go
+++ b/src/pkg/crypto/dsa/dsa.go
@@ -173,6 +173,16 @@ func GenerateKey(priv *PrivateKey, rand io.Reader) error {
 	return nil
 }
 
+// fermatInverse calculates the inverse of k in GF(P) using Fermat's method.
+// This has better constant-time properties than Euclid's method (implemented
+// in math/big.Int.ModInverse) although math/big itself isn't strictly
+// constant-time so it's not perfect.
+func fermatInverse(k, P *big.Int) *big.Int {
+	two := big.NewInt(2)
+	pMinus2 := new(big.Int).Sub(P, two)
+	return new(big.Int).Exp(k, pMinus2, P)
+}
+
 // Sign signs an arbitrary length hash (which should be the result of hashing a
 // larger message) using the private key, priv. It returns the signature as a
 // pair of integers. The security of the private key depends on the entropy of
@@ -205,7 +215,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
 			}
 		}
 
-		kInv := new(big.Int).ModInverse(k, priv.Q)
+		kInv := fermatInverse(k, priv.Q)
 
 		r = new(big.Int).Exp(priv.G, k, priv.P)
 		r.Mod(r, priv.Q)
diff --git a/src/pkg/crypto/ecdsa/ecdsa.go b/src/pkg/crypto/ecdsa/ecdsa.go
index d02f15c..1bec743 100644
--- a/src/pkg/crypto/ecdsa/ecdsa.go
+++ b/src/pkg/crypto/ecdsa/ecdsa.go
@@ -84,6 +84,16 @@ func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
 	return ret
 }
 
+// fermatInverse calculates the inverse of k in GF(P) using Fermat's method.
+// This has better constant-time properties than Euclid's method (implemented
+// in math/big.Int.ModInverse) although math/big itself isn't strictly
+// constant-time so it's not perfect.
+func fermatInverse(k, N *big.Int) *big.Int {
+	two := big.NewInt(2)
+	nMinus2 := new(big.Int).Sub(N, two)
+	return new(big.Int).Exp(k, nMinus2, N)
+}
+
 // Sign signs an arbitrary length hash (which should be the result of hashing a
 // larger message) using the private key, priv. It returns the signature as a
 // pair of integers. The security of the private key depends on the entropy of
@@ -102,7 +112,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
 				return
 			}
 
-			kInv = new(big.Int).ModInverse(k, N)
+			kInv = fermatInverse(k, N)
 			r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
 			r.Mod(r, N)
 			if r.Sign() != 0 {
diff --git a/src/pkg/crypto/hmac/hmac_test.go b/src/pkg/crypto/hmac/hmac_test.go
index d486042..e80b7e0 100644
--- a/src/pkg/crypto/hmac/hmac_test.go
+++ b/src/pkg/crypto/hmac/hmac_test.go
@@ -15,10 +15,12 @@ import (
 )
 
 type hmacTest struct {
-	hash func() hash.Hash
-	key  []byte
-	in   []byte
-	out  string
+	hash      func() hash.Hash
+	key       []byte
+	in        []byte
+	out       string
+	size      int
+	blocksize int
 }
 
 var hmacTests = []hmacTest{
@@ -38,6 +40,8 @@ var hmacTests = []hmacTest{
 		},
 		[]byte("Sample #1"),
 		"4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a",
+		sha1.Size,
+		sha1.BlockSize,
 	},
 	{
 		sha1.New,
@@ -48,6 +52,8 @@ var hmacTests = []hmacTest{
 		},
 		[]byte("Sample #2"),
 		"0922d3405faa3d194f82a45830737d5cc6c75d24",
+		sha1.Size,
+		sha1.BlockSize,
 	},
 	{
 		sha1.New,
@@ -68,6 +74,8 @@ var hmacTests = []hmacTest{
 		},
 		[]byte("Sample #3"),
 		"bcf41eab8bb2d802f3d05caf7cb092ecf8d1a3aa",
+		sha1.Size,
+		sha1.BlockSize,
 	},
 
 	// Test from Plan 9.
@@ -76,6 +84,8 @@ var hmacTests = []hmacTest{
 		[]byte("Jefe"),
 		[]byte("what do ya want for nothing?"),
 		"750c783e6ab0b503eaa86e310a5db738",
+		md5.Size,
+		md5.BlockSize,
 	},
 
 	// Tests from RFC 4231
@@ -88,12 +98,16 @@ var hmacTests = []hmacTest{
 		},
 		[]byte("Hi There"),
 		"b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7",
+		sha256.Size,
+		sha256.BlockSize,
 	},
 	{
 		sha256.New,
 		[]byte("Jefe"),
 		[]byte("what do ya want for nothing?"),
 		"5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843",
+		sha256.Size,
+		sha256.BlockSize,
 	},
 	{
 		sha256.New,
@@ -112,6 +126,8 @@ var hmacTests = []hmacTest{
 			0xdd, 0xdd,
 		},
 		"773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe",
+		sha256.Size,
+		sha256.BlockSize,
 	},
 	{
 		sha256.New,
@@ -131,6 +147,8 @@ var hmacTests = []hmacTest{
 			0xcd, 0xcd,
 		},
 		"82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b",
+		sha256.Size,
+		sha256.BlockSize,
 	},
 	{
 		sha256.New,
@@ -155,6 +173,8 @@ var hmacTests = []hmacTest{
 		},
 		[]byte("Test Using Larger Than Block-Size Key - Hash Key First"),
 		"60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54",
+		sha256.Size,
+		sha256.BlockSize,
 	},
 	{
 		sha256.New,
@@ -181,6 +201,8 @@ var hmacTests = []hmacTest{
 			"and a larger than block-size data. The key needs to " +
 			"be hashed before being used by the HMAC algorithm."),
 		"9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2",
+		sha256.Size,
+		sha256.BlockSize,
 	},
 
 	// Tests from http://csrc.nist.gov/groups/ST/toolkit/examples.html
@@ -199,6 +221,8 @@ var hmacTests = []hmacTest{
 		},
 		[]byte("Sample message for keylen=blocklen"),
 		"5fd596ee78d5553c8ff4e72d266dfd192366da29",
+		sha1.Size,
+		sha1.BlockSize,
 	},
 	{
 		sha1.New,
@@ -209,6 +233,8 @@ var hmacTests = []hmacTest{
 		},
 		[]byte("Sample message for keylen<blocklen"),
 		"4c99ff0cb1b31bd33f8431dbaf4d17fcd356a807",
+		sha1.Size,
+		sha1.BlockSize,
 	},
 	{
 		sha1.New,
@@ -229,6 +255,8 @@ var hmacTests = []hmacTest{
 		},
 		[]byte("Sample message for keylen=blocklen"),
 		"2d51b2f7750e410584662e38f133435f4c4fd42a",
+		sha1.Size,
+		sha1.BlockSize,
 	},
 	{
 		sha256.New224,
@@ -244,6 +272,8 @@ var hmacTests = []hmacTest{
 		},
 		[]byte("Sample message for keylen=blocklen"),
 		"c7405e3ae058e8cd30b08b4140248581ed174cb34e1224bcc1efc81b",
+		sha256.Size224,
+		sha256.BlockSize,
 	},
 	{
 		sha256.New224,
@@ -255,6 +285,8 @@ var hmacTests = []hmacTest{
 		},
 		[]byte("Sample message for keylen<blocklen"),
 		"e3d249a8cfb67ef8b7a169e9a0a599714a2cecba65999a51beb8fbbe",
+		sha256.Size224,
+		sha256.BlockSize,
 	},
 	{
 		sha256.New224,
@@ -275,6 +307,8 @@ var hmacTests = []hmacTest{
 		},
 		[]byte("Sample message for keylen=blocklen"),
 		"91c52509e5af8531601ae6230099d90bef88aaefb961f4080abc014d",
+		sha256.Size224,
+		sha256.BlockSize,
 	},
 	{
 		sha256.New,
@@ -290,6 +324,8 @@ var hmacTests = []hmacTest{
 		},
 		[]byte("Sample message for keylen=blocklen"),
 		"8bb9a1db9806f20df7f77b82138c7914d174d59e13dc4d0169c9057b133e1d62",
+		sha256.Size,
+		sha256.BlockSize,
 	},
 	{
 		sha256.New,
@@ -301,6 +337,8 @@ var hmacTests = []hmacTest{
 		},
 		[]byte("Sample message for keylen<blocklen"),
 		"a28cf43130ee696a98f14a37678b56bcfcbdd9e5cf69717fecf5480f0ebdf790",
+		sha256.Size,
+		sha256.BlockSize,
 	},
 	{
 		sha256.New,
@@ -321,6 +359,8 @@ var hmacTests = []hmacTest{
 		},
 		[]byte("Sample message for keylen=blocklen"),
 		"bdccb6c72ddeadb500ae768386cb38cc41c63dbb0878ddb9c7a38a431b78378d",
+		sha256.Size,
+		sha256.BlockSize,
 	},
 	{
 		sha512.New384,
@@ -344,6 +384,8 @@ var hmacTests = []hmacTest{
 		},
 		[]byte("Sample message for keylen=blocklen"),
 		"63c5daa5e651847ca897c95814ab830bededc7d25e83eef9195cd45857a37f448947858f5af50cc2b1b730ddf29671a9",
+		sha512.Size384,
+		sha512.BlockSize,
 	},
 	{
 		sha512.New384,
@@ -357,6 +399,8 @@ var hmacTests = []hmacTest{
 		},
 		[]byte("Sample message for keylen<blocklen"),
 		"6eb242bdbb582ca17bebfa481b1e23211464d2b7f8c20b9ff2201637b93646af5ae9ac316e98db45d9cae773675eeed0",
+		sha512.Size384,
+		sha512.BlockSize,
 	},
 	{
 		sha512.New384,
@@ -389,6 +433,8 @@ var hmacTests = []hmacTest{
 		},
 		[]byte("Sample message for keylen=blocklen"),
 		"5b664436df69b0ca22551231a3f0a3d5b4f97991713cfa84bff4d0792eff96c27dccbbb6f79b65d548b40e8564cef594",
+		sha512.Size384,
+		sha512.BlockSize,
 	},
 	{
 		sha512.New,
@@ -414,6 +460,8 @@ var hmacTests = []hmacTest{
 		"fc25e240658ca785b7a811a8d3f7b4ca" +
 			"48cfa26a8a366bf2cd1f836b05fcb024bd36853081811d6c" +
 			"ea4216ebad79da1cfcb95ea4586b8a0ce356596a55fb1347",
+		sha512.Size,
+		sha512.BlockSize,
 	},
 	{
 		sha512.New,
@@ -431,6 +479,8 @@ var hmacTests = []hmacTest{
 		"fd44c18bda0bb0a6ce0e82b031bf2818" +
 			"f6539bd56ec00bdc10a8a2d730b3634de2545d639b0f2cf7" +
 			"10d0692c72a1896f1f211c2b922d1a96c392e07e7ea9fedc",
+		sha512.Size,
+		sha512.BlockSize,
 	},
 	{
 		sha512.New,
@@ -465,12 +515,20 @@ var hmacTests = []hmacTest{
 		"d93ec8d2de1ad2a9957cb9b83f14e76a" +
 			"d6b5e0cce285079a127d3b14bccb7aa7286d4ac0d4ce6421" +
 			"5f2bc9e6870b33d97438be4aaa20cda5c5a912b48b8e27f3",
+		sha512.Size,
+		sha512.BlockSize,
 	},
 }
 
 func TestHMAC(t *testing.T) {
 	for i, tt := range hmacTests {
 		h := New(tt.hash, tt.key)
+		if s := h.Size(); s != tt.size {
+			t.Errorf("Size: got %v, want %v", s, tt.size)
+		}
+		if b := h.BlockSize(); b != tt.blocksize {
+			t.Errorf("BlockSize: got %v, want %v", b, tt.blocksize)
+		}
 		for j := 0; j < 2; j++ {
 			n, err := h.Write(tt.in)
 			if n != len(tt.in) || err != nil {
diff --git a/src/pkg/crypto/md5/example_test.go b/src/pkg/crypto/md5/example_test.go
index 28be770..d47bb45 100644
--- a/src/pkg/crypto/md5/example_test.go
+++ b/src/pkg/crypto/md5/example_test.go
@@ -17,3 +17,9 @@ func ExampleNew() {
 	fmt.Printf("%x", h.Sum(nil))
 	// Output: e2c569be17396eca2a2e3c11578123ed
 }
+
+func ExampleSum() {
+	data := []byte("These pretzels are making me thirsty.")
+	fmt.Printf("%x", md5.Sum(data))
+	// Output: b0804ec967f48520697662a204f5fe72
+}
diff --git a/src/pkg/crypto/md5/gen.go b/src/pkg/crypto/md5/gen.go
index ccaa7c1..75295e4 100644
--- a/src/pkg/crypto/md5/gen.go
+++ b/src/pkg/crypto/md5/gen.go
@@ -160,12 +160,13 @@ var data = Data{
 	},
 }
 
-var program = `
+var program = `// 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.
+
 // DO NOT EDIT.
 // Generate with: go run gen.go{{if .Full}} -full{{end}} | gofmt >md5block.go
 
-// +build !amd64,!386,!arm
-
 package md5
 
 import (
@@ -201,7 +202,7 @@ func init() {
 	littleEndian = *(*[4]byte)(unsafe.Pointer(&x)) == y
 }
 
-func block(dig *digest, p []byte) {
+func blockGeneric(dig *digest, p []byte) {
 	a := dig.s[0]
 	b := dig.s[1]
 	c := dig.s[2]
diff --git a/src/pkg/crypto/md5/md5_test.go b/src/pkg/crypto/md5/md5_test.go
index a8b7a1a..e7faf49 100644
--- a/src/pkg/crypto/md5/md5_test.go
+++ b/src/pkg/crypto/md5/md5_test.go
@@ -5,6 +5,7 @@
 package md5
 
 import (
+	"crypto/rand"
 	"fmt"
 	"io"
 	"testing"
@@ -105,6 +106,18 @@ func TestLarge(t *testing.T) {
 	}
 }
 
+// Tests that blockGeneric (pure Go) and block (in assembly for amd64, 386, arm) match.
+func TestBlockGeneric(t *testing.T) {
+	gen, asm := New().(*digest), New().(*digest)
+	buf := make([]byte, BlockSize*20) // arbitrary factor
+	rand.Read(buf)
+	blockGeneric(gen, buf)
+	block(asm, buf)
+	if *gen != *asm {
+		t.Error("block and blockGeneric resulted in different states")
+	}
+}
+
 var bench = New()
 var buf = make([]byte, 8192+1)
 var sum = make([]byte, bench.Size())
diff --git a/src/pkg/crypto/md5/md5block.go b/src/pkg/crypto/md5/md5block.go
index 3e739e3..e2a1767 100644
--- a/src/pkg/crypto/md5/md5block.go
+++ b/src/pkg/crypto/md5/md5block.go
@@ -1,8 +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.
+
 // DO NOT EDIT.
 // Generate with: go run gen.go -full | gofmt >md5block.go
 
-// +build !amd64,!386,!arm
-
 package md5
 
 import (
@@ -20,7 +22,7 @@ func init() {
 	littleEndian = *(*[4]byte)(unsafe.Pointer(&x)) == y
 }
 
-func block(dig *digest, p []byte) {
+func blockGeneric(dig *digest, p []byte) {
 	a := dig.s[0]
 	b := dig.s[1]
 	c := dig.s[2]
diff --git a/src/pkg/crypto/md5/md5block_amd64p32.s b/src/pkg/crypto/md5/md5block_amd64p32.s
new file mode 100644
index 0000000..a78a3f6
--- /dev/null
+++ b/src/pkg/crypto/md5/md5block_amd64p32.s
@@ -0,0 +1,184 @@
+// Original source:
+//	http://www.zorinaq.com/papers/md5-amd64.html
+//	http://www.zorinaq.com/papers/md5-amd64.tar.bz2
+//
+// Translated from Perl generating GNU assembly into
+// #defines generating 6a assembly by the Go Authors.
+//
+// Restrictions to make code safe for Native Client:
+// replace BP with R11, reloaded before use at return.
+// replace R15 with R11.
+
+#include "../../../cmd/ld/textflag.h"
+
+// MD5 optimized for AMD64.
+//
+// Author: Marc Bevand <bevand_m (at) epita.fr>
+// Licence: I hereby disclaim the copyright on this code and place it
+// in the public domain.
+
+TEXT	·block(SB),NOSPLIT,$0-32
+	MOVL	dig+0(FP),	R11
+	MOVL	p+4(FP),	SI
+	MOVL	p_len+8(FP), DX
+	SHRQ	$6,		DX
+	SHLQ	$6,		DX
+
+	LEAQ	(SI)(DX*1),	DI
+	MOVL	(0*4)(R11),	AX
+	MOVL	(1*4)(R11),	BX
+	MOVL	(2*4)(R11),	CX
+	MOVL	(3*4)(R11),	DX
+
+	CMPQ	SI,		DI
+	JEQ	end
+
+loop:
+	MOVL	AX,		R12
+	MOVL	BX,		R13
+	MOVL	CX,		R14
+	MOVL	DX,		R11
+
+	MOVL	(0*4)(SI),	R8
+	MOVL	DX,		R9
+
+#define ROUND1(a, b, c, d, index, const, shift) \
+	XORL	c, R9; \
+	LEAL	const(a)(R8*1), a; \
+	ANDL	b, R9; \
+	XORL d, R9; \
+	MOVL (index*4)(SI), R8; \
+	ADDL R9, a; \
+	ROLL $shift, a; \
+	MOVL c, R9; \
+	ADDL b, a
+
+	ROUND1(AX,BX,CX,DX, 1,0xd76aa478, 7);
+	ROUND1(DX,AX,BX,CX, 2,0xe8c7b756,12);
+	ROUND1(CX,DX,AX,BX, 3,0x242070db,17);
+	ROUND1(BX,CX,DX,AX, 4,0xc1bdceee,22);
+	ROUND1(AX,BX,CX,DX, 5,0xf57c0faf, 7);
+	ROUND1(DX,AX,BX,CX, 6,0x4787c62a,12);
+	ROUND1(CX,DX,AX,BX, 7,0xa8304613,17);
+	ROUND1(BX,CX,DX,AX, 8,0xfd469501,22);
+	ROUND1(AX,BX,CX,DX, 9,0x698098d8, 7);
+	ROUND1(DX,AX,BX,CX,10,0x8b44f7af,12);
+	ROUND1(CX,DX,AX,BX,11,0xffff5bb1,17);
+	ROUND1(BX,CX,DX,AX,12,0x895cd7be,22);
+	ROUND1(AX,BX,CX,DX,13,0x6b901122, 7);
+	ROUND1(DX,AX,BX,CX,14,0xfd987193,12);
+	ROUND1(CX,DX,AX,BX,15,0xa679438e,17);
+	ROUND1(BX,CX,DX,AX, 0,0x49b40821,22);
+
+	MOVL	(1*4)(SI),	R8
+	MOVL	DX,		R9
+	MOVL	DX,		R10
+
+#define ROUND2(a, b, c, d, index, const, shift) \
+	NOTL	R9; \
+	LEAL	const(a)(R8*1),a; \
+	ANDL	b,		R10; \
+	ANDL	c,		R9; \
+	MOVL	(index*4)(SI),R8; \
+	ORL	R9,		R10; \
+	MOVL	c,		R9; \
+	ADDL	R10,		a; \
+	MOVL	c,		R10; \
+	ROLL	$shift,	a; \
+	ADDL	b,		a
+
+	ROUND2(AX,BX,CX,DX, 6,0xf61e2562, 5);
+	ROUND2(DX,AX,BX,CX,11,0xc040b340, 9);
+	ROUND2(CX,DX,AX,BX, 0,0x265e5a51,14);
+	ROUND2(BX,CX,DX,AX, 5,0xe9b6c7aa,20);
+	ROUND2(AX,BX,CX,DX,10,0xd62f105d, 5);
+	ROUND2(DX,AX,BX,CX,15, 0x2441453, 9);
+	ROUND2(CX,DX,AX,BX, 4,0xd8a1e681,14);
+	ROUND2(BX,CX,DX,AX, 9,0xe7d3fbc8,20);
+	ROUND2(AX,BX,CX,DX,14,0x21e1cde6, 5);
+	ROUND2(DX,AX,BX,CX, 3,0xc33707d6, 9);
+	ROUND2(CX,DX,AX,BX, 8,0xf4d50d87,14);
+	ROUND2(BX,CX,DX,AX,13,0x455a14ed,20);
+	ROUND2(AX,BX,CX,DX, 2,0xa9e3e905, 5);
+	ROUND2(DX,AX,BX,CX, 7,0xfcefa3f8, 9);
+	ROUND2(CX,DX,AX,BX,12,0x676f02d9,14);
+	ROUND2(BX,CX,DX,AX, 0,0x8d2a4c8a,20);
+ 
+	MOVL	(5*4)(SI),	R8
+	MOVL	CX,		R9
+
+#define ROUND3(a, b, c, d, index, const, shift) \
+	LEAL	const(a)(R8*1),a; \
+	MOVL	(index*4)(SI),R8; \
+	XORL	d,		R9; \
+	XORL	b,		R9; \
+	ADDL	R9,		a; \
+	ROLL	$shift,		a; \
+	MOVL	b,		R9; \
+	ADDL	b,		a
+
+	ROUND3(AX,BX,CX,DX, 8,0xfffa3942, 4);
+	ROUND3(DX,AX,BX,CX,11,0x8771f681,11);
+	ROUND3(CX,DX,AX,BX,14,0x6d9d6122,16);
+	ROUND3(BX,CX,DX,AX, 1,0xfde5380c,23);
+	ROUND3(AX,BX,CX,DX, 4,0xa4beea44, 4);
+	ROUND3(DX,AX,BX,CX, 7,0x4bdecfa9,11);
+	ROUND3(CX,DX,AX,BX,10,0xf6bb4b60,16);
+	ROUND3(BX,CX,DX,AX,13,0xbebfbc70,23);
+	ROUND3(AX,BX,CX,DX, 0,0x289b7ec6, 4);
+	ROUND3(DX,AX,BX,CX, 3,0xeaa127fa,11);
+	ROUND3(CX,DX,AX,BX, 6,0xd4ef3085,16);
+	ROUND3(BX,CX,DX,AX, 9, 0x4881d05,23);
+	ROUND3(AX,BX,CX,DX,12,0xd9d4d039, 4);
+	ROUND3(DX,AX,BX,CX,15,0xe6db99e5,11);
+	ROUND3(CX,DX,AX,BX, 2,0x1fa27cf8,16);
+	ROUND3(BX,CX,DX,AX, 0,0xc4ac5665,23);
+
+	MOVL	(0*4)(SI),	R8
+	MOVL	$0xffffffff,	R9
+	XORL	DX,		R9
+
+#define ROUND4(a, b, c, d, index, const, shift) \
+	LEAL	const(a)(R8*1),a; \
+	ORL	b,		R9; \
+	XORL	c,		R9; \
+	ADDL	R9,		a; \
+	MOVL	(index*4)(SI),R8; \
+	MOVL	$0xffffffff,	R9; \
+	ROLL	$shift,		a; \
+	XORL	c,		R9; \
+	ADDL	b,		a
+	
+	ROUND4(AX,BX,CX,DX, 7,0xf4292244, 6);
+	ROUND4(DX,AX,BX,CX,14,0x432aff97,10);
+	ROUND4(CX,DX,AX,BX, 5,0xab9423a7,15);
+	ROUND4(BX,CX,DX,AX,12,0xfc93a039,21);
+	ROUND4(AX,BX,CX,DX, 3,0x655b59c3, 6);
+	ROUND4(DX,AX,BX,CX,10,0x8f0ccc92,10);
+	ROUND4(CX,DX,AX,BX, 1,0xffeff47d,15);
+	ROUND4(BX,CX,DX,AX, 8,0x85845dd1,21);
+	ROUND4(AX,BX,CX,DX,15,0x6fa87e4f, 6);
+	ROUND4(DX,AX,BX,CX, 6,0xfe2ce6e0,10);
+	ROUND4(CX,DX,AX,BX,13,0xa3014314,15);
+	ROUND4(BX,CX,DX,AX, 4,0x4e0811a1,21);
+	ROUND4(AX,BX,CX,DX,11,0xf7537e82, 6);
+	ROUND4(DX,AX,BX,CX, 2,0xbd3af235,10);
+	ROUND4(CX,DX,AX,BX, 9,0x2ad7d2bb,15);
+	ROUND4(BX,CX,DX,AX, 0,0xeb86d391,21);
+
+	ADDL	R12,	AX
+	ADDL	R13,	BX
+	ADDL	R14,	CX
+	ADDL	R11,	DX
+
+	ADDQ	$64,		SI
+	CMPQ	SI,		DI
+	JB	loop
+
+end:
+	MOVL	dig+0(FP),	R11
+	MOVL	AX,		(0*4)(R11)
+	MOVL	BX,		(1*4)(R11)
+	MOVL	CX,		(2*4)(R11)
+	MOVL	DX,		(3*4)(R11)
+	RET
diff --git a/src/pkg/crypto/md5/md5block_decl.go b/src/pkg/crypto/md5/md5block_decl.go
index c4d6aaa..d7956a6 100644
--- a/src/pkg/crypto/md5/md5block_decl.go
+++ b/src/pkg/crypto/md5/md5block_decl.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 amd64 386 arm
+// +build amd64 amd64p32 386 arm
 
 package md5
 
diff --git a/src/pkg/crypto/md5/md5block_generic.go b/src/pkg/crypto/md5/md5block_generic.go
new file mode 100644
index 0000000..263463e
--- /dev/null
+++ b/src/pkg/crypto/md5/md5block_generic.go
@@ -0,0 +1,9 @@
+// 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 !amd64,!amd64p32,!386,!arm
+
+package md5
+
+var block = blockGeneric
diff --git a/src/pkg/crypto/rand/rand_unix.go b/src/pkg/crypto/rand/rand_unix.go
index 238ceee..1e741fd 100644
--- a/src/pkg/crypto/rand/rand_unix.go
+++ b/src/pkg/crypto/rand/rand_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 plan9
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris
 
 // Unix cryptographically secure pseudorandom number
 // generator.
diff --git a/src/pkg/crypto/rand/util.go b/src/pkg/crypto/rand/util.go
index 0cd5e0e..5f74407 100644
--- a/src/pkg/crypto/rand/util.go
+++ b/src/pkg/crypto/rand/util.go
@@ -27,9 +27,11 @@ var smallPrimesProduct = new(big.Int).SetUint64(16294579238595022365)
 
 // Prime returns a number, p, of the given size, such that p is prime
 // with high probability.
+// Prime will return error for any error returned by rand.Read or if bits < 2.
 func Prime(rand io.Reader, bits int) (p *big.Int, err error) {
-	if bits < 1 {
-		err = errors.New("crypto/rand: prime size must be positive")
+	if bits < 2 {
+		err = errors.New("crypto/rand: prime size must be at least 2-bit")
+		return
 	}
 
 	b := uint(bits % 8)
@@ -79,7 +81,7 @@ func Prime(rand io.Reader, bits int) (p *big.Int, err error) {
 		for delta := uint64(0); delta < 1<<20; delta += 2 {
 			m := mod + delta
 			for _, prime := range smallPrimes {
-				if m%uint64(prime) == 0 {
+				if m%uint64(prime) == 0 && (bits > 6 || m != uint64(prime)) {
 					continue NextDelta
 				}
 			}
diff --git a/src/pkg/crypto/rand/util_test.go b/src/pkg/crypto/rand/util_test.go
new file mode 100644
index 0000000..1e2a4dd
--- /dev/null
+++ b/src/pkg/crypto/rand/util_test.go
@@ -0,0 +1,65 @@
+// 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 rand_test
+
+import (
+	"crypto/rand"
+	"math/big"
+	"testing"
+)
+
+// http://golang.org/issue/6849.
+func TestPrimeSmall(t *testing.T) {
+	for n := 2; n < 10; n++ {
+		p, err := rand.Prime(rand.Reader, n)
+		if err != nil {
+			t.Fatalf("Can't generate %d-bit prime: %v", n, err)
+		}
+		if p.BitLen() != n {
+			t.Fatalf("%v is not %d-bit", p, n)
+		}
+		if !p.ProbablyPrime(32) {
+			t.Fatalf("%v is not prime", p)
+		}
+	}
+}
+
+// Test that passing bits < 2 causes Prime to return nil, error
+func TestPrimeBitsLt2(t *testing.T) {
+	if p, err := rand.Prime(rand.Reader, 1); p != nil || err == nil {
+		t.Errorf("Prime should return nil, error when called with bits < 2")
+	}
+}
+
+func TestInt(t *testing.T) {
+	// start at 128 so the case of (max.BitLen() % 8) == 0 is covered
+	for n := 128; n < 140; n++ {
+		b := new(big.Int).SetInt64(int64(n))
+		if i, err := rand.Int(rand.Reader, b); err != nil {
+			t.Fatalf("Can't generate random value: %v, %v", i, err)
+		}
+	}
+}
+
+func testIntPanics(t *testing.T, b *big.Int) {
+	defer func() {
+		if err := recover(); err == nil {
+			t.Errorf("Int should panic when called with max <= 0: %v", b)
+		}
+	}()
+	rand.Int(rand.Reader, b)
+}
+
+// Test that passing a new big.Int as max causes Int to panic
+func TestIntEmptyMaxPanics(t *testing.T) {
+	b := new(big.Int)
+	testIntPanics(t, b)
+}
+
+// Test that passing a negative value as max causes Int to panic
+func TestIntNegativeMaxPanics(t *testing.T) {
+	b := new(big.Int).SetInt64(int64(-1))
+	testIntPanics(t, b)
+}
diff --git a/src/pkg/crypto/rc4/rc4.go b/src/pkg/crypto/rc4/rc4.go
index 3d717c6..9acb681 100644
--- a/src/pkg/crypto/rc4/rc4.go
+++ b/src/pkg/crypto/rc4/rc4.go
@@ -50,3 +50,20 @@ func (c *Cipher) Reset() {
 	}
 	c.i, c.j = 0, 0
 }
+
+// xorKeyStreamGeneric sets dst to the result of XORing src with the
+// key stream.  Dst and src may be the same slice but otherwise should
+// not overlap.
+//
+// This is the pure Go version. rc4_{amd64,386,arm}* contain assembly
+// implementations. This is here for tests and to prevent bitrot.
+func (c *Cipher) xorKeyStreamGeneric(dst, src []byte) {
+	i, j := c.i, c.j
+	for k, v := range src {
+		i += 1
+		j += uint8(c.s[i])
+		c.s[i], c.s[j] = c.s[j], c.s[i]
+		dst[k] = v ^ uint8(c.s[uint8(c.s[i]+c.s[j])])
+	}
+	c.i, c.j = i, j
+}
diff --git a/src/pkg/crypto/rc4/rc4_amd64p32.s b/src/pkg/crypto/rc4/rc4_amd64p32.s
new file mode 100644
index 0000000..27d8495
--- /dev/null
+++ b/src/pkg/crypto/rc4/rc4_amd64p32.s
@@ -0,0 +1,192 @@
+// Original source:
+//	http://www.zorinaq.com/papers/rc4-amd64.html
+//	http://www.zorinaq.com/papers/rc4-amd64.tar.bz2
+
+#include "../../../cmd/ld/textflag.h"
+
+// Local modifications:
+//
+// Transliterated from GNU to 6a assembly syntax by the Go authors.
+// The comments and spacing are from the original.
+//
+// The new EXTEND macros avoid a bad stall on some systems after 8-bit math.
+//
+// The original code accumulated 64 bits of key stream in an integer
+// register and then XOR'ed the key stream into the data 8 bytes at a time.
+// Modified to accumulate 128 bits of key stream into an XMM register
+// and then XOR the key stream into the data 16 bytes at a time.
+// Approximately doubles throughput.
+//
+// Converted to amd64p32.
+//
+// To make safe for Native Client, avoid use of BP, R15,
+// and two-register addressing modes.
+
+// NOTE: Changing EXTEND to a no-op makes the code run 1.2x faster on Core i5
+// but makes the code run 2.0x slower on Xeon.
+#define EXTEND(r) MOVBLZX r, r
+
+/*
+** RC4 implementation optimized for AMD64.
+**
+** Author: Marc Bevand <bevand_m (at) epita.fr>
+** Licence: I hereby disclaim the copyright on this code and place it
+** in the public domain.
+**
+** The code has been designed to be easily integrated into openssl:
+** the exported RC4() function can replace the actual implementations
+** openssl already contains. Please note that when linking with openssl,
+** it requires that sizeof(RC4_INT) == 8. So openssl must be compiled
+** with -DRC4_INT='unsigned long'.
+**
+** The throughput achieved by this code is about 320 MBytes/sec, on
+** a 1.8 GHz AMD Opteron (rev C0) processor.
+*/
+
+TEXT ·xorKeyStream(SB),NOSPLIT,$0
+	MOVL	n+8(FP),	BX		// rbx = ARG(len)
+	MOVL	src+4(FP),	SI		// in = ARG(in)
+	MOVL	dst+0(FP),	DI		// out = ARG(out)
+	MOVL	state+12(FP),	R10		// d = ARG(data)
+	MOVL	i+16(FP),	AX
+	MOVBQZX	0(AX),		CX		// x = *xp
+	MOVL	j+20(FP),	AX
+	MOVBQZX	0(AX),		DX		// y = *yp
+
+	LEAQ	(SI)(BX*1),	R9		// limit = in+len
+
+l1:	CMPQ	SI,		R9		// cmp in with in+len
+	JGE	finished			// jump if (in >= in+len)
+
+	INCB	CX
+	EXTEND(CX)
+	TESTL	$15,		CX
+	JZ	wordloop
+	LEAL	(R10)(CX*4), R12
+
+	MOVBLZX	(R12),	AX
+
+	ADDB	AX,		DX		// y += tx
+	EXTEND(DX)
+	LEAL (R10)(DX*4), R11
+	MOVBLZX	(R11),	BX		// ty = d[y]
+	MOVB	BX,		(R12)	// d[x] = ty
+	ADDB	AX,		BX		// val = ty+tx
+	EXTEND(BX)
+	LEAL (R10)(BX*4), R13
+	MOVB	AX,		(R11)	// d[y] = tx
+	MOVBLZX	(R13),	R8		// val = d[val]
+	XORB	(SI),		R8		// xor 1 byte
+	MOVB	R8,		(DI)
+	INCQ	SI				// in++
+	INCQ	DI				// out++
+	JMP l1
+
+wordloop:
+	SUBQ	$16,		R9
+	CMPQ	SI,		R9
+	JGT	end
+
+start:
+	ADDQ	$16,		SI		// increment in
+	ADDQ	$16,		DI		// increment out
+
+	// Each KEYROUND generates one byte of key and
+	// inserts it into an XMM register at the given 16-bit index.
+	// The key state array is uint32 words only using the bottom
+	// byte of each word, so the 16-bit OR only copies 8 useful bits.
+	// We accumulate alternating bytes into X0 and X1, and then at
+	// the end we OR X1<<8 into X0 to produce the actual key.
+	//
+	// At the beginning of the loop, CX%16 == 0, so the 16 loads
+	// at state[CX], state[CX+1], ..., state[CX+15] can precompute
+	// (state+CX) as R12 and then become R12[0], R12[1], ... R12[15],
+	// without fear of the byte computation CX+15 wrapping around.
+	//
+	// The first round needs R12[0], the second needs R12[1], and so on.
+	// We can avoid memory stalls by starting the load for round n+1
+	// before the end of round n, using the LOAD macro.
+	LEAQ	(R10)(CX*4),	R12
+
+#define KEYROUND(xmm, load, off, r1, r2, index) \
+	LEAL (R10)(DX*4), R11; \
+	MOVBLZX	(R11),	R8; \
+	MOVB	r1,		(R11); \
+	load((off+1), r2); \
+	MOVB	R8,		(off*4)(R12); \
+	ADDB	r1,		R8; \
+	EXTEND(R8); \
+	LEAL (R10)(R8*4), R14; \
+	PINSRW	$index, (R14), xmm
+
+#define LOAD(off, reg) \
+	MOVBLZX	(off*4)(R12),	reg; \
+	ADDB	reg,		DX; \
+	EXTEND(DX)
+
+#define SKIP(off, reg)
+
+	LOAD(0, AX)
+	KEYROUND(X0, LOAD, 0, AX, BX, 0)
+	KEYROUND(X1, LOAD, 1, BX, AX, 0)
+	KEYROUND(X0, LOAD, 2, AX, BX, 1)
+	KEYROUND(X1, LOAD, 3, BX, AX, 1)
+	KEYROUND(X0, LOAD, 4, AX, BX, 2)
+	KEYROUND(X1, LOAD, 5, BX, AX, 2)
+	KEYROUND(X0, LOAD, 6, AX, BX, 3)
+	KEYROUND(X1, LOAD, 7, BX, AX, 3)
+	KEYROUND(X0, LOAD, 8, AX, BX, 4)
+	KEYROUND(X1, LOAD, 9, BX, AX, 4)
+	KEYROUND(X0, LOAD, 10, AX, BX, 5)
+	KEYROUND(X1, LOAD, 11, BX, AX, 5)
+	KEYROUND(X0, LOAD, 12, AX, BX, 6)
+	KEYROUND(X1, LOAD, 13, BX, AX, 6)
+	KEYROUND(X0, LOAD, 14, AX, BX, 7)
+	KEYROUND(X1, SKIP, 15, BX, AX, 7)
+	
+	ADDB	$16,		CX
+
+	PSLLQ	$8,		X1
+	PXOR	X1,		X0
+	MOVOU	-16(SI),	X2
+	PXOR	X0,		X2
+	MOVOU	X2,		-16(DI)
+
+	CMPQ	SI,		R9		// cmp in with in+len-16
+	JLE	start				// jump if (in <= in+len-16)
+
+end:
+	DECB	CX
+	ADDQ	$16,		R9		// tmp = in+len
+
+	// handle the last bytes, one by one
+l2:	CMPQ	SI,		R9		// cmp in with in+len
+	JGE	finished			// jump if (in >= in+len)
+
+	INCB	CX
+	EXTEND(CX)
+	LEAL (R10)(CX*4), R12
+	MOVBLZX	(R12),	AX
+
+	ADDB	AX,		DX		// y += tx
+	EXTEND(DX)
+	LEAL (R10)(DX*4), R11
+	MOVBLZX	(R11),	BX		// ty = d[y]
+	MOVB	BX,		(R12)	// d[x] = ty
+	ADDB	AX,		BX		// val = ty+tx
+	EXTEND(BX)
+	LEAL (R10)(BX*4), R13
+	MOVB	AX,		(R11)	// d[y] = tx
+	MOVBLZX	(R13),	R8		// val = d[val]
+	XORB	(SI),		R8		// xor 1 byte
+	MOVB	R8,		(DI)
+	INCQ	SI				// in++
+	INCQ	DI				// out++
+	JMP l2
+
+finished:
+	MOVL	j+20(FP),	BX
+	MOVB	DX, 0(BX)
+	MOVL	i+16(FP),	AX
+	MOVB	CX, 0(AX)
+	RET
diff --git a/src/pkg/crypto/rc4/rc4_asm.go b/src/pkg/crypto/rc4/rc4_asm.go
index c582a44..fc71b9a 100644
--- a/src/pkg/crypto/rc4/rc4_asm.go
+++ b/src/pkg/crypto/rc4/rc4_asm.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 amd64 arm 386
+// +build amd64 amd64p32 arm 386
 
 package rc4
 
diff --git a/src/pkg/crypto/rc4/rc4_ref.go b/src/pkg/crypto/rc4/rc4_ref.go
index 44d3804..1ecce1a 100644
--- a/src/pkg/crypto/rc4/rc4_ref.go
+++ b/src/pkg/crypto/rc4/rc4_ref.go
@@ -2,19 +2,12 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !amd64,!arm,!386
+// +build !amd64,!amd64p32,!arm,!386
 
 package rc4
 
 // XORKeyStream sets dst to the result of XORing src with the key stream.
 // Dst and src may be the same slice but otherwise should not overlap.
 func (c *Cipher) XORKeyStream(dst, src []byte) {
-	i, j := c.i, c.j
-	for k, v := range src {
-		i += 1
-		j += c.s[i]
-		c.s[i], c.s[j] = c.s[j], c.s[i]
-		dst[k] = v ^ c.s[c.s[i]+c.s[j]]
-	}
-	c.i, c.j = i, j
+	c.xorKeyStreamGeneric(dst, src)
 }
diff --git a/src/pkg/crypto/rc4/rc4_test.go b/src/pkg/crypto/rc4/rc4_test.go
index 7b4df67..af79882 100644
--- a/src/pkg/crypto/rc4/rc4_test.go
+++ b/src/pkg/crypto/rc4/rc4_test.go
@@ -117,19 +117,30 @@ func TestGolden(t *testing.T) {
 }
 
 func TestBlock(t *testing.T) {
+	testBlock(t, (*Cipher).XORKeyStream)
+}
+
+// Test the pure Go version.
+// Because we have assembly for amd64, 386, and arm, this prevents
+// bitrot of the reference implementations.
+func TestBlockGeneric(t *testing.T) {
+	testBlock(t, (*Cipher).xorKeyStreamGeneric)
+}
+
+func testBlock(t *testing.T, xor func(c *Cipher, dst, src []byte)) {
 	c1a, _ := NewCipher(golden[0].key)
 	c1b, _ := NewCipher(golden[1].key)
 	data1 := make([]byte, 1<<20)
 	for i := range data1 {
-		c1a.XORKeyStream(data1[i:i+1], data1[i:i+1])
-		c1b.XORKeyStream(data1[i:i+1], data1[i:i+1])
+		xor(c1a, data1[i:i+1], data1[i:i+1])
+		xor(c1b, data1[i:i+1], data1[i:i+1])
 	}
 
 	c2a, _ := NewCipher(golden[0].key)
 	c2b, _ := NewCipher(golden[1].key)
 	data2 := make([]byte, 1<<20)
-	c2a.XORKeyStream(data2, data2)
-	c2b.XORKeyStream(data2, data2)
+	xor(c2a, data2, data2)
+	xor(c2b, data2, data2)
 
 	if !bytes.Equal(data1, data2) {
 		t.Fatalf("bad block")
diff --git a/src/pkg/crypto/rsa/pkcs1v15.go b/src/pkg/crypto/rsa/pkcs1v15.go
index 1a055a3..d9957ae 100644
--- a/src/pkg/crypto/rsa/pkcs1v15.go
+++ b/src/pkg/crypto/rsa/pkcs1v15.go
@@ -176,7 +176,8 @@ var hashPrefixes = map[crypto.Hash][]byte{
 
 // SignPKCS1v15 calculates the signature of hashed using RSASSA-PKCS1-V1_5-SIGN from RSA PKCS#1 v1.5.
 // Note that hashed must be the result of hashing the input message using the
-// given hash function.
+// given hash function. If hash is zero, hashed is signed directly. This isn't
+// advisable except for interoperability.
 func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) (s []byte, err error) {
 	hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
 	if err != nil {
@@ -212,7 +213,8 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b
 // VerifyPKCS1v15 verifies an RSA PKCS#1 v1.5 signature.
 // hashed is the result of hashing the input message using the given hash
 // function and sig is the signature. A valid signature is indicated by
-// returning a nil error.
+// returning a nil error. If hash is zero then hashed is used directly. This
+// isn't advisable except for interoperability.
 func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (err error) {
 	hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
 	if err != nil {
@@ -249,6 +251,12 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte)
 }
 
 func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err error) {
+	// Special case: crypto.Hash(0) is used to indicate that the data is
+	// signed directly.
+	if hash == 0 {
+		return inLen, nil, nil
+	}
+
 	hashLen = hash.Size()
 	if inLen != hashLen {
 		return 0, nil, errors.New("crypto/rsa: input must be hashed message")
diff --git a/src/pkg/crypto/rsa/pkcs1v15_test.go b/src/pkg/crypto/rsa/pkcs1v15_test.go
index 70bb228..37c14d1 100644
--- a/src/pkg/crypto/rsa/pkcs1v15_test.go
+++ b/src/pkg/crypto/rsa/pkcs1v15_test.go
@@ -205,6 +205,28 @@ func TestOverlongMessagePKCS1v15(t *testing.T) {
 	}
 }
 
+func TestUnpaddedSignature(t *testing.T) {
+	msg := []byte("Thu Dec 19 18:06:16 EST 2013\n")
+	// This base64 value was generated with:
+	// % echo Thu Dec 19 18:06:16 EST 2013 > /tmp/msg
+	// % openssl rsautl -sign -inkey key -out /tmp/sig -in /tmp/msg
+	//
+	// Where "key" contains the RSA private key given at the bottom of this
+	// file.
+	expectedSig := decodeBase64("pX4DR8azytjdQ1rtUiC040FjkepuQut5q2ZFX1pTjBrOVKNjgsCDyiJDGZTCNoh9qpXYbhl7iEym30BWWwuiZg==")
+
+	sig, err := SignPKCS1v15(nil, rsaPrivateKey, crypto.Hash(0), msg)
+	if err != nil {
+		t.Fatalf("SignPKCS1v15 failed: %s", err)
+	}
+	if !bytes.Equal(sig, expectedSig) {
+		t.Fatalf("signature is not expected value: got %x, want %x", sig, expectedSig)
+	}
+	if err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.Hash(0), msg, sig); err != nil {
+		t.Fatalf("signature failed to verify: %s", err)
+	}
+}
+
 // In order to generate new test vectors you'll need the PEM form of this key:
 // -----BEGIN RSA PRIVATE KEY-----
 // MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
diff --git a/src/pkg/crypto/rsa/pss.go b/src/pkg/crypto/rsa/pss.go
index f9abec3..18eafbc 100644
--- a/src/pkg/crypto/rsa/pss.go
+++ b/src/pkg/crypto/rsa/pss.go
@@ -4,7 +4,7 @@
 
 package rsa
 
-// This file implementes the PSS signature scheme [1].
+// This file implements the PSS signature scheme [1].
 //
 // [1] http://www.rsa.com/rsalabs/pkcs/files/h11300-wp-pkcs-1v2-2-rsa-cryptography-standard.pdf
 
@@ -189,7 +189,7 @@ func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) error {
 
 // signPSSWithSalt calculates the signature of hashed using PSS [1] with specified salt.
 // Note that hashed must be the result of hashing the input message using the
-// given hash funcion. salt is a random sequence of bytes whose length will be
+// given hash function. salt is a random sequence of bytes whose length will be
 // later used to verify the signature.
 func signPSSWithSalt(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed, salt []byte) (s []byte, err error) {
 	nBits := priv.N.BitLen()
@@ -233,7 +233,7 @@ func (opts *PSSOptions) saltLength() int {
 
 // SignPSS calculates the signature of hashed using RSASSA-PSS [1].
 // Note that hashed must be the result of hashing the input message using the
-// given hash funcion. The opts argument may be nil, in which case sensible
+// given hash function. The opts argument may be nil, in which case sensible
 // defaults are used.
 func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte, opts *PSSOptions) (s []byte, err error) {
 	saltLength := opts.saltLength()
diff --git a/src/pkg/crypto/rsa/rsa.go b/src/pkg/crypto/rsa/rsa.go
index c7353ea..bce6ba4 100644
--- a/src/pkg/crypto/rsa/rsa.go
+++ b/src/pkg/crypto/rsa/rsa.go
@@ -60,7 +60,7 @@ type PrivateKey struct {
 
 type PrecomputedValues struct {
 	Dp, Dq *big.Int // D mod (P-1) (or mod Q-1)
-	Qinv   *big.Int // Q^-1 mod Q
+	Qinv   *big.Int // Q^-1 mod P
 
 	// CRTValues is used for the 3rd and subsequent primes. Due to a
 	// historical accident, the CRT for the first two primes is handled
@@ -120,16 +120,18 @@ func (priv *PrivateKey) Validate() error {
 	return nil
 }
 
-// GenerateKey generates an RSA keypair of the given bit size.
+// GenerateKey generates an RSA keypair of the given bit size using the
+// random source random (for example, crypto/rand.Reader).
 func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err error) {
 	return GenerateMultiPrimeKey(random, 2, bits)
 }
 
 // GenerateMultiPrimeKey generates a multi-prime RSA keypair of the given bit
-// size, as suggested in [1]. Although the public keys are compatible
-// (actually, indistinguishable) from the 2-prime case, the private keys are
-// not. Thus it may not be possible to export multi-prime private keys in
-// certain formats or to subsequently import them into other code.
+// size and the given random source, as suggested in [1]. Although the public
+// keys are compatible (actually, indistinguishable) from the 2-prime case,
+// the private keys are not. Thus it may not be possible to export multi-prime
+// private keys in certain formats or to subsequently import them into other
+// code.
 //
 // Table 1 in [2] suggests maximum numbers of primes for a given size.
 //
diff --git a/src/pkg/crypto/rsa/rsa_test.go b/src/pkg/crypto/rsa/rsa_test.go
index cf193c6..4ee1c3a 100644
--- a/src/pkg/crypto/rsa/rsa_test.go
+++ b/src/pkg/crypto/rsa/rsa_test.go
@@ -197,7 +197,7 @@ func TestEncryptOAEP(t *testing.T) {
 		public := PublicKey{n, test.e}
 
 		for j, message := range test.msgs {
-			randomSource := bytes.NewBuffer(message.seed)
+			randomSource := bytes.NewReader(message.seed)
 			out, err := EncryptOAEP(sha1, randomSource, &public, message.in, nil)
 			if err != nil {
 				t.Errorf("#%d,%d error: %s", i, j, err)
diff --git a/src/pkg/crypto/sha1/example_test.go b/src/pkg/crypto/sha1/example_test.go
index 25fe5f3..42aec8a 100644
--- a/src/pkg/crypto/sha1/example_test.go
+++ b/src/pkg/crypto/sha1/example_test.go
@@ -12,7 +12,14 @@ import (
 
 func ExampleNew() {
 	h := sha1.New()
-	io.WriteString(h, "His money is twice tainted: 'taint yours and 'taint mine.")
+	io.WriteString(h, "His money is twice tainted:")
+	io.WriteString(h, " 'taint yours and 'taint mine.")
 	fmt.Printf("% x", h.Sum(nil))
 	// Output: 59 7f 6a 54 00 10 f9 4c 15 d7 18 06 a9 9a 2c 87 10 e7 47 bd
 }
+
+func ExampleSum() {
+	data := []byte("This page intentionally left blank.")
+	fmt.Printf("% x", sha1.Sum(data))
+	// Output: af 06 49 23 bb f2 30 15 96 aa c4 c2 73 ba 32 17 8e bc 4a 96
+}
diff --git a/src/pkg/crypto/sha1/sha1.go b/src/pkg/crypto/sha1/sha1.go
index 8eb3f7a..9f1a96e 100644
--- a/src/pkg/crypto/sha1/sha1.go
+++ b/src/pkg/crypto/sha1/sha1.go
@@ -62,16 +62,10 @@ func (d *digest) Write(p []byte) (nn int, err error) {
 	nn = len(p)
 	d.len += uint64(nn)
 	if d.nx > 0 {
-		n := len(p)
-		if n > chunk-d.nx {
-			n = chunk - d.nx
-		}
-		for i := 0; i < n; i++ {
-			d.x[d.nx+i] = p[i]
-		}
+		n := copy(d.x[d.nx:], p)
 		d.nx += n
 		if d.nx == chunk {
-			block(d, d.x[0:])
+			block(d, d.x[:])
 			d.nx = 0
 		}
 		p = p[n:]
diff --git a/src/pkg/crypto/sha1/sha1_test.go b/src/pkg/crypto/sha1/sha1_test.go
index c3868d7..4a62951 100644
--- a/src/pkg/crypto/sha1/sha1_test.go
+++ b/src/pkg/crypto/sha1/sha1_test.go
@@ -7,6 +7,7 @@
 package sha1
 
 import (
+	"crypto/rand"
 	"fmt"
 	"io"
 	"testing"
@@ -76,6 +77,32 @@ func TestGolden(t *testing.T) {
 	}
 }
 
+func TestSize(t *testing.T) {
+	c := New()
+	if got := c.Size(); got != Size {
+		t.Errorf("Size = %d; want %d", got, Size)
+	}
+}
+
+func TestBlockSize(t *testing.T) {
+	c := New()
+	if got := c.BlockSize(); got != BlockSize {
+		t.Errorf("BlockSize = %d; want %d", got, BlockSize)
+	}
+}
+
+// Tests that blockGeneric (pure Go) and block (in assembly for amd64, 386, arm) match.
+func TestBlockGeneric(t *testing.T) {
+	gen, asm := New().(*digest), New().(*digest)
+	buf := make([]byte, BlockSize*20) // arbitrary factor
+	rand.Read(buf)
+	blockGeneric(gen, buf)
+	block(asm, buf)
+	if *gen != *asm {
+		t.Error("block and blockGeneric resulted in different states")
+	}
+}
+
 var bench = New()
 var buf = make([]byte, 8192)
 
diff --git a/src/pkg/crypto/sha1/sha1block.go b/src/pkg/crypto/sha1/sha1block.go
index 92224fc..fde3c98 100644
--- a/src/pkg/crypto/sha1/sha1block.go
+++ b/src/pkg/crypto/sha1/sha1block.go
@@ -2,12 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !amd64,!386
-
-// SHA1 block step.
-// In its own file so that a faster assembly or C version
-// can be substituted easily.
-
 package sha1
 
 const (
@@ -17,7 +11,9 @@ const (
 	_K3 = 0xCA62C1D6
 )
 
-func block(dig *digest, p []byte) {
+// blockGeneric is a portable, pure Go version of the SHA1 block step.
+// It's used by sha1block_generic.go and tests.
+func blockGeneric(dig *digest, p []byte) {
 	var w [16]uint32
 
 	h0, h1, h2, h3, h4 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4]
diff --git a/src/pkg/crypto/sha1/sha1block_386.s b/src/pkg/crypto/sha1/sha1block_386.s
index 890b3ae..688851c 100644
--- a/src/pkg/crypto/sha1/sha1block_386.s
+++ b/src/pkg/crypto/sha1/sha1block_386.s
@@ -46,12 +46,10 @@
 	ADDL	DI, e
 
 #define FUNC1(a, b, c, d, e) \
-	MOVL	b, SI; \
-	ANDL	c, SI; \
-	MOVL	b, DI; \
-	NOTL	DI; \
-	ANDL	d, DI; \
-	ORL	SI, DI
+	MOVL	d, DI; \
+	XORL	c, DI; \
+	ANDL	b, DI; \
+	XORL	d, DI
 
 #define FUNC2(a, b, c, d, e) \
 	MOVL	b, DI; \
diff --git a/src/pkg/crypto/sha1/sha1block_amd64.s b/src/pkg/crypto/sha1/sha1block_amd64.s
index 0bb6c20..8ffb9d5 100644
--- a/src/pkg/crypto/sha1/sha1block_amd64.s
+++ b/src/pkg/crypto/sha1/sha1block_amd64.s
@@ -34,12 +34,10 @@
 	MOVL	R10, (((index)&0xf)*4)(SP)
 
 #define FUNC1(a, b, c, d, e) \
-	MOVL	b, R8; \
-	ANDL	c, R8; \
-	MOVL	b, R9; \
-	NOTL	R9; \
-	ANDL	d, R9; \
-	ORL	R8, R9
+	MOVL	d, R9; \
+	XORL	c, R9; \
+	ANDL	b, R9; \
+	XORL	d, R9
 
 #define FUNC2(a, b, c, d, e) \
 	MOVL	b, R9; \
diff --git a/src/pkg/crypto/sha1/sha1block_amd64p32.s b/src/pkg/crypto/sha1/sha1block_amd64p32.s
new file mode 100644
index 0000000..3c589d9
--- /dev/null
+++ b/src/pkg/crypto/sha1/sha1block_amd64p32.s
@@ -0,0 +1,216 @@
+// 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 "../../../cmd/ld/textflag.h"
+
+// SHA1 block routine. See sha1block.go for Go equivalent.
+//
+// There are 80 rounds of 4 types:
+//   - rounds 0-15 are type 1 and load data (ROUND1 macro).
+//   - rounds 16-19 are type 1 and do not load data (ROUND1x macro).
+//   - rounds 20-39 are type 2 and do not load data (ROUND2 macro).
+//   - rounds 40-59 are type 3 and do not load data (ROUND3 macro).
+//   - rounds 60-79 are type 4 and do not load data (ROUND4 macro).
+//
+// Each round loads or shuffles the data, then computes a per-round
+// function of b, c, d, and then mixes the result into and rotates the
+// five registers a, b, c, d, e holding the intermediate results.
+//
+// The register rotation is implemented by rotating the arguments to
+// the round macros instead of by explicit move instructions.
+//
+// amd64p32 version.
+// To ensure safety for Native Client, avoids use of BP and R15
+// as well as two-register addressing modes.
+
+#define LOAD(index) \
+	MOVL	(index*4)(SI), R10; \
+	BSWAPL	R10; \
+	MOVL	R10, (index*4)(SP)
+
+#define SHUFFLE(index) \
+	MOVL	(((index)&0xf)*4)(SP), R10; \
+	XORL	(((index-3)&0xf)*4)(SP), R10; \
+	XORL	(((index-8)&0xf)*4)(SP), R10; \
+	XORL	(((index-14)&0xf)*4)(SP), R10; \
+	ROLL	$1, R10; \
+	MOVL	R10, (((index)&0xf)*4)(SP)
+
+#define FUNC1(a, b, c, d, e) \
+	MOVL	d, R9; \
+	XORL	c, R9; \
+	ANDL	b, R9; \
+	XORL	d, R9
+
+#define FUNC2(a, b, c, d, e) \
+	MOVL	b, R9; \
+	XORL	c, R9; \
+	XORL	d, R9
+
+#define FUNC3(a, b, c, d, e) \
+	MOVL	b, R8; \
+	ORL	c, R8; \
+	ANDL	d, R8; \
+	MOVL	b, R9; \
+	ANDL	c, R9; \
+	ORL	R8, R9
+	
+#define FUNC4 FUNC2
+
+#define MIX(a, b, c, d, e, const) \
+	ROLL	$30, b; \
+	ADDL	R9, e; \
+	MOVL	a, R8; \
+	ROLL	$5, R8; \
+	LEAL	const(e)(R10*1), e; \
+	ADDL	R8, e
+
+#define ROUND1(a, b, c, d, e, index) \
+	LOAD(index); \
+	FUNC1(a, b, c, d, e); \
+	MIX(a, b, c, d, e, 0x5A827999)
+
+#define ROUND1x(a, b, c, d, e, index) \
+	SHUFFLE(index); \
+	FUNC1(a, b, c, d, e); \
+	MIX(a, b, c, d, e, 0x5A827999)
+
+#define ROUND2(a, b, c, d, e, index) \
+	SHUFFLE(index); \
+	FUNC2(a, b, c, d, e); \
+	MIX(a, b, c, d, e, 0x6ED9EBA1)
+
+#define ROUND3(a, b, c, d, e, index) \
+	SHUFFLE(index); \
+	FUNC3(a, b, c, d, e); \
+	MIX(a, b, c, d, e, 0x8F1BBCDC)
+
+#define ROUND4(a, b, c, d, e, index) \
+	SHUFFLE(index); \
+	FUNC4(a, b, c, d, e); \
+	MIX(a, b, c, d, e, 0xCA62C1D6)
+
+TEXT ·block(SB),NOSPLIT,$64-32
+	MOVL	dig+0(FP),	R14
+	MOVL	p_base+4(FP),	SI
+	MOVL	p_len+8(FP),	DX
+	SHRQ	$6,		DX
+	SHLQ	$6,		DX
+	
+	LEAQ	(SI)(DX*1),	DI
+	MOVL	(0*4)(R14),	AX
+	MOVL	(1*4)(R14),	BX
+	MOVL	(2*4)(R14),	CX
+	MOVL	(3*4)(R14),	DX
+	MOVL	(4*4)(R14),	R13
+
+	CMPQ	SI,		DI
+	JEQ	end
+
+loop:
+#define BP R13 /* keep diff from sha1block_amd64.s small */
+	ROUND1(AX, BX, CX, DX, BP, 0)
+	ROUND1(BP, AX, BX, CX, DX, 1)
+	ROUND1(DX, BP, AX, BX, CX, 2)
+	ROUND1(CX, DX, BP, AX, BX, 3)
+	ROUND1(BX, CX, DX, BP, AX, 4)
+	ROUND1(AX, BX, CX, DX, BP, 5)
+	ROUND1(BP, AX, BX, CX, DX, 6)
+	ROUND1(DX, BP, AX, BX, CX, 7)
+	ROUND1(CX, DX, BP, AX, BX, 8)
+	ROUND1(BX, CX, DX, BP, AX, 9)
+	ROUND1(AX, BX, CX, DX, BP, 10)
+	ROUND1(BP, AX, BX, CX, DX, 11)
+	ROUND1(DX, BP, AX, BX, CX, 12)
+	ROUND1(CX, DX, BP, AX, BX, 13)
+	ROUND1(BX, CX, DX, BP, AX, 14)
+	ROUND1(AX, BX, CX, DX, BP, 15)
+
+	ROUND1x(BP, AX, BX, CX, DX, 16)
+	ROUND1x(DX, BP, AX, BX, CX, 17)
+	ROUND1x(CX, DX, BP, AX, BX, 18)
+	ROUND1x(BX, CX, DX, BP, AX, 19)
+	
+	ROUND2(AX, BX, CX, DX, BP, 20)
+	ROUND2(BP, AX, BX, CX, DX, 21)
+	ROUND2(DX, BP, AX, BX, CX, 22)
+	ROUND2(CX, DX, BP, AX, BX, 23)
+	ROUND2(BX, CX, DX, BP, AX, 24)
+	ROUND2(AX, BX, CX, DX, BP, 25)
+	ROUND2(BP, AX, BX, CX, DX, 26)
+	ROUND2(DX, BP, AX, BX, CX, 27)
+	ROUND2(CX, DX, BP, AX, BX, 28)
+	ROUND2(BX, CX, DX, BP, AX, 29)
+	ROUND2(AX, BX, CX, DX, BP, 30)
+	ROUND2(BP, AX, BX, CX, DX, 31)
+	ROUND2(DX, BP, AX, BX, CX, 32)
+	ROUND2(CX, DX, BP, AX, BX, 33)
+	ROUND2(BX, CX, DX, BP, AX, 34)
+	ROUND2(AX, BX, CX, DX, BP, 35)
+	ROUND2(BP, AX, BX, CX, DX, 36)
+	ROUND2(DX, BP, AX, BX, CX, 37)
+	ROUND2(CX, DX, BP, AX, BX, 38)
+	ROUND2(BX, CX, DX, BP, AX, 39)
+	
+	ROUND3(AX, BX, CX, DX, BP, 40)
+	ROUND3(BP, AX, BX, CX, DX, 41)
+	ROUND3(DX, BP, AX, BX, CX, 42)
+	ROUND3(CX, DX, BP, AX, BX, 43)
+	ROUND3(BX, CX, DX, BP, AX, 44)
+	ROUND3(AX, BX, CX, DX, BP, 45)
+	ROUND3(BP, AX, BX, CX, DX, 46)
+	ROUND3(DX, BP, AX, BX, CX, 47)
+	ROUND3(CX, DX, BP, AX, BX, 48)
+	ROUND3(BX, CX, DX, BP, AX, 49)
+	ROUND3(AX, BX, CX, DX, BP, 50)
+	ROUND3(BP, AX, BX, CX, DX, 51)
+	ROUND3(DX, BP, AX, BX, CX, 52)
+	ROUND3(CX, DX, BP, AX, BX, 53)
+	ROUND3(BX, CX, DX, BP, AX, 54)
+	ROUND3(AX, BX, CX, DX, BP, 55)
+	ROUND3(BP, AX, BX, CX, DX, 56)
+	ROUND3(DX, BP, AX, BX, CX, 57)
+	ROUND3(CX, DX, BP, AX, BX, 58)
+	ROUND3(BX, CX, DX, BP, AX, 59)
+	
+	ROUND4(AX, BX, CX, DX, BP, 60)
+	ROUND4(BP, AX, BX, CX, DX, 61)
+	ROUND4(DX, BP, AX, BX, CX, 62)
+	ROUND4(CX, DX, BP, AX, BX, 63)
+	ROUND4(BX, CX, DX, BP, AX, 64)
+	ROUND4(AX, BX, CX, DX, BP, 65)
+	ROUND4(BP, AX, BX, CX, DX, 66)
+	ROUND4(DX, BP, AX, BX, CX, 67)
+	ROUND4(CX, DX, BP, AX, BX, 68)
+	ROUND4(BX, CX, DX, BP, AX, 69)
+	ROUND4(AX, BX, CX, DX, BP, 70)
+	ROUND4(BP, AX, BX, CX, DX, 71)
+	ROUND4(DX, BP, AX, BX, CX, 72)
+	ROUND4(CX, DX, BP, AX, BX, 73)
+	ROUND4(BX, CX, DX, BP, AX, 74)
+	ROUND4(AX, BX, CX, DX, BP, 75)
+	ROUND4(BP, AX, BX, CX, DX, 76)
+	ROUND4(DX, BP, AX, BX, CX, 77)
+	ROUND4(CX, DX, BP, AX, BX, 78)
+	ROUND4(BX, CX, DX, BP, AX, 79)
+#undef BP
+
+	ADDL	(0*4)(R14), AX
+	ADDL	(1*4)(R14), BX
+	ADDL	(2*4)(R14), CX
+	ADDL	(3*4)(R14), DX
+	ADDL	(4*4)(R14), R13
+
+	MOVL	AX, (0*4)(R14)
+	MOVL	BX, (1*4)(R14)
+	MOVL	CX, (2*4)(R14)
+	MOVL	DX, (3*4)(R14)
+	MOVL	R13, (4*4)(R14)
+
+	ADDQ	$64, SI
+	CMPQ	SI, DI
+	JB	loop
+
+end:
+	RET
diff --git a/src/pkg/crypto/sha1/sha1block_arm.s b/src/pkg/crypto/sha1/sha1block_arm.s
new file mode 100644
index 0000000..5917e8b
--- /dev/null
+++ b/src/pkg/crypto/sha1/sha1block_arm.s
@@ -0,0 +1,217 @@
+// 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.
+//
+// ARM version of md5block.go
+
+#include "../../../cmd/ld/textflag.h"
+
+// SHA1 block routine. See sha1block.go for Go equivalent.
+//
+// There are 80 rounds of 4 types:
+//   - rounds 0-15 are type 1 and load data (ROUND1 macro).
+//   - rounds 16-19 are type 1 and do not load data (ROUND1x macro).
+//   - rounds 20-39 are type 2 and do not load data (ROUND2 macro).
+//   - rounds 40-59 are type 3 and do not load data (ROUND3 macro).
+//   - rounds 60-79 are type 4 and do not load data (ROUND4 macro).
+//
+// Each round loads or shuffles the data, then computes a per-round
+// function of b, c, d, and then mixes the result into and rotates the
+// five registers a, b, c, d, e holding the intermediate results.
+//
+// The register rotation is implemented by rotating the arguments to
+// the round macros instead of by explicit move instructions.
+
+// Register definitions
+data = 0	// Pointer to incoming data
+const = 1	// Current constant for SHA round
+a = 2		// SHA1 accumulator
+b = 3		// SHA1 accumulator
+c = 4		// SHA1 accumulator
+d = 5		// SHA1 accumulator
+e = 6		// SHA1 accumulator
+t0 = 7		// Temporary
+t1 = 8		// Temporary
+// r9, r10 are forbidden
+// r11 is OK provided you check the assembler that no synthetic instructions use it
+t2 = 11		// Temporary
+ctr = 12	// loop counter
+w = 14		// point to w buffer
+
+// func block(dig *digest, p []byte)
+// 0(FP) is *digest
+// 4(FP) is p.array (struct Slice)
+// 8(FP) is p.len
+//12(FP) is p.cap
+//
+// Stack frame
+p_end = -4		// -4(SP) pointer to the end of data
+p_data = p_end - 4	// -8(SP) current data pointer
+w_buf = p_data - 4*80	// -328(SP) 80 words temporary buffer w uint32[80]
+saved = w_buf - 4*5	// -348(SP) saved sha1 registers a,b,c,d,e - these must be last
+// Total size +4 for saved LR is 352
+
+	// w[i] = p[j]<<24 | p[j+1]<<16 | p[j+2]<<8 | p[j+3]
+	// e += w[i]
+#define LOAD(e) \
+	MOVBU	2(R(data)), R(t0) ; \
+	MOVBU	3(R(data)), R(t1) ; \
+	MOVBU	1(R(data)), R(t2) ; \
+	ORR	R(t0)<<8, R(t1), R(t0)	    ; \
+	MOVBU.P	4(R(data)), R(t1) ; \
+	ORR	R(t2)<<16, R(t0), R(t0)	    ; \
+	ORR	R(t1)<<24, R(t0), R(t0)	    ; \
+	MOVW.P	R(t0), 4(R(w))		    ; \
+	ADD	R(t0), R(e), R(e)
+	
+	// tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf]
+	// w[i&0xf] = tmp<<1 | tmp>>(32-1)
+	// e += w[i&0xf] 
+#define SHUFFLE(e) \
+	MOVW	(-16*4)(R(w)), R(t0) ; \
+	MOVW	(-14*4)(R(w)), R(t1) ; \
+	MOVW	(-8*4)(R(w)), R(t2)  ; \
+	EOR	R(t0), R(t1), R(t0)  ; \
+	MOVW	(-3*4)(R(w)), R(t1)  ; \
+	EOR	R(t2), R(t0), R(t0)  ; \
+	EOR	R(t0), R(t1), R(t0)  ; \
+	MOVW	R(t0)@>(32-1), R(t0)  ; \
+	MOVW.P	R(t0), 4(R(w))	  ; \
+	ADD	R(t0), R(e), R(e)
+
+	// t1 = (b & c) | ((~b) & d)
+#define FUNC1(a, b, c, d, e) \
+	MVN	R(b), R(t1)	   ; \
+	AND	R(b), R(c), R(t0)  ; \
+	AND	R(d), R(t1), R(t1) ; \
+	ORR	R(t0), R(t1), R(t1)
+
+	// t1 = b ^ c ^ d
+#define FUNC2(a, b, c, d, e) \
+	EOR	R(b), R(c), R(t1) ; \
+	EOR	R(d), R(t1), R(t1)
+
+	// t1 = (b & c) | (b & d) | (c & d) =
+	// t1 = (b & c) | ((b | c) & d)
+#define FUNC3(a, b, c, d, e) \
+	ORR	R(b), R(c), R(t0)  ; \
+	AND	R(b), R(c), R(t1)  ; \
+	AND	R(d), R(t0), R(t0) ; \
+	ORR	R(t0), R(t1), R(t1)
+
+#define FUNC4 FUNC2
+
+	// a5 := a<<5 | a>>(32-5)
+	// b = b<<30 | b>>(32-30)
+	// e = a5 + t1 + e + const
+#define MIX(a, b, c, d, e) \
+	ADD	R(t1), R(e), R(e)	 ; \
+	MOVW	R(b)@>(32-30), R(b)	 ; \
+	ADD	R(a)@>(32-5), R(e), R(e) ; \
+	ADD	R(const), R(e), R(e)
+
+#define ROUND1(a, b, c, d, e) \
+	LOAD(e)		; \
+	FUNC1(a, b, c, d, e)	; \
+	MIX(a, b, c, d, e)
+
+#define ROUND1x(a, b, c, d, e) \
+	SHUFFLE(e)	; \
+	FUNC1(a, b, c, d, e)	; \
+	MIX(a, b, c, d, e)
+
+#define ROUND2(a, b, c, d, e) \
+	SHUFFLE(e)	; \
+	FUNC2(a, b, c, d, e)	; \
+	MIX(a, b, c, d, e)
+
+#define ROUND3(a, b, c, d, e) \
+	SHUFFLE(e)	; \
+	FUNC3(a, b, c, d, e)	; \
+	MIX(a, b, c, d, e)
+
+#define ROUND4(a, b, c, d, e) \
+	SHUFFLE(e)	; \
+	FUNC4(a, b, c, d, e)	; \
+	MIX(a, b, c, d, e)
+
+
+// func block(dig *digest, p []byte)
+TEXT	·block(SB), 0, $352-16
+	MOVW	p+4(FP), R(data)	// pointer to the data
+	MOVW	p_len+8(FP), R(t0)	// number of bytes
+	ADD	R(data), R(t0)
+	MOVW	R(t0), p_end(SP)	// pointer to end of data
+
+	// Load up initial SHA1 accumulator
+	MOVW	dig+0(FP), R(t0)
+	MOVM.IA (R(t0)), [R(a),R(b),R(c),R(d),R(e)]
+
+loop:
+	// Save registers at SP+4 onwards
+	MOVM.IB [R(a),R(b),R(c),R(d),R(e)], (R13)
+
+	MOVW	$w_buf(SP), R(w)
+	MOVW	$0x5A827999, R(const)
+	MOVW	$3, R(ctr)
+loop1:	ROUND1(a, b, c, d, e)
+	ROUND1(e, a, b, c, d)
+	ROUND1(d, e, a, b, c)
+	ROUND1(c, d, e, a, b)
+	ROUND1(b, c, d, e, a)
+	SUB.S	$1, R(ctr)
+	BNE	loop1
+
+	ROUND1(a, b, c, d, e)
+	ROUND1x(e, a, b, c, d)
+	ROUND1x(d, e, a, b, c)
+	ROUND1x(c, d, e, a, b)
+	ROUND1x(b, c, d, e, a)
+	
+	MOVW	$0x6ED9EBA1, R(const)
+	MOVW	$4, R(ctr)
+loop2:	ROUND2(a, b, c, d, e)
+	ROUND2(e, a, b, c, d)
+	ROUND2(d, e, a, b, c)
+	ROUND2(c, d, e, a, b)
+	ROUND2(b, c, d, e, a)
+	SUB.S	$1, R(ctr)
+	BNE	loop2
+	
+	MOVW	$0x8F1BBCDC, R(const)
+	MOVW	$4, R(ctr)
+loop3:	ROUND3(a, b, c, d, e)
+	ROUND3(e, a, b, c, d)
+	ROUND3(d, e, a, b, c)
+	ROUND3(c, d, e, a, b)
+	ROUND3(b, c, d, e, a)
+	SUB.S	$1, R(ctr)
+	BNE	loop3
+	
+	MOVW	$0xCA62C1D6, R(const)
+	MOVW	$4, R(ctr)
+loop4:	ROUND4(a, b, c, d, e)
+	ROUND4(e, a, b, c, d)
+	ROUND4(d, e, a, b, c)
+	ROUND4(c, d, e, a, b)
+	ROUND4(b, c, d, e, a)
+	SUB.S	$1, R(ctr)
+	BNE	loop4
+
+	// Accumulate - restoring registers from SP+4
+	MOVM.IB (R13), [R(t0),R(t1),R(t2),R(ctr),R(w)]
+	ADD	R(t0), R(a)
+	ADD	R(t1), R(b)
+	ADD	R(t2), R(c)
+	ADD	R(ctr), R(d)
+	ADD	R(w), R(e)
+
+	MOVW	p_end(SP), R(t0)
+	CMP	R(t0), R(data)
+	BLO	loop
+
+	// Save final SHA1 accumulator
+	MOVW	dig+0(FP), R(t0)
+	MOVM.IA [R(a),R(b),R(c),R(d),R(e)], (R(t0))
+
+	RET
diff --git a/src/pkg/crypto/sha1/sha1block_decl.go b/src/pkg/crypto/sha1/sha1block_decl.go
index 4cb157f..24e521a 100644
--- a/src/pkg/crypto/sha1/sha1block_decl.go
+++ b/src/pkg/crypto/sha1/sha1block_decl.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 amd64 386
+// +build amd64 amd64p32 arm 386
 
 package sha1
 
diff --git a/src/pkg/crypto/sha1/sha1block_generic.go b/src/pkg/crypto/sha1/sha1block_generic.go
new file mode 100644
index 0000000..696e26b
--- /dev/null
+++ b/src/pkg/crypto/sha1/sha1block_generic.go
@@ -0,0 +1,9 @@
+// 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 !amd64,!amd64p32,!386,!arm
+
+package sha1
+
+var block = blockGeneric
diff --git a/src/pkg/crypto/sha256/sha256.go b/src/pkg/crypto/sha256/sha256.go
index d69ed24..d84cebf 100644
--- a/src/pkg/crypto/sha256/sha256.go
+++ b/src/pkg/crypto/sha256/sha256.go
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // Package sha256 implements the SHA224 and SHA256 hash algorithms as defined
-// in FIPS 180-2.
+// in FIPS 180-4.
 package sha256
 
 import (
@@ -106,16 +106,10 @@ func (d *digest) Write(p []byte) (nn int, err error) {
 	nn = len(p)
 	d.len += uint64(nn)
 	if d.nx > 0 {
-		n := len(p)
-		if n > chunk-d.nx {
-			n = chunk - d.nx
-		}
-		for i := 0; i < n; i++ {
-			d.x[d.nx+i] = p[i]
-		}
+		n := copy(d.x[d.nx:], p)
 		d.nx += n
 		if d.nx == chunk {
-			block(d, d.x[0:])
+			block(d, d.x[:])
 			d.nx = 0
 		}
 		p = p[n:]
diff --git a/src/pkg/crypto/sha256/sha256_test.go b/src/pkg/crypto/sha256/sha256_test.go
index bb1ec3b..1d883d3 100644
--- a/src/pkg/crypto/sha256/sha256_test.go
+++ b/src/pkg/crypto/sha256/sha256_test.go
@@ -132,6 +132,24 @@ func TestGolden(t *testing.T) {
 	}
 }
 
+func TestSize(t *testing.T) {
+	c := New()
+	if got := c.Size(); got != Size {
+		t.Errorf("Size = %d; want %d", got, Size)
+	}
+	c = New224()
+	if got := c.Size(); got != Size224 {
+		t.Errorf("New224.Size = %d; want %d", got, Size224)
+	}
+}
+
+func TestBlockSize(t *testing.T) {
+	c := New()
+	if got := c.BlockSize(); got != BlockSize {
+		t.Errorf("BlockSize = %d want %d", got, BlockSize)
+	}
+}
+
 var bench = New()
 var buf = make([]byte, 8192)
 
diff --git a/src/pkg/crypto/sha256/sha256block.go b/src/pkg/crypto/sha256/sha256block.go
index 2ac4910..ca5efd1 100644
--- a/src/pkg/crypto/sha256/sha256block.go
+++ b/src/pkg/crypto/sha256/sha256block.go
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build !386,!amd64
+
 // SHA256 block step.
 // In its own file so that a faster assembly or C version
 // can be substituted easily.
diff --git a/src/pkg/crypto/sha256/sha256block_386.s b/src/pkg/crypto/sha256/sha256block_386.s
new file mode 100644
index 0000000..73ae2bf
--- /dev/null
+++ b/src/pkg/crypto/sha256/sha256block_386.s
@@ -0,0 +1,283 @@
+// 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.
+
+// SHA256 block routine. See sha256block.go for Go equivalent.
+//
+// The algorithm is detailed in FIPS 180-4:
+//
+//  http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+//
+// Wt = Mt; for 0 <= t <= 15
+// Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
+//
+// a = H0
+// b = H1
+// c = H2
+// d = H3
+// e = H4
+// f = H5
+// g = H6
+// h = H7
+//
+// for t = 0 to 63 {
+//    T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt
+//    T2 = BIGSIGMA0(a) + Maj(a,b,c)
+//    h = g
+//    g = f
+//    f = e
+//    e = d + T1
+//    d = c
+//    c = b
+//    b = a
+//    a = T1 + T2
+// }
+//
+// H0 = a + H0
+// H1 = b + H1
+// H2 = c + H2
+// H3 = d + H3
+// H4 = e + H4
+// H5 = f + H5
+// H6 = g + H6
+// H7 = h + H7
+
+// Wt = Mt; for 0 <= t <= 15
+#define MSGSCHEDULE0(index) \
+	MOVL	(index*4)(SI), AX; \
+	BSWAPL	AX; \
+	MOVL	AX, (index*4)(BP)
+
+// Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
+//   SIGMA0(x) = ROTR(7,x) XOR ROTR(18,x) XOR SHR(3,x)
+//   SIGMA1(x) = ROTR(17,x) XOR ROTR(19,x) XOR SHR(10,x)
+#define MSGSCHEDULE1(index) \
+	MOVL	((index-2)*4)(BP), AX; \
+	MOVL	AX, CX; \
+	RORL	$17, AX; \
+	MOVL	CX, DX; \
+	RORL	$19, CX; \
+	SHRL	$10, DX; \
+	MOVL	((index-15)*4)(BP), BX; \
+	XORL	CX, AX; \
+	MOVL	BX, CX; \
+	XORL	DX, AX; \
+	RORL	$7, BX; \
+	MOVL	CX, DX; \
+	SHRL	$3, DX; \
+	RORL	$18, CX; \
+	ADDL	((index-7)*4)(BP), AX; \
+	XORL	CX, BX; \
+	XORL	DX, BX; \
+	ADDL	((index-16)*4)(BP), BX; \
+	ADDL	BX, AX; \
+	MOVL	AX, ((index)*4)(BP)
+
+// Calculate T1 in AX - uses AX, BX, CX and DX registers.
+// Wt is passed in AX.
+//   T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt
+//     BIGSIGMA1(x) = ROTR(6,x) XOR ROTR(11,x) XOR ROTR(25,x)
+//     Ch(x, y, z) = (x AND y) XOR (NOT x AND z)
+#define SHA256T1(const, e, f, g, h) \
+	MOVL	(h*4)(DI), BX; \
+	ADDL	AX, BX; \
+	MOVL	(e*4)(DI), AX; \
+	ADDL	$const, BX; \
+	MOVL	(e*4)(DI), CX; \
+	RORL	$6, AX; \
+	MOVL	(e*4)(DI), DX; \
+	RORL	$11, CX; \
+	XORL	CX, AX; \
+	MOVL	(e*4)(DI), CX; \
+	RORL	$25, DX; \
+	ANDL	(f*4)(DI), CX; \
+	XORL	AX, DX; \
+	MOVL	(e*4)(DI), AX; \
+	NOTL	AX; \
+	ADDL	DX, BX; \
+	ANDL	(g*4)(DI), AX; \
+	XORL	CX, AX; \
+	ADDL	BX, AX
+
+// Calculate T2 in BX - uses AX, BX, CX and DX registers.
+//   T2 = BIGSIGMA0(a) + Maj(a, b, c)
+//     BIGSIGMA0(x) = ROTR(2,x) XOR ROTR(13,x) XOR ROTR(22,x)
+//     Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)
+#define SHA256T2(a, b, c) \
+	MOVL	(a*4)(DI), AX; \
+	MOVL	(c*4)(DI), BX; \
+	RORL	$2, AX; \
+	MOVL	(a*4)(DI), DX; \
+	ANDL	(b*4)(DI), BX; \
+	RORL	$13, DX; \
+	MOVL	(a*4)(DI), CX; \
+	ANDL	(c*4)(DI), CX; \
+	XORL	DX, AX; \
+	XORL	CX, BX; \
+	MOVL	(a*4)(DI), DX; \
+	MOVL	(b*4)(DI), CX; \
+	RORL	$22, DX; \
+	ANDL	(a*4)(DI), CX; \
+	XORL	CX, BX; \
+	XORL	DX, AX; \
+	ADDL	AX, BX
+
+// Calculate T1 and T2, then e = d + T1 and a = T1 + T2.
+// The values for e and a are stored in d and h, ready for rotation.
+#define SHA256ROUND(index, const, a, b, c, d, e, f, g, h) \
+	SHA256T1(const, e, f, g, h); \
+	MOVL	AX, 292(SP); \
+	SHA256T2(a, b, c); \
+	MOVL	292(SP), AX; \
+	ADDL	AX, BX; \
+	ADDL	AX, (d*4)(DI); \
+	MOVL	BX, (h*4)(DI)
+
+#define SHA256ROUND0(index, const, a, b, c, d, e, f, g, h) \
+	MSGSCHEDULE0(index); \
+	SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
+
+#define SHA256ROUND1(index, const, a, b, c, d, e, f, g, h) \
+	MSGSCHEDULE1(index); \
+	SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
+
+TEXT ·block(SB),0,$296-12
+	MOVL	p_base+4(FP), SI
+	MOVL	p_len+8(FP), DX
+	SHRL	$6, DX
+	SHLL	$6, DX
+
+	LEAL	(SI)(DX*1), DI
+	MOVL	DI, 288(SP)
+	CMPL	SI, DI
+	JEQ	end
+
+	LEAL	256(SP), DI		// variables
+
+	MOVL	dig+0(FP), BP
+	MOVL	(0*4)(BP), AX		// a = H0
+	MOVL	AX, (0*4)(DI)
+	MOVL	(1*4)(BP), BX		// b = H1
+	MOVL	BX, (1*4)(DI)
+	MOVL	(2*4)(BP), CX		// c = H2
+	MOVL	CX, (2*4)(DI)
+	MOVL	(3*4)(BP), DX		// d = H3
+	MOVL	DX, (3*4)(DI)
+	MOVL	(4*4)(BP), AX		// e = H4
+	MOVL	AX, (4*4)(DI)
+	MOVL	(5*4)(BP), BX		// f = H5
+	MOVL	BX, (5*4)(DI)
+	MOVL	(6*4)(BP), CX		// g = H6
+	MOVL	CX, (6*4)(DI)
+	MOVL	(7*4)(BP), DX		// h = H7
+	MOVL	DX, (7*4)(DI)
+
+loop:
+	MOVL	SP, BP			// message schedule
+
+	SHA256ROUND0(0, 0x428a2f98, 0, 1, 2, 3, 4, 5, 6, 7)
+	SHA256ROUND0(1, 0x71374491, 7, 0, 1, 2, 3, 4, 5, 6)
+	SHA256ROUND0(2, 0xb5c0fbcf, 6, 7, 0, 1, 2, 3, 4, 5)
+	SHA256ROUND0(3, 0xe9b5dba5, 5, 6, 7, 0, 1, 2, 3, 4)
+	SHA256ROUND0(4, 0x3956c25b, 4, 5, 6, 7, 0, 1, 2, 3)
+	SHA256ROUND0(5, 0x59f111f1, 3, 4, 5, 6, 7, 0, 1, 2)
+	SHA256ROUND0(6, 0x923f82a4, 2, 3, 4, 5, 6, 7, 0, 1)
+	SHA256ROUND0(7, 0xab1c5ed5, 1, 2, 3, 4, 5, 6, 7, 0)
+	SHA256ROUND0(8, 0xd807aa98, 0, 1, 2, 3, 4, 5, 6, 7)
+	SHA256ROUND0(9, 0x12835b01, 7, 0, 1, 2, 3, 4, 5, 6)
+	SHA256ROUND0(10, 0x243185be, 6, 7, 0, 1, 2, 3, 4, 5)
+	SHA256ROUND0(11, 0x550c7dc3, 5, 6, 7, 0, 1, 2, 3, 4)
+	SHA256ROUND0(12, 0x72be5d74, 4, 5, 6, 7, 0, 1, 2, 3)
+	SHA256ROUND0(13, 0x80deb1fe, 3, 4, 5, 6, 7, 0, 1, 2)
+	SHA256ROUND0(14, 0x9bdc06a7, 2, 3, 4, 5, 6, 7, 0, 1)
+	SHA256ROUND0(15, 0xc19bf174, 1, 2, 3, 4, 5, 6, 7, 0)
+
+	SHA256ROUND1(16, 0xe49b69c1, 0, 1, 2, 3, 4, 5, 6, 7)
+	SHA256ROUND1(17, 0xefbe4786, 7, 0, 1, 2, 3, 4, 5, 6)
+	SHA256ROUND1(18, 0x0fc19dc6, 6, 7, 0, 1, 2, 3, 4, 5)
+	SHA256ROUND1(19, 0x240ca1cc, 5, 6, 7, 0, 1, 2, 3, 4)
+	SHA256ROUND1(20, 0x2de92c6f, 4, 5, 6, 7, 0, 1, 2, 3)
+	SHA256ROUND1(21, 0x4a7484aa, 3, 4, 5, 6, 7, 0, 1, 2)
+	SHA256ROUND1(22, 0x5cb0a9dc, 2, 3, 4, 5, 6, 7, 0, 1)
+	SHA256ROUND1(23, 0x76f988da, 1, 2, 3, 4, 5, 6, 7, 0)
+	SHA256ROUND1(24, 0x983e5152, 0, 1, 2, 3, 4, 5, 6, 7)
+	SHA256ROUND1(25, 0xa831c66d, 7, 0, 1, 2, 3, 4, 5, 6)
+	SHA256ROUND1(26, 0xb00327c8, 6, 7, 0, 1, 2, 3, 4, 5)
+	SHA256ROUND1(27, 0xbf597fc7, 5, 6, 7, 0, 1, 2, 3, 4)
+	SHA256ROUND1(28, 0xc6e00bf3, 4, 5, 6, 7, 0, 1, 2, 3)
+	SHA256ROUND1(29, 0xd5a79147, 3, 4, 5, 6, 7, 0, 1, 2)
+	SHA256ROUND1(30, 0x06ca6351, 2, 3, 4, 5, 6, 7, 0, 1)
+	SHA256ROUND1(31, 0x14292967, 1, 2, 3, 4, 5, 6, 7, 0)
+	SHA256ROUND1(32, 0x27b70a85, 0, 1, 2, 3, 4, 5, 6, 7)
+	SHA256ROUND1(33, 0x2e1b2138, 7, 0, 1, 2, 3, 4, 5, 6)
+	SHA256ROUND1(34, 0x4d2c6dfc, 6, 7, 0, 1, 2, 3, 4, 5)
+	SHA256ROUND1(35, 0x53380d13, 5, 6, 7, 0, 1, 2, 3, 4)
+	SHA256ROUND1(36, 0x650a7354, 4, 5, 6, 7, 0, 1, 2, 3)
+	SHA256ROUND1(37, 0x766a0abb, 3, 4, 5, 6, 7, 0, 1, 2)
+	SHA256ROUND1(38, 0x81c2c92e, 2, 3, 4, 5, 6, 7, 0, 1)
+	SHA256ROUND1(39, 0x92722c85, 1, 2, 3, 4, 5, 6, 7, 0)
+	SHA256ROUND1(40, 0xa2bfe8a1, 0, 1, 2, 3, 4, 5, 6, 7)
+	SHA256ROUND1(41, 0xa81a664b, 7, 0, 1, 2, 3, 4, 5, 6)
+	SHA256ROUND1(42, 0xc24b8b70, 6, 7, 0, 1, 2, 3, 4, 5)
+	SHA256ROUND1(43, 0xc76c51a3, 5, 6, 7, 0, 1, 2, 3, 4)
+	SHA256ROUND1(44, 0xd192e819, 4, 5, 6, 7, 0, 1, 2, 3)
+	SHA256ROUND1(45, 0xd6990624, 3, 4, 5, 6, 7, 0, 1, 2)
+	SHA256ROUND1(46, 0xf40e3585, 2, 3, 4, 5, 6, 7, 0, 1)
+	SHA256ROUND1(47, 0x106aa070, 1, 2, 3, 4, 5, 6, 7, 0)
+	SHA256ROUND1(48, 0x19a4c116, 0, 1, 2, 3, 4, 5, 6, 7)
+	SHA256ROUND1(49, 0x1e376c08, 7, 0, 1, 2, 3, 4, 5, 6)
+	SHA256ROUND1(50, 0x2748774c, 6, 7, 0, 1, 2, 3, 4, 5)
+	SHA256ROUND1(51, 0x34b0bcb5, 5, 6, 7, 0, 1, 2, 3, 4)
+	SHA256ROUND1(52, 0x391c0cb3, 4, 5, 6, 7, 0, 1, 2, 3)
+	SHA256ROUND1(53, 0x4ed8aa4a, 3, 4, 5, 6, 7, 0, 1, 2)
+	SHA256ROUND1(54, 0x5b9cca4f, 2, 3, 4, 5, 6, 7, 0, 1)
+	SHA256ROUND1(55, 0x682e6ff3, 1, 2, 3, 4, 5, 6, 7, 0)
+	SHA256ROUND1(56, 0x748f82ee, 0, 1, 2, 3, 4, 5, 6, 7)
+	SHA256ROUND1(57, 0x78a5636f, 7, 0, 1, 2, 3, 4, 5, 6)
+	SHA256ROUND1(58, 0x84c87814, 6, 7, 0, 1, 2, 3, 4, 5)
+	SHA256ROUND1(59, 0x8cc70208, 5, 6, 7, 0, 1, 2, 3, 4)
+	SHA256ROUND1(60, 0x90befffa, 4, 5, 6, 7, 0, 1, 2, 3)
+	SHA256ROUND1(61, 0xa4506ceb, 3, 4, 5, 6, 7, 0, 1, 2)
+	SHA256ROUND1(62, 0xbef9a3f7, 2, 3, 4, 5, 6, 7, 0, 1)
+	SHA256ROUND1(63, 0xc67178f2, 1, 2, 3, 4, 5, 6, 7, 0)
+
+	MOVL	dig+0(FP), BP
+	MOVL	(0*4)(BP), AX		// H0 = a + H0
+	ADDL	(0*4)(DI), AX
+	MOVL	AX, (0*4)(DI)
+	MOVL	AX, (0*4)(BP)
+	MOVL	(1*4)(BP), BX		// H1 = b + H1
+	ADDL	(1*4)(DI), BX
+	MOVL	BX, (1*4)(DI)
+	MOVL	BX, (1*4)(BP)
+	MOVL	(2*4)(BP), CX		// H2 = c + H2
+	ADDL	(2*4)(DI), CX
+	MOVL	CX, (2*4)(DI)
+	MOVL	CX, (2*4)(BP)
+	MOVL	(3*4)(BP), DX		// H3 = d + H3
+	ADDL	(3*4)(DI), DX
+	MOVL	DX, (3*4)(DI)
+	MOVL	DX, (3*4)(BP)
+	MOVL	(4*4)(BP), AX		// H4 = e + H4
+	ADDL	(4*4)(DI), AX
+	MOVL	AX, (4*4)(DI)
+	MOVL	AX, (4*4)(BP)
+	MOVL	(5*4)(BP), BX		// H5 = f + H5
+	ADDL	(5*4)(DI), BX
+	MOVL	BX, (5*4)(DI)
+	MOVL	BX, (5*4)(BP)
+	MOVL	(6*4)(BP), CX		// H6 = g + H6
+	ADDL	(6*4)(DI), CX
+	MOVL	CX, (6*4)(DI)
+	MOVL	CX, (6*4)(BP)
+	MOVL	(7*4)(BP), DX		// H7 = h + H7
+	ADDL	(7*4)(DI), DX
+	MOVL	DX, (7*4)(DI)
+	MOVL	DX, (7*4)(BP)
+
+	ADDL	$64, SI
+	CMPL	SI, 288(SP)
+	JB	loop
+
+end:
+	RET
diff --git a/src/pkg/crypto/sha256/sha256block_amd64.s b/src/pkg/crypto/sha256/sha256block_amd64.s
new file mode 100644
index 0000000..95aebbe
--- /dev/null
+++ b/src/pkg/crypto/sha256/sha256block_amd64.s
@@ -0,0 +1,256 @@
+// 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 "../../../cmd/ld/textflag.h"
+
+// SHA256 block routine. See sha256block.go for Go equivalent.
+//
+// The algorithm is detailed in FIPS 180-4:
+//
+//  http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+//
+// Wt = Mt; for 0 <= t <= 15
+// Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
+//
+// a = H0
+// b = H1
+// c = H2
+// d = H3
+// e = H4
+// f = H5
+// g = H6
+// h = H7
+//
+// for t = 0 to 63 {
+//    T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt
+//    T2 = BIGSIGMA0(a) + Maj(a,b,c)
+//    h = g
+//    g = f
+//    f = e
+//    e = d + T1
+//    d = c
+//    c = b
+//    b = a
+//    a = T1 + T2
+// }
+//
+// H0 = a + H0
+// H1 = b + H1
+// H2 = c + H2
+// H3 = d + H3
+// H4 = e + H4
+// H5 = f + H5
+// H6 = g + H6
+// H7 = h + H7
+
+// Wt = Mt; for 0 <= t <= 15
+#define MSGSCHEDULE0(index) \
+	MOVL	(index*4)(SI), AX; \
+	BSWAPL	AX; \
+	MOVL	AX, (index*4)(BP)
+
+// Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
+//   SIGMA0(x) = ROTR(7,x) XOR ROTR(18,x) XOR SHR(3,x)
+//   SIGMA1(x) = ROTR(17,x) XOR ROTR(19,x) XOR SHR(10,x)
+#define MSGSCHEDULE1(index) \
+	MOVL	((index-2)*4)(BP), AX; \
+	MOVL	AX, CX; \
+	RORL	$17, AX; \
+	MOVL	CX, DX; \
+	RORL	$19, CX; \
+	SHRL	$10, DX; \
+	MOVL	((index-15)*4)(BP), BX; \
+	XORL	CX, AX; \
+	MOVL	BX, CX; \
+	XORL	DX, AX; \
+	RORL	$7, BX; \
+	MOVL	CX, DX; \
+	SHRL	$3, DX; \
+	RORL	$18, CX; \
+	ADDL	((index-7)*4)(BP), AX; \
+	XORL	CX, BX; \
+	XORL	DX, BX; \
+	ADDL	((index-16)*4)(BP), BX; \
+	ADDL	BX, AX; \
+	MOVL	AX, ((index)*4)(BP)
+
+// Calculate T1 in AX - uses AX, CX and DX registers.
+// h is also used as an accumulator. Wt is passed in AX.
+//   T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt
+//     BIGSIGMA1(x) = ROTR(6,x) XOR ROTR(11,x) XOR ROTR(25,x)
+//     Ch(x, y, z) = (x AND y) XOR (NOT x AND z)
+#define SHA256T1(const, e, f, g, h) \
+	ADDL	AX, h; \
+	MOVL	e, AX; \
+	ADDL	$const, h; \
+	MOVL	e, CX; \
+	RORL	$6, AX; \
+	MOVL	e, DX; \
+	RORL	$11, CX; \
+	XORL	CX, AX; \
+	MOVL	e, CX; \
+	RORL	$25, DX; \
+	ANDL	f, CX; \
+	XORL	AX, DX; \
+	MOVL	e, AX; \
+	NOTL	AX; \
+	ADDL	DX, h; \
+	ANDL	g, AX; \
+	XORL	CX, AX; \
+	ADDL	h, AX
+
+// Calculate T2 in BX - uses BX, CX, DX and DI registers.
+//   T2 = BIGSIGMA0(a) + Maj(a, b, c)
+//     BIGSIGMA0(x) = ROTR(2,x) XOR ROTR(13,x) XOR ROTR(22,x)
+//     Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)
+#define SHA256T2(a, b, c) \
+	MOVL	a, DI; \
+	MOVL	c, BX; \
+	RORL	$2, DI; \
+	MOVL	a, DX; \
+	ANDL	b, BX; \
+	RORL	$13, DX; \
+	MOVL	a, CX; \
+	ANDL	c, CX; \
+	XORL	DX, DI; \
+	XORL	CX, BX; \
+	MOVL	a, DX; \
+	MOVL	b, CX; \
+	RORL	$22, DX; \
+	ANDL	a, CX; \
+	XORL	CX, BX; \
+	XORL	DX, DI; \
+	ADDL	DI, BX
+
+// Calculate T1 and T2, then e = d + T1 and a = T1 + T2.
+// The values for e and a are stored in d and h, ready for rotation.
+#define SHA256ROUND(index, const, a, b, c, d, e, f, g, h) \
+	SHA256T1(const, e, f, g, h); \
+	SHA256T2(a, b, c); \
+	MOVL	BX, h; \
+	ADDL	AX, d; \
+	ADDL	AX, h
+
+#define SHA256ROUND0(index, const, a, b, c, d, e, f, g, h) \
+	MSGSCHEDULE0(index); \
+	SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
+
+#define SHA256ROUND1(index, const, a, b, c, d, e, f, g, h) \
+	MSGSCHEDULE1(index); \
+	SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
+
+TEXT ·block(SB),0,$264-32
+	MOVQ	p_base+8(FP), SI
+	MOVQ	p_len+16(FP), DX
+	SHRQ	$6, DX
+	SHLQ	$6, DX
+
+	LEAQ	(SI)(DX*1), DI
+	MOVQ	DI, 256(SP)
+	CMPQ	SI, DI
+	JEQ	end
+
+	MOVQ	dig+0(FP), BP
+	MOVL	(0*4)(BP), R8		// a = H0
+	MOVL	(1*4)(BP), R9		// b = H1
+	MOVL	(2*4)(BP), R10		// c = H2
+	MOVL	(3*4)(BP), R11		// d = H3
+	MOVL	(4*4)(BP), R12		// e = H4
+	MOVL	(5*4)(BP), R13		// f = H5
+	MOVL	(6*4)(BP), R14		// g = H6
+	MOVL	(7*4)(BP), R15		// h = H7
+
+loop:
+	MOVQ	SP, BP			// message schedule
+
+	SHA256ROUND0(0, 0x428a2f98, R8, R9, R10, R11, R12, R13, R14, R15)
+	SHA256ROUND0(1, 0x71374491, R15, R8, R9, R10, R11, R12, R13, R14)
+	SHA256ROUND0(2, 0xb5c0fbcf, R14, R15, R8, R9, R10, R11, R12, R13)
+	SHA256ROUND0(3, 0xe9b5dba5, R13, R14, R15, R8, R9, R10, R11, R12)
+	SHA256ROUND0(4, 0x3956c25b, R12, R13, R14, R15, R8, R9, R10, R11)
+	SHA256ROUND0(5, 0x59f111f1, R11, R12, R13, R14, R15, R8, R9, R10)
+	SHA256ROUND0(6, 0x923f82a4, R10, R11, R12, R13, R14, R15, R8, R9)
+	SHA256ROUND0(7, 0xab1c5ed5, R9, R10, R11, R12, R13, R14, R15, R8)
+	SHA256ROUND0(8, 0xd807aa98, R8, R9, R10, R11, R12, R13, R14, R15)
+	SHA256ROUND0(9, 0x12835b01, R15, R8, R9, R10, R11, R12, R13, R14)
+	SHA256ROUND0(10, 0x243185be, R14, R15, R8, R9, R10, R11, R12, R13)
+	SHA256ROUND0(11, 0x550c7dc3, R13, R14, R15, R8, R9, R10, R11, R12)
+	SHA256ROUND0(12, 0x72be5d74, R12, R13, R14, R15, R8, R9, R10, R11)
+	SHA256ROUND0(13, 0x80deb1fe, R11, R12, R13, R14, R15, R8, R9, R10)
+	SHA256ROUND0(14, 0x9bdc06a7, R10, R11, R12, R13, R14, R15, R8, R9)
+	SHA256ROUND0(15, 0xc19bf174, R9, R10, R11, R12, R13, R14, R15, R8)
+
+	SHA256ROUND1(16, 0xe49b69c1, R8, R9, R10, R11, R12, R13, R14, R15)
+	SHA256ROUND1(17, 0xefbe4786, R15, R8, R9, R10, R11, R12, R13, R14)
+	SHA256ROUND1(18, 0x0fc19dc6, R14, R15, R8, R9, R10, R11, R12, R13)
+	SHA256ROUND1(19, 0x240ca1cc, R13, R14, R15, R8, R9, R10, R11, R12)
+	SHA256ROUND1(20, 0x2de92c6f, R12, R13, R14, R15, R8, R9, R10, R11)
+	SHA256ROUND1(21, 0x4a7484aa, R11, R12, R13, R14, R15, R8, R9, R10)
+	SHA256ROUND1(22, 0x5cb0a9dc, R10, R11, R12, R13, R14, R15, R8, R9)
+	SHA256ROUND1(23, 0x76f988da, R9, R10, R11, R12, R13, R14, R15, R8)
+	SHA256ROUND1(24, 0x983e5152, R8, R9, R10, R11, R12, R13, R14, R15)
+	SHA256ROUND1(25, 0xa831c66d, R15, R8, R9, R10, R11, R12, R13, R14)
+	SHA256ROUND1(26, 0xb00327c8, R14, R15, R8, R9, R10, R11, R12, R13)
+	SHA256ROUND1(27, 0xbf597fc7, R13, R14, R15, R8, R9, R10, R11, R12)
+	SHA256ROUND1(28, 0xc6e00bf3, R12, R13, R14, R15, R8, R9, R10, R11)
+	SHA256ROUND1(29, 0xd5a79147, R11, R12, R13, R14, R15, R8, R9, R10)
+	SHA256ROUND1(30, 0x06ca6351, R10, R11, R12, R13, R14, R15, R8, R9)
+	SHA256ROUND1(31, 0x14292967, R9, R10, R11, R12, R13, R14, R15, R8)
+	SHA256ROUND1(32, 0x27b70a85, R8, R9, R10, R11, R12, R13, R14, R15)
+	SHA256ROUND1(33, 0x2e1b2138, R15, R8, R9, R10, R11, R12, R13, R14)
+	SHA256ROUND1(34, 0x4d2c6dfc, R14, R15, R8, R9, R10, R11, R12, R13)
+	SHA256ROUND1(35, 0x53380d13, R13, R14, R15, R8, R9, R10, R11, R12)
+	SHA256ROUND1(36, 0x650a7354, R12, R13, R14, R15, R8, R9, R10, R11)
+	SHA256ROUND1(37, 0x766a0abb, R11, R12, R13, R14, R15, R8, R9, R10)
+	SHA256ROUND1(38, 0x81c2c92e, R10, R11, R12, R13, R14, R15, R8, R9)
+	SHA256ROUND1(39, 0x92722c85, R9, R10, R11, R12, R13, R14, R15, R8)
+	SHA256ROUND1(40, 0xa2bfe8a1, R8, R9, R10, R11, R12, R13, R14, R15)
+	SHA256ROUND1(41, 0xa81a664b, R15, R8, R9, R10, R11, R12, R13, R14)
+	SHA256ROUND1(42, 0xc24b8b70, R14, R15, R8, R9, R10, R11, R12, R13)
+	SHA256ROUND1(43, 0xc76c51a3, R13, R14, R15, R8, R9, R10, R11, R12)
+	SHA256ROUND1(44, 0xd192e819, R12, R13, R14, R15, R8, R9, R10, R11)
+	SHA256ROUND1(45, 0xd6990624, R11, R12, R13, R14, R15, R8, R9, R10)
+	SHA256ROUND1(46, 0xf40e3585, R10, R11, R12, R13, R14, R15, R8, R9)
+	SHA256ROUND1(47, 0x106aa070, R9, R10, R11, R12, R13, R14, R15, R8)
+	SHA256ROUND1(48, 0x19a4c116, R8, R9, R10, R11, R12, R13, R14, R15)
+	SHA256ROUND1(49, 0x1e376c08, R15, R8, R9, R10, R11, R12, R13, R14)
+	SHA256ROUND1(50, 0x2748774c, R14, R15, R8, R9, R10, R11, R12, R13)
+	SHA256ROUND1(51, 0x34b0bcb5, R13, R14, R15, R8, R9, R10, R11, R12)
+	SHA256ROUND1(52, 0x391c0cb3, R12, R13, R14, R15, R8, R9, R10, R11)
+	SHA256ROUND1(53, 0x4ed8aa4a, R11, R12, R13, R14, R15, R8, R9, R10)
+	SHA256ROUND1(54, 0x5b9cca4f, R10, R11, R12, R13, R14, R15, R8, R9)
+	SHA256ROUND1(55, 0x682e6ff3, R9, R10, R11, R12, R13, R14, R15, R8)
+	SHA256ROUND1(56, 0x748f82ee, R8, R9, R10, R11, R12, R13, R14, R15)
+	SHA256ROUND1(57, 0x78a5636f, R15, R8, R9, R10, R11, R12, R13, R14)
+	SHA256ROUND1(58, 0x84c87814, R14, R15, R8, R9, R10, R11, R12, R13)
+	SHA256ROUND1(59, 0x8cc70208, R13, R14, R15, R8, R9, R10, R11, R12)
+	SHA256ROUND1(60, 0x90befffa, R12, R13, R14, R15, R8, R9, R10, R11)
+	SHA256ROUND1(61, 0xa4506ceb, R11, R12, R13, R14, R15, R8, R9, R10)
+	SHA256ROUND1(62, 0xbef9a3f7, R10, R11, R12, R13, R14, R15, R8, R9)
+	SHA256ROUND1(63, 0xc67178f2, R9, R10, R11, R12, R13, R14, R15, R8)
+
+	MOVQ	dig+0(FP), BP
+	ADDL	(0*4)(BP), R8	// H0 = a + H0
+	MOVL	R8, (0*4)(BP)
+	ADDL	(1*4)(BP), R9	// H1 = b + H1
+	MOVL	R9, (1*4)(BP)
+	ADDL	(2*4)(BP), R10	// H2 = c + H2
+	MOVL	R10, (2*4)(BP)
+	ADDL	(3*4)(BP), R11	// H3 = d + H3
+	MOVL	R11, (3*4)(BP)
+	ADDL	(4*4)(BP), R12	// H4 = e + H4
+	MOVL	R12, (4*4)(BP)
+	ADDL	(5*4)(BP), R13	// H5 = f + H5
+	MOVL	R13, (5*4)(BP)
+	ADDL	(6*4)(BP), R14	// H6 = g + H6
+	MOVL	R14, (6*4)(BP)
+	ADDL	(7*4)(BP), R15	// H7 = h + H7
+	MOVL	R15, (7*4)(BP)
+
+	ADDQ	$64, SI
+	CMPQ	SI, 256(SP)
+	JB	loop
+
+end:
+	RET
diff --git a/src/pkg/crypto/sha256/sha256block_decl.go b/src/pkg/crypto/sha256/sha256block_decl.go
new file mode 100644
index 0000000..a50c978
--- /dev/null
+++ b/src/pkg/crypto/sha256/sha256block_decl.go
@@ -0,0 +1,11 @@
+// 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 386 amd64
+
+package sha256
+
+//go:noescape
+
+func block(dig *digest, p []byte)
diff --git a/src/pkg/crypto/sha512/sha512.go b/src/pkg/crypto/sha512/sha512.go
index d2ada51..bca7a91 100644
--- a/src/pkg/crypto/sha512/sha512.go
+++ b/src/pkg/crypto/sha512/sha512.go
@@ -106,16 +106,10 @@ func (d *digest) Write(p []byte) (nn int, err error) {
 	nn = len(p)
 	d.len += uint64(nn)
 	if d.nx > 0 {
-		n := len(p)
-		if n > chunk-d.nx {
-			n = chunk - d.nx
-		}
-		for i := 0; i < n; i++ {
-			d.x[d.nx+i] = p[i]
-		}
+		n := copy(d.x[d.nx:], p)
 		d.nx += n
 		if d.nx == chunk {
-			block(d, d.x[0:])
+			block(d, d.x[:])
 			d.nx = 0
 		}
 		p = p[n:]
diff --git a/src/pkg/crypto/sha512/sha512_test.go b/src/pkg/crypto/sha512/sha512_test.go
index 167c20a..541860f 100644
--- a/src/pkg/crypto/sha512/sha512_test.go
+++ b/src/pkg/crypto/sha512/sha512_test.go
@@ -132,6 +132,24 @@ func TestGolden(t *testing.T) {
 	}
 }
 
+func TestSize(t *testing.T) {
+	c := New()
+	if got := c.Size(); got != Size {
+		t.Errorf("Size = %d; want %d", got, Size)
+	}
+	c = New384()
+	if got := c.Size(); got != Size384 {
+		t.Errorf("New384.Size = %d; want %d", got, Size384)
+	}
+}
+
+func TestBlockSize(t *testing.T) {
+	c := New()
+	if got := c.BlockSize(); got != BlockSize {
+		t.Errorf("BlockSize = %d; want %d", got, BlockSize)
+	}
+}
+
 var bench = New()
 var buf = make([]byte, 8192)
 
diff --git a/src/pkg/crypto/sha512/sha512block.go b/src/pkg/crypto/sha512/sha512block.go
index 3577b4f..648ae8f 100644
--- a/src/pkg/crypto/sha512/sha512block.go
+++ b/src/pkg/crypto/sha512/sha512block.go
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build !amd64
+
 // SHA512 block step.
 // In its own file so that a faster assembly or C version
 // can be substituted easily.
diff --git a/src/pkg/crypto/sha512/sha512block_amd64.s b/src/pkg/crypto/sha512/sha512block_amd64.s
new file mode 100644
index 0000000..344d8d2
--- /dev/null
+++ b/src/pkg/crypto/sha512/sha512block_amd64.s
@@ -0,0 +1,273 @@
+// 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 "../../../cmd/ld/textflag.h"
+
+// SHA512 block routine. See sha512block.go for Go equivalent.
+//
+// The algorithm is detailed in FIPS 180-4:
+//
+//  http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+//
+// Wt = Mt; for 0 <= t <= 15
+// Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79
+//
+// a = H0
+// b = H1
+// c = H2
+// d = H3
+// e = H4
+// f = H5
+// g = H6
+// h = H7
+//
+// for t = 0 to 79 {
+//    T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt
+//    T2 = BIGSIGMA0(a) + Maj(a,b,c)
+//    h = g
+//    g = f
+//    f = e
+//    e = d + T1
+//    d = c
+//    c = b
+//    b = a
+//    a = T1 + T2
+// }
+//
+// H0 = a + H0
+// H1 = b + H1
+// H2 = c + H2
+// H3 = d + H3
+// H4 = e + H4
+// H5 = f + H5
+// H6 = g + H6
+// H7 = h + H7
+
+// Wt = Mt; for 0 <= t <= 15
+#define MSGSCHEDULE0(index) \
+	MOVQ	(index*8)(SI), AX; \
+	BSWAPQ	AX; \
+	MOVQ	AX, (index*8)(BP)
+
+// Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79
+//   SIGMA0(x) = ROTR(1,x) XOR ROTR(8,x) XOR SHR(7,x)
+//   SIGMA1(x) = ROTR(19,x) XOR ROTR(61,x) XOR SHR(6,x)
+#define MSGSCHEDULE1(index) \
+	MOVQ	((index-2)*8)(BP), AX; \
+	MOVQ	AX, CX; \
+	RORQ	$19, AX; \
+	MOVQ	CX, DX; \
+	RORQ	$61, CX; \
+	SHRQ	$6, DX; \
+	MOVQ	((index-15)*8)(BP), BX; \
+	XORQ	CX, AX; \
+	MOVQ	BX, CX; \
+	XORQ	DX, AX; \
+	RORQ	$1, BX; \
+	MOVQ	CX, DX; \
+	SHRQ	$7, DX; \
+	RORQ	$8, CX; \
+	ADDQ	((index-7)*8)(BP), AX; \
+	XORQ	CX, BX; \
+	XORQ	DX, BX; \
+	ADDQ	((index-16)*8)(BP), BX; \
+	ADDQ	BX, AX; \
+	MOVQ	AX, ((index)*8)(BP)
+
+// Calculate T1 in AX - uses AX, CX and DX registers.
+// h is also used as an accumulator. Wt is passed in AX.
+//   T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt
+//     BIGSIGMA1(x) = ROTR(14,x) XOR ROTR(18,x) XOR ROTR(41,x)
+//     Ch(x, y, z) = (x AND y) XOR (NOT x AND z)
+#define SHA512T1(const, e, f, g, h) \
+	MOVQ	$const, DX; \
+	ADDQ	AX, h; \
+	MOVQ	e, AX; \
+	ADDQ	DX, h; \
+	MOVQ	e, CX; \
+	RORQ	$14, AX; \
+	MOVQ	e, DX; \
+	RORQ	$18, CX; \
+	XORQ	CX, AX; \
+	MOVQ	e, CX; \
+	RORQ	$41, DX; \
+	ANDQ	f, CX; \
+	XORQ	AX, DX; \
+	MOVQ	e, AX; \
+	NOTQ	AX; \
+	ADDQ	DX, h; \
+	ANDQ	g, AX; \
+	XORQ	CX, AX; \
+	ADDQ	h, AX
+
+// Calculate T2 in BX - uses BX, CX, DX and DI registers.
+//   T2 = BIGSIGMA0(a) + Maj(a, b, c)
+//     BIGSIGMA0(x) = ROTR(28,x) XOR ROTR(34,x) XOR ROTR(39,x)
+//     Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)
+#define SHA512T2(a, b, c) \
+	MOVQ	a, DI; \
+	MOVQ	c, BX; \
+	RORQ	$28, DI; \
+	MOVQ	a, DX; \
+	ANDQ	b, BX; \
+	RORQ	$34, DX; \
+	MOVQ	a, CX; \
+	ANDQ	c, CX; \
+	XORQ	DX, DI; \
+	XORQ	CX, BX; \
+	MOVQ	a, DX; \
+	MOVQ	b, CX; \
+	RORQ	$39, DX; \
+	ANDQ	a, CX; \
+	XORQ	CX, BX; \
+	XORQ	DX, DI; \
+	ADDQ	DI, BX
+
+// Calculate T1 and T2, then e = d + T1 and a = T1 + T2.
+// The values for e and a are stored in d and h, ready for rotation.
+#define SHA512ROUND(index, const, a, b, c, d, e, f, g, h) \
+	SHA512T1(const, e, f, g, h); \
+	SHA512T2(a, b, c); \
+	MOVQ	BX, h; \
+	ADDQ	AX, d; \
+	ADDQ	AX, h
+
+#define SHA512ROUND0(index, const, a, b, c, d, e, f, g, h) \
+	MSGSCHEDULE0(index); \
+	SHA512ROUND(index, const, a, b, c, d, e, f, g, h)
+
+#define SHA512ROUND1(index, const, a, b, c, d, e, f, g, h) \
+	MSGSCHEDULE1(index); \
+	SHA512ROUND(index, const, a, b, c, d, e, f, g, h)
+
+TEXT ·block(SB),0,$648-32
+	MOVQ	p_base+8(FP), SI
+	MOVQ	p_len+16(FP), DX
+	SHRQ	$7, DX
+	SHLQ	$7, DX
+
+	LEAQ	(SI)(DX*1), DI
+	MOVQ	DI, 640(SP)
+	CMPQ	SI, DI
+	JEQ	end
+
+	MOVQ	dig+0(FP), BP
+	MOVQ	(0*8)(BP), R8		// a = H0
+	MOVQ	(1*8)(BP), R9		// b = H1
+	MOVQ	(2*8)(BP), R10		// c = H2
+	MOVQ	(3*8)(BP), R11		// d = H3
+	MOVQ	(4*8)(BP), R12		// e = H4
+	MOVQ	(5*8)(BP), R13		// f = H5
+	MOVQ	(6*8)(BP), R14		// g = H6
+	MOVQ	(7*8)(BP), R15		// h = H7
+
+loop:
+	MOVQ	SP, BP			// message schedule
+
+	SHA512ROUND0(0, 0x428a2f98d728ae22, R8, R9, R10, R11, R12, R13, R14, R15)
+	SHA512ROUND0(1, 0x7137449123ef65cd, R15, R8, R9, R10, R11, R12, R13, R14)
+	SHA512ROUND0(2, 0xb5c0fbcfec4d3b2f, R14, R15, R8, R9, R10, R11, R12, R13)
+	SHA512ROUND0(3, 0xe9b5dba58189dbbc, R13, R14, R15, R8, R9, R10, R11, R12)
+	SHA512ROUND0(4, 0x3956c25bf348b538, R12, R13, R14, R15, R8, R9, R10, R11)
+	SHA512ROUND0(5, 0x59f111f1b605d019, R11, R12, R13, R14, R15, R8, R9, R10)
+	SHA512ROUND0(6, 0x923f82a4af194f9b, R10, R11, R12, R13, R14, R15, R8, R9)
+	SHA512ROUND0(7, 0xab1c5ed5da6d8118, R9, R10, R11, R12, R13, R14, R15, R8)
+	SHA512ROUND0(8, 0xd807aa98a3030242, R8, R9, R10, R11, R12, R13, R14, R15)
+	SHA512ROUND0(9, 0x12835b0145706fbe, R15, R8, R9, R10, R11, R12, R13, R14)
+	SHA512ROUND0(10, 0x243185be4ee4b28c, R14, R15, R8, R9, R10, R11, R12, R13)
+	SHA512ROUND0(11, 0x550c7dc3d5ffb4e2, R13, R14, R15, R8, R9, R10, R11, R12)
+	SHA512ROUND0(12, 0x72be5d74f27b896f, R12, R13, R14, R15, R8, R9, R10, R11)
+	SHA512ROUND0(13, 0x80deb1fe3b1696b1, R11, R12, R13, R14, R15, R8, R9, R10)
+	SHA512ROUND0(14, 0x9bdc06a725c71235, R10, R11, R12, R13, R14, R15, R8, R9)
+	SHA512ROUND0(15, 0xc19bf174cf692694, R9, R10, R11, R12, R13, R14, R15, R8)
+
+	SHA512ROUND1(16, 0xe49b69c19ef14ad2, R8, R9, R10, R11, R12, R13, R14, R15)
+	SHA512ROUND1(17, 0xefbe4786384f25e3, R15, R8, R9, R10, R11, R12, R13, R14)
+	SHA512ROUND1(18, 0x0fc19dc68b8cd5b5, R14, R15, R8, R9, R10, R11, R12, R13)
+	SHA512ROUND1(19, 0x240ca1cc77ac9c65, R13, R14, R15, R8, R9, R10, R11, R12)
+	SHA512ROUND1(20, 0x2de92c6f592b0275, R12, R13, R14, R15, R8, R9, R10, R11)
+	SHA512ROUND1(21, 0x4a7484aa6ea6e483, R11, R12, R13, R14, R15, R8, R9, R10)
+	SHA512ROUND1(22, 0x5cb0a9dcbd41fbd4, R10, R11, R12, R13, R14, R15, R8, R9)
+	SHA512ROUND1(23, 0x76f988da831153b5, R9, R10, R11, R12, R13, R14, R15, R8)
+	SHA512ROUND1(24, 0x983e5152ee66dfab, R8, R9, R10, R11, R12, R13, R14, R15)
+	SHA512ROUND1(25, 0xa831c66d2db43210, R15, R8, R9, R10, R11, R12, R13, R14)
+	SHA512ROUND1(26, 0xb00327c898fb213f, R14, R15, R8, R9, R10, R11, R12, R13)
+	SHA512ROUND1(27, 0xbf597fc7beef0ee4, R13, R14, R15, R8, R9, R10, R11, R12)
+	SHA512ROUND1(28, 0xc6e00bf33da88fc2, R12, R13, R14, R15, R8, R9, R10, R11)
+	SHA512ROUND1(29, 0xd5a79147930aa725, R11, R12, R13, R14, R15, R8, R9, R10)
+	SHA512ROUND1(30, 0x06ca6351e003826f, R10, R11, R12, R13, R14, R15, R8, R9)
+	SHA512ROUND1(31, 0x142929670a0e6e70, R9, R10, R11, R12, R13, R14, R15, R8)
+	SHA512ROUND1(32, 0x27b70a8546d22ffc, R8, R9, R10, R11, R12, R13, R14, R15)
+	SHA512ROUND1(33, 0x2e1b21385c26c926, R15, R8, R9, R10, R11, R12, R13, R14)
+	SHA512ROUND1(34, 0x4d2c6dfc5ac42aed, R14, R15, R8, R9, R10, R11, R12, R13)
+	SHA512ROUND1(35, 0x53380d139d95b3df, R13, R14, R15, R8, R9, R10, R11, R12)
+	SHA512ROUND1(36, 0x650a73548baf63de, R12, R13, R14, R15, R8, R9, R10, R11)
+	SHA512ROUND1(37, 0x766a0abb3c77b2a8, R11, R12, R13, R14, R15, R8, R9, R10)
+	SHA512ROUND1(38, 0x81c2c92e47edaee6, R10, R11, R12, R13, R14, R15, R8, R9)
+	SHA512ROUND1(39, 0x92722c851482353b, R9, R10, R11, R12, R13, R14, R15, R8)
+	SHA512ROUND1(40, 0xa2bfe8a14cf10364, R8, R9, R10, R11, R12, R13, R14, R15)
+	SHA512ROUND1(41, 0xa81a664bbc423001, R15, R8, R9, R10, R11, R12, R13, R14)
+	SHA512ROUND1(42, 0xc24b8b70d0f89791, R14, R15, R8, R9, R10, R11, R12, R13)
+	SHA512ROUND1(43, 0xc76c51a30654be30, R13, R14, R15, R8, R9, R10, R11, R12)
+	SHA512ROUND1(44, 0xd192e819d6ef5218, R12, R13, R14, R15, R8, R9, R10, R11)
+	SHA512ROUND1(45, 0xd69906245565a910, R11, R12, R13, R14, R15, R8, R9, R10)
+	SHA512ROUND1(46, 0xf40e35855771202a, R10, R11, R12, R13, R14, R15, R8, R9)
+	SHA512ROUND1(47, 0x106aa07032bbd1b8, R9, R10, R11, R12, R13, R14, R15, R8)
+	SHA512ROUND1(48, 0x19a4c116b8d2d0c8, R8, R9, R10, R11, R12, R13, R14, R15)
+	SHA512ROUND1(49, 0x1e376c085141ab53, R15, R8, R9, R10, R11, R12, R13, R14)
+	SHA512ROUND1(50, 0x2748774cdf8eeb99, R14, R15, R8, R9, R10, R11, R12, R13)
+	SHA512ROUND1(51, 0x34b0bcb5e19b48a8, R13, R14, R15, R8, R9, R10, R11, R12)
+	SHA512ROUND1(52, 0x391c0cb3c5c95a63, R12, R13, R14, R15, R8, R9, R10, R11)
+	SHA512ROUND1(53, 0x4ed8aa4ae3418acb, R11, R12, R13, R14, R15, R8, R9, R10)
+	SHA512ROUND1(54, 0x5b9cca4f7763e373, R10, R11, R12, R13, R14, R15, R8, R9)
+	SHA512ROUND1(55, 0x682e6ff3d6b2b8a3, R9, R10, R11, R12, R13, R14, R15, R8)
+	SHA512ROUND1(56, 0x748f82ee5defb2fc, R8, R9, R10, R11, R12, R13, R14, R15)
+	SHA512ROUND1(57, 0x78a5636f43172f60, R15, R8, R9, R10, R11, R12, R13, R14)
+	SHA512ROUND1(58, 0x84c87814a1f0ab72, R14, R15, R8, R9, R10, R11, R12, R13)
+	SHA512ROUND1(59, 0x8cc702081a6439ec, R13, R14, R15, R8, R9, R10, R11, R12)
+	SHA512ROUND1(60, 0x90befffa23631e28, R12, R13, R14, R15, R8, R9, R10, R11)
+	SHA512ROUND1(61, 0xa4506cebde82bde9, R11, R12, R13, R14, R15, R8, R9, R10)
+	SHA512ROUND1(62, 0xbef9a3f7b2c67915, R10, R11, R12, R13, R14, R15, R8, R9)
+	SHA512ROUND1(63, 0xc67178f2e372532b, R9, R10, R11, R12, R13, R14, R15, R8)
+	SHA512ROUND1(64, 0xca273eceea26619c, R8, R9, R10, R11, R12, R13, R14, R15)
+	SHA512ROUND1(65, 0xd186b8c721c0c207, R15, R8, R9, R10, R11, R12, R13, R14)
+	SHA512ROUND1(66, 0xeada7dd6cde0eb1e, R14, R15, R8, R9, R10, R11, R12, R13)
+	SHA512ROUND1(67, 0xf57d4f7fee6ed178, R13, R14, R15, R8, R9, R10, R11, R12)
+	SHA512ROUND1(68, 0x06f067aa72176fba, R12, R13, R14, R15, R8, R9, R10, R11)
+	SHA512ROUND1(69, 0x0a637dc5a2c898a6, R11, R12, R13, R14, R15, R8, R9, R10)
+	SHA512ROUND1(70, 0x113f9804bef90dae, R10, R11, R12, R13, R14, R15, R8, R9)
+	SHA512ROUND1(71, 0x1b710b35131c471b, R9, R10, R11, R12, R13, R14, R15, R8)
+	SHA512ROUND1(72, 0x28db77f523047d84, R8, R9, R10, R11, R12, R13, R14, R15)
+	SHA512ROUND1(73, 0x32caab7b40c72493, R15, R8, R9, R10, R11, R12, R13, R14)
+	SHA512ROUND1(74, 0x3c9ebe0a15c9bebc, R14, R15, R8, R9, R10, R11, R12, R13)
+	SHA512ROUND1(75, 0x431d67c49c100d4c, R13, R14, R15, R8, R9, R10, R11, R12)
+	SHA512ROUND1(76, 0x4cc5d4becb3e42b6, R12, R13, R14, R15, R8, R9, R10, R11)
+	SHA512ROUND1(77, 0x597f299cfc657e2a, R11, R12, R13, R14, R15, R8, R9, R10)
+	SHA512ROUND1(78, 0x5fcb6fab3ad6faec, R10, R11, R12, R13, R14, R15, R8, R9)
+	SHA512ROUND1(79, 0x6c44198c4a475817, R9, R10, R11, R12, R13, R14, R15, R8)
+
+	MOVQ	dig+0(FP), BP
+	ADDQ	(0*8)(BP), R8	// H0 = a + H0
+	MOVQ	R8, (0*8)(BP)
+	ADDQ	(1*8)(BP), R9	// H1 = b + H1
+	MOVQ	R9, (1*8)(BP)
+	ADDQ	(2*8)(BP), R10	// H2 = c + H2
+	MOVQ	R10, (2*8)(BP)
+	ADDQ	(3*8)(BP), R11	// H3 = d + H3
+	MOVQ	R11, (3*8)(BP)
+	ADDQ	(4*8)(BP), R12	// H4 = e + H4
+	MOVQ	R12, (4*8)(BP)
+	ADDQ	(5*8)(BP), R13	// H5 = f + H5
+	MOVQ	R13, (5*8)(BP)
+	ADDQ	(6*8)(BP), R14	// H6 = g + H6
+	MOVQ	R14, (6*8)(BP)
+	ADDQ	(7*8)(BP), R15	// H7 = h + H7
+	MOVQ	R15, (7*8)(BP)
+
+	ADDQ	$128, SI
+	CMPQ	SI, 640(SP)
+	JB	loop
+
+end:
+	RET
diff --git a/src/pkg/crypto/sha512/sha512block_decl.go b/src/pkg/crypto/sha512/sha512block_decl.go
new file mode 100644
index 0000000..bef99de
--- /dev/null
+++ b/src/pkg/crypto/sha512/sha512block_decl.go
@@ -0,0 +1,11 @@
+// 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 amd64
+
+package sha512
+
+//go:noescape
+
+func block(dig *digest, p []byte)
diff --git a/src/pkg/crypto/subtle/constant_time.go b/src/pkg/crypto/subtle/constant_time.go
index dfb6584..de1a4e8 100644
--- a/src/pkg/crypto/subtle/constant_time.go
+++ b/src/pkg/crypto/subtle/constant_time.go
@@ -10,6 +10,10 @@ package subtle
 // and y, have equal contents. The time taken is a function of the length of
 // the slices and is independent of the contents.
 func ConstantTimeCompare(x, y []byte) int {
+	if len(x) != len(y) {
+		panic("subtle: slices have different lengths")
+	}
+
 	var v byte
 
 	for i := 0; i < len(x); i++ {
diff --git a/src/pkg/crypto/tls/common.go b/src/pkg/crypto/tls/common.go
index b7229d2..fca98bd 100644
--- a/src/pkg/crypto/tls/common.go
+++ b/src/pkg/crypto/tls/common.go
@@ -5,9 +5,11 @@
 package tls
 
 import (
+	"container/list"
 	"crypto"
 	"crypto/rand"
 	"crypto/x509"
+	"fmt"
 	"io"
 	"math/big"
 	"strings"
@@ -64,7 +66,7 @@ const (
 )
 
 // TLS extension numbers
-var (
+const (
 	extensionServerName          uint16 = 0
 	extensionStatusRequest       uint16 = 5
 	extensionSupportedCurves     uint16 = 10
@@ -72,19 +74,27 @@ var (
 	extensionSignatureAlgorithms uint16 = 13
 	extensionSessionTicket       uint16 = 35
 	extensionNextProtoNeg        uint16 = 13172 // not IANA assigned
+	extensionRenegotiationInfo   uint16 = 0xff01
+)
+
+// TLS signaling cipher suite values
+const (
+	scsvRenegotiation uint16 = 0x00ff
 )
 
-// TLS Elliptic Curves
+// CurveID is the type of a TLS identifier for an elliptic curve. See
 // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
-var (
-	curveP256 uint16 = 23
-	curveP384 uint16 = 24
-	curveP521 uint16 = 25
+type CurveID uint16
+
+const (
+	CurveP256 CurveID = 23
+	CurveP384 CurveID = 24
+	CurveP521 CurveID = 25
 )
 
 // TLS Elliptic Curve Point Formats
 // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9
-var (
+const (
 	pointFormatUncompressed uint8 = 0
 )
 
@@ -145,6 +155,7 @@ var supportedClientCertSignatureAlgorithms = []signatureAndHash{
 
 // ConnectionState records basic TLS details about the connection.
 type ConnectionState struct {
+	Version                    uint16                // TLS version used by the connection (e.g. VersionTLS12)
 	HandshakeComplete          bool                  // TLS handshake is complete
 	DidResume                  bool                  // connection resumes a previous TLS connection
 	CipherSuite                uint16                // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...)
@@ -167,12 +178,38 @@ const (
 	RequireAndVerifyClientCert
 )
 
-// A Config structure is used to configure a TLS client or server. After one
-// has been passed to a TLS function it must not be modified.
+// ClientSessionState contains the state needed by clients to resume TLS
+// sessions.
+type ClientSessionState struct {
+	sessionTicket      []uint8             // Encrypted ticket used for session resumption with server
+	vers               uint16              // SSL/TLS version negotiated for the session
+	cipherSuite        uint16              // Ciphersuite negotiated for the session
+	masterSecret       []byte              // MasterSecret generated by client on a full handshake
+	serverCertificates []*x509.Certificate // Certificate chain presented by the server
+}
+
+// ClientSessionCache is a cache of ClientSessionState objects that can be used
+// by a client to resume a TLS session with a given server. ClientSessionCache
+// implementations should expect to be called concurrently from different
+// goroutines.
+type ClientSessionCache interface {
+	// Get searches for a ClientSessionState associated with the given key.
+	// On return, ok is true if one was found.
+	Get(sessionKey string) (session *ClientSessionState, ok bool)
+
+	// Put adds the ClientSessionState to the cache with the given key.
+	Put(sessionKey string, cs *ClientSessionState)
+}
+
+// A Config structure is used to configure a TLS client or server.
+// After one has been passed to a TLS function it must not be
+// modified. A Config may be reused; the tls package will also not
+// modify it.
 type Config struct {
 	// Rand provides the source of entropy for nonces and RSA blinding.
 	// If Rand is nil, TLS uses the cryptographic random reader in package
 	// crypto/rand.
+	// The Reader must be safe for use by multiple goroutines.
 	Rand io.Reader
 
 	// Time returns the current time as the number of seconds since the epoch.
@@ -200,8 +237,9 @@ type Config struct {
 	// NextProtos is a list of supported, application level protocols.
 	NextProtos []string
 
-	// ServerName is included in the client's handshake to support virtual
-	// hosting.
+	// ServerName is used to verify the hostname on the returned
+	// certificates unless InsecureSkipVerify is given. It is also included
+	// in the client's handshake to support virtual hosting.
 	ServerName string
 
 	// ClientAuth determines the server's policy for
@@ -245,6 +283,10 @@ type Config struct {
 	// connections using that key are compromised.
 	SessionTicketKey [32]byte
 
+	// SessionCache is a cache of ClientSessionState entries for TLS session
+	// resumption.
+	ClientSessionCache ClientSessionCache
+
 	// MinVersion contains the minimum SSL/TLS version that is acceptable.
 	// If zero, then SSLv3 is taken as the minimum.
 	MinVersion uint16
@@ -254,6 +296,11 @@ type Config struct {
 	// which is currently TLS 1.2.
 	MaxVersion uint16
 
+	// CurvePreferences contains the elliptic curves that will be used in
+	// an ECDHE handshake, in preference order. If empty, the default will
+	// be used.
+	CurvePreferences []CurveID
+
 	serverInitOnce sync.Once // guards calling (*Config).serverInit
 }
 
@@ -312,6 +359,15 @@ func (c *Config) maxVersion() uint16 {
 	return c.MaxVersion
 }
 
+var defaultCurvePreferences = []CurveID{CurveP256, CurveP384, CurveP521}
+
+func (c *Config) curvePreferences() []CurveID {
+	if c == nil || len(c.CurvePreferences) == 0 {
+		return defaultCurvePreferences
+	}
+	return c.CurvePreferences
+}
+
 // mutualVersion returns the protocol version to use given the advertised
 // version of the peer.
 func (c *Config) mutualVersion(vers uint16) (uint16, bool) {
@@ -406,6 +462,77 @@ type handshakeMessage interface {
 	unmarshal([]byte) bool
 }
 
+// lruSessionCache is a ClientSessionCache implementation that uses an LRU
+// caching strategy.
+type lruSessionCache struct {
+	sync.Mutex
+
+	m        map[string]*list.Element
+	q        *list.List
+	capacity int
+}
+
+type lruSessionCacheEntry struct {
+	sessionKey string
+	state      *ClientSessionState
+}
+
+// NewLRUClientSessionCache returns a ClientSessionCache with the given
+// capacity that uses an LRU strategy. If capacity is < 1, a default capacity
+// is used instead.
+func NewLRUClientSessionCache(capacity int) ClientSessionCache {
+	const defaultSessionCacheCapacity = 64
+
+	if capacity < 1 {
+		capacity = defaultSessionCacheCapacity
+	}
+	return &lruSessionCache{
+		m:        make(map[string]*list.Element),
+		q:        list.New(),
+		capacity: capacity,
+	}
+}
+
+// Put adds the provided (sessionKey, cs) pair to the cache.
+func (c *lruSessionCache) Put(sessionKey string, cs *ClientSessionState) {
+	c.Lock()
+	defer c.Unlock()
+
+	if elem, ok := c.m[sessionKey]; ok {
+		entry := elem.Value.(*lruSessionCacheEntry)
+		entry.state = cs
+		c.q.MoveToFront(elem)
+		return
+	}
+
+	if c.q.Len() < c.capacity {
+		entry := &lruSessionCacheEntry{sessionKey, cs}
+		c.m[sessionKey] = c.q.PushFront(entry)
+		return
+	}
+
+	elem := c.q.Back()
+	entry := elem.Value.(*lruSessionCacheEntry)
+	delete(c.m, entry.sessionKey)
+	entry.sessionKey = sessionKey
+	entry.state = cs
+	c.q.MoveToFront(elem)
+	c.m[sessionKey] = elem
+}
+
+// Get returns the ClientSessionState value associated with a given key. It
+// returns (nil, false) if no value is found.
+func (c *lruSessionCache) Get(sessionKey string) (*ClientSessionState, bool) {
+	c.Lock()
+	defer c.Unlock()
+
+	if elem, ok := c.m[sessionKey]; ok {
+		c.q.MoveToFront(elem)
+		return elem.Value.(*lruSessionCacheEntry).state, true
+	}
+	return nil, false
+}
+
 // TODO(jsing): Make these available to both crypto/x509 and crypto/tls.
 type dsaSignature struct {
 	R, S *big.Int
@@ -435,3 +562,7 @@ func initDefaultCipherSuites() {
 		varDefaultCipherSuites[i] = suite.id
 	}
 }
+
+func unexpectedMessageError(wanted, got interface{}) error {
+	return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted)
+}
diff --git a/src/pkg/crypto/tls/conn.go b/src/pkg/crypto/tls/conn.go
index 2e64b88..8f7d2c1 100644
--- a/src/pkg/crypto/tls/conn.go
+++ b/src/pkg/crypto/tls/conn.go
@@ -12,6 +12,7 @@ import (
 	"crypto/subtle"
 	"crypto/x509"
 	"errors"
+	"fmt"
 	"io"
 	"net"
 	"sync"
@@ -27,6 +28,7 @@ type Conn struct {
 
 	// constant after handshake; protected by handshakeMutex
 	handshakeMutex    sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
+	handshakeErr      error      // error resulting from handshake
 	vers              uint16     // TLS version
 	haveVers          bool       // version has been negotiated
 	config            *Config    // configuration passed to constructor
@@ -44,9 +46,6 @@ type Conn struct {
 	clientProtocol         string
 	clientProtocolFallback bool
 
-	// first permanent error
-	connErr
-
 	// input/output
 	in, out  halfConn     // in.Mutex < out.Mutex
 	rawInput *block       // raw input, right off the wire
@@ -56,27 +55,6 @@ type Conn struct {
 	tmp [16]byte
 }
 
-type connErr struct {
-	mu    sync.Mutex
-	value error
-}
-
-func (e *connErr) setError(err error) error {
-	e.mu.Lock()
-	defer e.mu.Unlock()
-
-	if e.value == nil {
-		e.value = err
-	}
-	return err
-}
-
-func (e *connErr) error() error {
-	e.mu.Lock()
-	defer e.mu.Unlock()
-	return e.value
-}
-
 // Access to net.Conn methods.
 // Cannot just embed net.Conn because that would
 // export the struct field too.
@@ -104,7 +82,7 @@ func (c *Conn) SetReadDeadline(t time.Time) error {
 	return c.conn.SetReadDeadline(t)
 }
 
-// SetWriteDeadline sets the write deadline on the underlying conneciton.
+// SetWriteDeadline sets the write deadline on the underlying connection.
 // A zero value for t means Write will not time out.
 // After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.
 func (c *Conn) SetWriteDeadline(t time.Time) error {
@@ -115,6 +93,8 @@ func (c *Conn) SetWriteDeadline(t time.Time) error {
 // connection, either sending or receiving.
 type halfConn struct {
 	sync.Mutex
+
+	err     error       // first permanent error
 	version uint16      // protocol version
 	cipher  interface{} // cipher algorithm
 	mac     macFunction
@@ -128,6 +108,18 @@ type halfConn struct {
 	inDigestBuf, outDigestBuf []byte
 }
 
+func (hc *halfConn) setErrorLocked(err error) error {
+	hc.err = err
+	return err
+}
+
+func (hc *halfConn) error() error {
+	hc.Lock()
+	err := hc.err
+	hc.Unlock()
+	return err
+}
+
 // prepareCipherSpec sets the encryption and MAC states
 // that a subsequent changeCipherSpec will use.
 func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) {
@@ -459,6 +451,8 @@ func (b *block) readFromUntil(r io.Reader, n int) error {
 		m, err := r.Read(b.data[len(b.data):cap(b.data)])
 		b.data = b.data[0 : len(b.data)+m]
 		if len(b.data) >= n {
+			// TODO(bradfitz,agl): slightly suspicious
+			// that we're throwing away r.Read's err here.
 			break
 		}
 		if err != nil {
@@ -518,14 +512,17 @@ func (c *Conn) readRecord(want recordType) error {
 	// else application data.  (We don't support renegotiation.)
 	switch want {
 	default:
-		return c.sendAlert(alertInternalError)
+		c.sendAlert(alertInternalError)
+		return c.in.setErrorLocked(errors.New("tls: unknown record type requested"))
 	case recordTypeHandshake, recordTypeChangeCipherSpec:
 		if c.handshakeComplete {
-			return c.sendAlert(alertInternalError)
+			c.sendAlert(alertInternalError)
+			return c.in.setErrorLocked(errors.New("tls: handshake or ChangeCipherSpec requested after handshake complete"))
 		}
 	case recordTypeApplicationData:
 		if !c.handshakeComplete {
-			return c.sendAlert(alertInternalError)
+			c.sendAlert(alertInternalError)
+			return c.in.setErrorLocked(errors.New("tls: application data record requested before handshake complete"))
 		}
 	}
 
@@ -544,7 +541,7 @@ Again:
 		// 	err = io.ErrUnexpectedEOF
 		// }
 		if e, ok := err.(net.Error); !ok || !e.Temporary() {
-			c.setError(err)
+			c.in.setErrorLocked(err)
 		}
 		return err
 	}
@@ -556,16 +553,18 @@ Again:
 	// an SSLv2 client.
 	if want == recordTypeHandshake && typ == 0x80 {
 		c.sendAlert(alertProtocolVersion)
-		return errors.New("tls: unsupported SSLv2 handshake received")
+		return c.in.setErrorLocked(errors.New("tls: unsupported SSLv2 handshake received"))
 	}
 
 	vers := uint16(b.data[1])<<8 | uint16(b.data[2])
 	n := int(b.data[3])<<8 | int(b.data[4])
 	if c.haveVers && vers != c.vers {
-		return c.sendAlert(alertProtocolVersion)
+		c.sendAlert(alertProtocolVersion)
+		return c.in.setErrorLocked(fmt.Errorf("tls: received record with version %x when expecting version %x", vers, c.vers))
 	}
 	if n > maxCiphertext {
-		return c.sendAlert(alertRecordOverflow)
+		c.sendAlert(alertRecordOverflow)
+		return c.in.setErrorLocked(fmt.Errorf("tls: oversized record received with length %d", n))
 	}
 	if !c.haveVers {
 		// First message, be extra suspicious:
@@ -577,7 +576,8 @@ Again:
 		// well under a kilobyte.  If the length is >= 12 kB,
 		// it's probably not real.
 		if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 || n >= 0x3000 {
-			return c.sendAlert(alertUnexpectedMessage)
+			c.sendAlert(alertUnexpectedMessage)
+			return c.in.setErrorLocked(fmt.Errorf("tls: first record does not look like a TLS handshake"))
 		}
 	}
 	if err := b.readFromUntil(c.conn, recordHeaderLen+n); err != nil {
@@ -585,7 +585,7 @@ Again:
 			err = io.ErrUnexpectedEOF
 		}
 		if e, ok := err.(net.Error); !ok || !e.Temporary() {
-			c.setError(err)
+			c.in.setErrorLocked(err)
 		}
 		return err
 	}
@@ -594,27 +594,27 @@ Again:
 	b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n)
 	ok, off, err := c.in.decrypt(b)
 	if !ok {
-		return c.sendAlert(err)
+		c.in.setErrorLocked(c.sendAlert(err))
 	}
 	b.off = off
 	data := b.data[b.off:]
 	if len(data) > maxPlaintext {
-		c.sendAlert(alertRecordOverflow)
+		err := c.sendAlert(alertRecordOverflow)
 		c.in.freeBlock(b)
-		return c.error()
+		return c.in.setErrorLocked(err)
 	}
 
 	switch typ {
 	default:
-		c.sendAlert(alertUnexpectedMessage)
+		c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
 
 	case recordTypeAlert:
 		if len(data) != 2 {
-			c.sendAlert(alertUnexpectedMessage)
+			c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
 			break
 		}
 		if alert(data[1]) == alertCloseNotify {
-			c.setError(io.EOF)
+			c.in.setErrorLocked(io.EOF)
 			break
 		}
 		switch data[0] {
@@ -623,24 +623,24 @@ Again:
 			c.in.freeBlock(b)
 			goto Again
 		case alertLevelError:
-			c.setError(&net.OpError{Op: "remote error", Err: alert(data[1])})
+			c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])})
 		default:
-			c.sendAlert(alertUnexpectedMessage)
+			c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
 		}
 
 	case recordTypeChangeCipherSpec:
 		if typ != want || len(data) != 1 || data[0] != 1 {
-			c.sendAlert(alertUnexpectedMessage)
+			c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
 			break
 		}
 		err := c.in.changeCipherSpec()
 		if err != nil {
-			c.sendAlert(err.(alert))
+			c.in.setErrorLocked(c.sendAlert(err.(alert)))
 		}
 
 	case recordTypeApplicationData:
 		if typ != want {
-			c.sendAlert(alertUnexpectedMessage)
+			c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
 			break
 		}
 		c.input = b
@@ -649,7 +649,7 @@ Again:
 	case recordTypeHandshake:
 		// TODO(rsc): Should at least pick off connection close.
 		if typ != want {
-			return c.sendAlert(alertNoRenegotiation)
+			return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation))
 		}
 		c.hand.Write(data)
 	}
@@ -657,7 +657,7 @@ Again:
 	if b != nil {
 		c.in.freeBlock(b)
 	}
-	return c.error()
+	return c.in.err
 }
 
 // sendAlert sends a TLS alert message.
@@ -673,7 +673,7 @@ func (c *Conn) sendAlertLocked(err alert) error {
 	c.writeRecord(recordTypeAlert, c.tmp[0:2])
 	// closeNotify is a special case in that it isn't an error:
 	if err != alertCloseNotify {
-		return c.setError(&net.OpError{Op: "local error", Err: err})
+		return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
 	}
 	return nil
 }
@@ -759,7 +759,7 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
 			c.tmp[0] = alertLevelError
 			c.tmp[1] = byte(err.(alert))
 			c.writeRecord(recordTypeAlert, c.tmp[0:2])
-			return n, c.setError(&net.OpError{Op: "local error", Err: err})
+			return n, c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
 		}
 	}
 	return
@@ -770,7 +770,7 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
 // c.in.Mutex < L; c.out.Mutex < L.
 func (c *Conn) readHandshake() (interface{}, error) {
 	for c.hand.Len() < 4 {
-		if err := c.error(); err != nil {
+		if err := c.in.err; err != nil {
 			return nil, err
 		}
 		if err := c.readRecord(recordTypeHandshake); err != nil {
@@ -781,11 +781,10 @@ func (c *Conn) readHandshake() (interface{}, error) {
 	data := c.hand.Bytes()
 	n := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
 	if n > maxHandshake {
-		c.sendAlert(alertInternalError)
-		return nil, c.error()
+		return nil, c.in.setErrorLocked(c.sendAlert(alertInternalError))
 	}
 	for c.hand.Len() < 4+n {
-		if err := c.error(); err != nil {
+		if err := c.in.err; err != nil {
 			return nil, err
 		}
 		if err := c.readRecord(recordTypeHandshake); err != nil {
@@ -799,6 +798,8 @@ func (c *Conn) readHandshake() (interface{}, error) {
 		m = new(clientHelloMsg)
 	case typeServerHello:
 		m = new(serverHelloMsg)
+	case typeNewSessionTicket:
+		m = new(newSessionTicketMsg)
 	case typeCertificate:
 		m = new(certificateMsg)
 	case typeCertificateRequest:
@@ -822,8 +823,7 @@ func (c *Conn) readHandshake() (interface{}, error) {
 	case typeFinished:
 		m = new(finishedMsg)
 	default:
-		c.sendAlert(alertUnexpectedMessage)
-		return nil, alertUnexpectedMessage
+		return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
 	}
 
 	// The handshake message unmarshallers
@@ -832,25 +832,24 @@ func (c *Conn) readHandshake() (interface{}, error) {
 	data = append([]byte(nil), data...)
 
 	if !m.unmarshal(data) {
-		c.sendAlert(alertUnexpectedMessage)
-		return nil, alertUnexpectedMessage
+		return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
 	}
 	return m, nil
 }
 
 // Write writes data to the connection.
 func (c *Conn) Write(b []byte) (int, error) {
-	if err := c.error(); err != nil {
-		return 0, err
-	}
-
 	if err := c.Handshake(); err != nil {
-		return 0, c.setError(err)
+		return 0, err
 	}
 
 	c.out.Lock()
 	defer c.out.Unlock()
 
+	if err := c.out.err; err != nil {
+		return 0, err
+	}
+
 	if !c.handshakeComplete {
 		return 0, alertInternalError
 	}
@@ -869,14 +868,14 @@ func (c *Conn) Write(b []byte) (int, error) {
 		if _, ok := c.out.cipher.(cipher.BlockMode); ok {
 			n, err := c.writeRecord(recordTypeApplicationData, b[:1])
 			if err != nil {
-				return n, c.setError(err)
+				return n, c.out.setErrorLocked(err)
 			}
 			m, b = 1, b[1:]
 		}
 	}
 
 	n, err := c.writeRecord(recordTypeApplicationData, b)
-	return n + m, c.setError(err)
+	return n + m, c.out.setErrorLocked(err)
 }
 
 // Read can be made to time out and return a net.Error with Timeout() == true
@@ -885,6 +884,11 @@ func (c *Conn) Read(b []byte) (n int, err error) {
 	if err = c.Handshake(); err != nil {
 		return
 	}
+	if len(b) == 0 {
+		// Put this after Handshake, in case people were calling
+		// Read(nil) for the side effect of the Handshake.
+		return
+	}
 
 	c.in.Lock()
 	defer c.in.Unlock()
@@ -893,13 +897,13 @@ func (c *Conn) Read(b []byte) (n int, err error) {
 	// CBC IV. So this loop ignores a limited number of empty records.
 	const maxConsecutiveEmptyRecords = 100
 	for emptyRecordCount := 0; emptyRecordCount <= maxConsecutiveEmptyRecords; emptyRecordCount++ {
-		for c.input == nil && c.error() == nil {
+		for c.input == nil && c.in.err == nil {
 			if err := c.readRecord(recordTypeApplicationData); err != nil {
 				// Soft error, like EAGAIN
 				return 0, err
 			}
 		}
-		if err := c.error(); err != nil {
+		if err := c.in.err; err != nil {
 			return 0, err
 		}
 
@@ -909,6 +913,25 @@ func (c *Conn) Read(b []byte) (n int, err error) {
 			c.input = nil
 		}
 
+		// If a close-notify alert is waiting, read it so that
+		// we can return (n, EOF) instead of (n, nil), to signal
+		// to the HTTP response reading goroutine that the
+		// connection is now closed. This eliminates a race
+		// where the HTTP response reading goroutine would
+		// otherwise not observe the EOF until its next read,
+		// by which time a client goroutine might have already
+		// tried to reuse the HTTP connection for a new
+		// request.
+		// See https://codereview.appspot.com/76400046
+		// and http://golang.org/issue/3514
+		if ri := c.rawInput; ri != nil &&
+			n != 0 && err == nil &&
+			c.input == nil && len(ri.data) > 0 && recordType(ri.data[0]) == recordTypeAlert {
+			if recErr := c.readRecord(recordTypeApplicationData); recErr != nil {
+				err = recErr // will be io.EOF on closeNotify
+			}
+		}
+
 		if n != 0 || err != nil {
 			return n, err
 		}
@@ -940,16 +963,19 @@ func (c *Conn) Close() error {
 func (c *Conn) Handshake() error {
 	c.handshakeMutex.Lock()
 	defer c.handshakeMutex.Unlock()
-	if err := c.error(); err != nil {
+	if err := c.handshakeErr; err != nil {
 		return err
 	}
 	if c.handshakeComplete {
 		return nil
 	}
+
 	if c.isClient {
-		return c.clientHandshake()
+		c.handshakeErr = c.clientHandshake()
+	} else {
+		c.handshakeErr = c.serverHandshake()
 	}
-	return c.serverHandshake()
+	return c.handshakeErr
 }
 
 // ConnectionState returns basic TLS details about the connection.
@@ -960,6 +986,7 @@ func (c *Conn) ConnectionState() ConnectionState {
 	var state ConnectionState
 	state.HandshakeComplete = c.handshakeComplete
 	if c.handshakeComplete {
+		state.Version = c.vers
 		state.NegotiatedProtocol = c.clientProtocol
 		state.DidResume = c.didResume
 		state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback
@@ -988,10 +1015,10 @@ func (c *Conn) VerifyHostname(host string) error {
 	c.handshakeMutex.Lock()
 	defer c.handshakeMutex.Unlock()
 	if !c.isClient {
-		return errors.New("VerifyHostname called on TLS server connection")
+		return errors.New("tls: VerifyHostname called on TLS server connection")
 	}
 	if !c.handshakeComplete {
-		return errors.New("TLS handshake has not yet been performed")
+		return errors.New("tls: handshake has not yet been performed")
 	}
 	return c.peerCertificates[0].VerifyHostname(host)
 }
diff --git a/src/pkg/crypto/tls/example_test.go b/src/pkg/crypto/tls/example_test.go
new file mode 100644
index 0000000..7628e43
--- /dev/null
+++ b/src/pkg/crypto/tls/example_test.go
@@ -0,0 +1,57 @@
+// 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 tls_test
+
+import (
+	"crypto/tls"
+	"crypto/x509"
+)
+
+func ExampleDial() {
+	// Connecting with a custom root-certificate set.
+
+	const rootPEM = `
+-----BEGIN CERTIFICATE-----
+MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG
+EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy
+bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP
+VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv
+h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE
+ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ
+EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC
+DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7
+qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD
+VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g
+K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI
+KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n
+ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB
+BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY
+/iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/
+zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza
+HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto
+WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6
+yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx
+-----END CERTIFICATE-----`
+
+	// First, create the set of root certificates. For this example we only
+	// have one. It's also possible to omit this in order to use the
+	// default root set of the current operating system.
+	roots := x509.NewCertPool()
+	ok := roots.AppendCertsFromPEM([]byte(rootPEM))
+	if !ok {
+		panic("failed to parse root certificate")
+	}
+
+	conn, err := tls.Dial("tcp", "mail.google.com:443", &tls.Config{
+		RootCAs: roots,
+	})
+	if err != nil {
+		panic("failed to connect: " + err.Error())
+	}
+	conn.Close()
+}
diff --git a/src/pkg/crypto/tls/generate_cert.go b/src/pkg/crypto/tls/generate_cert.go
index b417ea4..5c6d839 100644
--- a/src/pkg/crypto/tls/generate_cert.go
+++ b/src/pkg/crypto/tls/generate_cert.go
@@ -43,7 +43,6 @@ func main() {
 	priv, err := rsa.GenerateKey(rand.Reader, *rsaBits)
 	if err != nil {
 		log.Fatalf("failed to generate private key: %s", err)
-		return
 	}
 
 	var notBefore time.Time
@@ -59,14 +58,14 @@ func main() {
 
 	notAfter := notBefore.Add(*validFor)
 
-	// end of ASN.1 time
-	endOfTime := time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC)
-	if notAfter.After(endOfTime) {
-		notAfter = endOfTime
+	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
+	if err != nil {
+		log.Fatalf("failed to generate serial number: %s", err)
 	}
 
 	template := x509.Certificate{
-		SerialNumber: new(big.Int).SetInt64(0),
+		SerialNumber: serialNumber,
 		Subject: pkix.Name{
 			Organization: []string{"Acme Co"},
 		},
@@ -95,13 +94,11 @@ func main() {
 	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
 	if err != nil {
 		log.Fatalf("Failed to create certificate: %s", err)
-		return
 	}
 
 	certOut, err := os.Create("cert.pem")
 	if err != nil {
 		log.Fatalf("failed to open cert.pem for writing: %s", err)
-		return
 	}
 	pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
 	certOut.Close()
diff --git a/src/pkg/crypto/tls/handshake_client.go b/src/pkg/crypto/tls/handshake_client.go
index 85e4ade..a320fde 100644
--- a/src/pkg/crypto/tls/handshake_client.go
+++ b/src/pkg/crypto/tls/handshake_client.go
@@ -12,24 +12,41 @@ import (
 	"crypto/x509"
 	"encoding/asn1"
 	"errors"
+	"fmt"
 	"io"
+	"net"
 	"strconv"
 )
 
+type clientHandshakeState struct {
+	c            *Conn
+	serverHello  *serverHelloMsg
+	hello        *clientHelloMsg
+	suite        *cipherSuite
+	finishedHash finishedHash
+	masterSecret []byte
+	session      *ClientSessionState
+}
+
 func (c *Conn) clientHandshake() error {
 	if c.config == nil {
 		c.config = defaultConfig()
 	}
 
+	if len(c.config.ServerName) == 0 && !c.config.InsecureSkipVerify {
+		return errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config")
+	}
+
 	hello := &clientHelloMsg{
-		vers:               c.config.maxVersion(),
-		compressionMethods: []uint8{compressionNone},
-		random:             make([]byte, 32),
-		ocspStapling:       true,
-		serverName:         c.config.ServerName,
-		supportedCurves:    []uint16{curveP256, curveP384, curveP521},
-		supportedPoints:    []uint8{pointFormatUncompressed},
-		nextProtoNeg:       len(c.config.NextProtos) > 0,
+		vers:                c.config.maxVersion(),
+		compressionMethods:  []uint8{compressionNone},
+		random:              make([]byte, 32),
+		ocspStapling:        true,
+		serverName:          c.config.ServerName,
+		supportedCurves:     c.config.curvePreferences(),
+		supportedPoints:     []uint8{pointFormatUncompressed},
+		nextProtoNeg:        len(c.config.NextProtos) > 0,
+		secureRenegotiation: true,
 	}
 
 	possibleCipherSuites := c.config.cipherSuites()
@@ -51,21 +68,61 @@ NextCipherSuite:
 		}
 	}
 
-	t := uint32(c.config.time().Unix())
-	hello.random[0] = byte(t >> 24)
-	hello.random[1] = byte(t >> 16)
-	hello.random[2] = byte(t >> 8)
-	hello.random[3] = byte(t)
-	_, err := io.ReadFull(c.config.rand(), hello.random[4:])
+	_, err := io.ReadFull(c.config.rand(), hello.random)
 	if err != nil {
 		c.sendAlert(alertInternalError)
-		return errors.New("short read from Rand")
+		return errors.New("tls: short read from Rand: " + err.Error())
 	}
 
 	if hello.vers >= VersionTLS12 {
 		hello.signatureAndHashes = supportedSKXSignatureAlgorithms
 	}
 
+	var session *ClientSessionState
+	var cacheKey string
+	sessionCache := c.config.ClientSessionCache
+	if c.config.SessionTicketsDisabled {
+		sessionCache = nil
+	}
+
+	if sessionCache != nil {
+		hello.ticketSupported = true
+
+		// Try to resume a previously negotiated TLS session, if
+		// available.
+		cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
+		candidateSession, ok := sessionCache.Get(cacheKey)
+		if ok {
+			// Check that the ciphersuite/version used for the
+			// previous session are still valid.
+			cipherSuiteOk := false
+			for _, id := range hello.cipherSuites {
+				if id == candidateSession.cipherSuite {
+					cipherSuiteOk = true
+					break
+				}
+			}
+
+			versOk := candidateSession.vers >= c.config.minVersion() &&
+				candidateSession.vers <= c.config.maxVersion()
+			if versOk && cipherSuiteOk {
+				session = candidateSession
+			}
+		}
+	}
+
+	if session != nil {
+		hello.sessionTicket = session.sessionTicket
+		// A random session ID is used to detect when the
+		// server accepted the ticket and is resuming a session
+		// (see RFC 5077).
+		hello.sessionId = make([]byte, 16)
+		if _, err := io.ReadFull(c.config.rand(), hello.sessionId); err != nil {
+			c.sendAlert(alertInternalError)
+			return errors.New("tls: short read from Rand: " + err.Error())
+		}
+	}
+
 	c.writeRecord(recordTypeHandshake, hello.marshal())
 
 	msg, err := c.readHandshake()
@@ -74,51 +131,103 @@ NextCipherSuite:
 	}
 	serverHello, ok := msg.(*serverHelloMsg)
 	if !ok {
-		return c.sendAlert(alertUnexpectedMessage)
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(serverHello, msg)
 	}
 
 	vers, ok := c.config.mutualVersion(serverHello.vers)
 	if !ok || vers < VersionTLS10 {
 		// TLS 1.0 is the minimum version supported as a client.
-		return c.sendAlert(alertProtocolVersion)
+		c.sendAlert(alertProtocolVersion)
+		return fmt.Errorf("tls: server selected unsupported protocol version %x", serverHello.vers)
 	}
 	c.vers = vers
 	c.haveVers = true
 
-	finishedHash := newFinishedHash(c.vers)
-	finishedHash.Write(hello.marshal())
-	finishedHash.Write(serverHello.marshal())
+	suite := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
+	if suite == nil {
+		c.sendAlert(alertHandshakeFailure)
+		return fmt.Errorf("tls: server selected an unsupported cipher suite")
+	}
 
-	if serverHello.compressionMethod != compressionNone {
-		return c.sendAlert(alertUnexpectedMessage)
+	hs := &clientHandshakeState{
+		c:            c,
+		serverHello:  serverHello,
+		hello:        hello,
+		suite:        suite,
+		finishedHash: newFinishedHash(c.vers),
+		session:      session,
 	}
 
-	if !hello.nextProtoNeg && serverHello.nextProtoNeg {
-		c.sendAlert(alertHandshakeFailure)
-		return errors.New("server advertised unrequested NPN")
+	hs.finishedHash.Write(hs.hello.marshal())
+	hs.finishedHash.Write(hs.serverHello.marshal())
+
+	isResume, err := hs.processServerHello()
+	if err != nil {
+		return err
 	}
 
-	suite := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
-	if suite == nil {
-		return c.sendAlert(alertHandshakeFailure)
+	if isResume {
+		if err := hs.establishKeys(); err != nil {
+			return err
+		}
+		if err := hs.readSessionTicket(); err != nil {
+			return err
+		}
+		if err := hs.readFinished(); err != nil {
+			return err
+		}
+		if err := hs.sendFinished(); err != nil {
+			return err
+		}
+	} else {
+		if err := hs.doFullHandshake(); err != nil {
+			return err
+		}
+		if err := hs.establishKeys(); err != nil {
+			return err
+		}
+		if err := hs.sendFinished(); err != nil {
+			return err
+		}
+		if err := hs.readSessionTicket(); err != nil {
+			return err
+		}
+		if err := hs.readFinished(); err != nil {
+			return err
+		}
 	}
 
-	msg, err = c.readHandshake()
+	if sessionCache != nil && hs.session != nil && session != hs.session {
+		sessionCache.Put(cacheKey, hs.session)
+	}
+
+	c.didResume = isResume
+	c.handshakeComplete = true
+	c.cipherSuite = suite.id
+	return nil
+}
+
+func (hs *clientHandshakeState) doFullHandshake() error {
+	c := hs.c
+
+	msg, err := c.readHandshake()
 	if err != nil {
 		return err
 	}
 	certMsg, ok := msg.(*certificateMsg)
 	if !ok || len(certMsg.certificates) == 0 {
-		return c.sendAlert(alertUnexpectedMessage)
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(certMsg, msg)
 	}
-	finishedHash.Write(certMsg.marshal())
+	hs.finishedHash.Write(certMsg.marshal())
 
 	certs := make([]*x509.Certificate, len(certMsg.certificates))
 	for i, asn1Data := range certMsg.certificates {
 		cert, err := x509.ParseCertificate(asn1Data)
 		if err != nil {
 			c.sendAlert(alertBadCertificate)
-			return errors.New("failed to parse certificate from server: " + err.Error())
+			return errors.New("tls: failed to parse certificate from server: " + err.Error())
 		}
 		certs[i] = cert
 	}
@@ -148,21 +257,23 @@ NextCipherSuite:
 	case *rsa.PublicKey, *ecdsa.PublicKey:
 		break
 	default:
-		return c.sendAlert(alertUnsupportedCertificate)
+		c.sendAlert(alertUnsupportedCertificate)
+		return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey)
 	}
 
 	c.peerCertificates = certs
 
-	if serverHello.ocspStapling {
+	if hs.serverHello.ocspStapling {
 		msg, err = c.readHandshake()
 		if err != nil {
 			return err
 		}
 		cs, ok := msg.(*certificateStatusMsg)
 		if !ok {
-			return c.sendAlert(alertUnexpectedMessage)
+			c.sendAlert(alertUnexpectedMessage)
+			return unexpectedMessageError(cs, msg)
 		}
-		finishedHash.Write(cs.marshal())
+		hs.finishedHash.Write(cs.marshal())
 
 		if cs.statusType == statusTypeOCSP {
 			c.ocspResponse = cs.response
@@ -174,12 +285,12 @@ NextCipherSuite:
 		return err
 	}
 
-	keyAgreement := suite.ka(c.vers)
+	keyAgreement := hs.suite.ka(c.vers)
 
 	skx, ok := msg.(*serverKeyExchangeMsg)
 	if ok {
-		finishedHash.Write(skx.marshal())
-		err = keyAgreement.processServerKeyExchange(c.config, hello, serverHello, certs[0], skx)
+		hs.finishedHash.Write(skx.marshal())
+		err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, certs[0], skx)
 		if err != nil {
 			c.sendAlert(alertUnexpectedMessage)
 			return err
@@ -208,7 +319,7 @@ NextCipherSuite:
 		// ClientCertificateType, unless there is some external
 		// arrangement to the contrary.
 
-		finishedHash.Write(certReq.marshal())
+		hs.finishedHash.Write(certReq.marshal())
 
 		var rsaAvail, ecdsaAvail bool
 		for _, certType := range certReq.certificateTypes {
@@ -271,9 +382,10 @@ NextCipherSuite:
 
 	shd, ok := msg.(*serverHelloDoneMsg)
 	if !ok {
-		return c.sendAlert(alertUnexpectedMessage)
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(shd, msg)
 	}
-	finishedHash.Write(shd.marshal())
+	hs.finishedHash.Write(shd.marshal())
 
 	// If the server requested a certificate then we have to send a
 	// Certificate message, even if it's empty because we don't have a
@@ -283,17 +395,17 @@ NextCipherSuite:
 		if chainToSend != nil {
 			certMsg.certificates = chainToSend.Certificate
 		}
-		finishedHash.Write(certMsg.marshal())
+		hs.finishedHash.Write(certMsg.marshal())
 		c.writeRecord(recordTypeHandshake, certMsg.marshal())
 	}
 
-	preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hello, certs[0])
+	preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, certs[0])
 	if err != nil {
 		c.sendAlert(alertInternalError)
 		return err
 	}
 	if ckx != nil {
-		finishedHash.Write(ckx.marshal())
+		hs.finishedHash.Write(ckx.marshal())
 		c.writeRecord(recordTypeHandshake, ckx.marshal())
 	}
 
@@ -305,7 +417,7 @@ NextCipherSuite:
 
 		switch key := c.config.Certificates[0].PrivateKey.(type) {
 		case *ecdsa.PrivateKey:
-			digest, _, hashId := finishedHash.hashForClientCertificate(signatureECDSA)
+			digest, _, hashId := hs.finishedHash.hashForClientCertificate(signatureECDSA)
 			r, s, err := ecdsa.Sign(c.config.rand(), key, digest)
 			if err == nil {
 				signed, err = asn1.Marshal(ecdsaSignature{r, s})
@@ -313,7 +425,7 @@ NextCipherSuite:
 			certVerify.signatureAndHash.signature = signatureECDSA
 			certVerify.signatureAndHash.hash = hashId
 		case *rsa.PrivateKey:
-			digest, hashFunc, hashId := finishedHash.hashForClientCertificate(signatureRSA)
+			digest, hashFunc, hashId := hs.finishedHash.hashForClientCertificate(signatureRSA)
 			signed, err = rsa.SignPKCS1v15(c.config.rand(), key, hashFunc, digest)
 			certVerify.signatureAndHash.signature = signatureRSA
 			certVerify.signatureAndHash.hash = hashId
@@ -321,79 +433,157 @@ NextCipherSuite:
 			err = errors.New("unknown private key type")
 		}
 		if err != nil {
-			return c.sendAlert(alertInternalError)
+			c.sendAlert(alertInternalError)
+			return errors.New("tls: failed to sign handshake with client certificate: " + err.Error())
 		}
 		certVerify.signature = signed
 
-		finishedHash.Write(certVerify.marshal())
+		hs.finishedHash.Write(certVerify.marshal())
 		c.writeRecord(recordTypeHandshake, certVerify.marshal())
 	}
 
-	masterSecret := masterFromPreMasterSecret(c.vers, preMasterSecret, hello.random, serverHello.random)
-	clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
-		keysFromMasterSecret(c.vers, masterSecret, hello.random, serverHello.random, suite.macLen, suite.keyLen, suite.ivLen)
+	hs.masterSecret = masterFromPreMasterSecret(c.vers, preMasterSecret, hs.hello.random, hs.serverHello.random)
+	return nil
+}
+
+func (hs *clientHandshakeState) establishKeys() error {
+	c := hs.c
 
-	var clientCipher interface{}
-	var clientHash macFunction
-	if suite.cipher != nil {
-		clientCipher = suite.cipher(clientKey, clientIV, false /* not for reading */)
-		clientHash = suite.mac(c.vers, clientMAC)
+	clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+		keysFromMasterSecret(c.vers, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
+	var clientCipher, serverCipher interface{}
+	var clientHash, serverHash macFunction
+	if hs.suite.cipher != nil {
+		clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */)
+		clientHash = hs.suite.mac(c.vers, clientMAC)
+		serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */)
+		serverHash = hs.suite.mac(c.vers, serverMAC)
 	} else {
-		clientCipher = suite.aead(clientKey, clientIV)
+		clientCipher = hs.suite.aead(clientKey, clientIV)
+		serverCipher = hs.suite.aead(serverKey, serverIV)
 	}
+
+	c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)
 	c.out.prepareCipherSpec(c.vers, clientCipher, clientHash)
-	c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+	return nil
+}
 
-	if serverHello.nextProtoNeg {
-		nextProto := new(nextProtoMsg)
-		proto, fallback := mutualProtocol(c.config.NextProtos, serverHello.nextProtos)
-		nextProto.proto = proto
-		c.clientProtocol = proto
-		c.clientProtocolFallback = fallback
+func (hs *clientHandshakeState) serverResumedSession() bool {
+	// If the server responded with the same sessionId then it means the
+	// sessionTicket is being used to resume a TLS session.
+	return hs.session != nil && hs.hello.sessionId != nil &&
+		bytes.Equal(hs.serverHello.sessionId, hs.hello.sessionId)
+}
 
-		finishedHash.Write(nextProto.marshal())
-		c.writeRecord(recordTypeHandshake, nextProto.marshal())
+func (hs *clientHandshakeState) processServerHello() (bool, error) {
+	c := hs.c
+
+	if hs.serverHello.compressionMethod != compressionNone {
+		c.sendAlert(alertUnexpectedMessage)
+		return false, errors.New("tls: server selected unsupported compression format")
 	}
 
-	finished := new(finishedMsg)
-	finished.verifyData = finishedHash.clientSum(masterSecret)
-	finishedHash.Write(finished.marshal())
-	c.writeRecord(recordTypeHandshake, finished.marshal())
+	if !hs.hello.nextProtoNeg && hs.serverHello.nextProtoNeg {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("server advertised unrequested NPN extension")
+	}
 
-	var serverCipher interface{}
-	var serverHash macFunction
-	if suite.cipher != nil {
-		serverCipher = suite.cipher(serverKey, serverIV, true /* for reading */)
-		serverHash = suite.mac(c.vers, serverMAC)
-	} else {
-		serverCipher = suite.aead(serverKey, serverIV)
+	if hs.serverResumedSession() {
+		// Restore masterSecret and peerCerts from previous state
+		hs.masterSecret = hs.session.masterSecret
+		c.peerCertificates = hs.session.serverCertificates
+		return true, nil
 	}
-	c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)
+	return false, nil
+}
+
+func (hs *clientHandshakeState) readFinished() error {
+	c := hs.c
+
 	c.readRecord(recordTypeChangeCipherSpec)
-	if err := c.error(); err != nil {
+	if err := c.in.error(); err != nil {
 		return err
 	}
 
-	msg, err = c.readHandshake()
+	msg, err := c.readHandshake()
 	if err != nil {
 		return err
 	}
 	serverFinished, ok := msg.(*finishedMsg)
 	if !ok {
-		return c.sendAlert(alertUnexpectedMessage)
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(serverFinished, msg)
 	}
 
-	verify := finishedHash.serverSum(masterSecret)
+	verify := hs.finishedHash.serverSum(hs.masterSecret)
 	if len(verify) != len(serverFinished.verifyData) ||
 		subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
-		return c.sendAlert(alertHandshakeFailure)
+		c.sendAlert(alertHandshakeFailure)
+		return errors.New("tls: server's Finished message was incorrect")
+	}
+	hs.finishedHash.Write(serverFinished.marshal())
+	return nil
+}
+
+func (hs *clientHandshakeState) readSessionTicket() error {
+	if !hs.serverHello.ticketSupported {
+		return nil
+	}
+
+	c := hs.c
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+	sessionTicketMsg, ok := msg.(*newSessionTicketMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(sessionTicketMsg, msg)
+	}
+	hs.finishedHash.Write(sessionTicketMsg.marshal())
+
+	hs.session = &ClientSessionState{
+		sessionTicket:      sessionTicketMsg.ticket,
+		vers:               c.vers,
+		cipherSuite:        hs.suite.id,
+		masterSecret:       hs.masterSecret,
+		serverCertificates: c.peerCertificates,
 	}
 
-	c.handshakeComplete = true
-	c.cipherSuite = suite.id
 	return nil
 }
 
+func (hs *clientHandshakeState) sendFinished() error {
+	c := hs.c
+
+	c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+	if hs.serverHello.nextProtoNeg {
+		nextProto := new(nextProtoMsg)
+		proto, fallback := mutualProtocol(c.config.NextProtos, hs.serverHello.nextProtos)
+		nextProto.proto = proto
+		c.clientProtocol = proto
+		c.clientProtocolFallback = fallback
+
+		hs.finishedHash.Write(nextProto.marshal())
+		c.writeRecord(recordTypeHandshake, nextProto.marshal())
+	}
+
+	finished := new(finishedMsg)
+	finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
+	hs.finishedHash.Write(finished.marshal())
+	c.writeRecord(recordTypeHandshake, finished.marshal())
+	return nil
+}
+
+// clientSessionCacheKey returns a key used to cache sessionTickets that could
+// be used to resume previously negotiated TLS sessions with a server.
+func clientSessionCacheKey(serverAddr net.Addr, config *Config) string {
+	if len(config.ServerName) > 0 {
+		return config.ServerName
+	}
+	return serverAddr.String()
+}
+
 // mutualProtocol finds the mutual Next Protocol Negotiation protocol given the
 // set of client and server supported protocols. The set of client supported
 // protocols must not be empty. It returns the resulting protocol and flag
diff --git a/src/pkg/crypto/tls/handshake_client_test.go b/src/pkg/crypto/tls/handshake_client_test.go
index 6c56400..0d73c8e 100644
--- a/src/pkg/crypto/tls/handshake_client_test.go
+++ b/src/pkg/crypto/tls/handshake_client_test.go
@@ -6,3045 +6,434 @@ package tls
 
 import (
 	"bytes"
-	"flag"
+	"crypto/ecdsa"
+	"crypto/rsa"
+	"crypto/x509"
+	"encoding/pem"
+	"fmt"
 	"io"
 	"net"
 	"os"
+	"os/exec"
+	"path/filepath"
+	"strconv"
 	"testing"
+	"time"
 )
 
-func testClientScript(t *testing.T, name string, clientScript [][]byte, config *Config) {
-	c, s := net.Pipe()
-	cli := Client(c, config)
-	go func() {
-		cli.Write([]byte("hello\n"))
-		cli.Close()
-		c.Close()
-	}()
+// Note: see comment in handshake_test.go for details of how the reference
+// tests work.
 
-	defer c.Close()
-	for i, b := range clientScript {
-		if i%2 == 1 {
-			s.Write(b)
-			continue
-		}
-		bb := make([]byte, len(b))
-		_, err := io.ReadFull(s, bb)
-		if err != nil {
-			t.Fatalf("%s #%d: %s", name, i, err)
-		}
-		if !bytes.Equal(b, bb) {
-			t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", name, i, bb, b)
-		}
-	}
-}
-
-func TestHandshakeClientRSARC4(t *testing.T) {
-	var config = *testConfig
-	config.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA}
-	testClientScript(t, "RSA-RC4", rsaRC4ClientScript, &config)
-}
+// blockingSource is an io.Reader that blocks a Read call until it's closed.
+type blockingSource chan bool
 
-func TestHandshakeClientECDHERSAAES(t *testing.T) {
-	var config = *testConfig
-	config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}
-	testClientScript(t, "ECDHE-RSA-AES", ecdheRSAAESClientScript, &config)
+func (b blockingSource) Read([]byte) (n int, err error) {
+	<-b
+	return 0, io.EOF
 }
 
-func TestHandshakeClientECDHECDSAAES(t *testing.T) {
-	var config = *testConfig
-	config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA}
-	config.Certificates = nil
-	config.BuildNameToCertificate()
-	testClientScript(t, "ECDHE-ECDSA-AES", ecdheECDSAAESClientScript, &config)
+// clientTest represents a test of the TLS client handshake against a reference
+// implementation.
+type clientTest struct {
+	// name is a freeform string identifying the test and the file in which
+	// the expected results will be stored.
+	name string
+	// command, if not empty, contains a series of arguments for the
+	// command to run for the reference server.
+	command []string
+	// config, if not nil, contains a custom Config to use for this test.
+	config *Config
+	// cert, if not empty, contains a DER-encoded certificate for the
+	// reference server.
+	cert []byte
+	// key, if not nil, contains either a *rsa.PrivateKey or
+	// *ecdsa.PrivateKey which is the private key for the reference server.
+	key interface{}
 }
 
-func TestLongClientCerticiateChain(t *testing.T) {
-	config := *testConfig
-	cert, _ := X509KeyPair(testClientChainCertificate, testClientChainCertificate)
-	config.Certificates = []Certificate{cert}
-	testClientScript(t, "Long client certificate chains", clientChainCertificateScript, &config)
-}
+var defaultServerCommand = []string{"openssl", "s_server"}
 
-func TestHandshakeClientTLS11(t *testing.T) {
-	var config = *testConfig
-	config.MaxVersion = VersionTLS11
-	config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}
-	testClientScript(t, "TLS11-ECDHE-AES", tls11ECDHEAESClientScript, &config)
-}
+// connFromCommand starts the reference server process, connects to it and
+// returns a recordingConn for the connection. The stdin return value is a
+// blockingSource for the stdin of the child process. It must be closed before
+// Waiting for child.
+func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd, stdin blockingSource, err error) {
+	cert := testRSACertificate
+	if len(test.cert) > 0 {
+		cert = test.cert
+	}
+	certPath := tempFile(string(cert))
+	defer os.Remove(certPath)
 
-func TestHandshakeClientTLS12(t *testing.T) {
-	config := *testConfig
-	config.MaxVersion = VersionTLS12
-	config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}
-	cert, _ := X509KeyPair(testClientChainCertificate, testClientChainCertificate)
-	config.Certificates = []Certificate{cert}
-	testClientScript(t, "TLS12", clientTLS12Script, &config)
-}
+	var key interface{} = testRSAPrivateKey
+	if test.key != nil {
+		key = test.key
+	}
+	var pemType string
+	var derBytes []byte
+	switch key := key.(type) {
+	case *rsa.PrivateKey:
+		pemType = "RSA"
+		derBytes = x509.MarshalPKCS1PrivateKey(key)
+	case *ecdsa.PrivateKey:
+		pemType = "EC"
+		var err error
+		derBytes, err = x509.MarshalECPrivateKey(key)
+		if err != nil {
+			panic(err)
+		}
+	default:
+		panic("unknown key type")
+	}
 
-func TestHandshakeClientTLS12ClientCert(t *testing.T) {
-	config := *testConfig
-	config.MaxVersion = VersionTLS12
-	config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
-	cert, _ := X509KeyPair(testClientChainCertificate, testClientChainCertificate)
-	config.Certificates = []Certificate{cert}
-	testClientScript(t, "TLS12ClientCert", clientTLS12ClientCertScript, &config)
-}
+	var pemOut bytes.Buffer
+	pem.Encode(&pemOut, &pem.Block{Type: pemType + " PRIVATE KEY", Bytes: derBytes})
 
-var connect = flag.Bool("connect", false, "connect to a TLS server on :10443")
+	keyPath := tempFile(string(pemOut.Bytes()))
+	defer os.Remove(keyPath)
 
-func TestRunClient(t *testing.T) {
-	if !*connect {
-		return
+	var command []string
+	if len(test.command) > 0 {
+		command = append(command, test.command...)
+	} else {
+		command = append(command, defaultServerCommand...)
+	}
+	command = append(command, "-cert", certPath, "-certform", "DER", "-key", keyPath)
+	// serverPort contains the port that OpenSSL will listen on. OpenSSL
+	// can't take "0" as an argument here so we have to pick a number and
+	// hope that it's not in use on the machine. Since this only occurs
+	// when -update is given and thus when there's a human watching the
+	// test, this isn't too bad.
+	const serverPort = 24323
+	command = append(command, "-accept", strconv.Itoa(serverPort))
+
+	cmd := exec.Command(command[0], command[1:]...)
+	stdin = blockingSource(make(chan bool))
+	cmd.Stdin = stdin
+	var out bytes.Buffer
+	cmd.Stdout = &out
+	cmd.Stderr = &out
+	if err := cmd.Start(); err != nil {
+		return nil, nil, nil, err
 	}
 
-	tcpConn, err := net.Dial("tcp", "127.0.0.1:10443")
-	if err != nil {
-		t.Fatal(err)
+	// OpenSSL does print an "ACCEPT" banner, but it does so *before*
+	// opening the listening socket, so we can't use that to wait until it
+	// has started listening. Thus we are forced to poll until we get a
+	// connection.
+	var tcpConn net.Conn
+	for i := uint(0); i < 5; i++ {
+		var err error
+		tcpConn, err = net.DialTCP("tcp", nil, &net.TCPAddr{
+			IP:   net.IPv4(127, 0, 0, 1),
+			Port: serverPort,
+		})
+		if err == nil {
+			break
+		}
+		time.Sleep((1 << i) * 5 * time.Millisecond)
+	}
+	if tcpConn == nil {
+		close(stdin)
+		out.WriteTo(os.Stdout)
+		cmd.Process.Kill()
+		return nil, nil, nil, cmd.Wait()
 	}
 
 	record := &recordingConn{
 		Conn: tcpConn,
 	}
 
-	config := GetTestConfig()
-	conn := Client(record, config)
-	if err := conn.Handshake(); err != nil {
-		t.Fatalf("error from TLS handshake: %s", err)
-	}
-
-	conn.Write([]byte("hello\n"))
-	conn.Close()
+	return record, cmd, stdin, nil
+}
 
-	record.WriteTo(os.Stdout)
+func (test *clientTest) dataPath() string {
+	return filepath.Join("testdata", "Client-"+test.name)
 }
 
-func TestEmptyRecords(t *testing.T) {
-	// emptyRecordScript contains a TLS connection with an empty record as
-	// the first application data from the server. This test ensures that
-	// the empty record doesn't cause (0, nil) to be returned from
-	// Conn.Read.
-	config := *testConfig
-	config.CipherSuites = []uint16{TLS_RSA_WITH_AES_256_CBC_SHA}
+func (test *clientTest) loadData() (flows [][]byte, err error) {
+	in, err := os.Open(test.dataPath())
+	if err != nil {
+		return nil, err
+	}
+	defer in.Close()
+	return parseTestData(in)
+}
 
-	c, s := net.Pipe()
-	cli := Client(c, &config)
-	go func() {
-		buf := make([]byte, 1024)
-		n, err := cli.Read(buf)
-		defer c.Close()
-		defer cli.Close()
+func (test *clientTest) run(t *testing.T, write bool) {
+	var clientConn, serverConn net.Conn
+	var recordingConn *recordingConn
+	var childProcess *exec.Cmd
+	var stdin blockingSource
 
+	if write {
+		var err error
+		recordingConn, childProcess, stdin, err = test.connFromCommand()
 		if err != nil {
-			t.Fatalf("error reading from tls.Client: %s", err)
+			t.Fatalf("Failed to start subcommand: %s", err)
 		}
-		const expectedLength = 197
-		if n != expectedLength {
-			t.Fatalf("incorrect length reading from tls.Client, got %d, want %d", n, expectedLength)
+		clientConn = recordingConn
+	} else {
+		clientConn, serverConn = net.Pipe()
+	}
+
+	config := test.config
+	if config == nil {
+		config = testConfig
+	}
+	client := Client(clientConn, config)
+
+	doneChan := make(chan bool)
+	go func() {
+		if _, err := client.Write([]byte("hello\n")); err != nil {
+			t.Logf("Client.Write failed: %s", err)
 		}
+		client.Close()
+		clientConn.Close()
+		doneChan <- true
 	}()
 
-	defer c.Close()
-	for i, b := range emptyRecordScript {
-		if i%2 == 1 {
-			s.Write(b)
-			continue
+	if !write {
+		flows, err := test.loadData()
+		if err != nil {
+			t.Fatalf("%s: failed to load data from %s", test.name, test.dataPath())
+		}
+		for i, b := range flows {
+			if i%2 == 1 {
+				serverConn.Write(b)
+				continue
+			}
+			bb := make([]byte, len(b))
+			_, err := io.ReadFull(serverConn, bb)
+			if err != nil {
+				t.Fatalf("%s #%d: %s", test.name, i, err)
+			}
+			if !bytes.Equal(b, bb) {
+				t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", test.name, i, bb, b)
+			}
 		}
-		bb := make([]byte, len(b))
-		_, err := io.ReadFull(s, bb)
+		serverConn.Close()
+	}
+
+	<-doneChan
+
+	if write {
+		path := test.dataPath()
+		out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
 		if err != nil {
-			t.Fatalf("#%d: %s", i, err)
+			t.Fatalf("Failed to create output file: %s", err)
 		}
-		if !bytes.Equal(b, bb) {
-			t.Fatalf("#%d: mismatch on read: got:%x want:%x", i, bb, b)
+		defer out.Close()
+		recordingConn.Close()
+		close(stdin)
+		childProcess.Process.Kill()
+		childProcess.Wait()
+		if len(recordingConn.flows) < 3 {
+			childProcess.Stdout.(*bytes.Buffer).WriteTo(os.Stdout)
+			t.Fatalf("Client connection didn't work")
 		}
+		recordingConn.WriteTo(out)
+		fmt.Printf("Wrote %s\n", path)
 	}
 }
 
-// Script of interaction with gnutls implementation.
-// The values for this test are obtained by building and running in client mode:
-//   % go test -test.run "TestRunClient" -connect
-// The recorded bytes are written to stdout.
-//
-// The server private key is:
-// -----BEGIN RSA PRIVATE KEY-----
-// MIIBPAIBAAJBAJ+zw4Qnlf8SMVIPFe9GEcStgOY2Ww/dgNdhjeD8ckUJNP5VZkVD
-// TGiXav6ooKXfX3j/7tdkuD8Ey2//Kv7+ue0CAwEAAQJAN6W31vDEP2DjdqhzCDDu
-// OA4NACqoiFqyblo7yc2tM4h4xMbC3Yx5UKMN9ZkCtX0gzrz6DyF47bdKcWBzNWCj
-// gQIhANEoojVt7hq+SQ6MCN6FTAysGgQf56Q3TYoJMoWvdiXVAiEAw3e3rc+VJpOz
-// rHuDo6bgpjUAAXM+v3fcpsfZSNO6V7kCIQCtbVjanpUwvZkMI9by02oUk9taki3b
-// PzPfAfNPYAbCJQIhAJXNQDWyqwn/lGmR11cqY2y9nZ1+5w3yHGatLrcDnQHxAiEA
-// vnlEGo8K85u+KwIOimM48ZG8oTk7iFdkqLJR1utT3aU=
-// -----END RSA PRIVATE KEY-----
-//
-// and certificate is:
-// -----BEGIN CERTIFICATE-----
-// MIICKzCCAdWgAwIBAgIJALE1E2URIMWSMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
-// BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
-// aWRnaXRzIFB0eSBMdGQwHhcNMTIwNDA2MTcxMDEzWhcNMTUwNDA2MTcxMDEzWjBF
-// MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
-// ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ+z
-// w4Qnlf8SMVIPFe9GEcStgOY2Ww/dgNdhjeD8ckUJNP5VZkVDTGiXav6ooKXfX3j/
-// 7tdkuD8Ey2//Kv7+ue0CAwEAAaOBpzCBpDAdBgNVHQ4EFgQUeKaXmmO1xaGlM7oi
-// fCNuWxt6zCswdQYDVR0jBG4wbIAUeKaXmmO1xaGlM7oifCNuWxt6zCuhSaRHMEUx
-// CzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRl
-// cm5ldCBXaWRnaXRzIFB0eSBMdGSCCQCxNRNlESDFkjAMBgNVHRMEBTADAQH/MA0G
-// CSqGSIb3DQEBBQUAA0EAhTZAc8G7GtrUWZ8tonAxRnTsg26oyDxRrzms7EC86CJG
-// HZnWRiok1IsFCEv7NRFukrt3uuQSu/TIXpyBqJdgTA==
-// -----END CERTIFICATE-----
-var rsaRC4ClientScript = [][]byte{
-	{
-		0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
-		0x46, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05,
-		0x01, 0x00, 0x00, 0x1b, 0x00, 0x05, 0x00, 0x05,
-		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
-		0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
-		0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00,
-	},
+func runClientTestForVersion(t *testing.T, template *clientTest, prefix, option string) {
+	test := *template
+	test.name = prefix + test.name
+	if len(test.command) == 0 {
+		test.command = defaultClientCommand
+	}
+	test.command = append([]string(nil), test.command...)
+	test.command = append(test.command, option)
+	test.run(t, *update)
+}
 
-	{
-		0x16, 0x03, 0x01, 0x00, 0x4a, 0x02, 0x00, 0x00,
-		0x46, 0x03, 0x01, 0x4d, 0x0a, 0x56, 0x16, 0xb5,
-		0x91, 0xd1, 0xcb, 0x80, 0x4d, 0xc7, 0x46, 0xf3,
-		0x37, 0x0c, 0xef, 0xea, 0x64, 0x11, 0x14, 0x56,
-		0x97, 0x9b, 0xc5, 0x67, 0x08, 0xb7, 0x13, 0xea,
-		0xf8, 0xc9, 0xb3, 0x20, 0xe2, 0xfc, 0x41, 0xf6,
-		0x96, 0x90, 0x9d, 0x43, 0x9b, 0xe9, 0x6e, 0xf8,
-		0x41, 0x16, 0xcc, 0xf3, 0xc7, 0xde, 0xda, 0x5a,
-		0xa1, 0x33, 0x69, 0xe2, 0xde, 0x5b, 0xaf, 0x2a,
-		0x92, 0xe7, 0xd4, 0xa0, 0x00, 0x05, 0x00, 0x16,
-		0x03, 0x01, 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xf3,
-		0x00, 0x01, 0xf0, 0x00, 0x01, 0xed, 0x30, 0x82,
-		0x01, 0xe9, 0x30, 0x82, 0x01, 0x52, 0x02, 0x01,
-		0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
-		0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00,
-		0x30, 0x5b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
-		0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31,
-		0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
-		0x13, 0x0a, 0x51, 0x75, 0x65, 0x65, 0x6e, 0x73,
-		0x6c, 0x61, 0x6e, 0x64, 0x31, 0x1a, 0x30, 0x18,
-		0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x43,
-		0x72, 0x79, 0x70, 0x74, 0x53, 0x6f, 0x66, 0x74,
-		0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64,
-		0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04,
-		0x03, 0x13, 0x12, 0x54, 0x65, 0x73, 0x74, 0x20,
-		0x43, 0x41, 0x20, 0x28, 0x31, 0x30, 0x32, 0x34,
-		0x20, 0x62, 0x69, 0x74, 0x29, 0x30, 0x1e, 0x17,
-		0x0d, 0x30, 0x30, 0x31, 0x30, 0x31, 0x36, 0x32,
-		0x32, 0x33, 0x31, 0x30, 0x33, 0x5a, 0x17, 0x0d,
-		0x30, 0x33, 0x30, 0x31, 0x31, 0x34, 0x32, 0x32,
-		0x33, 0x31, 0x30, 0x33, 0x5a, 0x30, 0x63, 0x31,
-		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
-		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x51,
-		0x75, 0x65, 0x65, 0x6e, 0x73, 0x6c, 0x61, 0x6e,
-		0x64, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55,
-		0x04, 0x0a, 0x13, 0x11, 0x43, 0x72, 0x79, 0x70,
-		0x74, 0x53, 0x6f, 0x66, 0x74, 0x20, 0x50, 0x74,
-		0x79, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x23, 0x30,
-		0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1a,
-		0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x74,
-		0x65, 0x73, 0x74, 0x20, 0x63, 0x65, 0x72, 0x74,
-		0x20, 0x28, 0x35, 0x31, 0x32, 0x20, 0x62, 0x69,
-		0x74, 0x29, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09,
-		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-		0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48,
-		0x02, 0x41, 0x00, 0x9f, 0xb3, 0xc3, 0x84, 0x27,
-		0x95, 0xff, 0x12, 0x31, 0x52, 0x0f, 0x15, 0xef,
-		0x46, 0x11, 0xc4, 0xad, 0x80, 0xe6, 0x36, 0x5b,
-		0x0f, 0xdd, 0x80, 0xd7, 0x61, 0x8d, 0xe0, 0xfc,
-		0x72, 0x45, 0x09, 0x34, 0xfe, 0x55, 0x66, 0x45,
-		0x43, 0x4c, 0x68, 0x97, 0x6a, 0xfe, 0xa8, 0xa0,
-		0xa5, 0xdf, 0x5f, 0x78, 0xff, 0xee, 0xd7, 0x64,
-		0xb8, 0x3f, 0x04, 0xcb, 0x6f, 0xff, 0x2a, 0xfe,
-		0xfe, 0xb9, 0xed, 0x02, 0x03, 0x01, 0x00, 0x01,
-		0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
-		0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00, 0x03,
-		0x81, 0x81, 0x00, 0x93, 0xd2, 0x0a, 0xc5, 0x41,
-		0xe6, 0x5a, 0xa9, 0x86, 0xf9, 0x11, 0x87, 0xe4,
-		0xdb, 0x45, 0xe2, 0xc5, 0x95, 0x78, 0x1a, 0x6c,
-		0x80, 0x6d, 0x73, 0x1f, 0xb4, 0x6d, 0x44, 0xa3,
-		0xba, 0x86, 0x88, 0xc8, 0x58, 0xcd, 0x1c, 0x06,
-		0x35, 0x6c, 0x44, 0x62, 0x88, 0xdf, 0xe4, 0xf6,
-		0x64, 0x61, 0x95, 0xef, 0x4a, 0xa6, 0x7f, 0x65,
-		0x71, 0xd7, 0x6b, 0x88, 0x39, 0xf6, 0x32, 0xbf,
-		0xac, 0x93, 0x67, 0x69, 0x51, 0x8c, 0x93, 0xec,
-		0x48, 0x5f, 0xc9, 0xb1, 0x42, 0xf9, 0x55, 0xd2,
-		0x7e, 0x4e, 0xf4, 0xf2, 0x21, 0x6b, 0x90, 0x57,
-		0xe6, 0xd7, 0x99, 0x9e, 0x41, 0xca, 0x80, 0xbf,
-		0x1a, 0x28, 0xa2, 0xca, 0x5b, 0x50, 0x4a, 0xed,
-		0x84, 0xe7, 0x82, 0xc7, 0xd2, 0xcf, 0x36, 0x9e,
-		0x6a, 0x67, 0xb9, 0x88, 0xa7, 0xf3, 0x8a, 0xd0,
-		0x04, 0xf8, 0xe8, 0xc6, 0x17, 0xe3, 0xc5, 0x29,
-		0xbc, 0x17, 0xf1, 0x16, 0x03, 0x01, 0x00, 0x04,
-		0x0e, 0x00, 0x00, 0x00,
-	},
+func runClientTestTLS10(t *testing.T, template *clientTest) {
+	runClientTestForVersion(t, template, "TLSv10-", "-tls1")
+}
 
-	{
-		0x16, 0x03, 0x01, 0x00, 0x46, 0x10, 0x00, 0x00,
-		0x42, 0x00, 0x40, 0x87, 0xa1, 0x1f, 0x14, 0xe1,
-		0xfb, 0x91, 0xac, 0x58, 0x2e, 0xf3, 0x71, 0xce,
-		0x01, 0x85, 0x2c, 0xc7, 0xfe, 0x84, 0x87, 0x82,
-		0xb7, 0x57, 0xdb, 0x37, 0x4d, 0x46, 0x83, 0x67,
-		0x52, 0x82, 0x51, 0x01, 0x95, 0x23, 0x68, 0x69,
-		0x6b, 0xd0, 0xa7, 0xa7, 0xe5, 0x88, 0xd0, 0x47,
-		0x71, 0xb8, 0xd2, 0x03, 0x05, 0x25, 0x56, 0x5c,
-		0x10, 0x08, 0xc6, 0x9b, 0xd4, 0x67, 0xcd, 0x28,
-		0xbe, 0x9c, 0x48, 0x14, 0x03, 0x01, 0x00, 0x01,
-		0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xc1, 0xb8,
-		0xd3, 0x7f, 0xc5, 0xc2, 0x5a, 0x1d, 0x6d, 0x5b,
-		0x2d, 0x5c, 0x82, 0x87, 0xc2, 0x6f, 0x0d, 0x63,
-		0x7b, 0x72, 0x2b, 0xda, 0x69, 0xc4, 0xfe, 0x3c,
-		0x84, 0xa1, 0x5a, 0x62, 0x38, 0x37, 0xc6, 0x54,
-		0x25, 0x2a,
-	},
+func runClientTestTLS11(t *testing.T, template *clientTest) {
+	runClientTestForVersion(t, template, "TLSv11-", "-tls1_1")
+}
 
-	{
-		0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
-		0x01, 0x00, 0x24, 0xea, 0x88, 0x9c, 0x00, 0xf6,
-		0x35, 0xb8, 0x42, 0x7f, 0x15, 0x17, 0x76, 0x5e,
-		0x4b, 0x24, 0xcb, 0x7e, 0xa0, 0x7b, 0xc3, 0x70,
-		0x52, 0x0a, 0x88, 0x2a, 0x7a, 0x45, 0x59, 0x90,
-		0x59, 0xac, 0xc6, 0xb5, 0x56, 0x55, 0x96,
-	},
+func runClientTestTLS12(t *testing.T, template *clientTest) {
+	runClientTestForVersion(t, template, "TLSv12-", "-tls1_2")
 }
 
-var ecdheRSAAESClientScript = [][]byte{
-	{
-		0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
-		0x46, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x13,
-		0x01, 0x00, 0x00, 0x1b, 0x00, 0x05, 0x00, 0x05,
-		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
-		0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
-		0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x52, 0x02, 0x00, 0x00,
-		0x4e, 0x03, 0x01, 0x50, 0xad, 0x72, 0xb1, 0x14,
-		0x45, 0xce, 0x0a, 0x95, 0xf9, 0x63, 0xef, 0xa8,
-		0xe5, 0x07, 0x34, 0x04, 0xe9, 0x08, 0x0f, 0x38,
-		0xe4, 0x28, 0x27, 0x91, 0x07, 0x03, 0xe2, 0xfe,
-		0xe3, 0x25, 0xf7, 0x20, 0x08, 0x42, 0xa2, 0x01,
-		0x69, 0x53, 0xf0, 0xd9, 0x4c, 0xfa, 0x01, 0xa1,
-		0xce, 0x4b, 0xf8, 0x28, 0x21, 0xad, 0x06, 0xbe,
-		0xe0, 0x1b, 0x3b, 0xf7, 0xec, 0xd2, 0x52, 0xae,
-		0x2a, 0x57, 0xb7, 0xa8, 0xc0, 0x13, 0x00, 0x00,
-		0x06, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x16,
-		0x03, 0x01, 0x02, 0x39, 0x0b, 0x00, 0x02, 0x35,
-		0x00, 0x02, 0x32, 0x00, 0x02, 0x2f, 0x30, 0x82,
-		0x02, 0x2b, 0x30, 0x82, 0x01, 0xd5, 0xa0, 0x03,
-		0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xb1, 0x35,
-		0x13, 0x65, 0x11, 0x20, 0xc5, 0x92, 0x30, 0x0d,
-		0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
-		0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
-		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
-		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
-		0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
-		0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
-		0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
-		0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
-		0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
-		0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
-		0x31, 0x32, 0x30, 0x34, 0x30, 0x36, 0x31, 0x37,
-		0x31, 0x30, 0x31, 0x33, 0x5a, 0x17, 0x0d, 0x31,
-		0x35, 0x30, 0x34, 0x30, 0x36, 0x31, 0x37, 0x31,
-		0x30, 0x31, 0x33, 0x5a, 0x30, 0x45, 0x31, 0x0b,
-		0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
-		0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
-		0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
-		0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
-		0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
-		0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
-		0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
-		0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
-		0x4c, 0x74, 0x64, 0x30, 0x5c, 0x30, 0x0d, 0x06,
-		0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-		0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30,
-		0x48, 0x02, 0x41, 0x00, 0x9f, 0xb3, 0xc3, 0x84,
-		0x27, 0x95, 0xff, 0x12, 0x31, 0x52, 0x0f, 0x15,
-		0xef, 0x46, 0x11, 0xc4, 0xad, 0x80, 0xe6, 0x36,
-		0x5b, 0x0f, 0xdd, 0x80, 0xd7, 0x61, 0x8d, 0xe0,
-		0xfc, 0x72, 0x45, 0x09, 0x34, 0xfe, 0x55, 0x66,
-		0x45, 0x43, 0x4c, 0x68, 0x97, 0x6a, 0xfe, 0xa8,
-		0xa0, 0xa5, 0xdf, 0x5f, 0x78, 0xff, 0xee, 0xd7,
-		0x64, 0xb8, 0x3f, 0x04, 0xcb, 0x6f, 0xff, 0x2a,
-		0xfe, 0xfe, 0xb9, 0xed, 0x02, 0x03, 0x01, 0x00,
-		0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81, 0xa4, 0x30,
-		0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
-		0x04, 0x14, 0x78, 0xa6, 0x97, 0x9a, 0x63, 0xb5,
-		0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22, 0x7c, 0x23,
-		0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b, 0x30, 0x75,
-		0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x6e, 0x30,
-		0x6c, 0x80, 0x14, 0x78, 0xa6, 0x97, 0x9a, 0x63,
-		0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22, 0x7c,
-		0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b, 0xa1,
-		0x49, 0xa4, 0x47, 0x30, 0x45, 0x31, 0x0b, 0x30,
-		0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
-		0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
-		0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
-		0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
-		0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
-		0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
-		0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
-		0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
-		0x74, 0x64, 0x82, 0x09, 0x00, 0xb1, 0x35, 0x13,
-		0x65, 0x11, 0x20, 0xc5, 0x92, 0x30, 0x0c, 0x06,
-		0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03,
-		0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a,
-		0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
-		0x05, 0x00, 0x03, 0x41, 0x00, 0x85, 0x36, 0x40,
-		0x73, 0xc1, 0xbb, 0x1a, 0xda, 0xd4, 0x59, 0x9f,
-		0x2d, 0xa2, 0x70, 0x31, 0x46, 0x74, 0xec, 0x83,
-		0x6e, 0xa8, 0xc8, 0x3c, 0x51, 0xaf, 0x39, 0xac,
-		0xec, 0x40, 0xbc, 0xe8, 0x22, 0x46, 0x1d, 0x99,
-		0xd6, 0x46, 0x2a, 0x24, 0xd4, 0x8b, 0x05, 0x08,
-		0x4b, 0xfb, 0x35, 0x11, 0x6e, 0x92, 0xbb, 0x77,
-		0xba, 0xe4, 0x12, 0xbb, 0xf4, 0xc8, 0x5e, 0x9c,
-		0x81, 0xa8, 0x97, 0x60, 0x4c, 0x16, 0x03, 0x01,
-		0x00, 0x8b, 0x0c, 0x00, 0x00, 0x87, 0x03, 0x00,
-		0x17, 0x41, 0x04, 0x1c, 0x8f, 0x9c, 0x6d, 0xe7,
-		0xab, 0x3e, 0xf8, 0x0a, 0x5d, 0xe1, 0x86, 0xb4,
-		0xe2, 0x8e, 0xb2, 0x1c, 0x3b, 0xd9, 0xb6, 0x08,
-		0x80, 0x58, 0x21, 0xe9, 0x0e, 0xc6, 0x66, 0x67,
-		0x97, 0xcb, 0xb9, 0x92, 0x07, 0x00, 0xc4, 0xe5,
-		0xec, 0x5f, 0xb4, 0xe2, 0x20, 0xa9, 0xc9, 0x62,
-		0xd0, 0x98, 0xd5, 0xe3, 0x53, 0xff, 0xd0, 0x0a,
-		0x6e, 0x29, 0x69, 0x39, 0x2a, 0x4b, 0x5c, 0xd8,
-		0x6c, 0xf5, 0xfe, 0x00, 0x40, 0x35, 0xa7, 0x26,
-		0x2e, 0xc2, 0x48, 0x93, 0x32, 0xf7, 0x7d, 0x0f,
-		0x0d, 0x77, 0x56, 0x9a, 0x85, 0x0c, 0xa6, 0x74,
-		0x06, 0xb8, 0x3d, 0x90, 0x56, 0x12, 0x63, 0xff,
-		0x00, 0x5e, 0x0f, 0xf7, 0x24, 0xf7, 0xdb, 0x48,
-		0x71, 0xe9, 0x2e, 0x03, 0xd3, 0xfa, 0x3a, 0xae,
-		0xa0, 0xc1, 0x77, 0x3c, 0x4c, 0x59, 0xce, 0x33,
-		0x1a, 0xd2, 0x47, 0x83, 0xfa, 0xea, 0xd8, 0x1e,
-		0x06, 0xe7, 0x7d, 0xa0, 0x9b, 0x16, 0x03, 0x01,
-		0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x46, 0x10, 0x00, 0x00,
-		0x42, 0x41, 0x04, 0x1e, 0x18, 0x37, 0xef, 0x0d,
-		0x19, 0x51, 0x88, 0x35, 0x75, 0x71, 0xb5, 0xe5,
-		0x54, 0x5b, 0x12, 0x2e, 0x8f, 0x09, 0x67, 0xfd,
-		0xa7, 0x24, 0x20, 0x3e, 0xb2, 0x56, 0x1c, 0xce,
-		0x97, 0x28, 0x5e, 0xf8, 0x2b, 0x2d, 0x4f, 0x9e,
-		0xf1, 0x07, 0x9f, 0x6c, 0x4b, 0x5b, 0x83, 0x56,
-		0xe2, 0x32, 0x42, 0xe9, 0x58, 0xb6, 0xd7, 0x49,
-		0xa6, 0xb5, 0x68, 0x1a, 0x41, 0x03, 0x56, 0x6b,
-		0xdc, 0x5a, 0x89, 0x14, 0x03, 0x01, 0x00, 0x01,
-		0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0xd9, 0xa7,
-		0x80, 0x56, 0x3f, 0xa3, 0x8f, 0x96, 0x72, 0x4e,
-		0x4e, 0x6e, 0x23, 0x41, 0x8f, 0xda, 0x91, 0xb2,
-		0x9e, 0x63, 0x23, 0x82, 0x64, 0xcd, 0x07, 0x24,
-		0xd3, 0x40, 0x20, 0x22, 0x4c, 0xe3, 0xff, 0x38,
-		0xbb, 0x43, 0x9d, 0x57, 0x11, 0xd5, 0x46, 0xa5,
-		0x05, 0x29, 0x92, 0x02, 0xce, 0xdf,
-	},
-	{
-		0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
-		0x01, 0x00, 0x90, 0xe7, 0xba, 0x0e, 0xb1, 0xda,
-		0x92, 0xb5, 0x77, 0x56, 0x38, 0xa6, 0x22, 0xc1,
-		0x72, 0xeb, 0x8a, 0x68, 0x09, 0xb6, 0x74, 0xad,
-		0xb3, 0x4a, 0xf2, 0xdd, 0x09, 0x9b, 0xc9, 0x4f,
-		0x84, 0x73, 0x8b, 0xd6, 0x97, 0x50, 0x23, 0x1c,
-		0xa0, 0xc2, 0x0c, 0x25, 0x18, 0xdd, 0x5e, 0x15,
-		0x4d, 0xd9, 0xef, 0x4f, 0x6a, 0x43, 0x61, 0x9c,
-		0x95, 0xde, 0x3c, 0x66, 0xc4, 0xc1, 0x33, 0x56,
-		0xdd, 0x2f, 0x90, 0xaf, 0x68, 0x5c, 0x9c, 0xa4,
-		0x90, 0x6d, 0xbf, 0x51, 0x1d, 0x68, 0xcb, 0x81,
-		0x77, 0x52, 0xa0, 0x93, 0x2a, 0xf8, 0xc7, 0x61,
-		0x87, 0x76, 0xca, 0x93, 0x9e, 0xd6, 0xee, 0x6f,
-		0x3f, 0xeb, 0x7d, 0x06, 0xdd, 0x73, 0x4e, 0x27,
-		0x16, 0x63, 0x92, 0xe4, 0xb2, 0x3f, 0x91, 0x23,
-		0x21, 0x97, 0x90, 0xce, 0x53, 0xb8, 0xb0, 0x9d,
-		0xbd, 0xbd, 0x33, 0x84, 0xad, 0x6b, 0x2e, 0x7b,
-		0xf5, 0xeb, 0x1d, 0x64, 0x37, 0x2e, 0x29, 0x4e,
-		0xb0, 0x93, 0xdb, 0x92, 0xc7, 0xaa, 0x94, 0xa5,
-		0x3b, 0x64, 0xd0,
-	},
-	{
-		0x17, 0x03, 0x01, 0x00, 0x20, 0x11, 0xd8, 0x6b,
-		0x3c, 0xf6, 0xbe, 0xf4, 0x54, 0x87, 0xec, 0x75,
-		0x0c, 0x44, 0xdb, 0x92, 0xfc, 0xde, 0x7e, 0x0f,
-		0x9f, 0x87, 0x87, 0x9c, 0x03, 0xd5, 0x07, 0x84,
-		0xe0, 0x3a, 0xf8, 0xae, 0x14, 0x17, 0x03, 0x01,
-		0x00, 0x20, 0xba, 0x54, 0xef, 0x5b, 0xce, 0xfd,
-		0x47, 0x76, 0x6d, 0xa1, 0x8b, 0xfd, 0x48, 0xde,
-		0x6e, 0x26, 0xc1, 0x0c, 0x9d, 0x54, 0xbf, 0x98,
-		0xf6, 0x1c, 0x80, 0xb9, 0xca, 0x93, 0x81, 0x0a,
-		0x2e, 0x06, 0x15, 0x03, 0x01, 0x00, 0x20, 0x93,
-		0x3e, 0x38, 0x17, 0xc9, 0x0a, 0xc3, 0xea, 0xd3,
-		0x92, 0x75, 0xa6, 0x53, 0x37, 0x4d, 0x74, 0x94,
-		0xbe, 0x01, 0xdc, 0x5c, 0x5a, 0x0f, 0x09, 0xf6,
-		0x57, 0x33, 0xc3, 0xbc, 0x3f, 0x7a, 0x4d,
-	},
+func TestHandshakeClientRSARC4(t *testing.T) {
+	test := &clientTest{
+		name:    "RSA-RC4",
+		command: []string{"openssl", "s_server", "-cipher", "RC4-SHA"},
+	}
+	runClientTestTLS10(t, test)
+	runClientTestTLS11(t, test)
+	runClientTestTLS12(t, test)
 }
 
-var emptyRecordScript = [][]byte{
-	{
-		0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
-		0x46, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x35,
-		0x01, 0x00, 0x00, 0x1b, 0x00, 0x05, 0x00, 0x05,
-		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
-		0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
-		0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x4a, 0x02, 0x00, 0x00,
-		0x46, 0x03, 0x01, 0x51, 0x71, 0x8e, 0x03, 0x02,
-		0xef, 0x09, 0xf2, 0x0e, 0xf5, 0x3b, 0x29, 0x9a,
-		0xa8, 0x8b, 0x46, 0xa3, 0xd4, 0xb4, 0xc1, 0x14,
-		0xc3, 0x19, 0x99, 0xba, 0x3d, 0x78, 0xcf, 0x50,
-		0xd1, 0xe7, 0x26, 0x20, 0xa0, 0x37, 0x6d, 0xc9,
-		0xae, 0x93, 0x33, 0x81, 0x20, 0xe3, 0xc1, 0x90,
-		0x64, 0x6e, 0x67, 0x93, 0xdb, 0xb4, 0x04, 0x16,
-		0xc4, 0x25, 0xdd, 0x10, 0x79, 0x3c, 0x18, 0x0a,
-		0x7c, 0xfd, 0x28, 0x65, 0x00, 0x35, 0x00, 0x16,
-		0x03, 0x01, 0x09, 0x9e, 0x0b, 0x00, 0x09, 0x9a,
-		0x00, 0x09, 0x97, 0x00, 0x04, 0xea, 0x30, 0x82,
-		0x04, 0xe6, 0x30, 0x82, 0x03, 0xce, 0xa0, 0x03,
-		0x02, 0x01, 0x02, 0x02, 0x11, 0x00, 0xff, 0xab,
-		0x02, 0x93, 0xe0, 0x72, 0x99, 0x18, 0x6c, 0x9e,
-		0x96, 0xb8, 0xb9, 0xf7, 0x47, 0xcb, 0x30, 0x0d,
-		0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
-		0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x41, 0x31,
-		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-		0x13, 0x02, 0x46, 0x52, 0x31, 0x12, 0x30, 0x10,
-		0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09, 0x47,
-		0x41, 0x4e, 0x44, 0x49, 0x20, 0x53, 0x41, 0x53,
-		0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04,
-		0x03, 0x13, 0x15, 0x47, 0x61, 0x6e, 0x64, 0x69,
-		0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72,
-		0x64, 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41,
-		0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x31,
-		0x31, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
-		0x5a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x31, 0x31,
-		0x34, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a,
-		0x30, 0x62, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
-		0x55, 0x04, 0x0b, 0x13, 0x18, 0x44, 0x6f, 0x6d,
-		0x61, 0x69, 0x6e, 0x20, 0x43, 0x6f, 0x6e, 0x74,
-		0x72, 0x6f, 0x6c, 0x20, 0x56, 0x61, 0x6c, 0x69,
-		0x64, 0x61, 0x74, 0x65, 0x64, 0x31, 0x24, 0x30,
-		0x22, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1b,
-		0x47, 0x61, 0x6e, 0x64, 0x69, 0x20, 0x53, 0x74,
-		0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x57,
-		0x69, 0x6c, 0x64, 0x63, 0x61, 0x72, 0x64, 0x20,
-		0x53, 0x53, 0x4c, 0x31, 0x17, 0x30, 0x15, 0x06,
-		0x03, 0x55, 0x04, 0x03, 0x14, 0x0e, 0x2a, 0x2e,
-		0x66, 0x72, 0x65, 0x65, 0x6e, 0x6f, 0x64, 0x65,
-		0x2e, 0x6e, 0x65, 0x74, 0x30, 0x82, 0x01, 0x22,
-		0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
-		0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
-		0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
-		0x02, 0x82, 0x01, 0x01, 0x00, 0xdc, 0xe3, 0xfd,
-		0xce, 0xc1, 0x66, 0x62, 0x28, 0x8b, 0x99, 0x65,
-		0x72, 0x52, 0x88, 0x93, 0x5b, 0x3f, 0x8d, 0xde,
-		0x2b, 0xb0, 0xa0, 0xf4, 0xbd, 0xb4, 0x07, 0x5f,
-		0x9e, 0x01, 0x47, 0x60, 0x57, 0x5f, 0xdf, 0xdc,
-		0x63, 0x28, 0x1c, 0x1e, 0x5b, 0xc8, 0xe6, 0x29,
-		0xdd, 0xeb, 0x26, 0x63, 0xd5, 0xbf, 0x83, 0xb2,
-		0x2d, 0xcd, 0x2c, 0xa0, 0xb6, 0x91, 0xad, 0xaf,
-		0x95, 0x21, 0x1d, 0x1f, 0x39, 0x8d, 0x3e, 0x17,
-		0xd6, 0xbd, 0x99, 0xf5, 0x6c, 0xd4, 0xcb, 0x79,
-		0x12, 0x3e, 0x11, 0xb9, 0x7e, 0x62, 0xbc, 0x2d,
-		0xbf, 0xe0, 0x55, 0x1b, 0x5c, 0x1e, 0xce, 0x31,
-		0xd9, 0xf8, 0x56, 0x68, 0x95, 0x2b, 0x15, 0x84,
-		0x35, 0xae, 0x98, 0x2c, 0x63, 0x01, 0xb2, 0x0d,
-		0xab, 0xa8, 0x61, 0xef, 0x7f, 0x15, 0x2c, 0x6d,
-		0xf7, 0x67, 0x1d, 0xb8, 0x8d, 0xf6, 0xa2, 0x1c,
-		0x4e, 0x85, 0xf0, 0xea, 0x1a, 0x2b, 0xc8, 0xac,
-		0x70, 0x86, 0x9a, 0xbb, 0x9e, 0x9d, 0xbd, 0xc9,
-		0x87, 0x2b, 0x9f, 0x5e, 0x40, 0x44, 0x9b, 0xba,
-		0x96, 0x45, 0x24, 0xbc, 0x49, 0xb8, 0xfe, 0x26,
-		0x3a, 0x1d, 0x1a, 0x0a, 0x3a, 0x90, 0x9c, 0x75,
-		0x51, 0x59, 0x89, 0x98, 0x1a, 0x56, 0xe1, 0x3a,
-		0x1a, 0xba, 0xff, 0xb4, 0x37, 0x7d, 0xd8, 0x99,
-		0xe2, 0xeb, 0x45, 0x27, 0xe2, 0x42, 0x42, 0x46,
-		0xbb, 0x00, 0x29, 0x9f, 0x30, 0xc9, 0x1e, 0x6c,
-		0xce, 0x59, 0x0e, 0xbe, 0x16, 0x03, 0x31, 0xec,
-		0x10, 0xc1, 0x6d, 0xca, 0x9d, 0x5f, 0x6d, 0xf1,
-		0x26, 0x11, 0xe5, 0x50, 0xa1, 0xbb, 0x67, 0xb2,
-		0xe0, 0x2b, 0xed, 0x76, 0x5b, 0xc7, 0x68, 0xc0,
-		0x18, 0xad, 0x91, 0x9e, 0xb5, 0xd4, 0x4d, 0x21,
-		0xcd, 0x98, 0xd9, 0xe0, 0x05, 0x0a, 0x4d, 0x24,
-		0xa3, 0xe6, 0x12, 0x04, 0xdd, 0x50, 0xe6, 0xc8,
-		0x7a, 0x69, 0xb9, 0x32, 0x43, 0x02, 0x03, 0x01,
-		0x00, 0x01, 0xa3, 0x82, 0x01, 0xb6, 0x30, 0x82,
-		0x01, 0xb2, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
-		0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xb6,
-		0xa8, 0xff, 0xa2, 0xa8, 0x2f, 0xd0, 0xa6, 0xcd,
-		0x4b, 0xb1, 0x68, 0xf3, 0xe7, 0x50, 0x10, 0x31,
-		0xa7, 0x79, 0x21, 0x30, 0x1d, 0x06, 0x03, 0x55,
-		0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x62, 0x37,
-		0xd4, 0x3c, 0xbf, 0xd9, 0xc2, 0x99, 0xf3, 0x28,
-		0x3e, 0xdb, 0xca, 0xee, 0xf3, 0xb3, 0xc8, 0x73,
-		0xb0, 0x3c, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
-		0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02,
-		0x05, 0xa0, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d,
-		0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00,
-		0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04,
-		0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01,
-		0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b,
-		0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30,
-		0x60, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x59,
-		0x30, 0x57, 0x30, 0x4b, 0x06, 0x0b, 0x2b, 0x06,
-		0x01, 0x04, 0x01, 0xb2, 0x31, 0x01, 0x02, 0x02,
-		0x1a, 0x30, 0x3c, 0x30, 0x3a, 0x06, 0x08, 0x2b,
-		0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16,
-		0x2e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
-		0x77, 0x77, 0x77, 0x2e, 0x67, 0x61, 0x6e, 0x64,
-		0x69, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x63, 0x6f,
-		0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x73, 0x2f,
-		0x66, 0x72, 0x2f, 0x73, 0x73, 0x6c, 0x2f, 0x63,
-		0x70, 0x73, 0x2f, 0x70, 0x64, 0x66, 0x2f, 0x30,
-		0x08, 0x06, 0x06, 0x67, 0x81, 0x0c, 0x01, 0x02,
-		0x01, 0x30, 0x3c, 0x06, 0x03, 0x55, 0x1d, 0x1f,
-		0x04, 0x35, 0x30, 0x33, 0x30, 0x31, 0xa0, 0x2f,
-		0xa0, 0x2d, 0x86, 0x2b, 0x68, 0x74, 0x74, 0x70,
-		0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x67,
-		0x61, 0x6e, 0x64, 0x69, 0x2e, 0x6e, 0x65, 0x74,
-		0x2f, 0x47, 0x61, 0x6e, 0x64, 0x69, 0x53, 0x74,
-		0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x53, 0x53,
-		0x4c, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30,
-		0x6a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
-		0x07, 0x01, 0x01, 0x04, 0x5e, 0x30, 0x5c, 0x30,
-		0x37, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
-		0x07, 0x30, 0x02, 0x86, 0x2b, 0x68, 0x74, 0x74,
-		0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x74, 0x2e,
-		0x67, 0x61, 0x6e, 0x64, 0x69, 0x2e, 0x6e, 0x65,
-		0x74, 0x2f, 0x47, 0x61, 0x6e, 0x64, 0x69, 0x53,
-		0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x53,
-		0x53, 0x4c, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74,
-		0x30, 0x21, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
-		0x05, 0x07, 0x30, 0x01, 0x86, 0x15, 0x68, 0x74,
-		0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73,
-		0x70, 0x2e, 0x67, 0x61, 0x6e, 0x64, 0x69, 0x2e,
-		0x6e, 0x65, 0x74, 0x30, 0x27, 0x06, 0x03, 0x55,
-		0x1d, 0x11, 0x04, 0x20, 0x30, 0x1e, 0x82, 0x0e,
-		0x2a, 0x2e, 0x66, 0x72, 0x65, 0x65, 0x6e, 0x6f,
-		0x64, 0x65, 0x2e, 0x6e, 0x65, 0x74, 0x82, 0x0c,
-		0x66, 0x72, 0x65, 0x65, 0x6e, 0x6f, 0x64, 0x65,
-		0x2e, 0x6e, 0x65, 0x74, 0x30, 0x0d, 0x06, 0x09,
-		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-		0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
-		0x5b, 0x4a, 0x3a, 0x1d, 0x75, 0xe0, 0xc0, 0x9e,
-		0xc9, 0x16, 0x66, 0x7f, 0x73, 0x95, 0x6e, 0x35,
-		0xe4, 0x27, 0xfa, 0x8c, 0x9d, 0xee, 0xb1, 0x37,
-		0x42, 0x3f, 0x54, 0x6a, 0x9d, 0x41, 0x84, 0x57,
-		0xe1, 0x03, 0x3d, 0x69, 0x61, 0x77, 0x3b, 0x91,
-		0xa2, 0x70, 0x94, 0xb6, 0x8e, 0x41, 0x63, 0x70,
-		0xf2, 0x16, 0x04, 0x50, 0x05, 0x14, 0xfb, 0x59,
-		0x7d, 0x89, 0x09, 0x3f, 0xb6, 0xef, 0xca, 0x3c,
-		0x89, 0x88, 0x08, 0xe9, 0xa1, 0xf3, 0x33, 0x31,
-		0x05, 0x4d, 0x70, 0xff, 0xdd, 0xa7, 0xd2, 0xe2,
-		0xa0, 0x94, 0x3a, 0xf7, 0xc2, 0x9f, 0xad, 0x2b,
-		0x2e, 0x20, 0xfa, 0x6c, 0xe1, 0xfc, 0xe6, 0x62,
-		0x22, 0xa1, 0x38, 0x93, 0xec, 0x3e, 0xce, 0xfd,
-		0x1f, 0xdd, 0xd4, 0x7c, 0x39, 0x46, 0x8b, 0xb4,
-		0x64, 0xfa, 0xa1, 0x46, 0x87, 0x78, 0x2c, 0xd7,
-		0x9c, 0xdd, 0x60, 0xd6, 0xda, 0x8e, 0xd8, 0x29,
-		0x6d, 0x61, 0xa7, 0x29, 0x07, 0x76, 0xfc, 0xf9,
-		0xbd, 0xfd, 0x14, 0xeb, 0x44, 0x70, 0xff, 0xd0,
-		0x23, 0x99, 0x83, 0xc5, 0x5c, 0x56, 0x88, 0xaa,
-		0x34, 0xda, 0xa6, 0xb3, 0x9a, 0xbf, 0xda, 0x58,
-		0x1e, 0xa4, 0xb8, 0xc0, 0x40, 0x9d, 0xf0, 0xfc,
-		0xf1, 0x23, 0xc2, 0xbc, 0x59, 0xe1, 0x82, 0xed,
-		0x5d, 0xfb, 0x99, 0xaf, 0xf5, 0xf5, 0x15, 0xb8,
-		0x8b, 0x59, 0xce, 0xaa, 0xca, 0xdf, 0xdc, 0x94,
-		0x11, 0xe0, 0x96, 0xbf, 0x9f, 0x54, 0xa4, 0x9f,
-		0x54, 0x36, 0x4a, 0xe8, 0x93, 0xda, 0xf4, 0x8c,
-		0xb0, 0x6b, 0x8d, 0x4a, 0x9e, 0x11, 0xae, 0xcb,
-		0xcb, 0x33, 0x8a, 0x4d, 0xcd, 0x4e, 0xa5, 0x9b,
-		0xe9, 0x14, 0x46, 0x43, 0x9b, 0x96, 0x5f, 0x6d,
-		0xf2, 0xea, 0x40, 0xef, 0x14, 0xc3, 0x99, 0x9f,
-		0x23, 0x1e, 0xa5, 0x13, 0xab, 0x08, 0xea, 0x8f,
-		0x68, 0x5b, 0x7d, 0x71, 0xdf, 0x18, 0xd1, 0x57,
-		0x00, 0x04, 0xa7, 0x30, 0x82, 0x04, 0xa3, 0x30,
-		0x82, 0x03, 0x8b, 0xa0, 0x03, 0x02, 0x01, 0x02,
-		0x02, 0x10, 0x5a, 0xb6, 0x1d, 0xac, 0x1e, 0x4d,
-		0xa2, 0x06, 0x14, 0xc7, 0x55, 0x3d, 0x3d, 0xa9,
-		0xb2, 0xdc, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
-		0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
-		0x00, 0x30, 0x81, 0x97, 0x31, 0x0b, 0x30, 0x09,
-		0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
-		0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
-		0x04, 0x08, 0x13, 0x02, 0x55, 0x54, 0x31, 0x17,
-		0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13,
-		0x0e, 0x53, 0x61, 0x6c, 0x74, 0x20, 0x4c, 0x61,
-		0x6b, 0x65, 0x20, 0x43, 0x69, 0x74, 0x79, 0x31,
-		0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a,
-		0x13, 0x15, 0x54, 0x68, 0x65, 0x20, 0x55, 0x53,
-		0x45, 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20,
-		0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31,
-		0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b,
-		0x13, 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
-		0x2f, 0x77, 0x77, 0x77, 0x2e, 0x75, 0x73, 0x65,
-		0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63,
-		0x6f, 0x6d, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03,
-		0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54, 0x4e,
-		0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72,
-		0x73, 0x74, 0x2d, 0x48, 0x61, 0x72, 0x64, 0x77,
-		0x61, 0x72, 0x65, 0x30, 0x1e, 0x17, 0x0d, 0x30,
-		0x38, 0x31, 0x30, 0x32, 0x33, 0x30, 0x30, 0x30,
-		0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x30,
-		0x30, 0x35, 0x33, 0x30, 0x31, 0x30, 0x34, 0x38,
-		0x33, 0x38, 0x5a, 0x30, 0x41, 0x31, 0x0b, 0x30,
-		0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
-		0x46, 0x52, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03,
-		0x55, 0x04, 0x0a, 0x13, 0x09, 0x47, 0x41, 0x4e,
-		0x44, 0x49, 0x20, 0x53, 0x41, 0x53, 0x31, 0x1e,
-		0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
-		0x15, 0x47, 0x61, 0x6e, 0x64, 0x69, 0x20, 0x53,
-		0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20,
-		0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x30, 0x82,
-		0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
-		0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
-		0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,
-		0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb6,
-		0x54, 0x3d, 0xa5, 0xdb, 0x0d, 0x22, 0x78, 0x50,
-		0x6a, 0x5a, 0x23, 0x89, 0x3f, 0x97, 0xa1, 0xd4,
-		0x07, 0x1a, 0xa9, 0x58, 0x08, 0x9b, 0xa0, 0x15,
-		0xc3, 0x32, 0xb6, 0xb7, 0xf1, 0xe8, 0xb9, 0xa5,
-		0x6f, 0xad, 0x37, 0xf6, 0x6e, 0x71, 0x1b, 0xb4,
-		0x75, 0x2d, 0x48, 0x5e, 0x9f, 0xc6, 0x15, 0xaa,
-		0x81, 0xef, 0xe5, 0xc4, 0x88, 0x95, 0x8a, 0x3a,
-		0x6c, 0x77, 0xcc, 0xb5, 0xcd, 0x65, 0xe4, 0x67,
-		0xe5, 0x73, 0xc9, 0x50, 0x52, 0x94, 0xc1, 0x27,
-		0x49, 0x3e, 0xa0, 0x6b, 0x41, 0x16, 0x41, 0xb6,
-		0x94, 0x99, 0x41, 0xae, 0x3e, 0xcb, 0xe2, 0x06,
-		0x46, 0x09, 0xe9, 0x4d, 0xbe, 0xc9, 0x4c, 0x55,
-		0xa9, 0x18, 0x7e, 0xa6, 0xdf, 0x6e, 0xfd, 0x4a,
-		0xb2, 0xcc, 0x6c, 0x4e, 0xd9, 0xc8, 0x50, 0x15,
-		0x93, 0xb3, 0xf2, 0xe9, 0xe3, 0xc2, 0x6a, 0xad,
-		0x3a, 0xd5, 0xfb, 0xc3, 0x79, 0x50, 0x9f, 0x25,
-		0x79, 0x29, 0xb2, 0x47, 0x64, 0x7c, 0x20, 0x3e,
-		0xe2, 0x08, 0x4d, 0x93, 0x29, 0x14, 0xb6, 0x34,
-		0x6e, 0xcf, 0x71, 0x46, 0x7e, 0x76, 0x10, 0xf4,
-		0xfd, 0x6c, 0xaa, 0x01, 0xd2, 0xc2, 0x06, 0xde,
-		0x92, 0x83, 0xcc, 0x58, 0x90, 0x2e, 0x92, 0xde,
-		0x1e, 0x65, 0xb7, 0x63, 0x2f, 0x3d, 0xb2, 0xeb,
-		0x70, 0x8c, 0x4c, 0xe0, 0xbe, 0x15, 0x9d, 0xde,
-		0xc1, 0x4d, 0x56, 0xf8, 0x0b, 0xc6, 0x8e, 0x07,
-		0xb9, 0x5d, 0xdf, 0x95, 0xf0, 0x7b, 0x40, 0x1f,
-		0x1a, 0x2c, 0xd7, 0x9c, 0x2b, 0x4b, 0x76, 0xf4,
-		0x59, 0xf5, 0x43, 0xc1, 0x2c, 0x66, 0x10, 0x9e,
-		0x9e, 0x66, 0x96, 0x60, 0x9d, 0x1c, 0x74, 0x1b,
-		0x4e, 0x18, 0x5c, 0x08, 0xb0, 0x6e, 0x6c, 0xca,
-		0x69, 0x1a, 0x02, 0xe9, 0xbb, 0xca, 0x78, 0xef,
-		0x66, 0x2e, 0xe3, 0x32, 0xfd, 0x41, 0x5c, 0x95,
-		0x74, 0x81, 0x4d, 0xf4, 0xda, 0xfe, 0x4b, 0x02,
-		0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x3e,
-		0x30, 0x82, 0x01, 0x3a, 0x30, 0x1f, 0x06, 0x03,
-		0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80,
-		0x14, 0xa1, 0x72, 0x5f, 0x26, 0x1b, 0x28, 0x98,
-		0x43, 0x95, 0x5d, 0x07, 0x37, 0xd5, 0x85, 0x96,
-		0x9d, 0x4b, 0xd2, 0xc3, 0x45, 0x30, 0x1d, 0x06,
-		0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
-		0xb6, 0xa8, 0xff, 0xa2, 0xa8, 0x2f, 0xd0, 0xa6,
-		0xcd, 0x4b, 0xb1, 0x68, 0xf3, 0xe7, 0x50, 0x10,
-		0x31, 0xa7, 0x79, 0x21, 0x30, 0x0e, 0x06, 0x03,
-		0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04,
-		0x03, 0x02, 0x01, 0x06, 0x30, 0x12, 0x06, 0x03,
-		0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08,
-		0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00,
-		0x30, 0x18, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04,
-		0x11, 0x30, 0x0f, 0x30, 0x0d, 0x06, 0x0b, 0x2b,
-		0x06, 0x01, 0x04, 0x01, 0xb2, 0x31, 0x01, 0x02,
-		0x02, 0x1a, 0x30, 0x44, 0x06, 0x03, 0x55, 0x1d,
-		0x1f, 0x04, 0x3d, 0x30, 0x3b, 0x30, 0x39, 0xa0,
-		0x37, 0xa0, 0x35, 0x86, 0x33, 0x68, 0x74, 0x74,
-		0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e,
-		0x75, 0x73, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73,
-		0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x54,
-		0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69,
-		0x72, 0x73, 0x74, 0x2d, 0x48, 0x61, 0x72, 0x64,
-		0x77, 0x61, 0x72, 0x65, 0x2e, 0x63, 0x72, 0x6c,
-		0x30, 0x74, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
-		0x05, 0x07, 0x01, 0x01, 0x04, 0x68, 0x30, 0x66,
-		0x30, 0x3d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
-		0x05, 0x07, 0x30, 0x02, 0x86, 0x31, 0x68, 0x74,
-		0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x74,
-		0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x72, 0x75,
-		0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55,
-		0x54, 0x4e, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75,
-		0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
-		0x5f, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30,
-		0x25, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
-		0x07, 0x30, 0x01, 0x86, 0x19, 0x68, 0x74, 0x74,
-		0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70,
-		0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x72, 0x75,
-		0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x0d,
-		0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
-		0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01,
-		0x01, 0x00, 0x19, 0x53, 0xbf, 0x03, 0x3d, 0x9b,
-		0xe2, 0x6b, 0x5a, 0xfd, 0xba, 0x49, 0x1f, 0x4f,
-		0xec, 0xe1, 0xc6, 0x82, 0x39, 0x3c, 0xd2, 0x03,
-		0x04, 0x0f, 0xab, 0x7b, 0x3e, 0x82, 0xa9, 0x85,
-		0x10, 0x1f, 0xf4, 0xde, 0x32, 0xaf, 0x58, 0x3f,
-		0xff, 0x70, 0xf3, 0x30, 0x1d, 0x97, 0x2d, 0x4c,
-		0x9a, 0xe2, 0xec, 0x0c, 0x3e, 0x14, 0x2d, 0x2f,
-		0x98, 0x48, 0x9d, 0xae, 0x16, 0x6a, 0xac, 0x2d,
-		0x42, 0xaa, 0xb5, 0x64, 0xa4, 0x70, 0xbb, 0xeb,
-		0x73, 0x94, 0x7b, 0x46, 0x4c, 0xe7, 0x7a, 0x14,
-		0x76, 0x5b, 0x4c, 0x1d, 0x84, 0xa1, 0x20, 0x74,
-		0x1f, 0x2e, 0x4b, 0x5c, 0x70, 0x88, 0xdc, 0xbd,
-		0xf7, 0x19, 0x3d, 0xed, 0x59, 0x0d, 0xe2, 0x3f,
-		0x26, 0xe2, 0x9c, 0xac, 0xa4, 0x3c, 0x95, 0x1c,
-		0xf8, 0xbe, 0x8c, 0x03, 0xae, 0xf0, 0xe5, 0x9c,
-		0x4d, 0xbc, 0xc7, 0x9b, 0x58, 0x00, 0xbf, 0xaf,
-		0xad, 0xfa, 0x37, 0x6e, 0x71, 0x6d, 0x18, 0x34,
-		0x0e, 0xc1, 0xea, 0x6a, 0xf8, 0x0d, 0xdf, 0x69,
-		0x54, 0x56, 0x15, 0xf2, 0x28, 0xb3, 0xfe, 0xa4,
-		0x63, 0xec, 0xc5, 0x04, 0x64, 0x60, 0xbb, 0xfe,
-		0x2a, 0xf0, 0xf4, 0x87, 0xa1, 0xb0, 0xae, 0xbd,
-		0xaa, 0xe4, 0x2f, 0xe3, 0x03, 0x0b, 0x2f, 0x66,
-		0x5f, 0x85, 0xa4, 0x32, 0x7b, 0x46, 0xed, 0x25,
-		0x0c, 0xe7, 0xf1, 0xb7, 0xe7, 0x19, 0xfd, 0x60,
-		0xba, 0x5f, 0x87, 0x77, 0xde, 0x98, 0x07, 0x96,
-		0xe4, 0x5e, 0xea, 0x63, 0x7d, 0xa8, 0xde, 0x55,
-		0xda, 0x61, 0x5c, 0x3c, 0x90, 0x83, 0x43, 0x04,
-		0x07, 0x3c, 0xdd, 0xf3, 0xf8, 0x9f, 0x06, 0x52,
-		0x0a, 0xde, 0xc7, 0xb6, 0x7b, 0x8f, 0xe1, 0x11,
-		0xf7, 0x04, 0x7a, 0x35, 0xff, 0x6a, 0xbc, 0x5b,
-		0xc7, 0x50, 0x49, 0x08, 0x70, 0x6f, 0x94, 0x43,
-		0xcd, 0x9e, 0xc7, 0x70, 0xf1, 0xdb, 0xd0, 0x6d,
-		0xda, 0x8f, 0x16, 0x03, 0x01, 0x00, 0x0e, 0x0d,
-		0x00, 0x00, 0x06, 0x03, 0x01, 0x02, 0x40, 0x00,
-		0x00, 0x0e, 0x00, 0x00, 0x00,
-	},
-	{
-		0x16, 0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02,
-		0xba, 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30,
-		0x82, 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0,
-		0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85,
-		0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
-		0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
-		0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45,
-		0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
-		0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30,
-		0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
-		0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
-		0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
-		0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74,
-		0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69,
-		0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74,
-		0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17,
-		0x0d, 0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30,
-		0x39, 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d,
-		0x31, 0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
-		0x30, 0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31,
-		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
-		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
-		0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
-		0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
-		0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
-		0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
-		0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
-		0x20, 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30,
-		0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
-		0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81,
-		0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81,
-		0x00, 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5,
-		0xbf, 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6,
-		0x2b, 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a,
-		0x7a, 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5,
-		0x65, 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5,
-		0xb4, 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e,
-		0x62, 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12,
-		0x5c, 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa,
-		0x58, 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3,
-		0xd0, 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54,
-		0x9f, 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe,
-		0x18, 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d,
-		0xf1, 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51,
-		0xc9, 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66,
-		0x01, 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a,
-		0x1d, 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d,
-		0x79, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81,
-		0xa7, 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03,
-		0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1,
-		0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
-		0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
-		0x18, 0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55,
-		0x1d, 0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14,
-		0xb1, 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28,
-		0xdb, 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26,
-		0x8e, 0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47,
-		0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
-		0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31,
-		0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
-		0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53,
-		0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f,
-		0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49,
-		0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20,
-		0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20,
-		0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82,
-		0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f,
-		0xb8, 0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d,
-		0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
-		0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
-		0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03,
-		0x81, 0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7,
-		0x6b, 0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2,
-		0xb0, 0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75,
-		0xb5, 0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e,
-		0xae, 0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3,
-		0x6e, 0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08,
-		0xb5, 0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb,
-		0x30, 0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec,
-		0xe7, 0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d,
-		0x78, 0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a,
-		0x2d, 0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9,
-		0x75, 0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5,
-		0xcd, 0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0,
-		0x1c, 0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd,
-		0x57, 0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99,
-		0x9b, 0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90,
-		0xa7, 0xbd, 0xd9, 0x16, 0x03, 0x01, 0x01, 0x06,
-		0x10, 0x00, 0x01, 0x02, 0x01, 0x00, 0x25, 0x48,
-		0x6c, 0x0a, 0xde, 0x9d, 0x3a, 0x57, 0xe4, 0x2e,
-		0xb9, 0xfc, 0xb4, 0x46, 0x1f, 0x20, 0x4f, 0x58,
-		0x4d, 0x12, 0x08, 0xb4, 0x3e, 0x4c, 0xf5, 0xa8,
-		0xa5, 0x16, 0x40, 0x29, 0x19, 0x04, 0x4d, 0xf9,
-		0x54, 0x3a, 0x32, 0xd7, 0x79, 0xf2, 0x0e, 0xc1,
-		0x7b, 0x0c, 0x62, 0x71, 0xbb, 0xb4, 0x8c, 0xe7,
-		0x84, 0xd5, 0xf8, 0x11, 0x77, 0x7f, 0x87, 0x6c,
-		0xfc, 0x25, 0xf3, 0x2d, 0x97, 0x3d, 0x1f, 0xf5,
-		0xfc, 0x64, 0x94, 0x9f, 0xdd, 0x90, 0x82, 0xdd,
-		0x11, 0x74, 0x74, 0x59, 0xa2, 0x1a, 0x71, 0xb2,
-		0x55, 0x6d, 0x18, 0xca, 0x85, 0x47, 0x8b, 0x79,
-		0x73, 0x06, 0x24, 0x38, 0xc3, 0x34, 0x98, 0x84,
-		0x62, 0x81, 0xd8, 0xad, 0x54, 0xad, 0x13, 0xa5,
-		0xf4, 0xe4, 0x82, 0x85, 0xd3, 0xe3, 0x9e, 0xeb,
-		0xb5, 0xf5, 0x95, 0x83, 0x0e, 0xb9, 0x7d, 0xb6,
-		0xda, 0x0c, 0xf6, 0x14, 0x6a, 0x60, 0x8c, 0x75,
-		0x56, 0xf0, 0xe9, 0x60, 0xe0, 0x4c, 0xf4, 0x4e,
-		0x84, 0x8b, 0x4f, 0xf4, 0x2f, 0xde, 0xb7, 0xec,
-		0x61, 0xd3, 0x77, 0x07, 0x6e, 0x41, 0x57, 0xc9,
-		0xd9, 0x1d, 0x75, 0xee, 0x42, 0x63, 0xdc, 0x58,
-		0xad, 0xfc, 0xc7, 0xe1, 0x77, 0x49, 0xb1, 0x58,
-		0x21, 0x96, 0x00, 0x55, 0x90, 0x6b, 0xf6, 0x2a,
-		0x5a, 0x19, 0x25, 0x93, 0x59, 0x9d, 0xaf, 0x79,
-		0x9b, 0x18, 0x5d, 0xf6, 0x5d, 0x64, 0x4b, 0x9a,
-		0xf4, 0xde, 0xf2, 0x7f, 0xbd, 0x93, 0x7e, 0x45,
-		0x3e, 0x17, 0xae, 0xbf, 0x52, 0xe1, 0xba, 0x8e,
-		0x0b, 0xbc, 0x1e, 0x91, 0x9d, 0xf1, 0x4e, 0x0b,
-		0xab, 0x9e, 0x5c, 0x4c, 0x6f, 0xf7, 0xf3, 0x8d,
-		0x8c, 0x6d, 0xeb, 0x46, 0x05, 0x36, 0x7e, 0x2f,
-		0x9c, 0xa1, 0x86, 0x15, 0xe1, 0xe4, 0xb4, 0x20,
-		0x06, 0x44, 0x7b, 0x3c, 0x8b, 0x13, 0x96, 0xf5,
-		0x02, 0xb1, 0x4f, 0x3c, 0x2d, 0x4a, 0x16, 0x03,
-		0x01, 0x00, 0x86, 0x0f, 0x00, 0x00, 0x82, 0x00,
-		0x80, 0x52, 0xb1, 0x0d, 0xfc, 0x85, 0x34, 0x56,
-		0xb9, 0xdf, 0xa7, 0x8e, 0xf4, 0xfd, 0x02, 0x46,
-		0x8a, 0x23, 0xcc, 0x53, 0x3b, 0x0f, 0xa7, 0x61,
-		0xf3, 0xb5, 0xbf, 0xfe, 0x59, 0x77, 0x10, 0xd6,
-		0x56, 0x93, 0x19, 0x6b, 0x2c, 0xf1, 0x35, 0x71,
-		0xe3, 0x36, 0x2f, 0xa0, 0x90, 0x4e, 0x5a, 0xdf,
-		0x8d, 0x06, 0x88, 0xcf, 0xb1, 0x06, 0x56, 0x8b,
-		0x74, 0x8f, 0x02, 0x8e, 0x10, 0xd2, 0xab, 0x8d,
-		0x3f, 0x3e, 0x02, 0xf1, 0x1a, 0x80, 0x6d, 0x0f,
-		0x9e, 0x77, 0xd8, 0xfa, 0x92, 0xb3, 0x16, 0x40,
-		0xeb, 0x9e, 0xca, 0xd7, 0xe4, 0x31, 0xcc, 0x63,
-		0x5f, 0xe2, 0x4c, 0x85, 0x0e, 0xf2, 0xdd, 0xd3,
-		0xfe, 0x7e, 0xa7, 0x60, 0x1c, 0xb4, 0x00, 0xd8,
-		0xbe, 0x4b, 0x9b, 0x66, 0x78, 0x0f, 0xfb, 0x3b,
-		0x52, 0x30, 0x2b, 0x8b, 0xd9, 0xef, 0x82, 0x0a,
-		0xa4, 0x18, 0x1d, 0xb0, 0xb5, 0xbf, 0x54, 0x97,
-		0x0c, 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16,
-		0x03, 0x01, 0x00, 0x30, 0xa1, 0x74, 0x22, 0xd8,
-		0x86, 0x6a, 0xbe, 0x53, 0x34, 0x1d, 0xb3, 0x73,
-		0xff, 0x51, 0xc0, 0xce, 0x8e, 0x7d, 0x9b, 0xab,
-		0xcb, 0x8b, 0x79, 0xae, 0x04, 0x01, 0xa7, 0xf2,
-		0x8e, 0x9d, 0xab, 0xa3, 0x73, 0x80, 0x5c, 0xff,
-		0x96, 0x20, 0xbb, 0x8d, 0xc0, 0x02, 0x66, 0x6c,
-		0x83, 0x4b, 0x78, 0x20,
-	},
-	{
-		0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
-		0x01, 0x00, 0x30, 0x29, 0xd4, 0xfd, 0x03, 0x8b,
-		0x30, 0x20, 0xf7, 0xca, 0xc0, 0x6c, 0x83, 0x5d,
-		0x73, 0xcb, 0x81, 0x60, 0xe0, 0x9a, 0x09, 0xcb,
-		0x33, 0x03, 0x80, 0x81, 0x4e, 0x84, 0x47, 0xd5,
-		0x74, 0x6c, 0x3b, 0xb5, 0xc0, 0x48, 0x0d, 0x52,
-		0xdd, 0xbe, 0xc2, 0x06, 0xf5, 0x79, 0x2b, 0x3e,
-		0x99, 0x56, 0x94, 0x17, 0x03, 0x01, 0x00, 0x20,
-		0x26, 0x46, 0x90, 0x9d, 0xef, 0x59, 0x00, 0xb6,
-		0x70, 0xe8, 0x1e, 0x1a, 0x80, 0x8b, 0x04, 0xb2,
-		0xfc, 0x51, 0xf8, 0x93, 0xbe, 0x00, 0x28, 0xba,
-		0xb8, 0xdc, 0x51, 0x7e, 0x92, 0x80, 0xfa, 0xf2,
-		0x17, 0x03, 0x01, 0x00, 0xe0, 0xb8, 0x2e, 0xc4,
-		0x6b, 0x3f, 0xda, 0x39, 0x87, 0x7f, 0x03, 0x43,
-		0x28, 0xdd, 0xb9, 0xf9, 0x9e, 0x16, 0xf5, 0xce,
-		0x3f, 0x7e, 0x6a, 0x7b, 0xb3, 0x60, 0x14, 0xe1,
-		0xea, 0x54, 0xc5, 0xe6, 0x05, 0x0a, 0x6c, 0xe0,
-		0xef, 0x58, 0x29, 0x8a, 0x77, 0x64, 0x77, 0x5d,
-		0x9c, 0xe2, 0xe0, 0x3c, 0x6d, 0x87, 0x82, 0xbe,
-		0x47, 0x63, 0xd4, 0xfd, 0x0c, 0x25, 0xc4, 0xb1,
-		0xfe, 0x29, 0x6f, 0x84, 0xfb, 0xab, 0x6e, 0xa7,
-		0xf9, 0x22, 0x89, 0x97, 0x5b, 0x91, 0x0a, 0x07,
-		0xe0, 0xef, 0x3d, 0x67, 0xee, 0x87, 0xa8, 0x33,
-		0x02, 0x64, 0x33, 0xca, 0x15, 0x10, 0xb9, 0x57,
-		0xd8, 0xe5, 0x1a, 0x4b, 0xe3, 0x45, 0xc1, 0x62,
-		0x85, 0x50, 0xf1, 0x79, 0x54, 0xe1, 0x2e, 0x25,
-		0x01, 0x3c, 0xdb, 0x2d, 0x39, 0x14, 0x2f, 0x9b,
-		0xd0, 0x1d, 0xc1, 0xac, 0x73, 0x7d, 0xa4, 0xed,
-		0x89, 0x98, 0xb1, 0xae, 0x8a, 0x9e, 0xc8, 0xa7,
-		0xfe, 0x55, 0x27, 0xb5, 0xb5, 0xa2, 0xec, 0x7e,
-		0xe3, 0x6b, 0x45, 0x19, 0xfa, 0x20, 0x1c, 0x33,
-		0x83, 0x22, 0x33, 0x97, 0xd2, 0x5a, 0xc4, 0xf8,
-		0x9a, 0x03, 0x13, 0x85, 0xf2, 0x2b, 0x04, 0x59,
-		0x27, 0xd7, 0x0b, 0x42, 0x47, 0x9b, 0x7d, 0x4d,
-		0xb2, 0x1a, 0x85, 0x7f, 0x97, 0xc2, 0xf2, 0x10,
-		0xf0, 0xfa, 0x4e, 0x4b, 0x62, 0x43, 0x3a, 0x09,
-		0x2e, 0xcd, 0x8f, 0xa8, 0xb6, 0x0b, 0x5f, 0x34,
-		0xd7, 0x3b, 0xba, 0xd9, 0xe5, 0x01, 0x2d, 0x35,
-		0xae, 0xc5, 0x4c, 0xab, 0x40, 0x64, 0xc2, 0xc9,
-		0x8c, 0x69, 0x44, 0xf4, 0xb8, 0xb5, 0x3a, 0x05,
-		0x3c, 0x29, 0x19, 0xb4, 0x09, 0x17, 0x03, 0x01,
-		0x00, 0x20, 0xc8, 0xc5, 0xb7, 0xe3, 0xd2, 0x3e,
-		0x27, 0xb5, 0x71, 0x8f, 0x52, 0x0b, 0xce, 0x17,
-		0x64, 0x86, 0xa4, 0x34, 0x16, 0x1b, 0x61, 0x64,
-		0x7c, 0xb3, 0xf2, 0xe5, 0x3e, 0xfd, 0xdd, 0xfb,
-		0x40, 0x78, 0x17, 0x03, 0x01, 0x00, 0x50, 0x8e,
-		0x79, 0xf0, 0x8e, 0x76, 0x5d, 0x34, 0x09, 0xdc,
-		0xec, 0x6d, 0xc3, 0x43, 0x1d, 0xcb, 0x2d, 0xaa,
-		0x08, 0x7a, 0x51, 0x94, 0x4e, 0xc5, 0x26, 0xe4,
-		0x0b, 0x8e, 0x8f, 0x51, 0xf2, 0x9f, 0xeb, 0xc3,
-		0x18, 0x43, 0x95, 0x15, 0xfc, 0x59, 0x18, 0x25,
-		0x47, 0xb6, 0x4a, 0x6e, 0xa3, 0xa4, 0x3b, 0xa3,
-		0x47, 0x34, 0x74, 0x6b, 0xc5, 0x3d, 0x41, 0x14,
-		0x64, 0xd5, 0x69, 0x5f, 0x77, 0xf3, 0x7c, 0x41,
-		0xc6, 0xed, 0x2e, 0xcf, 0xff, 0x40, 0xf2, 0xce,
-		0xbb, 0xa7, 0x4e, 0x73, 0x88, 0x98, 0x10,
-	},
-	{
-		0x15, 0x03, 0x01, 0x00, 0x20, 0x1a, 0xbc, 0x70,
-		0x24, 0xf8, 0xfb, 0xf2, 0x4a, 0xf9, 0x44, 0x1e,
-		0x58, 0xf8, 0xaa, 0x41, 0x24, 0xe8, 0x80, 0x33,
-		0x45, 0x18, 0xa1, 0x5d, 0xee, 0x16, 0x80, 0xae,
-		0x40, 0x41, 0x8e, 0x41, 0x9b,
-	},
+func TestHandshakeClientECDHERSAAES(t *testing.T) {
+	test := &clientTest{
+		name:    "ECDHE-RSA-AES",
+		command: []string{"openssl", "s_server", "-cipher", "ECDHE-RSA-AES128-SHA"},
+	}
+	runClientTestTLS10(t, test)
+	runClientTestTLS11(t, test)
+	runClientTestTLS12(t, test)
 }
 
-var tls11ECDHEAESClientScript = [][]byte{
-	{
-		0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
-		0x46, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x13,
-		0x01, 0x00, 0x00, 0x1b, 0x00, 0x05, 0x00, 0x05,
-		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
-		0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
-		0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00,
-	},
-	{
-		0x16, 0x03, 0x02, 0x00, 0x54, 0x02, 0x00, 0x00,
-		0x50, 0x03, 0x02, 0x51, 0x9f, 0xa2, 0x21, 0x1a,
-		0xb7, 0x75, 0x42, 0x69, 0xd3, 0x14, 0xdd, 0x05,
-		0x1e, 0xda, 0x13, 0x71, 0x8d, 0x6a, 0x45, 0x97,
-		0xcb, 0xee, 0x0e, 0x77, 0x01, 0x0d, 0x6e, 0xe5,
-		0x22, 0x70, 0x16, 0x20, 0x69, 0xfc, 0xa6, 0x9a,
-		0xe8, 0x21, 0xcc, 0x46, 0x65, 0x05, 0xb4, 0x48,
-		0x0f, 0x34, 0x63, 0x2c, 0xac, 0xa4, 0xf5, 0x4b,
-		0x64, 0xd1, 0x07, 0x13, 0xa7, 0xe4, 0x5b, 0xa3,
-		0x4d, 0x31, 0x41, 0x53, 0xc0, 0x13, 0x00, 0x00,
-		0x08, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01,
-		0x02, 0x16, 0x03, 0x02, 0x02, 0x39, 0x0b, 0x00,
-		0x02, 0x35, 0x00, 0x02, 0x32, 0x00, 0x02, 0x2f,
-		0x30, 0x82, 0x02, 0x2b, 0x30, 0x82, 0x01, 0xd5,
-		0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00,
-		0xb1, 0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92,
-		0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
-		0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
-		0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
-		0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
-		0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
-		0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
-		0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
-		0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
-		0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
-		0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
-		0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e,
-		0x17, 0x0d, 0x31, 0x32, 0x30, 0x34, 0x30, 0x36,
-		0x31, 0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x17,
-		0x0d, 0x31, 0x35, 0x30, 0x34, 0x30, 0x36, 0x31,
-		0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x30, 0x45,
-		0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
-		0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30,
-		0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
-		0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
-		0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
-		0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74,
-		0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69,
-		0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74,
-		0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x5c, 0x30,
-		0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
-		0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b,
-		0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0x9f, 0xb3,
-		0xc3, 0x84, 0x27, 0x95, 0xff, 0x12, 0x31, 0x52,
-		0x0f, 0x15, 0xef, 0x46, 0x11, 0xc4, 0xad, 0x80,
-		0xe6, 0x36, 0x5b, 0x0f, 0xdd, 0x80, 0xd7, 0x61,
-		0x8d, 0xe0, 0xfc, 0x72, 0x45, 0x09, 0x34, 0xfe,
-		0x55, 0x66, 0x45, 0x43, 0x4c, 0x68, 0x97, 0x6a,
-		0xfe, 0xa8, 0xa0, 0xa5, 0xdf, 0x5f, 0x78, 0xff,
-		0xee, 0xd7, 0x64, 0xb8, 0x3f, 0x04, 0xcb, 0x6f,
-		0xff, 0x2a, 0xfe, 0xfe, 0xb9, 0xed, 0x02, 0x03,
-		0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
-		0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
-		0x04, 0x16, 0x04, 0x14, 0x78, 0xa6, 0x97, 0x9a,
-		0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22,
-		0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b,
-		0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
-		0x6e, 0x30, 0x6c, 0x80, 0x14, 0x78, 0xa6, 0x97,
-		0x9a, 0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba,
-		0x22, 0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc,
-		0x2b, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
-		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
-		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
-		0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
-		0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
-		0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
-		0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
-		0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
-		0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0xb1,
-		0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92, 0x30,
-		0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
-		0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
-		0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-		0x01, 0x05, 0x05, 0x00, 0x03, 0x41, 0x00, 0x85,
-		0x36, 0x40, 0x73, 0xc1, 0xbb, 0x1a, 0xda, 0xd4,
-		0x59, 0x9f, 0x2d, 0xa2, 0x70, 0x31, 0x46, 0x74,
-		0xec, 0x83, 0x6e, 0xa8, 0xc8, 0x3c, 0x51, 0xaf,
-		0x39, 0xac, 0xec, 0x40, 0xbc, 0xe8, 0x22, 0x46,
-		0x1d, 0x99, 0xd6, 0x46, 0x2a, 0x24, 0xd4, 0x8b,
-		0x05, 0x08, 0x4b, 0xfb, 0x35, 0x11, 0x6e, 0x92,
-		0xbb, 0x77, 0xba, 0xe4, 0x12, 0xbb, 0xf4, 0xc8,
-		0x5e, 0x9c, 0x81, 0xa8, 0x97, 0x60, 0x4c, 0x16,
-		0x03, 0x02, 0x00, 0x8b, 0x0c, 0x00, 0x00, 0x87,
-		0x03, 0x00, 0x17, 0x41, 0x04, 0x34, 0xde, 0x50,
-		0x32, 0x8f, 0x25, 0x6b, 0x37, 0x2c, 0x36, 0x24,
-		0x27, 0x0e, 0xf9, 0x67, 0xb4, 0xf8, 0x29, 0x1c,
-		0xa5, 0xa4, 0x59, 0x9a, 0xca, 0x40, 0x26, 0x15,
-		0x61, 0x72, 0x34, 0x4a, 0xd3, 0x0c, 0xac, 0x69,
-		0xcb, 0x2a, 0x9e, 0xf8, 0x80, 0xfb, 0x7a, 0xc4,
-		0xd4, 0x4b, 0x91, 0x1b, 0xbe, 0x24, 0x26, 0xad,
-		0x19, 0x24, 0xbe, 0x32, 0x58, 0xfb, 0xc7, 0x77,
-		0xce, 0x7e, 0x71, 0x51, 0x1a, 0x00, 0x40, 0x1a,
-		0x0b, 0xe8, 0x91, 0x84, 0x64, 0x54, 0xb6, 0x19,
-		0xe8, 0xd4, 0x43, 0x7c, 0x09, 0x0c, 0x2e, 0xba,
-		0x42, 0xb9, 0x74, 0xc3, 0x6c, 0x06, 0x9b, 0xa6,
-		0x7e, 0x92, 0xe9, 0xee, 0x7c, 0x74, 0xa9, 0xd3,
-		0x63, 0xf0, 0x16, 0x20, 0x60, 0x71, 0x8e, 0x24,
-		0xc7, 0x7f, 0xc5, 0x5b, 0x9c, 0x19, 0x0c, 0x80,
-		0x15, 0x61, 0xbf, 0xb6, 0xed, 0x5b, 0x7b, 0x90,
-		0xc5, 0x05, 0x13, 0x72, 0x45, 0x79, 0xdf, 0x16,
-		0x03, 0x02, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
-	},
-	{
-		0x16, 0x03, 0x02, 0x00, 0x46, 0x10, 0x00, 0x00,
-		0x42, 0x41, 0x04, 0x1e, 0x18, 0x37, 0xef, 0x0d,
-		0x19, 0x51, 0x88, 0x35, 0x75, 0x71, 0xb5, 0xe5,
-		0x54, 0x5b, 0x12, 0x2e, 0x8f, 0x09, 0x67, 0xfd,
-		0xa7, 0x24, 0x20, 0x3e, 0xb2, 0x56, 0x1c, 0xce,
-		0x97, 0x28, 0x5e, 0xf8, 0x2b, 0x2d, 0x4f, 0x9e,
-		0xf1, 0x07, 0x9f, 0x6c, 0x4b, 0x5b, 0x83, 0x56,
-		0xe2, 0x32, 0x42, 0xe9, 0x58, 0xb6, 0xd7, 0x49,
-		0xa6, 0xb5, 0x68, 0x1a, 0x41, 0x03, 0x56, 0x6b,
-		0xdc, 0x5a, 0x89, 0x14, 0x03, 0x02, 0x00, 0x01,
-		0x01, 0x16, 0x03, 0x02, 0x00, 0x40, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x50,
-		0x32, 0x26, 0x51, 0xbd, 0xbd, 0x3c, 0x4f, 0x72,
-		0xbf, 0xbc, 0x91, 0x70, 0x4b, 0x5d, 0x43, 0x4a,
-		0x65, 0x26, 0x0d, 0xaa, 0xed, 0x00, 0x91, 0xaf,
-		0x4f, 0x47, 0x09, 0xaa, 0x79, 0xc4, 0x47, 0x21,
-		0x71, 0xd8, 0x2b, 0xc1, 0x51, 0xc8, 0xef, 0xed,
-		0x67, 0xde, 0x97, 0xef, 0x18, 0x53,
-	},
-	{
-		0x14, 0x03, 0x02, 0x00, 0x01, 0x01, 0x16, 0x03,
-		0x02, 0x00, 0x40, 0x72, 0x20, 0xbf, 0xd1, 0xbd,
-		0x83, 0x53, 0x57, 0xb0, 0x4e, 0xac, 0xba, 0x1a,
-		0x2b, 0x2d, 0xeb, 0x8a, 0x48, 0x17, 0xfa, 0x69,
-		0xf9, 0xb5, 0x94, 0x8e, 0x6f, 0x9c, 0xda, 0x59,
-		0xba, 0x6c, 0x7c, 0x82, 0xe2, 0x53, 0xa9, 0x46,
-		0xdc, 0x33, 0xa0, 0x9b, 0xf0, 0x1e, 0xf1, 0x53,
-		0x83, 0x48, 0xbf, 0x5e, 0xef, 0x03, 0x2b, 0x50,
-		0x7a, 0xa6, 0xf8, 0xc3, 0x9e, 0x24, 0x43, 0x3a,
-		0xdf, 0x44, 0x3e,
-	},
-	{
-		0x17, 0x03, 0x02, 0x00, 0x30, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x0b, 0x8f,
-		0x6b, 0xf9, 0xd3, 0x9f, 0x2b, 0x49, 0xe0, 0x62,
-		0x9a, 0x0b, 0x3e, 0xa2, 0x72, 0x8b, 0x96, 0x0c,
-		0x41, 0x09, 0x95, 0x9e, 0x6b, 0x26, 0xa1, 0x46,
-		0xca, 0xb8, 0xb6, 0xd2, 0xd4, 0x15, 0x03, 0x02,
-		0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0xa0, 0xd4, 0x84, 0xc6, 0x7e, 0x1c,
-		0x2f, 0xbd, 0x6b, 0x45, 0x31, 0x1d, 0x7d, 0x8f,
-		0x31, 0x39, 0x5a, 0x4e, 0xaa, 0xf1, 0x0a, 0x8a,
-		0x6c, 0x33, 0x59, 0x19, 0xd8, 0x75, 0x80, 0xab,
-		0x93, 0x81,
-	},
+func TestHandshakeClientECDHEECDSAAES(t *testing.T) {
+	test := &clientTest{
+		name:    "ECDHE-ECDSA-AES",
+		command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA"},
+		cert:    testECDSACertificate,
+		key:     testECDSAPrivateKey,
+	}
+	runClientTestTLS10(t, test)
+	runClientTestTLS11(t, test)
+	runClientTestTLS12(t, test)
 }
 
-var clientChainCertificateScript = [][]byte{
-	{
-		0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
-		0x46, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05,
-		0x01, 0x00, 0x00, 0x1b, 0x00, 0x05, 0x00, 0x05,
-		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
-		0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
-		0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x4a, 0x02, 0x00, 0x00,
-		0x46, 0x03, 0x01, 0x51, 0xa2, 0x9b, 0x8b, 0xd4,
-		0xe6, 0x33, 0xa2, 0x70, 0x38, 0x37, 0xba, 0x55,
-		0x86, 0xcf, 0x87, 0xea, 0x6d, 0x2c, 0x3e, 0x17,
-		0xc2, 0x09, 0xf8, 0x4d, 0xb0, 0x5d, 0x93, 0x2b,
-		0x15, 0x99, 0x0c, 0x20, 0x5d, 0x61, 0x21, 0x2c,
-		0xed, 0x49, 0x32, 0x29, 0x08, 0x6e, 0x21, 0x58,
-		0x00, 0xdb, 0x34, 0xb7, 0x37, 0xcd, 0x27, 0x75,
-		0x31, 0x1e, 0x6c, 0x74, 0xa6, 0xef, 0xa2, 0xc4,
-		0x2b, 0x6c, 0xc3, 0x03, 0x00, 0x05, 0x00, 0x16,
-		0x03, 0x01, 0x03, 0xef, 0x0b, 0x00, 0x03, 0xeb,
-		0x00, 0x03, 0xe8, 0x00, 0x03, 0xe5, 0x30, 0x82,
-		0x03, 0xe1, 0x30, 0x82, 0x02, 0xc9, 0xa0, 0x03,
-		0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xcc, 0x22,
-		0x4c, 0x4b, 0x98, 0xa2, 0x88, 0xfc, 0x30, 0x0d,
-		0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
-		0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x86,
-		0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
-		0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30,
-		0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02,
-		0x4e, 0x59, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
-		0x55, 0x04, 0x07, 0x0c, 0x08, 0x42, 0x72, 0x6f,
-		0x6f, 0x6b, 0x6c, 0x79, 0x6e, 0x31, 0x21, 0x30,
-		0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18,
-		0x4d, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
-		0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41,
-		0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
-		0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
-		0x03, 0x0c, 0x08, 0x6d, 0x79, 0x63, 0x61, 0x2e,
-		0x6f, 0x72, 0x67, 0x31, 0x21, 0x30, 0x1f, 0x06,
-		0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-		0x09, 0x01, 0x16, 0x12, 0x6a, 0x76, 0x73, 0x68,
-		0x61, 0x68, 0x69, 0x64, 0x40, 0x67, 0x6d, 0x61,
-		0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e,
-		0x17, 0x0d, 0x31, 0x33, 0x30, 0x35, 0x32, 0x36,
-		0x32, 0x31, 0x30, 0x35, 0x30, 0x31, 0x5a, 0x17,
-		0x0d, 0x32, 0x33, 0x30, 0x35, 0x32, 0x34, 0x32,
-		0x31, 0x30, 0x35, 0x30, 0x31, 0x5a, 0x30, 0x81,
-		0x86, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
-		0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b,
-		0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
-		0x02, 0x4e, 0x59, 0x31, 0x11, 0x30, 0x0f, 0x06,
-		0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x42, 0x72,
-		0x6f, 0x6f, 0x6b, 0x6c, 0x79, 0x6e, 0x31, 0x21,
-		0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
-		0x18, 0x4d, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74,
-		0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20,
-		0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
-		0x79, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
-		0x04, 0x03, 0x0c, 0x08, 0x6d, 0x79, 0x63, 0x61,
-		0x2e, 0x6f, 0x72, 0x67, 0x31, 0x21, 0x30, 0x1f,
-		0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
-		0x01, 0x09, 0x01, 0x16, 0x12, 0x6a, 0x76, 0x73,
-		0x68, 0x61, 0x68, 0x69, 0x64, 0x40, 0x67, 0x6d,
-		0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30,
-		0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a,
-		0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
-		0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30,
-		0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00,
-		0xf0, 0xfb, 0xad, 0x80, 0x5e, 0x37, 0xd3, 0x6d,
-		0xee, 0x2e, 0xcc, 0xbc, 0x0c, 0xd7, 0x56, 0x4b,
-		0x56, 0x45, 0xcd, 0x28, 0xb6, 0x22, 0xe9, 0xe2,
-		0x0f, 0xd1, 0x87, 0x2a, 0x27, 0xce, 0x77, 0x8d,
-		0x6e, 0x0e, 0x0f, 0xfb, 0x66, 0xe1, 0xb5, 0x0e,
-		0x9a, 0xb6, 0x05, 0x8e, 0xb3, 0xe1, 0xc5, 0x77,
-		0x86, 0x5b, 0x46, 0xd2, 0x0b, 0x92, 0x03, 0x1b,
-		0x89, 0x0c, 0x1b, 0x10, 0x0e, 0x99, 0x8f, 0xe2,
-		0x17, 0xe8, 0xc2, 0x30, 0x00, 0x47, 0xd6, 0xfc,
-		0xf9, 0x0f, 0x3b, 0x75, 0x34, 0x8d, 0x4d, 0xb0,
-		0x99, 0xb7, 0xa0, 0x6d, 0xa0, 0xb6, 0xad, 0xda,
-		0x07, 0x5e, 0x38, 0x2e, 0x02, 0xe4, 0x30, 0x6d,
-		0xae, 0x13, 0x72, 0xd4, 0xc8, 0xce, 0x14, 0x07,
-		0xae, 0x23, 0x8c, 0x8f, 0x9e, 0x8c, 0x60, 0xd6,
-		0x06, 0xb9, 0xef, 0x00, 0x18, 0xc0, 0x1d, 0x25,
-		0x1e, 0xda, 0x3e, 0x2f, 0xcf, 0x2b, 0x56, 0x84,
-		0x9e, 0x30, 0x21, 0xc7, 0x29, 0xf6, 0x03, 0x8a,
-		0x24, 0xf9, 0x34, 0xac, 0x65, 0x9d, 0x80, 0x36,
-		0xc8, 0x3b, 0x15, 0x10, 0xbd, 0x51, 0xe9, 0xbc,
-		0x02, 0xe1, 0xe9, 0xb3, 0x5a, 0x9a, 0x99, 0x41,
-		0x1b, 0x27, 0xa0, 0x4d, 0x50, 0x9e, 0x27, 0x7f,
-		0xa1, 0x7d, 0x09, 0x87, 0xbd, 0x8a, 0xca, 0x5f,
-		0xb1, 0xa5, 0x08, 0xb8, 0x04, 0xd4, 0x52, 0x89,
-		0xaa, 0xe0, 0x7d, 0x42, 0x2e, 0x2f, 0x15, 0xee,
-		0x66, 0x57, 0x0f, 0x13, 0x19, 0x45, 0xa8, 0x4b,
-		0x5d, 0x81, 0x66, 0xcc, 0x12, 0x37, 0x94, 0x5e,
-		0xfd, 0x3c, 0x10, 0x81, 0x51, 0x3f, 0xfa, 0x0f,
-		0xdd, 0xa1, 0x89, 0x03, 0xa9, 0x78, 0x91, 0xf5,
-		0x3b, 0xf3, 0xbc, 0xac, 0xbe, 0x93, 0x30, 0x2e,
-		0xbe, 0xca, 0x7f, 0x46, 0xd3, 0x28, 0xb4, 0x4e,
-		0x91, 0x7b, 0x5b, 0x43, 0x6c, 0xaf, 0x9b, 0x5c,
-		0x6a, 0x6d, 0x5a, 0xdb, 0x79, 0x5e, 0x6a, 0x6b,
-		0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x50, 0x30,
-		0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
-		0x04, 0x16, 0x04, 0x14, 0x6b, 0x1e, 0x00, 0xa8,
-		0x9f, 0xfa, 0x7d, 0x00, 0xf9, 0xe0, 0x9d, 0x0f,
-		0x90, 0x8c, 0x90, 0xa8, 0xa1, 0x37, 0x6b, 0xda,
-		0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
-		0x18, 0x30, 0x16, 0x80, 0x14, 0x6b, 0x1e, 0x00,
-		0xa8, 0x9f, 0xfa, 0x7d, 0x00, 0xf9, 0xe0, 0x9d,
-		0x0f, 0x90, 0x8c, 0x90, 0xa8, 0xa1, 0x37, 0x6b,
-		0xda, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
-		0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
-		0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
-		0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82,
-		0x01, 0x01, 0x00, 0xcd, 0x6f, 0x73, 0x4d, 0x56,
-		0x0b, 0xf3, 0x2e, 0x1c, 0xe2, 0x02, 0x0c, 0x14,
-		0xbb, 0x2f, 0xdd, 0x3c, 0x43, 0xfe, 0xdf, 0x94,
-		0x2d, 0xa9, 0x89, 0x81, 0x51, 0xf8, 0x5f, 0xa7,
-		0xa0, 0x13, 0xaa, 0xcc, 0xb0, 0x18, 0xe2, 0x57,
-		0x3e, 0x0d, 0x29, 0x93, 0xe8, 0x95, 0xd5, 0x1b,
-		0x53, 0xd2, 0x51, 0xf2, 0xbd, 0xf5, 0x9e, 0x7b,
-		0x22, 0x65, 0x62, 0x5c, 0xc4, 0x4c, 0x1d, 0xe8,
-		0xe9, 0xc3, 0xd4, 0x2b, 0xe7, 0x78, 0xcb, 0x10,
-		0xf3, 0xfe, 0x06, 0x83, 0xdc, 0x3a, 0x1e, 0x62,
-		0x10, 0xc0, 0x46, 0x77, 0xc6, 0x9d, 0x9f, 0xab,
-		0x96, 0x25, 0x5c, 0xfb, 0x26, 0xc1, 0x15, 0x1f,
-		0xa5, 0x33, 0xee, 0x4f, 0x9a, 0x14, 0x6a, 0x14,
-		0x97, 0x93, 0x2b, 0x95, 0x0b, 0xdc, 0xa8, 0xd7,
-		0x69, 0x2e, 0xf0, 0x01, 0x0e, 0xfd, 0x4e, 0xd0,
-		0xd9, 0xa8, 0xe5, 0x65, 0xde, 0xfb, 0xca, 0xca,
-		0x1c, 0x5f, 0xf9, 0x53, 0xa0, 0x87, 0xe7, 0x33,
-		0x9b, 0x2f, 0xcf, 0xe4, 0x13, 0xfc, 0xec, 0x7a,
-		0x6c, 0xb0, 0x90, 0x13, 0x9b, 0xb6, 0xc5, 0x03,
-		0xf6, 0x0e, 0x5e, 0xe2, 0xe4, 0x26, 0xc1, 0x7e,
-		0x53, 0xfe, 0x69, 0xa3, 0xc7, 0xd8, 0x8e, 0x6e,
-		0x94, 0x32, 0xa0, 0xde, 0xca, 0xb6, 0xcc, 0xd6,
-		0x01, 0xd5, 0x78, 0x40, 0x28, 0x63, 0x9b, 0xee,
-		0xcf, 0x09, 0x3b, 0x35, 0x04, 0xf0, 0x14, 0x02,
-		0xf6, 0x80, 0x0e, 0x90, 0xb2, 0x94, 0xd2, 0x25,
-		0x16, 0xb8, 0x7a, 0x76, 0x87, 0x84, 0x9f, 0x84,
-		0xc5, 0xaf, 0xc2, 0x6d, 0x68, 0x7a, 0x84, 0x9c,
-		0xc6, 0x8a, 0x63, 0x60, 0x87, 0x6a, 0x25, 0xc1,
-		0xa1, 0x78, 0x0f, 0xba, 0xe8, 0x5f, 0xe1, 0xba,
-		0xac, 0xa4, 0x6f, 0xdd, 0x09, 0x3f, 0x12, 0xcb,
-		0x1d, 0xf3, 0xcf, 0x48, 0xd7, 0xd3, 0x26, 0xe8,
-		0x9c, 0xc3, 0x53, 0xb3, 0xba, 0xdc, 0x32, 0x99,
-		0x98, 0x96, 0xd6, 0x16, 0x03, 0x01, 0x00, 0x99,
-		0x0d, 0x00, 0x00, 0x91, 0x03, 0x01, 0x02, 0x40,
-		0x00, 0x8b, 0x00, 0x89, 0x30, 0x81, 0x86, 0x31,
-		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-		0x13, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09,
-		0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e,
-		0x59, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
-		0x04, 0x07, 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f,
-		0x6b, 0x6c, 0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f,
-		0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d,
-		0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
-		0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75,
-		0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31,
-		0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03,
-		0x0c, 0x08, 0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f,
-		0x72, 0x67, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09,
-		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09,
-		0x01, 0x16, 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61,
-		0x68, 0x69, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69,
-		0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0e, 0x00, 0x00,
-		0x00,
-	},
-	{
-		0x16, 0x03, 0x01, 0x0a, 0xfb, 0x0b, 0x00, 0x0a,
-		0xf7, 0x00, 0x0a, 0xf4, 0x00, 0x03, 0x7e, 0x30,
-		0x82, 0x03, 0x7a, 0x30, 0x82, 0x02, 0x62, 0x02,
-		0x09, 0x00, 0xb4, 0x47, 0x58, 0x57, 0x2b, 0x67,
-		0xc8, 0xc2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
-		0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
-		0x00, 0x30, 0x81, 0x80, 0x31, 0x0b, 0x30, 0x09,
-		0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
-		0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
-		0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59, 0x31, 0x11,
-		0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
-		0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c, 0x79,
-		0x6e, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55,
-		0x04, 0x0a, 0x0c, 0x0c, 0x4d, 0x79, 0x20, 0x43,
-		0x41, 0x20, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74,
-		0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
-		0x03, 0x0c, 0x0e, 0x6d, 0x79, 0x63, 0x61, 0x63,
-		0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f,
-		0x6d, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a,
-		0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01,
-		0x16, 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68,
-		0x69, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
-		0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d,
-		0x31, 0x33, 0x30, 0x35, 0x32, 0x36, 0x32, 0x31,
-		0x34, 0x34, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31,
-		0x33, 0x30, 0x36, 0x32, 0x35, 0x32, 0x31, 0x34,
-		0x34, 0x30, 0x30, 0x5a, 0x30, 0x7d, 0x31, 0x0b,
-		0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
-		0x02, 0x55, 0x53, 0x31, 0x11, 0x30, 0x0f, 0x06,
-		0x03, 0x55, 0x04, 0x08, 0x0c, 0x08, 0x4e, 0x65,
-		0x77, 0x20, 0x59, 0x6f, 0x72, 0x6b, 0x31, 0x11,
-		0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
-		0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c, 0x79,
-		0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
-		0x04, 0x0a, 0x0c, 0x07, 0x4d, 0x79, 0x20, 0x4c,
-		0x65, 0x61, 0x66, 0x31, 0x13, 0x30, 0x11, 0x06,
-		0x03, 0x55, 0x04, 0x03, 0x0c, 0x0a, 0x6d, 0x79,
-		0x6c, 0x65, 0x61, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
-		0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86,
-		0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
-		0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68, 0x69,
-		0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e,
-		0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30,
-		0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
-		0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
-		0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02,
-		0x82, 0x01, 0x01, 0x00, 0xa0, 0xa3, 0xef, 0xc1,
-		0x44, 0x7d, 0xa2, 0xe3, 0x71, 0x98, 0x27, 0x63,
-		0xb3, 0x1d, 0x71, 0x50, 0xa6, 0x34, 0x15, 0xcb,
-		0xc9, 0x2a, 0xc3, 0xea, 0xe4, 0x9e, 0x9c, 0x49,
-		0xa6, 0x01, 0x9b, 0x7e, 0xa9, 0xb5, 0x7a, 0xff,
-		0x15, 0x92, 0x71, 0xc8, 0x97, 0x9c, 0x25, 0xb7,
-		0x79, 0x2b, 0xff, 0xab, 0xc6, 0xb1, 0xa7, 0x00,
-		0x90, 0xb2, 0x8b, 0xd7, 0x71, 0xd5, 0xc2, 0x3a,
-		0xe6, 0x82, 0x42, 0x37, 0x89, 0x41, 0x04, 0xb0,
-		0xba, 0xc7, 0x5b, 0x8a, 0x43, 0x9f, 0x97, 0x39,
-		0x0c, 0x0f, 0xd5, 0x6d, 0x9e, 0x8d, 0xeb, 0xc0,
-		0x26, 0xc5, 0x18, 0xe8, 0x7a, 0x3d, 0x32, 0x2e,
-		0x38, 0x90, 0x40, 0x5b, 0x39, 0x2c, 0x07, 0xcb,
-		0x24, 0x10, 0xc5, 0xc9, 0x3b, 0xe3, 0x66, 0x47,
-		0x57, 0xb9, 0x6a, 0xad, 0x44, 0xf8, 0xd0, 0x70,
-		0x62, 0x3b, 0x8e, 0xed, 0x60, 0x5f, 0x22, 0xf8,
-		0xb8, 0x0c, 0xc9, 0x41, 0x2b, 0xc9, 0x80, 0x6e,
-		0x4e, 0x1b, 0xe1, 0x20, 0xfc, 0x47, 0xa4, 0xac,
-		0xc3, 0x3f, 0xe6, 0xc2, 0x81, 0x79, 0x03, 0x37,
-		0x25, 0x89, 0xca, 0xd6, 0xa5, 0x46, 0x91, 0x63,
-		0x41, 0xc5, 0x3e, 0xd5, 0xed, 0x7f, 0x4f, 0x8d,
-		0x06, 0xc0, 0x89, 0x00, 0xbe, 0x37, 0x7b, 0x7e,
-		0x73, 0xca, 0x70, 0x00, 0x14, 0x34, 0xbe, 0x47,
-		0xbc, 0xb2, 0x6a, 0x28, 0xa5, 0x29, 0x84, 0xa8,
-		0x9d, 0xc8, 0x1e, 0x77, 0x66, 0x1f, 0x9f, 0xaa,
-		0x2b, 0x47, 0xdb, 0xdd, 0x6b, 0x9c, 0xa8, 0xfc,
-		0x82, 0x36, 0x94, 0x62, 0x0d, 0x5c, 0x3f, 0xb2,
-		0x01, 0xb4, 0xa5, 0xb8, 0xc6, 0x0e, 0x94, 0x5b,
-		0xec, 0x5e, 0xbb, 0x7a, 0x63, 0x24, 0xf1, 0xf9,
-		0xd6, 0x50, 0x08, 0xc1, 0xa3, 0xcc, 0x90, 0x07,
-		0x5b, 0x04, 0x04, 0x42, 0x74, 0xcf, 0x37, 0xfa,
-		0xf0, 0xa5, 0xd9, 0xd3, 0x86, 0x89, 0x89, 0x18,
-		0xf3, 0x4c, 0xe2, 0x11, 0x02, 0x03, 0x01, 0x00,
-		0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
-		0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
-		0x03, 0x82, 0x01, 0x01, 0x00, 0x90, 0xbb, 0xf9,
-		0x5e, 0xba, 0x17, 0x1f, 0xac, 0x21, 0x9f, 0x6b,
-		0x4a, 0x46, 0xd0, 0x6d, 0x3c, 0x8f, 0x3d, 0xf8,
-		0x5e, 0x3e, 0x72, 0xaf, 0xa0, 0x1a, 0xf3, 0xff,
-		0x89, 0xac, 0x5b, 0x7a, 0xe2, 0x91, 0x2a, 0x23,
-		0x85, 0xc6, 0x4d, 0x47, 0x67, 0x01, 0x08, 0xa8,
-		0x05, 0x1d, 0x01, 0x60, 0x50, 0x5f, 0x59, 0xad,
-		0xfe, 0x7b, 0xc6, 0x0c, 0x54, 0x90, 0x68, 0x70,
-		0x67, 0x2e, 0xed, 0x87, 0xf8, 0x69, 0x8a, 0xac,
-		0x32, 0xfe, 0x6f, 0x90, 0x19, 0x2a, 0x64, 0x8d,
-		0x82, 0x66, 0x05, 0x43, 0x88, 0xee, 0xf2, 0x30,
-		0xed, 0xa4, 0x8f, 0xbf, 0xd6, 0x57, 0x20, 0xd4,
-		0x43, 0x1d, 0x52, 0x96, 0x6f, 0xae, 0x09, 0x96,
-		0x01, 0x52, 0x38, 0xe3, 0xaf, 0x99, 0xd7, 0xdc,
-		0x14, 0x99, 0xc4, 0x8b, 0x0e, 0x04, 0x0f, 0xb3,
-		0x14, 0x14, 0xd4, 0xa5, 0x93, 0xe1, 0xc9, 0x8a,
-		0x81, 0xef, 0x63, 0xfc, 0x36, 0x77, 0x05, 0x06,
-		0xf0, 0x2a, 0x04, 0x0a, 0xbe, 0x2e, 0xce, 0x81,
-		0x3d, 0x23, 0xa1, 0xda, 0xd8, 0xeb, 0xc6, 0xea,
-		0x5e, 0xcf, 0x28, 0x36, 0x51, 0x31, 0x95, 0x5e,
-		0x40, 0x04, 0xed, 0xac, 0xc1, 0xc8, 0x56, 0x69,
-		0x87, 0xec, 0x3b, 0x03, 0x3e, 0x9d, 0x0f, 0x4c,
-		0x4c, 0xeb, 0xd7, 0xba, 0x26, 0xdf, 0xe3, 0xde,
-		0x10, 0xee, 0x93, 0x62, 0x8d, 0x73, 0x52, 0x6e,
-		0xff, 0x37, 0x36, 0x98, 0x7b, 0x2d, 0x56, 0x4c,
-		0xba, 0x09, 0xb8, 0xa7, 0xf0, 0x3b, 0x16, 0x81,
-		0xca, 0xdb, 0x43, 0xab, 0xec, 0x4c, 0x6e, 0x7c,
-		0xc1, 0x0b, 0x22, 0x22, 0x43, 0x1d, 0xb6, 0x0c,
-		0xc1, 0xb9, 0xcf, 0xe4, 0x53, 0xee, 0x1d, 0x3e,
-		0x88, 0xa7, 0x13, 0xbe, 0x7f, 0xbd, 0xae, 0x72,
-		0xcf, 0xcd, 0x63, 0xd2, 0xc3, 0x18, 0x58, 0x92,
-		0xa2, 0xad, 0xb5, 0x09, 0x9d, 0x91, 0x03, 0xdd,
-		0x3c, 0xe2, 0x1c, 0xde, 0x78, 0x00, 0x03, 0x88,
-		0x30, 0x82, 0x03, 0x84, 0x30, 0x82, 0x02, 0x6c,
-		0x02, 0x09, 0x00, 0xab, 0xed, 0xa6, 0xe4, 0x4a,
-		0x2b, 0x2b, 0xf8, 0x30, 0x0d, 0x06, 0x09, 0x2a,
-		0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
-		0x05, 0x00, 0x30, 0x81, 0x86, 0x31, 0x0b, 0x30,
-		0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
-		0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
-		0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59, 0x31,
-		0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07,
-		0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c,
-		0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
-		0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d, 0x79, 0x20,
-		0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
-		0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
-		0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30,
-		0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
-		0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f, 0x72, 0x67,
-		0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86,
-		0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
-		0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68, 0x69,
-		0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e,
-		0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31,
-		0x33, 0x30, 0x35, 0x32, 0x36, 0x32, 0x31, 0x31,
-		0x38, 0x34, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x33,
-		0x30, 0x36, 0x32, 0x35, 0x32, 0x31, 0x31, 0x38,
-		0x34, 0x30, 0x5a, 0x30, 0x81, 0x80, 0x31, 0x0b,
-		0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
-		0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06,
-		0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59,
-		0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
-		0x07, 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b,
-		0x6c, 0x79, 0x6e, 0x31, 0x15, 0x30, 0x13, 0x06,
-		0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x4d, 0x79,
-		0x20, 0x43, 0x41, 0x20, 0x43, 0x6c, 0x69, 0x65,
-		0x6e, 0x74, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03,
-		0x55, 0x04, 0x03, 0x0c, 0x0e, 0x6d, 0x79, 0x63,
-		0x61, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e,
-		0x63, 0x6f, 0x6d, 0x31, 0x21, 0x30, 0x1f, 0x06,
-		0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-		0x09, 0x01, 0x16, 0x12, 0x6a, 0x76, 0x73, 0x68,
-		0x61, 0x68, 0x69, 0x64, 0x40, 0x67, 0x6d, 0x61,
-		0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82,
-		0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
-		0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
-		0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,
-		0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xce,
-		0x13, 0xf0, 0x72, 0xb0, 0x61, 0xc8, 0x18, 0x37,
-		0x8a, 0x41, 0x3d, 0x20, 0xa1, 0x1c, 0xcb, 0xbf,
-		0xf6, 0x3b, 0x74, 0x26, 0x2a, 0x96, 0x11, 0xec,
-		0x53, 0xa1, 0xcc, 0x7d, 0x77, 0x56, 0x45, 0x0f,
-		0x36, 0xb7, 0xf2, 0x48, 0x92, 0x1a, 0x62, 0xcc,
-		0xb6, 0xc0, 0xa1, 0x2f, 0x44, 0x2b, 0xc1, 0x89,
-		0xcb, 0x6e, 0x1e, 0xdb, 0x57, 0x92, 0xd5, 0x97,
-		0x60, 0x8c, 0x41, 0x2c, 0xd9, 0x20, 0xfe, 0xe9,
-		0x1f, 0x8e, 0xfc, 0x7f, 0x02, 0x44, 0x0f, 0x28,
-		0x81, 0xd6, 0x0c, 0xcd, 0xbc, 0xf0, 0x57, 0x6c,
-		0xcc, 0xa7, 0xba, 0x06, 0xa0, 0xa6, 0x91, 0xda,
-		0xef, 0x46, 0x8a, 0x60, 0x0f, 0x52, 0x6c, 0x90,
-		0x6c, 0x8c, 0x44, 0xaf, 0xb0, 0x9d, 0x90, 0xba,
-		0x21, 0x58, 0xa0, 0x3c, 0xee, 0x54, 0xb5, 0x29,
-		0x26, 0x1f, 0x0a, 0xac, 0xef, 0x48, 0x68, 0x33,
-		0xd0, 0x33, 0xd0, 0x8b, 0x1a, 0xec, 0x6e, 0x2f,
-		0xb5, 0x4a, 0x53, 0xc2, 0x1a, 0xd2, 0xf1, 0x50,
-		0x05, 0x59, 0x5c, 0xd9, 0xda, 0x03, 0x0a, 0x47,
-		0xb7, 0xdd, 0xf7, 0x3a, 0x69, 0xf5, 0x4e, 0xea,
-		0x4a, 0xc2, 0xca, 0x54, 0xb0, 0x8b, 0x76, 0xe1,
-		0x02, 0x2d, 0x52, 0x67, 0xb9, 0xdd, 0x50, 0xc9,
-		0x3b, 0x07, 0x24, 0x22, 0x6a, 0x00, 0x1d, 0x58,
-		0x83, 0xa8, 0xec, 0x95, 0xf1, 0xda, 0xe2, 0x73,
-		0xa0, 0xa1, 0x72, 0x60, 0x9e, 0x86, 0x53, 0xcb,
-		0x45, 0xa8, 0xc2, 0xa0, 0x50, 0xa0, 0x53, 0xd6,
-		0xfc, 0x18, 0x84, 0xb5, 0x4a, 0x26, 0xd0, 0xa2,
-		0xaa, 0xd0, 0xff, 0xb6, 0xfe, 0x3a, 0x9c, 0xb5,
-		0x19, 0x3b, 0x3f, 0xe1, 0x48, 0x0d, 0xa4, 0x09,
-		0x4f, 0x83, 0xc9, 0xc0, 0xc9, 0xa6, 0x0b, 0x58,
-		0x1f, 0x1c, 0x7b, 0xac, 0xa2, 0x42, 0xbc, 0x61,
-		0xf4, 0x21, 0x8a, 0x00, 0xda, 0x14, 0xa0, 0x60,
-		0x03, 0xfe, 0x93, 0x12, 0x6c, 0x56, 0xcd, 0x02,
-		0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09,
-		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-		0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
-		0x25, 0x29, 0x3b, 0x1e, 0xc3, 0x58, 0x32, 0xe6,
-		0x23, 0xc8, 0xee, 0x18, 0xf0, 0x1d, 0x62, 0x6d,
-		0x3b, 0x59, 0x99, 0x3a, 0xfe, 0x49, 0x72, 0x07,
-		0x3f, 0x58, 0x93, 0xdb, 0xc0, 0xaf, 0xb0, 0xb3,
-		0x5c, 0xd1, 0x5c, 0x98, 0xc8, 0xea, 0x4a, 0xe4,
-		0x58, 0x73, 0x0d, 0x57, 0xc5, 0x13, 0x7c, 0x5c,
-		0x79, 0x66, 0xda, 0x04, 0x1d, 0xe5, 0x98, 0xda,
-		0x35, 0x47, 0x44, 0xb0, 0xd2, 0x7a, 0x66, 0x9d,
-		0xcd, 0x41, 0xa5, 0x8f, 0xa1, 0x11, 0xb2, 0x1a,
-		0x87, 0xc0, 0xcd, 0x55, 0xed, 0xb4, 0x7b, 0x33,
-		0x72, 0xeb, 0xf7, 0xe3, 0x7b, 0x8b, 0x02, 0x86,
-		0xe9, 0x2b, 0x26, 0x32, 0x9f, 0x99, 0xf1, 0xcb,
-		0x93, 0xab, 0xb9, 0x16, 0xb3, 0x9a, 0xb2, 0x22,
-		0x13, 0x21, 0x1f, 0x5b, 0xcc, 0xa2, 0x59, 0xbb,
-		0x69, 0xf2, 0xb8, 0x07, 0x80, 0xce, 0x0c, 0xf7,
-		0x98, 0x4c, 0x85, 0xc2, 0x96, 0x6a, 0x22, 0x05,
-		0xe9, 0xbe, 0x48, 0xb0, 0x02, 0x5b, 0x69, 0x28,
-		0x18, 0x88, 0x96, 0xe3, 0xd7, 0xc6, 0x7a, 0xd3,
-		0xe9, 0x99, 0xff, 0x9d, 0xc3, 0x61, 0x4d, 0x9a,
-		0x96, 0xf2, 0xc6, 0x33, 0x4d, 0xe5, 0x5d, 0x5a,
-		0x68, 0x64, 0x5a, 0x82, 0x35, 0x65, 0x25, 0xe3,
-		0x8c, 0x5b, 0xb0, 0xf6, 0x96, 0x56, 0xbc, 0xbf,
-		0x97, 0x76, 0x4b, 0x66, 0x44, 0x81, 0xa4, 0xc4,
-		0xa7, 0x31, 0xc5, 0xa1, 0x4f, 0xe8, 0xa4, 0xca,
-		0x20, 0xf5, 0x01, 0x5b, 0x99, 0x4f, 0x5a, 0xf4,
-		0xf0, 0x78, 0xbf, 0x71, 0x49, 0xd5, 0xf1, 0xc1,
-		0xa2, 0x18, 0xfd, 0x72, 0x5b, 0x16, 0xe8, 0x92,
-		0xc7, 0x37, 0x48, 0xaf, 0xee, 0x24, 0xfc, 0x35,
-		0x0b, 0xc2, 0xdd, 0x05, 0xc7, 0x6e, 0xa3, 0x29,
-		0xbb, 0x29, 0x7d, 0xd3, 0x2b, 0x94, 0x80, 0xc3,
-		0x40, 0x53, 0x0e, 0x03, 0x54, 0x3d, 0x7b, 0x8b,
-		0xce, 0xf9, 0xa4, 0x03, 0x27, 0x63, 0xec, 0x51,
-		0x00, 0x03, 0xe5, 0x30, 0x82, 0x03, 0xe1, 0x30,
-		0x82, 0x02, 0xc9, 0xa0, 0x03, 0x02, 0x01, 0x02,
-		0x02, 0x09, 0x00, 0xcc, 0x22, 0x4c, 0x4b, 0x98,
-		0xa2, 0x88, 0xfc, 0x30, 0x0d, 0x06, 0x09, 0x2a,
-		0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
-		0x05, 0x00, 0x30, 0x81, 0x86, 0x31, 0x0b, 0x30,
-		0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
-		0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
-		0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59, 0x31,
-		0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07,
-		0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c,
-		0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
-		0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d, 0x79, 0x20,
-		0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
-		0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
-		0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30,
-		0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
-		0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f, 0x72, 0x67,
-		0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86,
-		0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
-		0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68, 0x69,
-		0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e,
-		0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31,
-		0x33, 0x30, 0x35, 0x32, 0x36, 0x32, 0x31, 0x30,
-		0x35, 0x30, 0x31, 0x5a, 0x17, 0x0d, 0x32, 0x33,
-		0x30, 0x35, 0x32, 0x34, 0x32, 0x31, 0x30, 0x35,
-		0x30, 0x31, 0x5a, 0x30, 0x81, 0x86, 0x31, 0x0b,
-		0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
-		0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06,
-		0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59,
-		0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
-		0x07, 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b,
-		0x6c, 0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06,
-		0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d, 0x79,
-		0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
-		0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74,
-		0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11,
-		0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
-		0x08, 0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f, 0x72,
-		0x67, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a,
-		0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01,
-		0x16, 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68,
-		0x69, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
-		0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22,
-		0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
-		0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
-		0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
-		0x02, 0x82, 0x01, 0x01, 0x00, 0xf0, 0xfb, 0xad,
-		0x80, 0x5e, 0x37, 0xd3, 0x6d, 0xee, 0x2e, 0xcc,
-		0xbc, 0x0c, 0xd7, 0x56, 0x4b, 0x56, 0x45, 0xcd,
-		0x28, 0xb6, 0x22, 0xe9, 0xe2, 0x0f, 0xd1, 0x87,
-		0x2a, 0x27, 0xce, 0x77, 0x8d, 0x6e, 0x0e, 0x0f,
-		0xfb, 0x66, 0xe1, 0xb5, 0x0e, 0x9a, 0xb6, 0x05,
-		0x8e, 0xb3, 0xe1, 0xc5, 0x77, 0x86, 0x5b, 0x46,
-		0xd2, 0x0b, 0x92, 0x03, 0x1b, 0x89, 0x0c, 0x1b,
-		0x10, 0x0e, 0x99, 0x8f, 0xe2, 0x17, 0xe8, 0xc2,
-		0x30, 0x00, 0x47, 0xd6, 0xfc, 0xf9, 0x0f, 0x3b,
-		0x75, 0x34, 0x8d, 0x4d, 0xb0, 0x99, 0xb7, 0xa0,
-		0x6d, 0xa0, 0xb6, 0xad, 0xda, 0x07, 0x5e, 0x38,
-		0x2e, 0x02, 0xe4, 0x30, 0x6d, 0xae, 0x13, 0x72,
-		0xd4, 0xc8, 0xce, 0x14, 0x07, 0xae, 0x23, 0x8c,
-		0x8f, 0x9e, 0x8c, 0x60, 0xd6, 0x06, 0xb9, 0xef,
-		0x00, 0x18, 0xc0, 0x1d, 0x25, 0x1e, 0xda, 0x3e,
-		0x2f, 0xcf, 0x2b, 0x56, 0x84, 0x9e, 0x30, 0x21,
-		0xc7, 0x29, 0xf6, 0x03, 0x8a, 0x24, 0xf9, 0x34,
-		0xac, 0x65, 0x9d, 0x80, 0x36, 0xc8, 0x3b, 0x15,
-		0x10, 0xbd, 0x51, 0xe9, 0xbc, 0x02, 0xe1, 0xe9,
-		0xb3, 0x5a, 0x9a, 0x99, 0x41, 0x1b, 0x27, 0xa0,
-		0x4d, 0x50, 0x9e, 0x27, 0x7f, 0xa1, 0x7d, 0x09,
-		0x87, 0xbd, 0x8a, 0xca, 0x5f, 0xb1, 0xa5, 0x08,
-		0xb8, 0x04, 0xd4, 0x52, 0x89, 0xaa, 0xe0, 0x7d,
-		0x42, 0x2e, 0x2f, 0x15, 0xee, 0x66, 0x57, 0x0f,
-		0x13, 0x19, 0x45, 0xa8, 0x4b, 0x5d, 0x81, 0x66,
-		0xcc, 0x12, 0x37, 0x94, 0x5e, 0xfd, 0x3c, 0x10,
-		0x81, 0x51, 0x3f, 0xfa, 0x0f, 0xdd, 0xa1, 0x89,
-		0x03, 0xa9, 0x78, 0x91, 0xf5, 0x3b, 0xf3, 0xbc,
-		0xac, 0xbe, 0x93, 0x30, 0x2e, 0xbe, 0xca, 0x7f,
-		0x46, 0xd3, 0x28, 0xb4, 0x4e, 0x91, 0x7b, 0x5b,
-		0x43, 0x6c, 0xaf, 0x9b, 0x5c, 0x6a, 0x6d, 0x5a,
-		0xdb, 0x79, 0x5e, 0x6a, 0x6b, 0x02, 0x03, 0x01,
-		0x00, 0x01, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x1d,
-		0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
-		0x14, 0x6b, 0x1e, 0x00, 0xa8, 0x9f, 0xfa, 0x7d,
-		0x00, 0xf9, 0xe0, 0x9d, 0x0f, 0x90, 0x8c, 0x90,
-		0xa8, 0xa1, 0x37, 0x6b, 0xda, 0x30, 0x1f, 0x06,
-		0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
-		0x80, 0x14, 0x6b, 0x1e, 0x00, 0xa8, 0x9f, 0xfa,
-		0x7d, 0x00, 0xf9, 0xe0, 0x9d, 0x0f, 0x90, 0x8c,
-		0x90, 0xa8, 0xa1, 0x37, 0x6b, 0xda, 0x30, 0x0c,
-		0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30,
-		0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09,
-		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-		0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
-		0xcd, 0x6f, 0x73, 0x4d, 0x56, 0x0b, 0xf3, 0x2e,
-		0x1c, 0xe2, 0x02, 0x0c, 0x14, 0xbb, 0x2f, 0xdd,
-		0x3c, 0x43, 0xfe, 0xdf, 0x94, 0x2d, 0xa9, 0x89,
-		0x81, 0x51, 0xf8, 0x5f, 0xa7, 0xa0, 0x13, 0xaa,
-		0xcc, 0xb0, 0x18, 0xe2, 0x57, 0x3e, 0x0d, 0x29,
-		0x93, 0xe8, 0x95, 0xd5, 0x1b, 0x53, 0xd2, 0x51,
-		0xf2, 0xbd, 0xf5, 0x9e, 0x7b, 0x22, 0x65, 0x62,
-		0x5c, 0xc4, 0x4c, 0x1d, 0xe8, 0xe9, 0xc3, 0xd4,
-		0x2b, 0xe7, 0x78, 0xcb, 0x10, 0xf3, 0xfe, 0x06,
-		0x83, 0xdc, 0x3a, 0x1e, 0x62, 0x10, 0xc0, 0x46,
-		0x77, 0xc6, 0x9d, 0x9f, 0xab, 0x96, 0x25, 0x5c,
-		0xfb, 0x26, 0xc1, 0x15, 0x1f, 0xa5, 0x33, 0xee,
-		0x4f, 0x9a, 0x14, 0x6a, 0x14, 0x97, 0x93, 0x2b,
-		0x95, 0x0b, 0xdc, 0xa8, 0xd7, 0x69, 0x2e, 0xf0,
-		0x01, 0x0e, 0xfd, 0x4e, 0xd0, 0xd9, 0xa8, 0xe5,
-		0x65, 0xde, 0xfb, 0xca, 0xca, 0x1c, 0x5f, 0xf9,
-		0x53, 0xa0, 0x87, 0xe7, 0x33, 0x9b, 0x2f, 0xcf,
-		0xe4, 0x13, 0xfc, 0xec, 0x7a, 0x6c, 0xb0, 0x90,
-		0x13, 0x9b, 0xb6, 0xc5, 0x03, 0xf6, 0x0e, 0x5e,
-		0xe2, 0xe4, 0x26, 0xc1, 0x7e, 0x53, 0xfe, 0x69,
-		0xa3, 0xc7, 0xd8, 0x8e, 0x6e, 0x94, 0x32, 0xa0,
-		0xde, 0xca, 0xb6, 0xcc, 0xd6, 0x01, 0xd5, 0x78,
-		0x40, 0x28, 0x63, 0x9b, 0xee, 0xcf, 0x09, 0x3b,
-		0x35, 0x04, 0xf0, 0x14, 0x02, 0xf6, 0x80, 0x0e,
-		0x90, 0xb2, 0x94, 0xd2, 0x25, 0x16, 0xb8, 0x7a,
-		0x76, 0x87, 0x84, 0x9f, 0x84, 0xc5, 0xaf, 0xc2,
-		0x6d, 0x68, 0x7a, 0x84, 0x9c, 0xc6, 0x8a, 0x63,
-		0x60, 0x87, 0x6a, 0x25, 0xc1, 0xa1, 0x78, 0x0f,
-		0xba, 0xe8, 0x5f, 0xe1, 0xba, 0xac, 0xa4, 0x6f,
-		0xdd, 0x09, 0x3f, 0x12, 0xcb, 0x1d, 0xf3, 0xcf,
-		0x48, 0xd7, 0xd3, 0x26, 0xe8, 0x9c, 0xc3, 0x53,
-		0xb3, 0xba, 0xdc, 0x32, 0x99, 0x98, 0x96, 0xd6,
-		0x16, 0x03, 0x01, 0x01, 0x06, 0x10, 0x00, 0x01,
-		0x02, 0x01, 0x00, 0x6e, 0xea, 0x15, 0x6f, 0x21,
-		0xbd, 0x2d, 0x14, 0xde, 0x9d, 0x02, 0xeb, 0xdf,
-		0x3b, 0x09, 0x75, 0xaf, 0x32, 0x80, 0x0c, 0xe2,
-		0xc2, 0x7b, 0x0d, 0xca, 0x24, 0x96, 0xf6, 0x3e,
-		0xa5, 0x97, 0xba, 0x0c, 0x50, 0x7e, 0xb3, 0x68,
-		0x58, 0xc6, 0xd8, 0xec, 0xab, 0xa9, 0xd9, 0x3a,
-		0xb1, 0x49, 0xea, 0x2f, 0xd7, 0xdb, 0x15, 0x1b,
-		0xb5, 0xaf, 0xec, 0xcc, 0x40, 0x5c, 0xe6, 0x0f,
-		0xc4, 0x33, 0x71, 0xe7, 0x41, 0xc0, 0x04, 0x89,
-		0x60, 0x3e, 0xb7, 0xe6, 0xda, 0x38, 0x62, 0x27,
-		0x6a, 0xd9, 0xfb, 0x93, 0x94, 0x9d, 0xc1, 0x63,
-		0x92, 0x5c, 0x88, 0x19, 0x38, 0x81, 0x79, 0x9d,
-		0x59, 0x48, 0x5e, 0xd3, 0xc8, 0xea, 0xcb, 0x6e,
-		0x66, 0x66, 0x03, 0xdc, 0x0c, 0x2d, 0x95, 0xb1,
-		0x4d, 0x68, 0xc7, 0xc5, 0x6e, 0xfa, 0x94, 0x14,
-		0xdf, 0x2c, 0x70, 0x69, 0x04, 0xf4, 0x69, 0xf1,
-		0xf0, 0x07, 0xbd, 0x23, 0x53, 0x63, 0xb3, 0x41,
-		0xec, 0xa7, 0x10, 0xa5, 0x04, 0x84, 0x24, 0xb5,
-		0xf5, 0x0c, 0x0f, 0x5d, 0x02, 0x47, 0x79, 0x60,
-		0x76, 0xbb, 0xdf, 0x60, 0xa6, 0xd7, 0x4d, 0x08,
-		0x7d, 0xa6, 0x85, 0x4f, 0x61, 0xac, 0x96, 0x3d,
-		0xbc, 0xaf, 0x07, 0xb0, 0x7c, 0xb6, 0x23, 0x3e,
-		0x1f, 0x0a, 0x62, 0x77, 0x97, 0x77, 0xae, 0x33,
-		0x55, 0x0f, 0x85, 0xdf, 0xdc, 0xbe, 0xc6, 0xe0,
-		0xe0, 0x14, 0x83, 0x4c, 0x50, 0xf0, 0xe5, 0x2d,
-		0xdc, 0x0b, 0x74, 0x7f, 0xc3, 0x28, 0x98, 0x16,
-		0xda, 0x74, 0xe6, 0x40, 0xc2, 0xf0, 0xea, 0xc0,
-		0x00, 0xd5, 0xfc, 0x16, 0xe4, 0x43, 0xa1, 0xfc,
-		0x31, 0x19, 0x81, 0x62, 0xec, 0x2b, 0xfe, 0xcc,
-		0xe8, 0x19, 0xed, 0xa1, 0x1e, 0x6a, 0x49, 0x73,
-		0xde, 0xc4, 0xe9, 0x22, 0x0a, 0x21, 0xde, 0x45,
-		0x1e, 0x55, 0x12, 0xd9, 0x44, 0xef, 0x4e, 0xaa,
-		0x5e, 0x26, 0x57, 0x16, 0x03, 0x01, 0x01, 0x06,
-		0x0f, 0x00, 0x01, 0x02, 0x01, 0x00, 0x23, 0xde,
-		0xb0, 0x39, 0x60, 0xe9, 0x82, 0xb8, 0xed, 0x17,
-		0x78, 0xd2, 0x37, 0x0e, 0x85, 0x69, 0xda, 0xcc,
-		0x9f, 0x54, 0x4d, 0xda, 0xce, 0xe8, 0x5a, 0xeb,
-		0x3c, 0x61, 0x4c, 0x7a, 0x84, 0x1f, 0x21, 0x03,
-		0xb3, 0x8a, 0x74, 0x3b, 0x6a, 0x9e, 0x4f, 0x44,
-		0xd9, 0x75, 0x0a, 0xd8, 0x7e, 0x56, 0xa3, 0xef,
-		0x5a, 0xfe, 0x8a, 0x35, 0xce, 0x29, 0x18, 0xfe,
-		0xa6, 0x61, 0x8e, 0x8f, 0x00, 0x90, 0x2d, 0x85,
-		0xe3, 0x6c, 0x0e, 0x8d, 0x8c, 0x27, 0x80, 0x8c,
-		0x9f, 0x51, 0xe9, 0xd3, 0xe6, 0x7d, 0x70, 0xe9,
-		0xfb, 0xcb, 0xb8, 0x24, 0x94, 0x30, 0x9b, 0xba,
-		0x01, 0x14, 0x49, 0x9f, 0xaf, 0x09, 0xd8, 0x26,
-		0x1b, 0x23, 0xa4, 0xb8, 0xd9, 0x44, 0x0a, 0xdc,
-		0x4e, 0x27, 0xe7, 0x32, 0xf5, 0x9c, 0xf3, 0x8d,
-		0xa0, 0xc5, 0xc4, 0xbe, 0x92, 0x02, 0x85, 0x4f,
-		0x33, 0x8f, 0xa7, 0xf7, 0x87, 0xa9, 0x44, 0xf3,
-		0x64, 0xbd, 0x32, 0x04, 0xeb, 0xc5, 0xc3, 0x62,
-		0xe9, 0xda, 0x2f, 0x95, 0x5c, 0xf7, 0x58, 0x3e,
-		0xad, 0x35, 0xd7, 0x7e, 0xad, 0xdd, 0x32, 0x8d,
-		0xce, 0x81, 0x08, 0xad, 0x49, 0xf7, 0xdb, 0xf7,
-		0xaf, 0xe3, 0xc6, 0xb2, 0xdd, 0x76, 0x0c, 0xcf,
-		0x0f, 0x87, 0x79, 0x90, 0x10, 0x79, 0xc6, 0xc8,
-		0x7b, 0xe6, 0x23, 0xf2, 0xda, 0x33, 0xca, 0xe1,
-		0xf0, 0x59, 0x42, 0x43, 0x03, 0x56, 0x19, 0xe3,
-		0x8b, 0xe6, 0xa8, 0x70, 0xbc, 0x80, 0xfa, 0x24,
-		0xae, 0x03, 0x13, 0x30, 0x0d, 0x1f, 0xab, 0xb7,
-		0x82, 0xd9, 0x24, 0x90, 0x80, 0xbf, 0x75, 0xe1,
-		0x0d, 0x1c, 0xb2, 0xfe, 0x92, 0x2c, 0x4d, 0x21,
-		0xe9, 0x5d, 0xa1, 0x68, 0xf3, 0x16, 0xd8, 0x3f,
-		0xb2, 0xc3, 0x00, 0x3e, 0xd8, 0x42, 0x25, 0x5c,
-		0x90, 0x11, 0xc0, 0x1b, 0xd4, 0x26, 0x5c, 0x37,
-		0x47, 0xbd, 0xf8, 0x1e, 0x34, 0xa9, 0x14, 0x03,
-		0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01, 0x00,
-		0x24, 0x8f, 0x94, 0x7e, 0x01, 0xee, 0xd5, 0x4f,
-		0x83, 0x41, 0x31, 0xc0, 0x36, 0x81, 0x46, 0xc3,
-		0xc0, 0xcc, 0x9c, 0xea, 0x0f, 0x29, 0x04, 0x10,
-		0x43, 0x1e, 0x08, 0x6e, 0x08, 0xce, 0xb2, 0x62,
-		0xa6, 0x0f, 0x68, 0x9f, 0x99,
-	},
-	{
-		0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
-		0x01, 0x00, 0x24, 0xd9, 0x46, 0x5b, 0xbf, 0xfd,
-		0x8a, 0xa1, 0x08, 0xd5, 0xf3, 0x0c, 0x1c, 0xd8,
-		0xa8, 0xb3, 0xe5, 0x89, 0x83, 0x9e, 0x23, 0x47,
-		0x81, 0x66, 0x77, 0x11, 0x98, 0xe5, 0xf4, 0xac,
-		0x06, 0xe9, 0x4c, 0x05, 0x8b, 0xc4, 0x16,
-	},
-	{
-		0x17, 0x03, 0x01, 0x00, 0x1a, 0xc5, 0x28, 0xfd,
-		0x71, 0xc0, 0xe6, 0x89, 0xb8, 0x82, 0x92, 0x1b,
-		0xdd, 0x39, 0xe5, 0xbf, 0x41, 0x82, 0x1f, 0xc1,
-		0xbc, 0x85, 0xe5, 0x32, 0x1b, 0x93, 0x46, 0x15,
-		0x03, 0x01, 0x00, 0x16, 0x1a, 0x8b, 0x10, 0x42,
-		0x12, 0xb2, 0xbd, 0xd3, 0xf1, 0x74, 0x1f, 0xc2,
-		0x10, 0x08, 0xc2, 0x79, 0x99, 0x2c, 0x55, 0xef,
-		0x4a, 0xbd,
-	},
+func TestHandshakeClientECDHEECDSAAESGCM(t *testing.T) {
+	test := &clientTest{
+		name:    "ECDHE-ECDSA-AES-GCM",
+		command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-GCM-SHA256"},
+		cert:    testECDSACertificate,
+		key:     testECDSAPrivateKey,
+	}
+	runClientTestTLS12(t, test)
 }
 
-// $ openssl s_server -tls1_2 -cert server.crt -key server.key \
-//     -cipher ECDHE-RSA-AES128-SHA -port 10443
-// $ go test -test.run "TestRunClient" -connect -ciphersuites=0xc013 \
-//     -minversion=0x0303 -maxversion=0x0303
-var clientTLS12Script = [][]byte{
-	{
-		0x16, 0x03, 0x01, 0x00, 0x58, 0x01, 0x00, 0x00,
-		0x54, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x13,
-		0x01, 0x00, 0x00, 0x29, 0x00, 0x05, 0x00, 0x05,
-		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
-		0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
-		0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00,
-		0x0d, 0x00, 0x0a, 0x00, 0x08, 0x04, 0x01, 0x04,
-		0x03, 0x02, 0x01, 0x02, 0x03,
-	},
-	{
-		0x16, 0x03, 0x03, 0x00, 0x54, 0x02, 0x00, 0x00,
-		0x50, 0x03, 0x03, 0x52, 0x65, 0x67, 0xbd, 0xe8,
-		0x72, 0x03, 0x6a, 0x52, 0x8d, 0x28, 0x2c, 0x9a,
-		0x53, 0xff, 0xc2, 0xa1, 0x62, 0x5f, 0x54, 0xfb,
-		0x73, 0x00, 0xcf, 0x4d, 0x28, 0x36, 0xc2, 0xee,
-		0xfd, 0x78, 0xf0, 0x20, 0x6f, 0xbe, 0x49, 0xec,
-		0x5b, 0x6f, 0xf9, 0x53, 0x42, 0x69, 0x0d, 0x6d,
-		0x8b, 0x68, 0x2e, 0xca, 0x3c, 0x3c, 0x88, 0x9e,
-		0x8b, 0xf9, 0x32, 0x65, 0x09, 0xd6, 0xa0, 0x7d,
-		0xea, 0xc6, 0xd5, 0xc4, 0xc0, 0x13, 0x00, 0x00,
-		0x08, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01,
-		0x02, 0x16, 0x03, 0x03, 0x02, 0x39, 0x0b, 0x00,
-		0x02, 0x35, 0x00, 0x02, 0x32, 0x00, 0x02, 0x2f,
-		0x30, 0x82, 0x02, 0x2b, 0x30, 0x82, 0x01, 0xd5,
-		0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00,
-		0xb1, 0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92,
-		0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
-		0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
-		0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
-		0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
-		0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
-		0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
-		0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
-		0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
-		0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
-		0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
-		0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e,
-		0x17, 0x0d, 0x31, 0x32, 0x30, 0x34, 0x30, 0x36,
-		0x31, 0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x17,
-		0x0d, 0x31, 0x35, 0x30, 0x34, 0x30, 0x36, 0x31,
-		0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x30, 0x45,
-		0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
-		0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30,
-		0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
-		0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
-		0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
-		0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74,
-		0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69,
-		0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74,
-		0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x5c, 0x30,
-		0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
-		0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b,
-		0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0x9f, 0xb3,
-		0xc3, 0x84, 0x27, 0x95, 0xff, 0x12, 0x31, 0x52,
-		0x0f, 0x15, 0xef, 0x46, 0x11, 0xc4, 0xad, 0x80,
-		0xe6, 0x36, 0x5b, 0x0f, 0xdd, 0x80, 0xd7, 0x61,
-		0x8d, 0xe0, 0xfc, 0x72, 0x45, 0x09, 0x34, 0xfe,
-		0x55, 0x66, 0x45, 0x43, 0x4c, 0x68, 0x97, 0x6a,
-		0xfe, 0xa8, 0xa0, 0xa5, 0xdf, 0x5f, 0x78, 0xff,
-		0xee, 0xd7, 0x64, 0xb8, 0x3f, 0x04, 0xcb, 0x6f,
-		0xff, 0x2a, 0xfe, 0xfe, 0xb9, 0xed, 0x02, 0x03,
-		0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
-		0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
-		0x04, 0x16, 0x04, 0x14, 0x78, 0xa6, 0x97, 0x9a,
-		0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22,
-		0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b,
-		0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
-		0x6e, 0x30, 0x6c, 0x80, 0x14, 0x78, 0xa6, 0x97,
-		0x9a, 0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba,
-		0x22, 0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc,
-		0x2b, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
-		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
-		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
-		0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
-		0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
-		0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
-		0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
-		0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
-		0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0xb1,
-		0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92, 0x30,
-		0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
-		0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
-		0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-		0x01, 0x05, 0x05, 0x00, 0x03, 0x41, 0x00, 0x85,
-		0x36, 0x40, 0x73, 0xc1, 0xbb, 0x1a, 0xda, 0xd4,
-		0x59, 0x9f, 0x2d, 0xa2, 0x70, 0x31, 0x46, 0x74,
-		0xec, 0x83, 0x6e, 0xa8, 0xc8, 0x3c, 0x51, 0xaf,
-		0x39, 0xac, 0xec, 0x40, 0xbc, 0xe8, 0x22, 0x46,
-		0x1d, 0x99, 0xd6, 0x46, 0x2a, 0x24, 0xd4, 0x8b,
-		0x05, 0x08, 0x4b, 0xfb, 0x35, 0x11, 0x6e, 0x92,
-		0xbb, 0x77, 0xba, 0xe4, 0x12, 0xbb, 0xf4, 0xc8,
-		0x5e, 0x9c, 0x81, 0xa8, 0x97, 0x60, 0x4c, 0x16,
-		0x03, 0x03, 0x00, 0x8d, 0x0c, 0x00, 0x00, 0x89,
-		0x03, 0x00, 0x17, 0x41, 0x04, 0x48, 0x93, 0x62,
-		0x6a, 0xf8, 0x7c, 0x94, 0xcc, 0xcc, 0x0a, 0x9b,
-		0x5e, 0x11, 0xad, 0x0b, 0x30, 0xc4, 0x5d, 0xf7,
-		0x63, 0x24, 0xc1, 0xb0, 0x40, 0x5f, 0xff, 0x9f,
-		0x0d, 0x7e, 0xd5, 0xa5, 0xd0, 0x4f, 0x80, 0x16,
-		0xa8, 0x66, 0x18, 0x31, 0x1f, 0x81, 0xb2, 0x9a,
-		0x41, 0x62, 0x5b, 0xcf, 0x73, 0xac, 0x4a, 0x64,
-		0xb5, 0xc1, 0x46, 0x4d, 0x8a, 0xac, 0x25, 0xba,
-		0x81, 0x7f, 0xbe, 0x64, 0x68, 0x04, 0x01, 0x00,
-		0x40, 0x4e, 0x3f, 0x1e, 0x04, 0x4c, 0xef, 0xd2,
-		0xa6, 0x82, 0xe6, 0x7c, 0x76, 0x23, 0x17, 0xb9,
-		0xe7, 0x52, 0x15, 0x6b, 0x3d, 0xb2, 0xb1, 0x17,
-		0x7d, 0xe6, 0xde, 0x06, 0x87, 0x30, 0xb0, 0xb5,
-		0x57, 0xae, 0xdf, 0xb2, 0xdc, 0x8d, 0xab, 0x76,
-		0x9c, 0xaa, 0x45, 0x6d, 0x23, 0x5d, 0xc1, 0xa8,
-		0x7b, 0x79, 0x79, 0xb1, 0x3c, 0xdc, 0xf5, 0x33,
-		0x2c, 0xa1, 0x62, 0x3e, 0xbd, 0xf5, 0x5d, 0x6c,
-		0x87, 0x16, 0x03, 0x03, 0x00, 0x04, 0x0e, 0x00,
-		0x00, 0x00,
-	},
-	{
-		0x16, 0x03, 0x03, 0x00, 0x46, 0x10, 0x00, 0x00,
-		0x42, 0x41, 0x04, 0x1e, 0x18, 0x37, 0xef, 0x0d,
-		0x19, 0x51, 0x88, 0x35, 0x75, 0x71, 0xb5, 0xe5,
-		0x54, 0x5b, 0x12, 0x2e, 0x8f, 0x09, 0x67, 0xfd,
-		0xa7, 0x24, 0x20, 0x3e, 0xb2, 0x56, 0x1c, 0xce,
-		0x97, 0x28, 0x5e, 0xf8, 0x2b, 0x2d, 0x4f, 0x9e,
-		0xf1, 0x07, 0x9f, 0x6c, 0x4b, 0x5b, 0x83, 0x56,
-		0xe2, 0x32, 0x42, 0xe9, 0x58, 0xb6, 0xd7, 0x49,
-		0xa6, 0xb5, 0x68, 0x1a, 0x41, 0x03, 0x56, 0x6b,
-		0xdc, 0x5a, 0x89, 0x14, 0x03, 0x03, 0x00, 0x01,
-		0x01, 0x16, 0x03, 0x03, 0x00, 0x40, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0x17,
-		0x54, 0x51, 0xb6, 0x1d, 0x8e, 0xe4, 0x6b, 0xed,
-		0x5b, 0xa1, 0x27, 0x7f, 0xdc, 0xa9, 0xa5, 0xcf,
-		0x38, 0xe6, 0x5d, 0x17, 0x34, 0xf9, 0xc0, 0x07,
-		0xb8, 0xbe, 0x56, 0xe6, 0xd6, 0x6a, 0xb6, 0x26,
-		0x4e, 0x45, 0x8d, 0x48, 0xe9, 0xc6, 0xb1, 0xa1,
-		0xea, 0xdc, 0xb1, 0x37, 0xd9, 0xf6,
-	},
-	{
-		0x14, 0x03, 0x03, 0x00, 0x01, 0x01, 0x16, 0x03,
-		0x03, 0x00, 0x40, 0x00, 0x68, 0xc5, 0x27, 0xd5,
-		0x3d, 0xba, 0x04, 0xde, 0x63, 0xf1, 0x5b, 0xc3,
-		0x86, 0xb9, 0x82, 0xc7, 0xb3, 0x90, 0x31, 0xea,
-		0x15, 0xe1, 0x42, 0x76, 0x7d, 0x90, 0xcb, 0xc9,
-		0xd1, 0x05, 0xe6, 0x8c, 0x76, 0xc7, 0x9a, 0x35,
-		0x67, 0xa2, 0x70, 0x9a, 0x8a, 0x6c, 0xb5, 0x6b,
-		0xc7, 0x87, 0xf3, 0x65, 0x0a, 0xa0, 0x98, 0xba,
-		0x57, 0xbb, 0x31, 0x7b, 0x1f, 0x1a, 0xf7, 0x2a,
-		0xf3, 0x12, 0xf6,
-	},
-	{
-		0x17, 0x03, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x10, 0x80,
-		0x54, 0x1e, 0x72, 0xd3, 0x1a, 0x86, 0x1c, 0xc4,
-		0x4a, 0x9b, 0xd4, 0x80, 0xd2, 0x03, 0x35, 0x0d,
-		0xe4, 0x12, 0xc2, 0x3d, 0x79, 0x4a, 0x2c, 0xba,
-		0xc2, 0xad, 0xf3, 0xd2, 0x16, 0x15, 0x03, 0x03,
-		0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x04, 0x9b, 0x68, 0x78, 0x92, 0x28,
-		0x62, 0x02, 0x65, 0x87, 0x90, 0xe4, 0x32, 0xd7,
-		0x72, 0x08, 0x70, 0xb8, 0x52, 0x32, 0x1f, 0x97,
-		0xd4, 0x6a, 0xc6, 0x28, 0x83, 0xb0, 0x1d, 0x6e,
-		0x16, 0xd5,
-	},
+func TestHandshakeClientCertRSA(t *testing.T) {
+	config := *testConfig
+	cert, _ := X509KeyPair([]byte(clientCertificatePEM), []byte(clientKeyPEM))
+	config.Certificates = []Certificate{cert}
+
+	test := &clientTest{
+		name:    "ClientCert-RSA-RSA",
+		command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"},
+		config:  &config,
+	}
+
+	runClientTestTLS10(t, test)
+	runClientTestTLS12(t, test)
+
+	test = &clientTest{
+		name:    "ClientCert-RSA-ECDSA",
+		command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA", "-verify", "1"},
+		config:  &config,
+		cert:    testECDSACertificate,
+		key:     testECDSAPrivateKey,
+	}
+
+	runClientTestTLS10(t, test)
+	runClientTestTLS12(t, test)
 }
 
-// $ openssl s_server -tls1_2 -cert server.crt -key server.key \
-//     -port 10443 -verify 0
-// $ go test -test.run "TestRunClient" -connect -ciphersuites=0xc02f \
-//     -maxversion=0x0303
-var clientTLS12ClientCertScript = [][]byte{
-	{
-		0x16, 0x03, 0x01, 0x00, 0x58, 0x01, 0x00, 0x00,
-		0x54, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x2f,
-		0x01, 0x00, 0x00, 0x29, 0x00, 0x05, 0x00, 0x05,
-		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
-		0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
-		0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00,
-		0x0d, 0x00, 0x0a, 0x00, 0x08, 0x04, 0x01, 0x04,
-		0x03, 0x02, 0x01, 0x02, 0x03,
-	},
-	{
-		0x16, 0x03, 0x03, 0x00, 0x54, 0x02, 0x00, 0x00,
-		0x50, 0x03, 0x03, 0x52, 0x65, 0x67, 0xe0, 0xe8,
-		0xf1, 0x13, 0x2a, 0x83, 0x28, 0xa8, 0x2e, 0x76,
-		0x69, 0xe6, 0x89, 0x55, 0x6c, 0x48, 0x49, 0x2e,
-		0x00, 0xf6, 0x87, 0x6c, 0x13, 0xa1, 0xd4, 0xaa,
-		0xd0, 0x76, 0x3b, 0x20, 0xe4, 0xd6, 0x5b, 0x1d,
-		0x11, 0xf2, 0x42, 0xf2, 0x82, 0x0c, 0x0d, 0x66,
-		0x6d, 0xec, 0x52, 0xf8, 0x4a, 0xd9, 0x45, 0xcf,
-		0xe4, 0x4a, 0xba, 0x8b, 0xf1, 0xab, 0x55, 0xe4,
-		0x57, 0x18, 0xa9, 0x36, 0xc0, 0x2f, 0x00, 0x00,
-		0x08, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01,
-		0x02, 0x16, 0x03, 0x03, 0x02, 0x39, 0x0b, 0x00,
-		0x02, 0x35, 0x00, 0x02, 0x32, 0x00, 0x02, 0x2f,
-		0x30, 0x82, 0x02, 0x2b, 0x30, 0x82, 0x01, 0xd5,
-		0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00,
-		0xb1, 0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92,
-		0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
-		0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
-		0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
-		0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
-		0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
-		0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
-		0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
-		0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
-		0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
-		0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
-		0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e,
-		0x17, 0x0d, 0x31, 0x32, 0x30, 0x34, 0x30, 0x36,
-		0x31, 0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x17,
-		0x0d, 0x31, 0x35, 0x30, 0x34, 0x30, 0x36, 0x31,
-		0x37, 0x31, 0x30, 0x31, 0x33, 0x5a, 0x30, 0x45,
-		0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
-		0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30,
-		0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
-		0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
-		0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
-		0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74,
-		0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69,
-		0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74,
-		0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x5c, 0x30,
-		0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
-		0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b,
-		0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0x9f, 0xb3,
-		0xc3, 0x84, 0x27, 0x95, 0xff, 0x12, 0x31, 0x52,
-		0x0f, 0x15, 0xef, 0x46, 0x11, 0xc4, 0xad, 0x80,
-		0xe6, 0x36, 0x5b, 0x0f, 0xdd, 0x80, 0xd7, 0x61,
-		0x8d, 0xe0, 0xfc, 0x72, 0x45, 0x09, 0x34, 0xfe,
-		0x55, 0x66, 0x45, 0x43, 0x4c, 0x68, 0x97, 0x6a,
-		0xfe, 0xa8, 0xa0, 0xa5, 0xdf, 0x5f, 0x78, 0xff,
-		0xee, 0xd7, 0x64, 0xb8, 0x3f, 0x04, 0xcb, 0x6f,
-		0xff, 0x2a, 0xfe, 0xfe, 0xb9, 0xed, 0x02, 0x03,
-		0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
-		0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
-		0x04, 0x16, 0x04, 0x14, 0x78, 0xa6, 0x97, 0x9a,
-		0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22,
-		0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b,
-		0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
-		0x6e, 0x30, 0x6c, 0x80, 0x14, 0x78, 0xa6, 0x97,
-		0x9a, 0x63, 0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba,
-		0x22, 0x7c, 0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc,
-		0x2b, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
-		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
-		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
-		0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
-		0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
-		0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
-		0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
-		0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
-		0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0xb1,
-		0x35, 0x13, 0x65, 0x11, 0x20, 0xc5, 0x92, 0x30,
-		0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
-		0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
-		0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-		0x01, 0x05, 0x05, 0x00, 0x03, 0x41, 0x00, 0x85,
-		0x36, 0x40, 0x73, 0xc1, 0xbb, 0x1a, 0xda, 0xd4,
-		0x59, 0x9f, 0x2d, 0xa2, 0x70, 0x31, 0x46, 0x74,
-		0xec, 0x83, 0x6e, 0xa8, 0xc8, 0x3c, 0x51, 0xaf,
-		0x39, 0xac, 0xec, 0x40, 0xbc, 0xe8, 0x22, 0x46,
-		0x1d, 0x99, 0xd6, 0x46, 0x2a, 0x24, 0xd4, 0x8b,
-		0x05, 0x08, 0x4b, 0xfb, 0x35, 0x11, 0x6e, 0x92,
-		0xbb, 0x77, 0xba, 0xe4, 0x12, 0xbb, 0xf4, 0xc8,
-		0x5e, 0x9c, 0x81, 0xa8, 0x97, 0x60, 0x4c, 0x16,
-		0x03, 0x03, 0x00, 0x8d, 0x0c, 0x00, 0x00, 0x89,
-		0x03, 0x00, 0x17, 0x41, 0x04, 0xaa, 0xf0, 0x0c,
-		0xa3, 0x60, 0xcf, 0x69, 0x1e, 0xad, 0x16, 0x9a,
-		0x01, 0x40, 0xc6, 0x22, 0xc4, 0xbb, 0x06, 0x3b,
-		0x84, 0x65, 0xea, 0xc7, 0xa2, 0x96, 0x79, 0x17,
-		0x2f, 0xc7, 0xbe, 0x56, 0x39, 0xe4, 0x79, 0xf3,
-		0xad, 0x17, 0xf3, 0x7e, 0xe2, 0x7b, 0xa2, 0x6f,
-		0x3f, 0x96, 0xea, 0xe5, 0x0e, 0xea, 0x39, 0x79,
-		0x77, 0xeb, 0x14, 0x18, 0xbb, 0x7c, 0x95, 0xda,
-		0xa7, 0x51, 0x09, 0xba, 0xd7, 0x04, 0x01, 0x00,
-		0x40, 0x82, 0x3e, 0xce, 0xee, 0x7e, 0xba, 0x3b,
-		0x51, 0xb1, 0xba, 0x71, 0x2e, 0x54, 0xa9, 0xb9,
-		0xe2, 0xb1, 0x59, 0x17, 0xa1, 0xac, 0x76, 0xb4,
-		0x4e, 0xf1, 0xae, 0x65, 0x17, 0x2b, 0x43, 0x06,
-		0x31, 0x29, 0x0b, 0xa0, 0x1e, 0xb6, 0xfa, 0x35,
-		0xe8, 0x63, 0x06, 0xde, 0x13, 0x89, 0x83, 0x69,
-		0x3b, 0xc2, 0x15, 0x73, 0x1c, 0xc5, 0x07, 0xe9,
-		0x38, 0x9b, 0x06, 0x81, 0x1b, 0x97, 0x7c, 0xa6,
-		0x89, 0x16, 0x03, 0x03, 0x00, 0x30, 0x0d, 0x00,
-		0x00, 0x28, 0x03, 0x01, 0x02, 0x40, 0x00, 0x20,
-		0x06, 0x01, 0x06, 0x02, 0x06, 0x03, 0x05, 0x01,
-		0x05, 0x02, 0x05, 0x03, 0x04, 0x01, 0x04, 0x02,
-		0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03,
-		0x02, 0x01, 0x02, 0x02, 0x02, 0x03, 0x01, 0x01,
-		0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
-	},
-	{
-		0x16, 0x03, 0x03, 0x0a, 0xfb, 0x0b, 0x00, 0x0a,
-		0xf7, 0x00, 0x0a, 0xf4, 0x00, 0x03, 0x7e, 0x30,
-		0x82, 0x03, 0x7a, 0x30, 0x82, 0x02, 0x62, 0x02,
-		0x09, 0x00, 0xb4, 0x47, 0x58, 0x57, 0x2b, 0x67,
-		0xc8, 0xc2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
-		0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
-		0x00, 0x30, 0x81, 0x80, 0x31, 0x0b, 0x30, 0x09,
-		0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
-		0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
-		0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59, 0x31, 0x11,
-		0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
-		0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c, 0x79,
-		0x6e, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55,
-		0x04, 0x0a, 0x0c, 0x0c, 0x4d, 0x79, 0x20, 0x43,
-		0x41, 0x20, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74,
-		0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
-		0x03, 0x0c, 0x0e, 0x6d, 0x79, 0x63, 0x61, 0x63,
-		0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x63, 0x6f,
-		0x6d, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a,
-		0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01,
-		0x16, 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68,
-		0x69, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
-		0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d,
-		0x31, 0x33, 0x30, 0x35, 0x32, 0x36, 0x32, 0x31,
-		0x34, 0x34, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31,
-		0x33, 0x30, 0x36, 0x32, 0x35, 0x32, 0x31, 0x34,
-		0x34, 0x30, 0x30, 0x5a, 0x30, 0x7d, 0x31, 0x0b,
-		0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
-		0x02, 0x55, 0x53, 0x31, 0x11, 0x30, 0x0f, 0x06,
-		0x03, 0x55, 0x04, 0x08, 0x0c, 0x08, 0x4e, 0x65,
-		0x77, 0x20, 0x59, 0x6f, 0x72, 0x6b, 0x31, 0x11,
-		0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
-		0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c, 0x79,
-		0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
-		0x04, 0x0a, 0x0c, 0x07, 0x4d, 0x79, 0x20, 0x4c,
-		0x65, 0x61, 0x66, 0x31, 0x13, 0x30, 0x11, 0x06,
-		0x03, 0x55, 0x04, 0x03, 0x0c, 0x0a, 0x6d, 0x79,
-		0x6c, 0x65, 0x61, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
-		0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86,
-		0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
-		0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68, 0x69,
-		0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e,
-		0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30,
-		0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
-		0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82,
-		0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02,
-		0x82, 0x01, 0x01, 0x00, 0xa0, 0xa3, 0xef, 0xc1,
-		0x44, 0x7d, 0xa2, 0xe3, 0x71, 0x98, 0x27, 0x63,
-		0xb3, 0x1d, 0x71, 0x50, 0xa6, 0x34, 0x15, 0xcb,
-		0xc9, 0x2a, 0xc3, 0xea, 0xe4, 0x9e, 0x9c, 0x49,
-		0xa6, 0x01, 0x9b, 0x7e, 0xa9, 0xb5, 0x7a, 0xff,
-		0x15, 0x92, 0x71, 0xc8, 0x97, 0x9c, 0x25, 0xb7,
-		0x79, 0x2b, 0xff, 0xab, 0xc6, 0xb1, 0xa7, 0x00,
-		0x90, 0xb2, 0x8b, 0xd7, 0x71, 0xd5, 0xc2, 0x3a,
-		0xe6, 0x82, 0x42, 0x37, 0x89, 0x41, 0x04, 0xb0,
-		0xba, 0xc7, 0x5b, 0x8a, 0x43, 0x9f, 0x97, 0x39,
-		0x0c, 0x0f, 0xd5, 0x6d, 0x9e, 0x8d, 0xeb, 0xc0,
-		0x26, 0xc5, 0x18, 0xe8, 0x7a, 0x3d, 0x32, 0x2e,
-		0x38, 0x90, 0x40, 0x5b, 0x39, 0x2c, 0x07, 0xcb,
-		0x24, 0x10, 0xc5, 0xc9, 0x3b, 0xe3, 0x66, 0x47,
-		0x57, 0xb9, 0x6a, 0xad, 0x44, 0xf8, 0xd0, 0x70,
-		0x62, 0x3b, 0x8e, 0xed, 0x60, 0x5f, 0x22, 0xf8,
-		0xb8, 0x0c, 0xc9, 0x41, 0x2b, 0xc9, 0x80, 0x6e,
-		0x4e, 0x1b, 0xe1, 0x20, 0xfc, 0x47, 0xa4, 0xac,
-		0xc3, 0x3f, 0xe6, 0xc2, 0x81, 0x79, 0x03, 0x37,
-		0x25, 0x89, 0xca, 0xd6, 0xa5, 0x46, 0x91, 0x63,
-		0x41, 0xc5, 0x3e, 0xd5, 0xed, 0x7f, 0x4f, 0x8d,
-		0x06, 0xc0, 0x89, 0x00, 0xbe, 0x37, 0x7b, 0x7e,
-		0x73, 0xca, 0x70, 0x00, 0x14, 0x34, 0xbe, 0x47,
-		0xbc, 0xb2, 0x6a, 0x28, 0xa5, 0x29, 0x84, 0xa8,
-		0x9d, 0xc8, 0x1e, 0x77, 0x66, 0x1f, 0x9f, 0xaa,
-		0x2b, 0x47, 0xdb, 0xdd, 0x6b, 0x9c, 0xa8, 0xfc,
-		0x82, 0x36, 0x94, 0x62, 0x0d, 0x5c, 0x3f, 0xb2,
-		0x01, 0xb4, 0xa5, 0xb8, 0xc6, 0x0e, 0x94, 0x5b,
-		0xec, 0x5e, 0xbb, 0x7a, 0x63, 0x24, 0xf1, 0xf9,
-		0xd6, 0x50, 0x08, 0xc1, 0xa3, 0xcc, 0x90, 0x07,
-		0x5b, 0x04, 0x04, 0x42, 0x74, 0xcf, 0x37, 0xfa,
-		0xf0, 0xa5, 0xd9, 0xd3, 0x86, 0x89, 0x89, 0x18,
-		0xf3, 0x4c, 0xe2, 0x11, 0x02, 0x03, 0x01, 0x00,
-		0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
-		0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
-		0x03, 0x82, 0x01, 0x01, 0x00, 0x90, 0xbb, 0xf9,
-		0x5e, 0xba, 0x17, 0x1f, 0xac, 0x21, 0x9f, 0x6b,
-		0x4a, 0x46, 0xd0, 0x6d, 0x3c, 0x8f, 0x3d, 0xf8,
-		0x5e, 0x3e, 0x72, 0xaf, 0xa0, 0x1a, 0xf3, 0xff,
-		0x89, 0xac, 0x5b, 0x7a, 0xe2, 0x91, 0x2a, 0x23,
-		0x85, 0xc6, 0x4d, 0x47, 0x67, 0x01, 0x08, 0xa8,
-		0x05, 0x1d, 0x01, 0x60, 0x50, 0x5f, 0x59, 0xad,
-		0xfe, 0x7b, 0xc6, 0x0c, 0x54, 0x90, 0x68, 0x70,
-		0x67, 0x2e, 0xed, 0x87, 0xf8, 0x69, 0x8a, 0xac,
-		0x32, 0xfe, 0x6f, 0x90, 0x19, 0x2a, 0x64, 0x8d,
-		0x82, 0x66, 0x05, 0x43, 0x88, 0xee, 0xf2, 0x30,
-		0xed, 0xa4, 0x8f, 0xbf, 0xd6, 0x57, 0x20, 0xd4,
-		0x43, 0x1d, 0x52, 0x96, 0x6f, 0xae, 0x09, 0x96,
-		0x01, 0x52, 0x38, 0xe3, 0xaf, 0x99, 0xd7, 0xdc,
-		0x14, 0x99, 0xc4, 0x8b, 0x0e, 0x04, 0x0f, 0xb3,
-		0x14, 0x14, 0xd4, 0xa5, 0x93, 0xe1, 0xc9, 0x8a,
-		0x81, 0xef, 0x63, 0xfc, 0x36, 0x77, 0x05, 0x06,
-		0xf0, 0x2a, 0x04, 0x0a, 0xbe, 0x2e, 0xce, 0x81,
-		0x3d, 0x23, 0xa1, 0xda, 0xd8, 0xeb, 0xc6, 0xea,
-		0x5e, 0xcf, 0x28, 0x36, 0x51, 0x31, 0x95, 0x5e,
-		0x40, 0x04, 0xed, 0xac, 0xc1, 0xc8, 0x56, 0x69,
-		0x87, 0xec, 0x3b, 0x03, 0x3e, 0x9d, 0x0f, 0x4c,
-		0x4c, 0xeb, 0xd7, 0xba, 0x26, 0xdf, 0xe3, 0xde,
-		0x10, 0xee, 0x93, 0x62, 0x8d, 0x73, 0x52, 0x6e,
-		0xff, 0x37, 0x36, 0x98, 0x7b, 0x2d, 0x56, 0x4c,
-		0xba, 0x09, 0xb8, 0xa7, 0xf0, 0x3b, 0x16, 0x81,
-		0xca, 0xdb, 0x43, 0xab, 0xec, 0x4c, 0x6e, 0x7c,
-		0xc1, 0x0b, 0x22, 0x22, 0x43, 0x1d, 0xb6, 0x0c,
-		0xc1, 0xb9, 0xcf, 0xe4, 0x53, 0xee, 0x1d, 0x3e,
-		0x88, 0xa7, 0x13, 0xbe, 0x7f, 0xbd, 0xae, 0x72,
-		0xcf, 0xcd, 0x63, 0xd2, 0xc3, 0x18, 0x58, 0x92,
-		0xa2, 0xad, 0xb5, 0x09, 0x9d, 0x91, 0x03, 0xdd,
-		0x3c, 0xe2, 0x1c, 0xde, 0x78, 0x00, 0x03, 0x88,
-		0x30, 0x82, 0x03, 0x84, 0x30, 0x82, 0x02, 0x6c,
-		0x02, 0x09, 0x00, 0xab, 0xed, 0xa6, 0xe4, 0x4a,
-		0x2b, 0x2b, 0xf8, 0x30, 0x0d, 0x06, 0x09, 0x2a,
-		0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
-		0x05, 0x00, 0x30, 0x81, 0x86, 0x31, 0x0b, 0x30,
-		0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
-		0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
-		0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59, 0x31,
-		0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07,
-		0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c,
-		0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
-		0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d, 0x79, 0x20,
-		0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
-		0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
-		0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30,
-		0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
-		0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f, 0x72, 0x67,
-		0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86,
-		0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
-		0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68, 0x69,
-		0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e,
-		0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31,
-		0x33, 0x30, 0x35, 0x32, 0x36, 0x32, 0x31, 0x31,
-		0x38, 0x34, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x33,
-		0x30, 0x36, 0x32, 0x35, 0x32, 0x31, 0x31, 0x38,
-		0x34, 0x30, 0x5a, 0x30, 0x81, 0x80, 0x31, 0x0b,
-		0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
-		0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06,
-		0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59,
-		0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
-		0x07, 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b,
-		0x6c, 0x79, 0x6e, 0x31, 0x15, 0x30, 0x13, 0x06,
-		0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x4d, 0x79,
-		0x20, 0x43, 0x41, 0x20, 0x43, 0x6c, 0x69, 0x65,
-		0x6e, 0x74, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03,
-		0x55, 0x04, 0x03, 0x0c, 0x0e, 0x6d, 0x79, 0x63,
-		0x61, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e,
-		0x63, 0x6f, 0x6d, 0x31, 0x21, 0x30, 0x1f, 0x06,
-		0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-		0x09, 0x01, 0x16, 0x12, 0x6a, 0x76, 0x73, 0x68,
-		0x61, 0x68, 0x69, 0x64, 0x40, 0x67, 0x6d, 0x61,
-		0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82,
-		0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
-		0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
-		0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,
-		0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xce,
-		0x13, 0xf0, 0x72, 0xb0, 0x61, 0xc8, 0x18, 0x37,
-		0x8a, 0x41, 0x3d, 0x20, 0xa1, 0x1c, 0xcb, 0xbf,
-		0xf6, 0x3b, 0x74, 0x26, 0x2a, 0x96, 0x11, 0xec,
-		0x53, 0xa1, 0xcc, 0x7d, 0x77, 0x56, 0x45, 0x0f,
-		0x36, 0xb7, 0xf2, 0x48, 0x92, 0x1a, 0x62, 0xcc,
-		0xb6, 0xc0, 0xa1, 0x2f, 0x44, 0x2b, 0xc1, 0x89,
-		0xcb, 0x6e, 0x1e, 0xdb, 0x57, 0x92, 0xd5, 0x97,
-		0x60, 0x8c, 0x41, 0x2c, 0xd9, 0x20, 0xfe, 0xe9,
-		0x1f, 0x8e, 0xfc, 0x7f, 0x02, 0x44, 0x0f, 0x28,
-		0x81, 0xd6, 0x0c, 0xcd, 0xbc, 0xf0, 0x57, 0x6c,
-		0xcc, 0xa7, 0xba, 0x06, 0xa0, 0xa6, 0x91, 0xda,
-		0xef, 0x46, 0x8a, 0x60, 0x0f, 0x52, 0x6c, 0x90,
-		0x6c, 0x8c, 0x44, 0xaf, 0xb0, 0x9d, 0x90, 0xba,
-		0x21, 0x58, 0xa0, 0x3c, 0xee, 0x54, 0xb5, 0x29,
-		0x26, 0x1f, 0x0a, 0xac, 0xef, 0x48, 0x68, 0x33,
-		0xd0, 0x33, 0xd0, 0x8b, 0x1a, 0xec, 0x6e, 0x2f,
-		0xb5, 0x4a, 0x53, 0xc2, 0x1a, 0xd2, 0xf1, 0x50,
-		0x05, 0x59, 0x5c, 0xd9, 0xda, 0x03, 0x0a, 0x47,
-		0xb7, 0xdd, 0xf7, 0x3a, 0x69, 0xf5, 0x4e, 0xea,
-		0x4a, 0xc2, 0xca, 0x54, 0xb0, 0x8b, 0x76, 0xe1,
-		0x02, 0x2d, 0x52, 0x67, 0xb9, 0xdd, 0x50, 0xc9,
-		0x3b, 0x07, 0x24, 0x22, 0x6a, 0x00, 0x1d, 0x58,
-		0x83, 0xa8, 0xec, 0x95, 0xf1, 0xda, 0xe2, 0x73,
-		0xa0, 0xa1, 0x72, 0x60, 0x9e, 0x86, 0x53, 0xcb,
-		0x45, 0xa8, 0xc2, 0xa0, 0x50, 0xa0, 0x53, 0xd6,
-		0xfc, 0x18, 0x84, 0xb5, 0x4a, 0x26, 0xd0, 0xa2,
-		0xaa, 0xd0, 0xff, 0xb6, 0xfe, 0x3a, 0x9c, 0xb5,
-		0x19, 0x3b, 0x3f, 0xe1, 0x48, 0x0d, 0xa4, 0x09,
-		0x4f, 0x83, 0xc9, 0xc0, 0xc9, 0xa6, 0x0b, 0x58,
-		0x1f, 0x1c, 0x7b, 0xac, 0xa2, 0x42, 0xbc, 0x61,
-		0xf4, 0x21, 0x8a, 0x00, 0xda, 0x14, 0xa0, 0x60,
-		0x03, 0xfe, 0x93, 0x12, 0x6c, 0x56, 0xcd, 0x02,
-		0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09,
-		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-		0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
-		0x25, 0x29, 0x3b, 0x1e, 0xc3, 0x58, 0x32, 0xe6,
-		0x23, 0xc8, 0xee, 0x18, 0xf0, 0x1d, 0x62, 0x6d,
-		0x3b, 0x59, 0x99, 0x3a, 0xfe, 0x49, 0x72, 0x07,
-		0x3f, 0x58, 0x93, 0xdb, 0xc0, 0xaf, 0xb0, 0xb3,
-		0x5c, 0xd1, 0x5c, 0x98, 0xc8, 0xea, 0x4a, 0xe4,
-		0x58, 0x73, 0x0d, 0x57, 0xc5, 0x13, 0x7c, 0x5c,
-		0x79, 0x66, 0xda, 0x04, 0x1d, 0xe5, 0x98, 0xda,
-		0x35, 0x47, 0x44, 0xb0, 0xd2, 0x7a, 0x66, 0x9d,
-		0xcd, 0x41, 0xa5, 0x8f, 0xa1, 0x11, 0xb2, 0x1a,
-		0x87, 0xc0, 0xcd, 0x55, 0xed, 0xb4, 0x7b, 0x33,
-		0x72, 0xeb, 0xf7, 0xe3, 0x7b, 0x8b, 0x02, 0x86,
-		0xe9, 0x2b, 0x26, 0x32, 0x9f, 0x99, 0xf1, 0xcb,
-		0x93, 0xab, 0xb9, 0x16, 0xb3, 0x9a, 0xb2, 0x22,
-		0x13, 0x21, 0x1f, 0x5b, 0xcc, 0xa2, 0x59, 0xbb,
-		0x69, 0xf2, 0xb8, 0x07, 0x80, 0xce, 0x0c, 0xf7,
-		0x98, 0x4c, 0x85, 0xc2, 0x96, 0x6a, 0x22, 0x05,
-		0xe9, 0xbe, 0x48, 0xb0, 0x02, 0x5b, 0x69, 0x28,
-		0x18, 0x88, 0x96, 0xe3, 0xd7, 0xc6, 0x7a, 0xd3,
-		0xe9, 0x99, 0xff, 0x9d, 0xc3, 0x61, 0x4d, 0x9a,
-		0x96, 0xf2, 0xc6, 0x33, 0x4d, 0xe5, 0x5d, 0x5a,
-		0x68, 0x64, 0x5a, 0x82, 0x35, 0x65, 0x25, 0xe3,
-		0x8c, 0x5b, 0xb0, 0xf6, 0x96, 0x56, 0xbc, 0xbf,
-		0x97, 0x76, 0x4b, 0x66, 0x44, 0x81, 0xa4, 0xc4,
-		0xa7, 0x31, 0xc5, 0xa1, 0x4f, 0xe8, 0xa4, 0xca,
-		0x20, 0xf5, 0x01, 0x5b, 0x99, 0x4f, 0x5a, 0xf4,
-		0xf0, 0x78, 0xbf, 0x71, 0x49, 0xd5, 0xf1, 0xc1,
-		0xa2, 0x18, 0xfd, 0x72, 0x5b, 0x16, 0xe8, 0x92,
-		0xc7, 0x37, 0x48, 0xaf, 0xee, 0x24, 0xfc, 0x35,
-		0x0b, 0xc2, 0xdd, 0x05, 0xc7, 0x6e, 0xa3, 0x29,
-		0xbb, 0x29, 0x7d, 0xd3, 0x2b, 0x94, 0x80, 0xc3,
-		0x40, 0x53, 0x0e, 0x03, 0x54, 0x3d, 0x7b, 0x8b,
-		0xce, 0xf9, 0xa4, 0x03, 0x27, 0x63, 0xec, 0x51,
-		0x00, 0x03, 0xe5, 0x30, 0x82, 0x03, 0xe1, 0x30,
-		0x82, 0x02, 0xc9, 0xa0, 0x03, 0x02, 0x01, 0x02,
-		0x02, 0x09, 0x00, 0xcc, 0x22, 0x4c, 0x4b, 0x98,
-		0xa2, 0x88, 0xfc, 0x30, 0x0d, 0x06, 0x09, 0x2a,
-		0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
-		0x05, 0x00, 0x30, 0x81, 0x86, 0x31, 0x0b, 0x30,
-		0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
-		0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
-		0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59, 0x31,
-		0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07,
-		0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b, 0x6c,
-		0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
-		0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d, 0x79, 0x20,
-		0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
-		0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68,
-		0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30,
-		0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08,
-		0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f, 0x72, 0x67,
-		0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86,
-		0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
-		0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68, 0x69,
-		0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e,
-		0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31,
-		0x33, 0x30, 0x35, 0x32, 0x36, 0x32, 0x31, 0x30,
-		0x35, 0x30, 0x31, 0x5a, 0x17, 0x0d, 0x32, 0x33,
-		0x30, 0x35, 0x32, 0x34, 0x32, 0x31, 0x30, 0x35,
-		0x30, 0x31, 0x5a, 0x30, 0x81, 0x86, 0x31, 0x0b,
-		0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
-		0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06,
-		0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x4e, 0x59,
-		0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
-		0x07, 0x0c, 0x08, 0x42, 0x72, 0x6f, 0x6f, 0x6b,
-		0x6c, 0x79, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06,
-		0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x4d, 0x79,
-		0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
-		0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74,
-		0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11,
-		0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
-		0x08, 0x6d, 0x79, 0x63, 0x61, 0x2e, 0x6f, 0x72,
-		0x67, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a,
-		0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01,
-		0x16, 0x12, 0x6a, 0x76, 0x73, 0x68, 0x61, 0x68,
-		0x69, 0x64, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
-		0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22,
-		0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
-		0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
-		0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
-		0x02, 0x82, 0x01, 0x01, 0x00, 0xf0, 0xfb, 0xad,
-		0x80, 0x5e, 0x37, 0xd3, 0x6d, 0xee, 0x2e, 0xcc,
-		0xbc, 0x0c, 0xd7, 0x56, 0x4b, 0x56, 0x45, 0xcd,
-		0x28, 0xb6, 0x22, 0xe9, 0xe2, 0x0f, 0xd1, 0x87,
-		0x2a, 0x27, 0xce, 0x77, 0x8d, 0x6e, 0x0e, 0x0f,
-		0xfb, 0x66, 0xe1, 0xb5, 0x0e, 0x9a, 0xb6, 0x05,
-		0x8e, 0xb3, 0xe1, 0xc5, 0x77, 0x86, 0x5b, 0x46,
-		0xd2, 0x0b, 0x92, 0x03, 0x1b, 0x89, 0x0c, 0x1b,
-		0x10, 0x0e, 0x99, 0x8f, 0xe2, 0x17, 0xe8, 0xc2,
-		0x30, 0x00, 0x47, 0xd6, 0xfc, 0xf9, 0x0f, 0x3b,
-		0x75, 0x34, 0x8d, 0x4d, 0xb0, 0x99, 0xb7, 0xa0,
-		0x6d, 0xa0, 0xb6, 0xad, 0xda, 0x07, 0x5e, 0x38,
-		0x2e, 0x02, 0xe4, 0x30, 0x6d, 0xae, 0x13, 0x72,
-		0xd4, 0xc8, 0xce, 0x14, 0x07, 0xae, 0x23, 0x8c,
-		0x8f, 0x9e, 0x8c, 0x60, 0xd6, 0x06, 0xb9, 0xef,
-		0x00, 0x18, 0xc0, 0x1d, 0x25, 0x1e, 0xda, 0x3e,
-		0x2f, 0xcf, 0x2b, 0x56, 0x84, 0x9e, 0x30, 0x21,
-		0xc7, 0x29, 0xf6, 0x03, 0x8a, 0x24, 0xf9, 0x34,
-		0xac, 0x65, 0x9d, 0x80, 0x36, 0xc8, 0x3b, 0x15,
-		0x10, 0xbd, 0x51, 0xe9, 0xbc, 0x02, 0xe1, 0xe9,
-		0xb3, 0x5a, 0x9a, 0x99, 0x41, 0x1b, 0x27, 0xa0,
-		0x4d, 0x50, 0x9e, 0x27, 0x7f, 0xa1, 0x7d, 0x09,
-		0x87, 0xbd, 0x8a, 0xca, 0x5f, 0xb1, 0xa5, 0x08,
-		0xb8, 0x04, 0xd4, 0x52, 0x89, 0xaa, 0xe0, 0x7d,
-		0x42, 0x2e, 0x2f, 0x15, 0xee, 0x66, 0x57, 0x0f,
-		0x13, 0x19, 0x45, 0xa8, 0x4b, 0x5d, 0x81, 0x66,
-		0xcc, 0x12, 0x37, 0x94, 0x5e, 0xfd, 0x3c, 0x10,
-		0x81, 0x51, 0x3f, 0xfa, 0x0f, 0xdd, 0xa1, 0x89,
-		0x03, 0xa9, 0x78, 0x91, 0xf5, 0x3b, 0xf3, 0xbc,
-		0xac, 0xbe, 0x93, 0x30, 0x2e, 0xbe, 0xca, 0x7f,
-		0x46, 0xd3, 0x28, 0xb4, 0x4e, 0x91, 0x7b, 0x5b,
-		0x43, 0x6c, 0xaf, 0x9b, 0x5c, 0x6a, 0x6d, 0x5a,
-		0xdb, 0x79, 0x5e, 0x6a, 0x6b, 0x02, 0x03, 0x01,
-		0x00, 0x01, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x1d,
-		0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
-		0x14, 0x6b, 0x1e, 0x00, 0xa8, 0x9f, 0xfa, 0x7d,
-		0x00, 0xf9, 0xe0, 0x9d, 0x0f, 0x90, 0x8c, 0x90,
-		0xa8, 0xa1, 0x37, 0x6b, 0xda, 0x30, 0x1f, 0x06,
-		0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
-		0x80, 0x14, 0x6b, 0x1e, 0x00, 0xa8, 0x9f, 0xfa,
-		0x7d, 0x00, 0xf9, 0xe0, 0x9d, 0x0f, 0x90, 0x8c,
-		0x90, 0xa8, 0xa1, 0x37, 0x6b, 0xda, 0x30, 0x0c,
-		0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30,
-		0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09,
-		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-		0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
-		0xcd, 0x6f, 0x73, 0x4d, 0x56, 0x0b, 0xf3, 0x2e,
-		0x1c, 0xe2, 0x02, 0x0c, 0x14, 0xbb, 0x2f, 0xdd,
-		0x3c, 0x43, 0xfe, 0xdf, 0x94, 0x2d, 0xa9, 0x89,
-		0x81, 0x51, 0xf8, 0x5f, 0xa7, 0xa0, 0x13, 0xaa,
-		0xcc, 0xb0, 0x18, 0xe2, 0x57, 0x3e, 0x0d, 0x29,
-		0x93, 0xe8, 0x95, 0xd5, 0x1b, 0x53, 0xd2, 0x51,
-		0xf2, 0xbd, 0xf5, 0x9e, 0x7b, 0x22, 0x65, 0x62,
-		0x5c, 0xc4, 0x4c, 0x1d, 0xe8, 0xe9, 0xc3, 0xd4,
-		0x2b, 0xe7, 0x78, 0xcb, 0x10, 0xf3, 0xfe, 0x06,
-		0x83, 0xdc, 0x3a, 0x1e, 0x62, 0x10, 0xc0, 0x46,
-		0x77, 0xc6, 0x9d, 0x9f, 0xab, 0x96, 0x25, 0x5c,
-		0xfb, 0x26, 0xc1, 0x15, 0x1f, 0xa5, 0x33, 0xee,
-		0x4f, 0x9a, 0x14, 0x6a, 0x14, 0x97, 0x93, 0x2b,
-		0x95, 0x0b, 0xdc, 0xa8, 0xd7, 0x69, 0x2e, 0xf0,
-		0x01, 0x0e, 0xfd, 0x4e, 0xd0, 0xd9, 0xa8, 0xe5,
-		0x65, 0xde, 0xfb, 0xca, 0xca, 0x1c, 0x5f, 0xf9,
-		0x53, 0xa0, 0x87, 0xe7, 0x33, 0x9b, 0x2f, 0xcf,
-		0xe4, 0x13, 0xfc, 0xec, 0x7a, 0x6c, 0xb0, 0x90,
-		0x13, 0x9b, 0xb6, 0xc5, 0x03, 0xf6, 0x0e, 0x5e,
-		0xe2, 0xe4, 0x26, 0xc1, 0x7e, 0x53, 0xfe, 0x69,
-		0xa3, 0xc7, 0xd8, 0x8e, 0x6e, 0x94, 0x32, 0xa0,
-		0xde, 0xca, 0xb6, 0xcc, 0xd6, 0x01, 0xd5, 0x78,
-		0x40, 0x28, 0x63, 0x9b, 0xee, 0xcf, 0x09, 0x3b,
-		0x35, 0x04, 0xf0, 0x14, 0x02, 0xf6, 0x80, 0x0e,
-		0x90, 0xb2, 0x94, 0xd2, 0x25, 0x16, 0xb8, 0x7a,
-		0x76, 0x87, 0x84, 0x9f, 0x84, 0xc5, 0xaf, 0xc2,
-		0x6d, 0x68, 0x7a, 0x84, 0x9c, 0xc6, 0x8a, 0x63,
-		0x60, 0x87, 0x6a, 0x25, 0xc1, 0xa1, 0x78, 0x0f,
-		0xba, 0xe8, 0x5f, 0xe1, 0xba, 0xac, 0xa4, 0x6f,
-		0xdd, 0x09, 0x3f, 0x12, 0xcb, 0x1d, 0xf3, 0xcf,
-		0x48, 0xd7, 0xd3, 0x26, 0xe8, 0x9c, 0xc3, 0x53,
-		0xb3, 0xba, 0xdc, 0x32, 0x99, 0x98, 0x96, 0xd6,
-		0x16, 0x03, 0x03, 0x00, 0x46, 0x10, 0x00, 0x00,
-		0x42, 0x41, 0x04, 0x1e, 0x18, 0x37, 0xef, 0x0d,
-		0x19, 0x51, 0x88, 0x35, 0x75, 0x71, 0xb5, 0xe5,
-		0x54, 0x5b, 0x12, 0x2e, 0x8f, 0x09, 0x67, 0xfd,
-		0xa7, 0x24, 0x20, 0x3e, 0xb2, 0x56, 0x1c, 0xce,
-		0x97, 0x28, 0x5e, 0xf8, 0x2b, 0x2d, 0x4f, 0x9e,
-		0xf1, 0x07, 0x9f, 0x6c, 0x4b, 0x5b, 0x83, 0x56,
-		0xe2, 0x32, 0x42, 0xe9, 0x58, 0xb6, 0xd7, 0x49,
-		0xa6, 0xb5, 0x68, 0x1a, 0x41, 0x03, 0x56, 0x6b,
-		0xdc, 0x5a, 0x89, 0x16, 0x03, 0x03, 0x01, 0x08,
-		0x0f, 0x00, 0x01, 0x04, 0x04, 0x01, 0x01, 0x00,
-		0x7e, 0xe4, 0x65, 0x02, 0x8e, 0xb3, 0x34, 0x6a,
-		0x47, 0x71, 0xd1, 0xb0, 0x8d, 0x3c, 0x0c, 0xe1,
-		0xde, 0x7e, 0x5f, 0xb4, 0x15, 0x2d, 0x32, 0x0a,
-		0x2a, 0xdb, 0x9b, 0x40, 0xba, 0xce, 0x8b, 0xf5,
-		0x74, 0xc1, 0x68, 0x20, 0x7c, 0x87, 0x23, 0x13,
-		0xc3, 0x13, 0xa7, 0xdb, 0xec, 0x59, 0xa0, 0x40,
-		0x9e, 0x64, 0x03, 0x60, 0xac, 0x76, 0xff, 0x01,
-		0x34, 0x7b, 0x32, 0x26, 0xd9, 0x41, 0x31, 0x93,
-		0xaa, 0x30, 0x51, 0x83, 0x85, 0x40, 0xeb, 0x4e,
-		0x66, 0x39, 0x83, 0xb1, 0x30, 0x0d, 0x96, 0x01,
-		0xee, 0x81, 0x53, 0x5e, 0xec, 0xa9, 0xc9, 0xdf,
-		0x7e, 0xc1, 0x09, 0x47, 0x8b, 0x35, 0xdb, 0x10,
-		0x15, 0xd4, 0xc7, 0x5a, 0x39, 0xe3, 0xc0, 0xf3,
-		0x93, 0x38, 0x11, 0xdc, 0x71, 0xbb, 0xc7, 0x62,
-		0x2b, 0x85, 0xad, 0x6b, 0x4f, 0x09, 0xb3, 0x31,
-		0xa8, 0xe5, 0xd1, 0xb3, 0xa9, 0x21, 0x37, 0x50,
-		0xc8, 0x7d, 0xc3, 0xd2, 0xf7, 0x00, 0xd3, 0xdb,
-		0x0f, 0x82, 0xf2, 0x43, 0xcf, 0x36, 0x6c, 0x98,
-		0x63, 0xd8, 0x1d, 0xb3, 0xf3, 0xde, 0x63, 0x79,
-		0x64, 0xf0, 0xdb, 0x46, 0x04, 0xe1, 0x1c, 0x57,
-		0x0f, 0x9e, 0x96, 0xb9, 0x93, 0x45, 0x71, 0x1c,
-		0x8b, 0x65, 0x7d, 0x1e, 0xad, 0xbd, 0x03, 0x51,
-		0xae, 0x44, 0xef, 0x97, 0x45, 0x0d, 0x8d, 0x41,
-		0x5c, 0x80, 0x7b, 0xe6, 0xe0, 0xbc, 0xa6, 0x72,
-		0x95, 0xa0, 0x97, 0xe1, 0xbb, 0xc0, 0xcc, 0xe5,
-		0x1e, 0xc3, 0xbe, 0xd7, 0x42, 0x2a, 0xf3, 0x75,
-		0x8a, 0x44, 0x67, 0x3c, 0xe5, 0x68, 0x78, 0xe5,
-		0x40, 0x1f, 0xf0, 0x89, 0x57, 0xda, 0xee, 0x45,
-		0xf4, 0x44, 0x81, 0x01, 0x77, 0xf0, 0x4a, 0x14,
-		0xb1, 0x3f, 0x60, 0x2b, 0xeb, 0x42, 0x38, 0xa6,
-		0xfb, 0xe5, 0x4d, 0x71, 0xdc, 0x7d, 0x0a, 0x72,
-		0x56, 0x28, 0x9d, 0xa6, 0x8e, 0x74, 0x2d, 0xbd,
-		0x14, 0x03, 0x03, 0x00, 0x01, 0x01, 0x16, 0x03,
-		0x03, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x31, 0x4d, 0x58, 0x94, 0x0b,
-		0x0b, 0x06, 0x5f, 0xae, 0x57, 0x17, 0x98, 0x86,
-		0xaa, 0x49, 0x17, 0x7f, 0xbd, 0x41, 0x05, 0xa5,
-		0x74, 0x1c, 0x58, 0xc8, 0x38, 0x2d, 0x99, 0x5d,
-		0xe5, 0x12, 0x43,
-	},
-	{
-		0x14, 0x03, 0x03, 0x00, 0x01, 0x01, 0x16, 0x03,
-		0x03, 0x00, 0x28, 0xf2, 0x60, 0xc2, 0x75, 0x27,
-		0x64, 0xf4, 0x05, 0x98, 0xc9, 0xd3, 0xa8, 0x00,
-		0x4c, 0xa0, 0x49, 0x82, 0x68, 0xf1, 0x21, 0x05,
-		0x7b, 0x4b, 0x25, 0x3e, 0xe1, 0x5f, 0x0f, 0x84,
-		0x26, 0x2d, 0x16, 0x2e, 0xc0, 0xfd, 0xdf, 0x0a,
-		0xf4, 0xba, 0x19,
-	},
-	{
-		0x17, 0x03, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x01, 0x35, 0xef, 0x9d,
-		0x6a, 0x86, 0x98, 0xc5, 0xca, 0x55, 0xca, 0x89,
-		0x29, 0xb4, 0x55, 0xd4, 0x41, 0x08, 0x96, 0xe0,
-		0xf3, 0x39, 0xfc, 0x15, 0x03, 0x03, 0x00, 0x1a,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
-		0x02, 0x63, 0x1b, 0xaa, 0xc6, 0xc9, 0x6d, 0x72,
-		0x24, 0x10, 0x55, 0xa9, 0x8c, 0x3b, 0x23, 0xce,
-		0xd8, 0x4a,
-	},
+func TestHandshakeClientCertECDSA(t *testing.T) {
+	config := *testConfig
+	cert, _ := X509KeyPair([]byte(clientECDSACertificatePEM), []byte(clientECDSAKeyPEM))
+	config.Certificates = []Certificate{cert}
+
+	test := &clientTest{
+		name:    "ClientCert-ECDSA-RSA",
+		command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"},
+		config:  &config,
+	}
+
+	runClientTestTLS10(t, test)
+	runClientTestTLS12(t, test)
+
+	test = &clientTest{
+		name:    "ClientCert-ECDSA-ECDSA",
+		command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA", "-verify", "1"},
+		config:  &config,
+		cert:    testECDSACertificate,
+		key:     testECDSAPrivateKey,
+	}
+
+	runClientTestTLS10(t, test)
+	runClientTestTLS12(t, test)
 }
 
-var testClientChainCertificate = fromHex(
-	"2d2d2d2d2d424547494e2050524956415445204b" +
-		"45592d2d2d2d2d0a4d494945766749424144414e" +
-		"42676b71686b6947397730424151454641415343" +
-		"424b67776767536b41674541416f494241514367" +
-		"6f2b2f4252483269343347590a4a324f7a485846" +
-		"51706a515679386b71772b726b6e70784a706747" +
-		"6266716d31657638566b6e48496c35776c74336b" +
-		"722f367647736163416b4c4b4c313348560a776a" +
-		"726d676b493369554545734c7248573470446e35" +
-		"633544412f56625a364e3638416d78526a6f656a" +
-		"30794c6a6951514673354c41664c4a4244467954" +
-		"766a0a5a6b64587557717452506a51634749376a" +
-		"75316758794c3475417a4a5153764a6747354f47" +
-		"2b45672f45656b724d4d2f35734b4265514d334a" +
-		"596e4b317156470a6b574e427854375637583950" +
-		"6a5162416951432b4e33742b6338707741425130" +
-		"766b6538736d6f6f70536d45714a3349486e646d" +
-		"48352b714b306662335775630a715079434e7052" +
-		"694456772f7367473070626a4744705262374636" +
-		"37656d4d6b38666e5755416a426f387951423173" +
-		"4542454a307a7a6636384b585a3034614a0a6952" +
-		"6a7a544f495241674d424141454367674542414a" +
-		"4b613676326b5a3144596146786e586d7369624c" +
-		"386734426f67514c6a42307362524a6d746b6b4d" +
-		"54370a685343325873537551522f446c654d7148" +
-		"664555786731784a717579597643544d44585972" +
-		"473667354a5051744d4432465a424a7239626c65" +
-		"467138386c706a0a543766514e793571354c2b4f" +
-		"682f6b62433835436e623641753641656978776d" +
-		"2b6e77665a4f3766726b6278306d35516b715975" +
-		"5739392f452b69502b454e570a76396a68773436" +
-		"76515065563236494b79717656462b4f7362722f" +
-		"6152316138707948336361566e3579594a433346" +
-		"5855756c6f5a77516331714a6b4c434c4c0a375a" +
-		"49744f525a78514c486d4d4a654d44722f5a4942" +
-		"34675467645650636145375a4d5141714d6d3066" +
-		"4c6b6d7671723149526b77642f6831455a645650" +
-		"79320a742f6b6b43413039566336663749556575" +
-		"6f67706d705a50303130564e376b6277394a6348" +
-		"75544561564543675945417a47395679426e6d62" +
-		"6858496c57764f0a71583747524f2f5231636a2b" +
-		"6b564e35377876674b54756b35592b7a4d774a48" +
-		"32626c57435945513251753974446c476854756b" +
-		"664273385746772b6e6263460a7a6f706d535245" +
-		"6c6d464d2f6141536d464733574e5a7072696a68" +
-		"504b77726338376470636b31703131635a415478" +
-		"5a413168566d43743457616343673634690a4d74" +
-		"64507a334e2f34416147664956794d2b69624949" +
-		"35332f515543675945417953693556735a356f6a" +
-		"644a795077426e6c6142554231686f2b336b7068" +
-		"70770a7264572b2b4d796b51494a345564534437" +
-		"3052486e5a315839754359713978616671746c51" +
-		"664c44395963442f436d665264706461586c5673" +
-		"5249467a5a556c0a454630557149644e77337046" +
-		"68634f4a6d6e5a3241434470434342476f763542" +
-		"6e3068302b3137686a4b376f69315833716e4542" +
-		"7857326c7462593476556a500a44394c5330666e" +
-		"4a76703043675942504a527330714c4a4a464333" +
-		"6669796b712f57574d38727474354b364a584b50" +
-		"734b674b53644144577a7463316645434d0a7a65" +
-		"2b394a6a5a376b4d77557063666a644c2b745047" +
-		"3455563048326c524375635735414131396d7058" +
-		"50367454494733713737655a6b416e65516f6163" +
-		"41340a716c3073583051476c6a5763414e30464b" +
-		"6f4759733975582b6378445a6e7265362f52392f" +
-		"3930567766443237454c57546373677734633463" +
-		"514b42675143420a6f5432326e745a5a59396d6e" +
-		"72455a36752f492f4a332f35664e396737783733" +
-		"3177746e463745745a5361575453587364597256" +
-		"466b564f6362505135494a6f0a714a6a7249372b" +
-		"474a4d69376f6a4c69642f4c45656f31764f3163" +
-		"454158334f43723236554e38612f6c7434394f5a" +
-		"69354c337348556b756c475951755671650a6737" +
-		"6e6e4632437749544c34503645486443575a4461" +
-		"7a4136626d7375524f2b6462536e335a6c567651" +
-		"4b42674859524c5a665458536c44755264776977" +
-		"746b0a513148546b6d6b57694156726c4f577864" +
-		"5858456d546130303045574c46446145797a7358" +
-		"7834424863357166776b5a4e746b634a56396e58" +
-		"63536e647441530a35767a427a676e797a4f7962" +
-		"68315878484a3966427472414f3847555878446c" +
-		"6634394457616753393449763072596e616b7656" +
-		"2f673039786875415763366e0a5365757230576b" +
-		"5376453847666653734d485149584c456b0a2d2d" +
-		"2d2d2d454e442050524956415445204b45592d2d" +
-		"2d2d2d0a2d2d2d2d2d424547494e204345525449" +
-		"4649434154452d2d2d2d2d0a4d494944656a4343" +
-		"416d494343514330523168584b326649776a414e" +
-		"42676b71686b6947397730424151554641444342" +
-		"6744454c4d416b474131554542684d430a56564d" +
-		"78437a414a42674e564241674d416b355a4d5245" +
-		"77447759445651514844416843636d3976613278" +
-		"35626a45564d424d47413155454367774d54586b" +
-		"670a51304567513278705a5735304d5263774651" +
-		"5944565151444441357465574e68593278705a57" +
-		"35304c6d4e76625445684d423847435371475349" +
-		"62334451454a0a41525953616e5a7a6147466f61" +
-		"5752415a32316861577775593239744d42345844" +
-		"54457a4d4455794e6a49784e4451774d466f5844" +
-		"54457a4d4459794e5449780a4e4451774d466f77" +
-		"6654454c4d416b474131554542684d4356564d78" +
-		"4554415042674e564241674d4345356c6479425a" +
-		"62334a724d52457744775944565151480a444168" +
-		"43636d397661327835626a45514d413447413155" +
-		"454367774854586b67544756685a6a45544d4245" +
-		"47413155454177774b62586c735a57466d4c6d4e" +
-		"760a625445684d42384743537147534962334451" +
-		"454a41525953616e5a7a6147466f615752415a32" +
-		"316861577775593239744d494942496a414e4267" +
-		"6b71686b69470a397730424151454641414f4341" +
-		"5138414d49494243674b43415145416f4b507677" +
-		"5552396f754e786d43646a73783178554b593046" +
-		"63764a4b735071354a36630a536159426d333670" +
-		"7458722f465a4a78794a65634a6264354b2f2b72" +
-		"7872476e414a43796939647831634936356f4a43" +
-		"4e346c42424c43367831754b51352b580a4f5177" +
-		"50315732656a6576414a73555936486f394d6934" +
-		"346b4542624f5377487979515178636b3734325a" +
-		"4856376c7172555434304842694f343774594638" +
-		"690a2b4c674d7955457279594275546876684950" +
-		"7848704b7a44502b624367586b444e79574a7974" +
-		"616c5270466a5163552b3165312f543430477749" +
-		"6b41766a64370a666e504b634141554e4c354876" +
-		"4c4a714b4b5570684b6964794235335a682b6671" +
-		"697448323931726e4b6a38676a61555967316350" +
-		"374942744b5734786736550a572b78657533706a" +
-		"4a504835316c41497761504d6b41646242415243" +
-		"644d38332b76436c32644f4769596b5938307a69" +
-		"45514944415141424d413047435371470a534962" +
-		"3344514542425155414134494241514351752f6c" +
-		"65756863667243476661307047304730386a7a33" +
-		"34586a357972364161382f2b4a72467436347045" +
-		"710a493458475455646e4151696f425230425946" +
-		"42665761332b6538594d564a426f634763753759" +
-		"6634615971734d7635766b426b715a4932435a67" +
-		"5644694f37790a4d4f326b6a372f575679445551" +
-		"7831536c6d2b75435a5942556a6a6a72356e5833" +
-		"42535a7849734f42412b7a46425455705a506879" +
-		"597142373250384e6e63460a427641714241712b" +
-		"4c73364250534f6832746a72787570657a796732" +
-		"55544756586b414537617a4279465a70682b7737" +
-		"417a36644430784d363965364a742f6a0a336844" +
-		"756b324b4e63314a752f7a63326d487374566b79" +
-		"364362696e384473576763726251367673544735" +
-		"3877517369496b4d6474677a4275632f6b552b34" +
-		"640a506f696e4537352f766135797a38316a3073" +
-		"4d59574a4b697262554a6e5a454433547a69484e" +
-		"35340a2d2d2d2d2d454e44204345525449464943" +
-		"4154452d2d2d2d2d0a2d2d2d2d2d424547494e20" +
-		"43455254494649434154452d2d2d2d2d0a4d4949" +
-		"4468444343416d7743435143723761626b536973" +
-		"722b44414e42676b71686b694739773042415155" +
-		"4641444342686a454c4d416b474131554542684d" +
-		"430a56564d78437a414a42674e564241674d416b" +
-		"355a4d524577447759445651514844416843636d" +
-		"397661327835626a45684d423847413155454367" +
-		"775954586b670a5132567964476c6d61574e6864" +
-		"4755675158563061473979615852354d52457744" +
-		"775944565151444441687465574e684c6d39795a" +
-		"7a45684d423847435371470a534962334451454a" +
-		"41525953616e5a7a6147466f615752415a323168" +
-		"61577775593239744d4234584454457a4d445579" +
-		"4e6a49784d5467304d466f584454457a0a4d4459" +
-		"794e5449784d5467304d466f7767594178437a41" +
-		"4a42674e5642415954416c56544d517377435159" +
-		"445651514944414a4f575445524d413847413155" +
-		"450a42777749516e4a7662327473655734784654" +
-		"415442674e5642416f4d4445313549454e424945" +
-		"4e7361575675644445584d425547413155454177" +
-		"774f62586c6a0a59574e73615756756443356a62" +
-		"3230784954416642676b71686b69473977304243" +
-		"514557456d70326332686861476c6b5147647459" +
-		"576c734c6d4e76625443430a415349774451594a" +
-		"4b6f5a496876634e415145424251414467674550" +
-		"4144434341516f4367674542414d345438484b77" +
-		"596367594e34704250534368484d752f0a396a74" +
-		"304a697157456578546f63783964315a46447a61" +
-		"33386b6953476d4c4d747343684c30517277596e" +
-		"4c6268376256354c566c32434d51537a5a495037" +
-		"700a4834373866774a454479694231677a4e7650" +
-		"4258624d796e75676167707048613730614b5941" +
-		"3953624a42736a455376734a3251756946596f44" +
-		"7a75564c55700a4a68384b724f3949614450514d" +
-		"39434c477578754c37564b553849613076465142" +
-		"566c6332646f44436b6533336663366166564f36" +
-		"6b7243796c5377693362680a416931535a376e64" +
-		"554d6b37427951696167416457494f6f374a5878" +
-		"32754a7a6f4b4679594a364755387446714d4b67" +
-		"554b425431767759684c564b4a7443690a717444" +
-		"2f747634366e4c555a4f7a2f685341326b43552b" +
-		"447963444a7067745948787837724b4a43764748" +
-		"3049596f41326853675941502b6b784a73567330" +
-		"430a417745414154414e42676b71686b69473977" +
-		"30424151554641414f43415145414a536b374873" +
-		"4e594d75596a794f3459384231696254745a6d54" +
-		"722b535849480a5031695432384376734c4e6330" +
-		"567959794f704b3546687a445666464533786365" +
-		"5762614242336c6d4e6f3152305377306e706d6e" +
-		"63314270592b68456249610a6838444e56653230" +
-		"657a4e79362f666a6534734368756b724a6a4b66" +
-		"6d66484c6b36753546724f617369495449523962" +
-		"7a4b4a5a75326e79754165417a677a330a6d4579" +
-		"4677705a7149675870766b6977416c74704b4269" +
-		"496c755058786e7254365a6e2f6e634e68545a71" +
-		"573873597a54655664576d686b576f49315a5358" +
-		"6a0a6a46757739705a57764c2b58646b746d5249" +
-		"476b784b637878614650364b544b495055425735" +
-		"6c5057765477654c397853645878776149592f58" +
-		"4a62467569530a787a6449722b346b2f44554c77" +
-		"7430467832366a4b62737066644d726c49444451" +
-		"464d4f413151396534764f2b6151444a32507355" +
-		"513d3d0a2d2d2d2d2d454e442043455254494649" +
-		"434154452d2d2d2d2d0a2d2d2d2d2d424547494e" +
-		"2043455254494649434154452d2d2d2d2d0a4d49" +
-		"49443454434341736d67417749424167494a414d" +
-		"7769544575596f6f6a384d413047435371475349" +
-		"623344514542425155414d4947474d5173774351" +
-		"59440a5651514745774a56557a454c4d416b4741" +
-		"31554543417743546c6b784554415042674e5642" +
-		"41634d43454a796232397262486c754d53457748" +
-		"7759445651514b0a4442684e655342445a584a30" +
-		"61575a70593246305a5342426458526f62334a70" +
-		"64486b784554415042674e5642414d4d43473135" +
-		"5932457562334a6e4d5345770a4877594a4b6f5a" +
-		"496876634e41516b4246684a71646e4e6f595768" +
-		"705a45426e625746706243356a62323077486863" +
-		"4e4d544d774e5449324d6a45774e5441780a5768" +
-		"634e4d6a4d774e5449304d6a45774e544178576a" +
-		"4342686a454c4d416b474131554542684d435656" +
-		"4d78437a414a42674e564241674d416b355a4d52" +
-		"45770a447759445651514844416843636d397661" +
-		"327835626a45684d423847413155454367775954" +
-		"586b675132567964476c6d61574e686447556751" +
-		"585630614739790a615852354d52457744775944" +
-		"565151444441687465574e684c6d39795a7a4568" +
-		"4d42384743537147534962334451454a41525953" +
-		"616e5a7a6147466f615752410a5a323168615777" +
-		"75593239744d494942496a414e42676b71686b69" +
-		"47397730424151454641414f43415138414d4949" +
-		"4243674b434151454138507574674634330a3032" +
-		"33754c737938444e645753315a467a5369324975" +
-		"6e69443947484b69664f6434317544672f375a75" +
-		"4731447071324259367a34635633686c74473067" +
-		"75530a4178754a4442735144706d503468666f77" +
-		"6a4141523962382b5138376454534e5462435a74" +
-		"3642746f4c6174326764654f4334433544427472" +
-		"684e79314d6a4f0a46416575493479506e6f7867" +
-		"31676135377741597742306c48746f2b4c383872" +
-		"566f53654d4348484b665944696954354e4b786c" +
-		"6e59413279447356454c31520a3662774334656d" +
-		"7a5770715a5152736e6f4531516e69642f6f5830" +
-		"4a6837324b796c2b7870516934424e5253696172" +
-		"67665549754c7858755a6c635045786c460a7145" +
-		"74646757624d456a65555876303845494652502f" +
-		"6f503361474a41366c346b665537383779737670" +
-		"4d774c72374b663062544b4c524f6b5874625132" +
-		"79760a6d31787162567262655635716177494441" +
-		"5141426f314177546a416442674e564851344546" +
-		"67515561783441714a2f3666514435344a30506b" +
-		"497951714b45330a61396f77487759445652306a" +
-		"42426777466f415561783441714a2f3666514435" +
-		"344a30506b497951714b453361396f7744415944" +
-		"5652305442415577417745420a2f7a414e42676b" +
-		"71686b6947397730424151554641414f43415145" +
-		"417a57397a5456594c387934633467494d464c73" +
-		"76335478442f742b554c616d4a675648340a5836" +
-		"65674536724d73426a69567a344e4b5a506f6c64" +
-		"556255394a52387233316e6e73695a574a637845" +
-		"7764364f6e443143766e654d7351382f34476739" +
-		"77360a486d495177455a33787032667135596c58" +
-		"50736d775255667054507554356f55616853586b" +
-		"7975564339796f31326b753841454f2f55375132" +
-		"616a6c5a6437370a79736f63582f6c546f49666e" +
-		"4d3573767a2b51542f4f7836624c435145357532" +
-		"78515032446c376935436242666c502b61615048" +
-		"324935756c444b67337371320a7a4e5942315868" +
-		"414b474f623773384a4f7a554538425143396f41" +
-		"4f6b4c4b55306955577548703268345366684d57" +
-		"76776d316f656f5363786f706a594964710a4a63" +
-		"476865412b3636462f687571796b6239304a5078" +
-		"4c4c48665050534e66544a75696377314f7a7574" +
-		"77796d5a695731673d3d0a2d2d2d2d2d454e4420" +
-		"43455254494649434154452d2d2d2d2d0a",
-)
+func TestClientResumption(t *testing.T) {
+	serverConfig := &Config{
+		CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
+		Certificates: testConfig.Certificates,
+	}
+	clientConfig := &Config{
+		CipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
+		InsecureSkipVerify: true,
+		ClientSessionCache: NewLRUClientSessionCache(32),
+	}
 
-// Script of interaction with openssl implementation:
-//
-//   openssl s_server -cipher ECDHE-ECDSA-AES128-SHA \
-//     -key server.key -cert server.crt -port 10443
-//
-// The values for this test are obtained by building and running in client mode:
-//   % go test -test.run "TestRunClient" -connect -ciphersuites=0xc009
-// The recorded bytes are written to stdout.
-//
-// The server private key is:
-//
-// -----BEGIN EC PARAMETERS-----
-// BgUrgQQAIw==
-// -----END EC PARAMETERS-----
-// -----BEGIN EC PRIVATE KEY-----
-// MIHcAgEBBEIBmIPpCa0Kyeo9M/nq5mHxeFIGlw+MqakWcvHu3Keo7xK9ZWG7JG3a
-// XfS01efjqSZJvF2DoL+Sly4A5iBn0Me9mdegBwYFK4EEACOhgYkDgYYABADEoe2+
-// mPkLSHM2fsMWVhEi8j1TwztNIT3Na3Xm9rDcmt8mwbyyh/ByMnyzZC8ckLzqaCMQ
-// fv7jJcBIOmngKG3TNwDvBGLdDaCccGKD2IHTZDGqnpcxvZawaMCbI952ZD8aXH/p
-// Eg5YWLZfcN2b2OrV1/XVzLm2nzBmW2aaIOIn5b/+Ow==
-// -----END EC PRIVATE KEY-----
-//
-// and certificate is:
-//
-// -----BEGIN CERTIFICATE-----
-// MIICADCCAWICCQC4vy1HoNLr9DAJBgcqhkjOPQQBMEUxCzAJBgNVBAYTAkFVMRMw
-// EQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0
-// eSBMdGQwHhcNMTIxMTIyMTUwNjMyWhcNMjIxMTIwMTUwNjMyWjBFMQswCQYDVQQG
-// EwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lk
-// Z2l0cyBQdHkgTHRkMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAxKHtvpj5C0hz
-// Nn7DFlYRIvI9U8M7TSE9zWt15vaw3JrfJsG8sofwcjJ8s2QvHJC86mgjEH7+4yXA
-// SDpp4Cht0zcA7wRi3Q2gnHBig9iB02Qxqp6XMb2WsGjAmyPedmQ/Glx/6RIOWFi2
-// X3Ddm9jq1df11cy5tp8wZltmmiDiJ+W//jswCQYHKoZIzj0EAQOBjAAwgYgCQgGI
-// ok/r4kXFSH0brPXtmJ2uR3DAXhu2L73xtk23YUDTEaLO7gt+kn7/dp3DO36lP876
-// EOJZ7EctfKzaTpcOFaBv0AJCAU38vmcTnC0FDr0/o4wlwTMTgw2UBrvUN3r27HrJ
-// hi7d1xFpf4V8Vt77MXgr5Md4Da7Lvp5ONiQxe2oPOZUSB48q
-// -----END CERTIFICATE-----
-var ecdheECDSAAESClientScript = [][]byte{
-	{
-		0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
-		0x46, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x09,
-		0x01, 0x00, 0x00, 0x1b, 0x00, 0x05, 0x00, 0x05,
-		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
-		0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
-		0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x54, 0x02, 0x00, 0x00,
-		0x50, 0x03, 0x01, 0x50, 0xd7, 0x19, 0xc9, 0x03,
-		0xc2, 0x3a, 0xc6, 0x1f, 0x0a, 0x84, 0x9e, 0xd7,
-		0xf4, 0x7e, 0x07, 0x6d, 0xa8, 0xe4, 0xa9, 0x4f,
-		0x22, 0x50, 0xa2, 0x19, 0x24, 0x44, 0x42, 0x65,
-		0xaa, 0xba, 0x3a, 0x20, 0x90, 0x70, 0xb7, 0xe5,
-		0x57, 0xed, 0xb1, 0xb1, 0x43, 0x4b, 0xa1, 0x4e,
-		0xee, 0x7a, 0x5b, 0x88, 0xf6, 0xa6, 0x73, 0x3b,
-		0xcb, 0xa7, 0xbd, 0x57, 0x50, 0xf2, 0x72, 0x8c,
-		0xbc, 0x45, 0x73, 0xaa, 0xc0, 0x09, 0x00, 0x00,
-		0x08, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01,
-		0x02, 0x16, 0x03, 0x01, 0x02, 0x0e, 0x0b, 0x00,
-		0x02, 0x0a, 0x00, 0x02, 0x07, 0x00, 0x02, 0x04,
-		0x30, 0x82, 0x02, 0x00, 0x30, 0x82, 0x01, 0x62,
-		0x02, 0x09, 0x00, 0xb8, 0xbf, 0x2d, 0x47, 0xa0,
-		0xd2, 0xeb, 0xf4, 0x30, 0x09, 0x06, 0x07, 0x2a,
-		0x86, 0x48, 0xce, 0x3d, 0x04, 0x01, 0x30, 0x45,
-		0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
-		0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30,
-		0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
-		0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
-		0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
-		0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74,
-		0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69,
-		0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74,
-		0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17,
-		0x0d, 0x31, 0x32, 0x31, 0x31, 0x32, 0x32, 0x31,
-		0x35, 0x30, 0x36, 0x33, 0x32, 0x5a, 0x17, 0x0d,
-		0x32, 0x32, 0x31, 0x31, 0x32, 0x30, 0x31, 0x35,
-		0x30, 0x36, 0x33, 0x32, 0x5a, 0x30, 0x45, 0x31,
-		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
-		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
-		0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
-		0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
-		0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
-		0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
-		0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
-		0x20, 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9b, 0x30,
-		0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d,
-		0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00,
-		0x23, 0x03, 0x81, 0x86, 0x00, 0x04, 0x00, 0xc4,
-		0xa1, 0xed, 0xbe, 0x98, 0xf9, 0x0b, 0x48, 0x73,
-		0x36, 0x7e, 0xc3, 0x16, 0x56, 0x11, 0x22, 0xf2,
-		0x3d, 0x53, 0xc3, 0x3b, 0x4d, 0x21, 0x3d, 0xcd,
-		0x6b, 0x75, 0xe6, 0xf6, 0xb0, 0xdc, 0x9a, 0xdf,
-		0x26, 0xc1, 0xbc, 0xb2, 0x87, 0xf0, 0x72, 0x32,
-		0x7c, 0xb3, 0x64, 0x2f, 0x1c, 0x90, 0xbc, 0xea,
-		0x68, 0x23, 0x10, 0x7e, 0xfe, 0xe3, 0x25, 0xc0,
-		0x48, 0x3a, 0x69, 0xe0, 0x28, 0x6d, 0xd3, 0x37,
-		0x00, 0xef, 0x04, 0x62, 0xdd, 0x0d, 0xa0, 0x9c,
-		0x70, 0x62, 0x83, 0xd8, 0x81, 0xd3, 0x64, 0x31,
-		0xaa, 0x9e, 0x97, 0x31, 0xbd, 0x96, 0xb0, 0x68,
-		0xc0, 0x9b, 0x23, 0xde, 0x76, 0x64, 0x3f, 0x1a,
-		0x5c, 0x7f, 0xe9, 0x12, 0x0e, 0x58, 0x58, 0xb6,
-		0x5f, 0x70, 0xdd, 0x9b, 0xd8, 0xea, 0xd5, 0xd7,
-		0xf5, 0xd5, 0xcc, 0xb9, 0xb6, 0x9f, 0x30, 0x66,
-		0x5b, 0x66, 0x9a, 0x20, 0xe2, 0x27, 0xe5, 0xbf,
-		0xfe, 0x3b, 0x30, 0x09, 0x06, 0x07, 0x2a, 0x86,
-		0x48, 0xce, 0x3d, 0x04, 0x01, 0x03, 0x81, 0x8c,
-		0x00, 0x30, 0x81, 0x88, 0x02, 0x42, 0x01, 0x88,
-		0xa2, 0x4f, 0xeb, 0xe2, 0x45, 0xc5, 0x48, 0x7d,
-		0x1b, 0xac, 0xf5, 0xed, 0x98, 0x9d, 0xae, 0x47,
-		0x70, 0xc0, 0x5e, 0x1b, 0xb6, 0x2f, 0xbd, 0xf1,
-		0xb6, 0x4d, 0xb7, 0x61, 0x40, 0xd3, 0x11, 0xa2,
-		0xce, 0xee, 0x0b, 0x7e, 0x92, 0x7e, 0xff, 0x76,
-		0x9d, 0xc3, 0x3b, 0x7e, 0xa5, 0x3f, 0xce, 0xfa,
-		0x10, 0xe2, 0x59, 0xec, 0x47, 0x2d, 0x7c, 0xac,
-		0xda, 0x4e, 0x97, 0x0e, 0x15, 0xa0, 0x6f, 0xd0,
-		0x02, 0x42, 0x01, 0x4d, 0xfc, 0xbe, 0x67, 0x13,
-		0x9c, 0x2d, 0x05, 0x0e, 0xbd, 0x3f, 0xa3, 0x8c,
-		0x25, 0xc1, 0x33, 0x13, 0x83, 0x0d, 0x94, 0x06,
-		0xbb, 0xd4, 0x37, 0x7a, 0xf6, 0xec, 0x7a, 0xc9,
-		0x86, 0x2e, 0xdd, 0xd7, 0x11, 0x69, 0x7f, 0x85,
-		0x7c, 0x56, 0xde, 0xfb, 0x31, 0x78, 0x2b, 0xe4,
-		0xc7, 0x78, 0x0d, 0xae, 0xcb, 0xbe, 0x9e, 0x4e,
-		0x36, 0x24, 0x31, 0x7b, 0x6a, 0x0f, 0x39, 0x95,
-		0x12, 0x07, 0x8f, 0x2a, 0x16, 0x03, 0x01, 0x00,
-		0xd6, 0x0c, 0x00, 0x00, 0xd2, 0x03, 0x00, 0x17,
-		0x41, 0x04, 0x33, 0xed, 0xe1, 0x10, 0x3d, 0xe2,
-		0xb0, 0x81, 0x5e, 0x01, 0x1b, 0x00, 0x4a, 0x7d,
-		0xdc, 0xc5, 0x78, 0x02, 0xb1, 0x9a, 0x78, 0x92,
-		0x34, 0xd9, 0x23, 0xcc, 0x01, 0xfb, 0x0c, 0x49,
-		0x1c, 0x4a, 0x59, 0x8a, 0x80, 0x1b, 0x34, 0xf0,
-		0xe8, 0x87, 0x1b, 0x7c, 0xfb, 0x72, 0xf5, 0xea,
-		0xf9, 0xf3, 0xff, 0xa6, 0x3e, 0x4e, 0xac, 0xbc,
-		0xee, 0x14, 0x2b, 0x87, 0xd4, 0x0b, 0xda, 0x19,
-		0x60, 0x2b, 0x00, 0x8b, 0x30, 0x81, 0x88, 0x02,
-		0x42, 0x01, 0x75, 0x46, 0x4f, 0x97, 0x9f, 0xc5,
-		0xf9, 0x4c, 0x38, 0xcf, 0x3b, 0x37, 0x1a, 0x6b,
-		0x53, 0xfc, 0x05, 0x73, 0x7d, 0x98, 0x2c, 0x5b,
-		0x76, 0xd4, 0x37, 0x1f, 0x50, 0x6d, 0xad, 0xc6,
-		0x0f, 0x8f, 0x7b, 0xcc, 0x60, 0x8e, 0x04, 0x00,
-		0x21, 0x80, 0xa8, 0xa5, 0x98, 0xf2, 0x42, 0xf2,
-		0xc3, 0xf6, 0x44, 0x50, 0xc4, 0x7a, 0xae, 0x6f,
-		0x74, 0xa0, 0x7f, 0x07, 0x7a, 0x0b, 0xbb, 0x41,
-		0x9e, 0x3c, 0x0b, 0x02, 0x42, 0x01, 0xbe, 0x64,
-		0xaa, 0x12, 0x03, 0xfb, 0xd8, 0x4f, 0x93, 0xf9,
-		0x92, 0x54, 0x0d, 0x9c, 0x9d, 0x53, 0x88, 0x19,
-		0x69, 0x94, 0xfc, 0xd6, 0xf7, 0x60, 0xcf, 0x70,
-		0x64, 0x15, 0x1b, 0x02, 0x22, 0x56, 0xb0, 0x2c,
-		0xb1, 0x72, 0x4c, 0x9e, 0x7b, 0xf0, 0x53, 0x97,
-		0x43, 0xac, 0x11, 0x62, 0xe5, 0x5a, 0xf1, 0x7e,
-		0x87, 0x8f, 0x5c, 0x43, 0x1d, 0xae, 0x56, 0x28,
-		0xdb, 0x76, 0x15, 0xd8, 0x1c, 0x73, 0xce, 0x16,
-		0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x46, 0x10, 0x00, 0x00,
-		0x42, 0x41, 0x04, 0x1e, 0x18, 0x37, 0xef, 0x0d,
-		0x19, 0x51, 0x88, 0x35, 0x75, 0x71, 0xb5, 0xe5,
-		0x54, 0x5b, 0x12, 0x2e, 0x8f, 0x09, 0x67, 0xfd,
-		0xa7, 0x24, 0x20, 0x3e, 0xb2, 0x56, 0x1c, 0xce,
-		0x97, 0x28, 0x5e, 0xf8, 0x2b, 0x2d, 0x4f, 0x9e,
-		0xf1, 0x07, 0x9f, 0x6c, 0x4b, 0x5b, 0x83, 0x56,
-		0xe2, 0x32, 0x42, 0xe9, 0x58, 0xb6, 0xd7, 0x49,
-		0xa6, 0xb5, 0x68, 0x1a, 0x41, 0x03, 0x56, 0x6b,
-		0xdc, 0x5a, 0x89, 0x14, 0x03, 0x01, 0x00, 0x01,
-		0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0x1a, 0x45,
-		0x92, 0x3b, 0xac, 0x8d, 0x91, 0x89, 0xd3, 0x2c,
-		0xf4, 0x3c, 0x5f, 0x70, 0xf1, 0x79, 0xa5, 0x6a,
-		0xcf, 0x97, 0x8f, 0x3f, 0x73, 0x08, 0xca, 0x3f,
-		0x55, 0xb0, 0x28, 0xd1, 0x6f, 0xcd, 0x9b, 0xca,
-		0xb6, 0xb7, 0xd0, 0xa5, 0x21, 0x5b, 0x08, 0xf8,
-		0x42, 0xe2, 0xdf, 0x25, 0x6a, 0x16,
-	},
-	{
-		0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
-		0x01, 0x00, 0x30, 0x30, 0x83, 0xb6, 0x51, 0x8a,
-		0x85, 0x4a, 0xee, 0xe4, 0xb6, 0xae, 0xf3, 0xc1,
-		0xdc, 0xd2, 0x04, 0xb3, 0xd0, 0x25, 0x47, 0x5f,
-		0xac, 0x83, 0xa3, 0x7d, 0xcf, 0x47, 0x92, 0xed,
-		0x92, 0x6c, 0xd1, 0x6e, 0xfd, 0x63, 0xf5, 0x2d,
-		0x89, 0xd8, 0x04, 0x8c, 0x62, 0x71, 0xae, 0x5e,
-		0x32, 0x48, 0xf8,
-	},
-	{
-		0x17, 0x03, 0x01, 0x00, 0x20, 0xcf, 0x5e, 0xba,
-		0xf4, 0x47, 0x32, 0x35, 0x9b, 0x85, 0xdc, 0xb3,
-		0xff, 0x77, 0x90, 0xd9, 0x2b, 0xbd, 0x59, 0x2a,
-		0x33, 0xe4, 0x6e, 0x9b, 0xfc, 0x1c, 0x73, 0x3f,
-		0x5e, 0x1e, 0xe3, 0xa4, 0xc2, 0x17, 0x03, 0x01,
-		0x00, 0x20, 0x05, 0xdf, 0x2d, 0x9b, 0x29, 0x7f,
-		0x97, 0xcd, 0x49, 0x04, 0x53, 0x22, 0x1a, 0xa1,
-		0xa1, 0xe6, 0x38, 0x3a, 0x56, 0x37, 0x1f, 0xd8,
-		0x3a, 0x12, 0x2c, 0xf0, 0xeb, 0x61, 0x35, 0x76,
-		0xe5, 0xf0, 0x15, 0x03, 0x01, 0x00, 0x20, 0xa5,
-		0x56, 0xb5, 0x49, 0x4b, 0xc2, 0xd4, 0x4c, 0xf6,
-		0x95, 0x15, 0x7d, 0x41, 0x1d, 0x5c, 0x00, 0x0e,
-		0x20, 0xb1, 0x0a, 0xbc, 0xc9, 0x2a, 0x09, 0x17,
-		0xb4, 0xaa, 0x1c, 0x79, 0xda, 0x79, 0x27,
-	},
+	testResumeState := func(test string, didResume bool) {
+		hs, err := testHandshake(clientConfig, serverConfig)
+		if err != nil {
+			t.Fatalf("%s: handshake failed: %s", test, err)
+		}
+		if hs.DidResume != didResume {
+			t.Fatalf("%s resumed: %v, expected: %v", test, hs.DidResume, didResume)
+		}
+	}
+
+	testResumeState("Handshake", false)
+	testResumeState("Resume", true)
+
+	if _, err := io.ReadFull(serverConfig.rand(), serverConfig.SessionTicketKey[:]); err != nil {
+		t.Fatalf("Failed to invalidate SessionTicketKey")
+	}
+	testResumeState("InvalidSessionTicketKey", false)
+	testResumeState("ResumeAfterInvalidSessionTicketKey", true)
+
+	clientConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}
+	testResumeState("DifferentCipherSuite", false)
+	testResumeState("DifferentCipherSuiteRecovers", true)
+
+	clientConfig.ClientSessionCache = nil
+	testResumeState("WithoutSessionCache", false)
+}
+
+func TestLRUClientSessionCache(t *testing.T) {
+	// Initialize cache of capacity 4.
+	cache := NewLRUClientSessionCache(4)
+	cs := make([]ClientSessionState, 6)
+	keys := []string{"0", "1", "2", "3", "4", "5", "6"}
+
+	// Add 4 entries to the cache and look them up.
+	for i := 0; i < 4; i++ {
+		cache.Put(keys[i], &cs[i])
+	}
+	for i := 0; i < 4; i++ {
+		if s, ok := cache.Get(keys[i]); !ok || s != &cs[i] {
+			t.Fatalf("session cache failed lookup for added key: %s", keys[i])
+		}
+	}
+
+	// Add 2 more entries to the cache. First 2 should be evicted.
+	for i := 4; i < 6; i++ {
+		cache.Put(keys[i], &cs[i])
+	}
+	for i := 0; i < 2; i++ {
+		if s, ok := cache.Get(keys[i]); ok || s != nil {
+			t.Fatalf("session cache should have evicted key: %s", keys[i])
+		}
+	}
+
+	// Touch entry 2. LRU should evict 3 next.
+	cache.Get(keys[2])
+	cache.Put(keys[0], &cs[0])
+	if s, ok := cache.Get(keys[3]); ok || s != nil {
+		t.Fatalf("session cache should have evicted key 3")
+	}
+
+	// Update entry 0 in place.
+	cache.Put(keys[0], &cs[3])
+	if s, ok := cache.Get(keys[0]); !ok || s != &cs[3] {
+		t.Fatalf("session cache failed update for key 0")
+	}
+
+	// Adding a nil entry is valid.
+	cache.Put(keys[0], nil)
+	if s, ok := cache.Get(keys[0]); !ok || s != nil {
+		t.Fatalf("failed to add nil entry to cache")
+	}
 }
diff --git a/src/pkg/crypto/tls/handshake_messages.go b/src/pkg/crypto/tls/handshake_messages.go
index 8395200..7bcaa5e 100644
--- a/src/pkg/crypto/tls/handshake_messages.go
+++ b/src/pkg/crypto/tls/handshake_messages.go
@@ -7,20 +7,21 @@ package tls
 import "bytes"
 
 type clientHelloMsg struct {
-	raw                []byte
-	vers               uint16
-	random             []byte
-	sessionId          []byte
-	cipherSuites       []uint16
-	compressionMethods []uint8
-	nextProtoNeg       bool
-	serverName         string
-	ocspStapling       bool
-	supportedCurves    []uint16
-	supportedPoints    []uint8
-	ticketSupported    bool
-	sessionTicket      []uint8
-	signatureAndHashes []signatureAndHash
+	raw                 []byte
+	vers                uint16
+	random              []byte
+	sessionId           []byte
+	cipherSuites        []uint16
+	compressionMethods  []uint8
+	nextProtoNeg        bool
+	serverName          string
+	ocspStapling        bool
+	supportedCurves     []CurveID
+	supportedPoints     []uint8
+	ticketSupported     bool
+	sessionTicket       []uint8
+	signatureAndHashes  []signatureAndHash
+	secureRenegotiation bool
 }
 
 func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -38,11 +39,12 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
 		m.nextProtoNeg == m1.nextProtoNeg &&
 		m.serverName == m1.serverName &&
 		m.ocspStapling == m1.ocspStapling &&
-		eqUint16s(m.supportedCurves, m1.supportedCurves) &&
+		eqCurveIDs(m.supportedCurves, m1.supportedCurves) &&
 		bytes.Equal(m.supportedPoints, m1.supportedPoints) &&
 		m.ticketSupported == m1.ticketSupported &&
 		bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
-		eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes)
+		eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) &&
+		m.secureRenegotiation == m1.secureRenegotiation
 }
 
 func (m *clientHelloMsg) marshal() []byte {
@@ -80,6 +82,10 @@ func (m *clientHelloMsg) marshal() []byte {
 		extensionsLength += 2 + 2*len(m.signatureAndHashes)
 		numExtensions++
 	}
+	if m.secureRenegotiation {
+		extensionsLength += 1
+		numExtensions++
+	}
 	if numExtensions > 0 {
 		extensionsLength += 4 * numExtensions
 		length += 2 + extensionsLength
@@ -114,13 +120,13 @@ func (m *clientHelloMsg) marshal() []byte {
 	}
 	if m.nextProtoNeg {
 		z[0] = byte(extensionNextProtoNeg >> 8)
-		z[1] = byte(extensionNextProtoNeg)
+		z[1] = byte(extensionNextProtoNeg & 0xff)
 		// The length is always 0
 		z = z[4:]
 	}
 	if len(m.serverName) > 0 {
 		z[0] = byte(extensionServerName >> 8)
-		z[1] = byte(extensionServerName)
+		z[1] = byte(extensionServerName & 0xff)
 		l := len(m.serverName) + 5
 		z[2] = byte(l >> 8)
 		z[3] = byte(l)
@@ -224,6 +230,13 @@ func (m *clientHelloMsg) marshal() []byte {
 			z = z[2:]
 		}
 	}
+	if m.secureRenegotiation {
+		z[0] = byte(extensionRenegotiationInfo >> 8)
+		z[1] = byte(extensionRenegotiationInfo & 0xff)
+		z[2] = 0
+		z[3] = 1
+		z = z[5:]
+	}
 
 	m.raw = x
 
@@ -256,6 +269,9 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
 	m.cipherSuites = make([]uint16, numCipherSuites)
 	for i := 0; i < numCipherSuites; i++ {
 		m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i])
+		if m.cipherSuites[i] == scsvRenegotiation {
+			m.secureRenegotiation = true
+		}
 	}
 	data = data[2+cipherSuiteLen:]
 	if len(data) < 1 {
@@ -341,10 +357,10 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
 				return false
 			}
 			numCurves := l / 2
-			m.supportedCurves = make([]uint16, numCurves)
+			m.supportedCurves = make([]CurveID, numCurves)
 			d := data[2:]
 			for i := 0; i < numCurves; i++ {
-				m.supportedCurves[i] = uint16(d[0])<<8 | uint16(d[1])
+				m.supportedCurves[i] = CurveID(d[0])<<8 | CurveID(d[1])
 				d = d[2:]
 			}
 		case extensionSupportedPoints:
@@ -379,6 +395,11 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
 				m.signatureAndHashes[i].signature = d[1]
 				d = d[2:]
 			}
+		case extensionRenegotiationInfo + 1:
+			if length != 1 || data[0] != 0 {
+				return false
+			}
+			m.secureRenegotiation = true
 		}
 		data = data[length:]
 	}
@@ -387,16 +408,17 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
 }
 
 type serverHelloMsg struct {
-	raw               []byte
-	vers              uint16
-	random            []byte
-	sessionId         []byte
-	cipherSuite       uint16
-	compressionMethod uint8
-	nextProtoNeg      bool
-	nextProtos        []string
-	ocspStapling      bool
-	ticketSupported   bool
+	raw                 []byte
+	vers                uint16
+	random              []byte
+	sessionId           []byte
+	cipherSuite         uint16
+	compressionMethod   uint8
+	nextProtoNeg        bool
+	nextProtos          []string
+	ocspStapling        bool
+	ticketSupported     bool
+	secureRenegotiation bool
 }
 
 func (m *serverHelloMsg) equal(i interface{}) bool {
@@ -414,7 +436,8 @@ func (m *serverHelloMsg) equal(i interface{}) bool {
 		m.nextProtoNeg == m1.nextProtoNeg &&
 		eqStrings(m.nextProtos, m1.nextProtos) &&
 		m.ocspStapling == m1.ocspStapling &&
-		m.ticketSupported == m1.ticketSupported
+		m.ticketSupported == m1.ticketSupported &&
+		m.secureRenegotiation == m1.secureRenegotiation
 }
 
 func (m *serverHelloMsg) marshal() []byte {
@@ -441,6 +464,10 @@ func (m *serverHelloMsg) marshal() []byte {
 	if m.ticketSupported {
 		numExtensions++
 	}
+	if m.secureRenegotiation {
+		extensionsLength += 1
+		numExtensions++
+	}
 	if numExtensions > 0 {
 		extensionsLength += 4 * numExtensions
 		length += 2 + extensionsLength
@@ -469,7 +496,7 @@ func (m *serverHelloMsg) marshal() []byte {
 	}
 	if m.nextProtoNeg {
 		z[0] = byte(extensionNextProtoNeg >> 8)
-		z[1] = byte(extensionNextProtoNeg)
+		z[1] = byte(extensionNextProtoNeg & 0xff)
 		z[2] = byte(nextProtoLen >> 8)
 		z[3] = byte(nextProtoLen)
 		z = z[4:]
@@ -494,6 +521,13 @@ func (m *serverHelloMsg) marshal() []byte {
 		z[1] = byte(extensionSessionTicket)
 		z = z[4:]
 	}
+	if m.secureRenegotiation {
+		z[0] = byte(extensionRenegotiationInfo >> 8)
+		z[1] = byte(extensionRenegotiationInfo & 0xff)
+		z[2] = 0
+		z[3] = 1
+		z = z[5:]
+	}
 
 	m.raw = x
 
@@ -573,6 +607,11 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
 				return false
 			}
 			m.ticketSupported = true
+		case extensionRenegotiationInfo:
+			if length != 1 || data[0] != 0 {
+				return false
+			}
+			m.secureRenegotiation = true
 		}
 		data = data[length:]
 	}
@@ -1255,6 +1294,18 @@ func eqUint16s(x, y []uint16) bool {
 	return true
 }
 
+func eqCurveIDs(x, y []CurveID) bool {
+	if len(x) != len(y) {
+		return false
+	}
+	for i, v := range x {
+		if y[i] != v {
+			return false
+		}
+	}
+	return true
+}
+
 func eqStrings(x, y []string) bool {
 	if len(x) != len(y) {
 		return false
diff --git a/src/pkg/crypto/tls/handshake_messages_test.go b/src/pkg/crypto/tls/handshake_messages_test.go
index 4f569ee..f46aabd 100644
--- a/src/pkg/crypto/tls/handshake_messages_test.go
+++ b/src/pkg/crypto/tls/handshake_messages_test.go
@@ -125,9 +125,9 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
 	}
 	m.ocspStapling = rand.Intn(10) > 5
 	m.supportedPoints = randomBytes(rand.Intn(5)+1, rand)
-	m.supportedCurves = make([]uint16, rand.Intn(5)+1)
+	m.supportedCurves = make([]CurveID, rand.Intn(5)+1)
 	for i := range m.supportedCurves {
-		m.supportedCurves[i] = uint16(rand.Intn(30000))
+		m.supportedCurves[i] = CurveID(rand.Intn(30000))
 	}
 	if rand.Intn(10) > 5 {
 		m.ticketSupported = true
diff --git a/src/pkg/crypto/tls/handshake_server.go b/src/pkg/crypto/tls/handshake_server.go
index c9ccf67..75111eb 100644
--- a/src/pkg/crypto/tls/handshake_server.go
+++ b/src/pkg/crypto/tls/handshake_server.go
@@ -12,6 +12,7 @@ import (
 	"crypto/x509"
 	"encoding/asn1"
 	"errors"
+	"fmt"
 	"io"
 )
 
@@ -100,11 +101,13 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
 	var ok bool
 	hs.clientHello, ok = msg.(*clientHelloMsg)
 	if !ok {
-		return false, c.sendAlert(alertUnexpectedMessage)
+		c.sendAlert(alertUnexpectedMessage)
+		return false, unexpectedMessageError(hs.clientHello, msg)
 	}
 	c.vers, ok = config.mutualVersion(hs.clientHello.vers)
 	if !ok {
-		return false, c.sendAlert(alertProtocolVersion)
+		c.sendAlert(alertProtocolVersion)
+		return false, fmt.Errorf("tls: client offered an unsupported, maximum protocol version of %x", hs.clientHello.vers)
 	}
 	c.haveVers = true
 
@@ -114,12 +117,14 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
 	hs.hello = new(serverHelloMsg)
 
 	supportedCurve := false
+	preferredCurves := config.curvePreferences()
 Curves:
 	for _, curve := range hs.clientHello.supportedCurves {
-		switch curve {
-		case curveP256, curveP384, curveP521:
-			supportedCurve = true
-			break Curves
+		for _, supported := range preferredCurves {
+			if supported == curve {
+				supportedCurve = true
+				break Curves
+			}
 		}
 	}
 
@@ -142,20 +147,18 @@ Curves:
 	}
 
 	if !foundCompression {
-		return false, c.sendAlert(alertHandshakeFailure)
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("tls: client does not support uncompressed connections")
 	}
 
 	hs.hello.vers = c.vers
-	t := uint32(config.time().Unix())
 	hs.hello.random = make([]byte, 32)
-	hs.hello.random[0] = byte(t >> 24)
-	hs.hello.random[1] = byte(t >> 16)
-	hs.hello.random[2] = byte(t >> 8)
-	hs.hello.random[3] = byte(t)
-	_, err = io.ReadFull(config.rand(), hs.hello.random[4:])
+	_, err = io.ReadFull(config.rand(), hs.hello.random)
 	if err != nil {
-		return false, c.sendAlert(alertInternalError)
+		c.sendAlert(alertInternalError)
+		return false, err
 	}
+	hs.hello.secureRenegotiation = hs.clientHello.secureRenegotiation
 	hs.hello.compressionMethod = compressionNone
 	if len(hs.clientHello.serverName) > 0 {
 		c.serverName = hs.clientHello.serverName
@@ -170,7 +173,8 @@ Curves:
 	}
 
 	if len(config.Certificates) == 0 {
-		return false, c.sendAlert(alertInternalError)
+		c.sendAlert(alertInternalError)
+		return false, errors.New("tls: no certificates configured")
 	}
 	hs.cert = &config.Certificates[0]
 	if len(hs.clientHello.serverName) > 0 {
@@ -199,7 +203,8 @@ Curves:
 	}
 
 	if hs.suite == nil {
-		return false, c.sendAlert(alertHandshakeFailure)
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("tls: no cipher suite supported by both client and server")
 	}
 
 	return false, nil
@@ -349,7 +354,8 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 	// certificate message, even if it's empty.
 	if config.ClientAuth >= RequestClientCert {
 		if certMsg, ok = msg.(*certificateMsg); !ok {
-			return c.sendAlert(alertHandshakeFailure)
+			c.sendAlert(alertUnexpectedMessage)
+			return unexpectedMessageError(certMsg, msg)
 		}
 		hs.finishedHash.Write(certMsg.marshal())
 
@@ -376,7 +382,8 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 	// Get client key exchange
 	ckx, ok := msg.(*clientKeyExchangeMsg)
 	if !ok {
-		return c.sendAlert(alertUnexpectedMessage)
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(ckx, msg)
 	}
 	hs.finishedHash.Write(ckx.marshal())
 
@@ -393,7 +400,8 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 		}
 		certVerify, ok := msg.(*certificateVerifyMsg)
 		if !ok {
-			return c.sendAlert(alertUnexpectedMessage)
+			c.sendAlert(alertUnexpectedMessage)
+			return unexpectedMessageError(certVerify, msg)
 		}
 
 		switch key := pub.(type) {
@@ -462,7 +470,7 @@ func (hs *serverHandshakeState) readFinished() error {
 	c := hs.c
 
 	c.readRecord(recordTypeChangeCipherSpec)
-	if err := c.error(); err != nil {
+	if err := c.in.error(); err != nil {
 		return err
 	}
 
@@ -473,7 +481,8 @@ func (hs *serverHandshakeState) readFinished() error {
 		}
 		nextProto, ok := msg.(*nextProtoMsg)
 		if !ok {
-			return c.sendAlert(alertUnexpectedMessage)
+			c.sendAlert(alertUnexpectedMessage)
+			return unexpectedMessageError(nextProto, msg)
 		}
 		hs.finishedHash.Write(nextProto.marshal())
 		c.clientProtocol = nextProto.proto
@@ -485,13 +494,15 @@ func (hs *serverHandshakeState) readFinished() error {
 	}
 	clientFinished, ok := msg.(*finishedMsg)
 	if !ok {
-		return c.sendAlert(alertUnexpectedMessage)
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(clientFinished, msg)
 	}
 
 	verify := hs.finishedHash.clientSum(hs.masterSecret)
 	if len(verify) != len(clientFinished.verifyData) ||
 		subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
-		return c.sendAlert(alertHandshakeFailure)
+		c.sendAlert(alertHandshakeFailure)
+		return errors.New("tls: client's Finished message is incorrect")
 	}
 
 	hs.finishedHash.Write(clientFinished.marshal())
@@ -594,7 +605,8 @@ func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (c
 		case *ecdsa.PublicKey, *rsa.PublicKey:
 			pub = key
 		default:
-			return nil, c.sendAlert(alertUnsupportedCertificate)
+			c.sendAlert(alertUnsupportedCertificate)
+			return nil, fmt.Errorf("tls: client's certificate contains an unsupported public key of type %T", certs[0].PublicKey)
 		}
 		c.peerCertificates = certs
 		return pub, nil
diff --git a/src/pkg/crypto/tls/handshake_server_test.go b/src/pkg/crypto/tls/handshake_server_test.go
index c08eba7..c3e3678 100644
--- a/src/pkg/crypto/tls/handshake_server_test.go
+++ b/src/pkg/crypto/tls/handshake_server_test.go
@@ -12,20 +12,20 @@ import (
 	"crypto/x509"
 	"encoding/hex"
 	"encoding/pem"
-	"flag"
+	"errors"
 	"fmt"
 	"io"
-	"log"
 	"math/big"
 	"net"
 	"os"
-	"strconv"
+	"os/exec"
+	"path/filepath"
 	"strings"
-	"sync"
 	"testing"
 	"time"
 )
 
+// zeroSource is an io.Reader that returns an unlimited number of zero bytes.
 type zeroSource struct{}
 
 func (zeroSource) Read(b []byte) (n int, err error) {
@@ -39,22 +39,22 @@ func (zeroSource) Read(b []byte) (n int, err error) {
 var testConfig *Config
 
 func init() {
-	testConfig = new(Config)
-	testConfig.Time = func() time.Time { return time.Unix(0, 0) }
-	testConfig.Rand = zeroSource{}
-	testConfig.Certificates = make([]Certificate, 2)
+	testConfig = &Config{
+		Time:               func() time.Time { return time.Unix(0, 0) },
+		Rand:               zeroSource{},
+		Certificates:       make([]Certificate, 2),
+		InsecureSkipVerify: true,
+		MinVersion:         VersionSSL30,
+		MaxVersion:         VersionTLS12,
+	}
 	testConfig.Certificates[0].Certificate = [][]byte{testRSACertificate}
 	testConfig.Certificates[0].PrivateKey = testRSAPrivateKey
 	testConfig.Certificates[1].Certificate = [][]byte{testSNICertificate}
 	testConfig.Certificates[1].PrivateKey = testRSAPrivateKey
 	testConfig.BuildNameToCertificate()
-	testConfig.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA}
-	testConfig.InsecureSkipVerify = true
-	testConfig.MinVersion = VersionSSL30
-	testConfig.MaxVersion = VersionTLS10
 }
 
-func testClientHelloFailure(t *testing.T, m handshakeMessage, expected error) {
+func testClientHelloFailure(t *testing.T, m handshakeMessage, expectedSubStr string) {
 	// Create in-memory network connection,
 	// send message to server.  Should return
 	// expected error.
@@ -69,20 +69,20 @@ func testClientHelloFailure(t *testing.T, m handshakeMessage, expected error) {
 	}()
 	err := Server(s, testConfig).Handshake()
 	s.Close()
-	if e, ok := err.(*net.OpError); !ok || e.Err != expected {
-		t.Errorf("Got error: %s; expected: %s", err, expected)
+	if err == nil || !strings.Contains(err.Error(), expectedSubStr) {
+		t.Errorf("Got error: %s; expected to match substring '%s'", err, expectedSubStr)
 	}
 }
 
 func TestSimpleError(t *testing.T) {
-	testClientHelloFailure(t, &serverHelloDoneMsg{}, alertUnexpectedMessage)
+	testClientHelloFailure(t, &serverHelloDoneMsg{}, "unexpected handshake message")
 }
 
 var badProtocolVersions = []uint16{0x0000, 0x0005, 0x0100, 0x0105, 0x0200, 0x0205}
 
 func TestRejectBadProtocolVersion(t *testing.T) {
 	for _, v := range badProtocolVersions {
-		testClientHelloFailure(t, &clientHelloMsg{vers: v}, alertProtocolVersion)
+		testClientHelloFailure(t, &clientHelloMsg{vers: v}, "unsupported, maximum protocol version")
 	}
 }
 
@@ -92,7 +92,7 @@ func TestNoSuiteOverlap(t *testing.T) {
 		cipherSuites:       []uint16{0xff00},
 		compressionMethods: []uint8{0},
 	}
-	testClientHelloFailure(t, clientHello, alertHandshakeFailure)
+	testClientHelloFailure(t, clientHello, "no cipher suite supported by both client and server")
 }
 
 func TestNoCompressionOverlap(t *testing.T) {
@@ -101,7 +101,7 @@ func TestNoCompressionOverlap(t *testing.T) {
 		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
 		compressionMethods: []uint8{0xff},
 	}
-	testClientHelloFailure(t, clientHello, alertHandshakeFailure)
+	testClientHelloFailure(t, clientHello, "client does not support uncompressed connections")
 }
 
 func TestTLS12OnlyCipherSuites(t *testing.T) {
@@ -121,7 +121,7 @@ func TestTLS12OnlyCipherSuites(t *testing.T) {
 			TLS_RSA_WITH_RC4_128_SHA,
 		},
 		compressionMethods: []uint8{compressionNone},
-		supportedCurves:    []uint16{curveP256, curveP384, curveP521},
+		supportedCurves:    []CurveID{CurveP256, CurveP384, CurveP521},
 		supportedPoints:    []uint8{pointFormatUncompressed},
 	}
 
@@ -178,10 +178,12 @@ func TestClose(t *testing.T) {
 
 func testHandshake(clientConfig, serverConfig *Config) (state ConnectionState, err error) {
 	c, s := net.Pipe()
+	done := make(chan bool)
 	go func() {
 		cli := Client(c, clientConfig)
 		cli.Handshake()
 		c.Close()
+		done <- true
 	}()
 	server := Server(s, serverConfig)
 	err = server.Handshake()
@@ -189,9 +191,27 @@ func testHandshake(clientConfig, serverConfig *Config) (state ConnectionState, e
 		state = server.ConnectionState()
 	}
 	s.Close()
+	<-done
 	return
 }
 
+func TestVersion(t *testing.T) {
+	serverConfig := &Config{
+		Certificates: testConfig.Certificates,
+		MaxVersion:   VersionTLS11,
+	}
+	clientConfig := &Config{
+		InsecureSkipVerify: true,
+	}
+	state, err := testHandshake(clientConfig, serverConfig)
+	if err != nil {
+		t.Fatalf("handshake failed: %s", err)
+	}
+	if state.Version != VersionTLS11 {
+		t.Fatalf("Incorrect version %x, should be %x", state.Version, VersionTLS11)
+	}
+}
+
 func TestCipherSuitePreference(t *testing.T) {
 	serverConfig := &Config{
 		CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
@@ -221,2920 +241,327 @@ func TestCipherSuitePreference(t *testing.T) {
 	}
 }
 
-func testServerScript(t *testing.T, name string, serverScript [][]byte, config *Config, peers []*x509.Certificate) {
-	c, s := net.Pipe()
-	srv := Server(s, config)
-	pchan := make(chan []*x509.Certificate, 1)
-	go func() {
-		srv.Write([]byte("hello, world\n"))
-		srv.Close()
-		s.Close()
-		st := srv.ConnectionState()
-		pchan <- st.PeerCertificates
-	}()
-
-	for i, b := range serverScript {
-		if i%2 == 0 {
-			c.Write(b)
-			continue
-		}
-		bb := make([]byte, len(b))
-		n, err := io.ReadFull(c, bb)
-		if err != nil {
-			t.Fatalf("%s #%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", name, i, err, n, len(bb), bb[:n], b)
-		}
-		if !bytes.Equal(b, bb) {
-			t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", name, i, bb, b)
-		}
-	}
-	c.Close()
-
-	if peers != nil {
-		gotpeers := <-pchan
-		if len(peers) == len(gotpeers) {
-			for i := range peers {
-				if !peers[i].Equal(gotpeers[i]) {
-					t.Fatalf("%s: mismatch on peer cert %d", name, i)
-				}
-			}
-		} else {
-			t.Fatalf("%s: mismatch on peer list length: %d (wanted) != %d (got)", name, len(peers), len(gotpeers))
-		}
+// Note: see comment in handshake_test.go for details of how the reference
+// tests work.
+
+// serverTest represents a test of the TLS server handshake against a reference
+// implementation.
+type serverTest struct {
+	// name is a freeform string identifying the test and the file in which
+	// the expected results will be stored.
+	name string
+	// command, if not empty, contains a series of arguments for the
+	// command to run for the reference server.
+	command []string
+	// expectedPeerCerts contains a list of PEM blocks of expected
+	// certificates from the client.
+	expectedPeerCerts []string
+	// config, if not nil, contains a custom Config to use for this test.
+	config *Config
+}
+
+var defaultClientCommand = []string{"openssl", "s_client", "-no_ticket"}
+
+// connFromCommand starts opens a listening socket and starts the reference
+// client to connect to it. It returns a recordingConn that wraps the resulting
+// connection.
+func (test *serverTest) connFromCommand() (conn *recordingConn, child *exec.Cmd, err error) {
+	l, err := net.ListenTCP("tcp", &net.TCPAddr{
+		IP:   net.IPv4(127, 0, 0, 1),
+		Port: 0,
+	})
+	if err != nil {
+		return nil, nil, err
 	}
-}
+	defer l.Close()
 
-func TestHandshakeServerRSARC4(t *testing.T) {
-	testServerScript(t, "RSA-RC4", rsaRC4ServerScript, testConfig, nil)
-}
-
-func TestHandshakeServerRSA3DES(t *testing.T) {
-	des3Config := new(Config)
-	*des3Config = *testConfig
-	des3Config.CipherSuites = []uint16{TLS_RSA_WITH_3DES_EDE_CBC_SHA}
-	testServerScript(t, "RSA-3DES", rsaDES3ServerScript, des3Config, nil)
-}
-
-func TestHandshakeServerRSAAES(t *testing.T) {
-	aesConfig := new(Config)
-	*aesConfig = *testConfig
-	aesConfig.CipherSuites = []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}
-	testServerScript(t, "RSA-AES", rsaAESServerScript, aesConfig, nil)
-}
+	port := l.Addr().(*net.TCPAddr).Port
 
-func TestHandshakeServerECDHEECDSAAES(t *testing.T) {
-	ecdsaConfig := new(Config)
-	*ecdsaConfig = *testConfig
-	ecdsaConfig.Certificates = make([]Certificate, 1)
-	ecdsaConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
-	ecdsaConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
-	ecdsaConfig.BuildNameToCertificate()
-	ecdsaConfig.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}
-	testServerScript(t, "ECDHE-ECDSA-AES", ecdheECDSAAESServerScript, ecdsaConfig, nil)
-}
-
-func TestHandshakeServerSSLv3(t *testing.T) {
-	testServerScript(t, "SSLv3", sslv3ServerScript, testConfig, nil)
-}
-
-// TestHandshakeServerSNI involves a client sending an SNI extension of
-// "snitest.com", which happens to match the CN of testSNICertificate. The test
-// verifies that the server correctly selects that certificate.
-func TestHandshakeServerSNI(t *testing.T) {
-	testServerScript(t, "SNI", selectCertificateBySNIScript, testConfig, nil)
-}
-
-func TestResumption(t *testing.T) {
-	testServerScript(t, "IssueTicket", issueSessionTicketTest, testConfig, nil)
-	testServerScript(t, "Resume", serverResumeTest, testConfig, nil)
-}
-
-func TestTLS12ClientCertServer(t *testing.T) {
-	config := *testConfig
-	config.MaxVersion = VersionTLS12
-	config.ClientAuth = RequireAnyClientCert
-	config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}
-
-	testServerScript(t, "TLS12", tls12ServerScript, &config, nil)
-}
-
-type clientauthTest struct {
-	name       string
-	clientauth ClientAuthType
-	peers      []*x509.Certificate
-	script     [][]byte
-}
-
-func TestClientAuthRSA(t *testing.T) {
-	for _, cat := range clientauthRSATests {
-		t.Log("running", cat.name)
-		cfg := new(Config)
-		*cfg = *testConfig
-		cfg.ClientAuth = cat.clientauth
-		testServerScript(t, cat.name, cat.script, cfg, cat.peers)
+	var command []string
+	command = append(command, test.command...)
+	if len(command) == 0 {
+		command = defaultClientCommand
 	}
-}
-
-func TestClientAuthECDSA(t *testing.T) {
-	for _, cat := range clientauthECDSATests {
-		t.Log("running", cat.name)
-		cfg := new(Config)
-		*cfg = *testConfig
-		cfg.Certificates = make([]Certificate, 1)
-		cfg.Certificates[0].Certificate = [][]byte{testECDSACertificate}
-		cfg.Certificates[0].PrivateKey = testECDSAPrivateKey
-		cfg.BuildNameToCertificate()
-		cfg.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}
-		cfg.ClientAuth = cat.clientauth
-		testServerScript(t, cat.name, cat.script, cfg, cat.peers)
+	command = append(command, "-connect")
+	command = append(command, fmt.Sprintf("127.0.0.1:%d", port))
+	cmd := exec.Command(command[0], command[1:]...)
+	cmd.Stdin = nil
+	var output bytes.Buffer
+	cmd.Stdout = &output
+	cmd.Stderr = &output
+	if err := cmd.Start(); err != nil {
+		return nil, nil, err
 	}
-}
 
-// TestCipherSuiteCertPreferance ensures that we select an RSA ciphersuite with
-// an RSA certificate and an ECDSA ciphersuite with an ECDSA certificate.
-func TestCipherSuiteCertPreferance(t *testing.T) {
-	var config = *testConfig
-	config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}
-	config.MaxVersion = VersionTLS11
-	config.PreferServerCipherSuites = true
-	testServerScript(t, "CipherSuiteCertPreference", tls11ECDHEAESServerScript, &config, nil)
+	connChan := make(chan interface{})
+	go func() {
+		tcpConn, err := l.Accept()
+		if err != nil {
+			connChan <- err
+		}
+		connChan <- tcpConn
+	}()
 
-	config = *testConfig
-	config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}
-	config.Certificates = []Certificate{
-		Certificate{
-			Certificate: [][]byte{testECDSACertificate},
-			PrivateKey:  testECDSAPrivateKey,
-		},
+	var tcpConn net.Conn
+	select {
+	case connOrError := <-connChan:
+		if err, ok := connOrError.(error); ok {
+			return nil, nil, err
+		}
+		tcpConn = connOrError.(net.Conn)
+	case <-time.After(2 * time.Second):
+		output.WriteTo(os.Stdout)
+		return nil, nil, errors.New("timed out waiting for connection from child process")
 	}
-	config.BuildNameToCertificate()
-	config.PreferServerCipherSuites = true
-	testServerScript(t, "CipherSuiteCertPreference2", ecdheECDSAAESServerScript, &config, nil)
-}
-
-func TestTLS11Server(t *testing.T) {
-	var config = *testConfig
-	config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}
-	config.MaxVersion = VersionTLS11
-	testServerScript(t, "TLS11", tls11ECDHEAESServerScript, &config, nil)
-}
-
-func TestAESGCM(t *testing.T) {
-	var config = *testConfig
-	config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
-	config.MaxVersion = VersionTLS12
-	testServerScript(t, "AES-GCM", aesGCMServerScript, &config, nil)
-}
 
-// recordingConn is a net.Conn that records the traffic that passes through it.
-// WriteTo can be used to produce Go code that contains the recorded traffic.
-type recordingConn struct {
-	net.Conn
-	lock             sync.Mutex
-	flows            [][]byte
-	currentlyReading bool
-}
-
-func (r *recordingConn) Read(b []byte) (n int, err error) {
-	if n, err = r.Conn.Read(b); n == 0 {
-		return
+	record := &recordingConn{
+		Conn: tcpConn,
 	}
-	b = b[:n]
-
-	r.lock.Lock()
-	defer r.lock.Unlock()
 
-	if l := len(r.flows); l == 0 || !r.currentlyReading {
-		buf := make([]byte, len(b))
-		copy(buf, b)
-		r.flows = append(r.flows, buf)
-	} else {
-		r.flows[l-1] = append(r.flows[l-1], b[:n]...)
-	}
-	r.currentlyReading = true
-	return
+	return record, cmd, nil
 }
 
-func (r *recordingConn) Write(b []byte) (n int, err error) {
-	if n, err = r.Conn.Write(b); n == 0 {
-		return
-	}
-	b = b[:n]
-
-	r.lock.Lock()
-	defer r.lock.Unlock()
-
-	if l := len(r.flows); l == 0 || r.currentlyReading {
-		buf := make([]byte, len(b))
-		copy(buf, b)
-		r.flows = append(r.flows, buf)
-	} else {
-		r.flows[l-1] = append(r.flows[l-1], b[:n]...)
-	}
-	r.currentlyReading = false
-	return
+func (test *serverTest) dataPath() string {
+	return filepath.Join("testdata", "Server-"+test.name)
 }
 
-// WriteTo writes Go source code to w that contains the recorded traffic.
-func (r *recordingConn) WriteTo(w io.Writer) {
-	fmt.Fprintf(w, "var changeMe = [][]byte {\n")
-	for _, buf := range r.flows {
-		fmt.Fprintf(w, "\t{")
-		for i, b := range buf {
-			if i%8 == 0 {
-				fmt.Fprintf(w, "\n\t\t")
-			}
-			fmt.Fprintf(w, "0x%02x, ", b)
-		}
-		fmt.Fprintf(w, "\n\t},\n")
+func (test *serverTest) loadData() (flows [][]byte, err error) {
+	in, err := os.Open(test.dataPath())
+	if err != nil {
+		return nil, err
 	}
-	fmt.Fprintf(w, "}\n")
+	defer in.Close()
+	return parseTestData(in)
 }
 
-var serve = flag.Bool("serve", false, "run a TLS server on :10443")
-var testCipherSuites = flag.String("ciphersuites",
-	"0x"+strconv.FormatInt(int64(TLS_RSA_WITH_RC4_128_SHA), 16),
-	"cipher suites to accept in serving mode")
-var testMinVersion = flag.String("minversion",
-	"0x"+strconv.FormatInt(int64(VersionSSL30), 16),
-	"minimum version to negotiate")
-var testMaxVersion = flag.String("maxversion",
-	"0x"+strconv.FormatInt(int64(VersionTLS10), 16),
-	"maximum version to negotiate")
-var testClientAuth = flag.Int("clientauth", 0, "value for tls.Config.ClientAuth")
-
-func GetTestConfig() *Config {
-	var config = *testConfig
-
-	minVersion, err := strconv.ParseUint(*testMinVersion, 0, 64)
-	if err != nil {
-		panic(err)
-	}
-	config.MinVersion = uint16(minVersion)
-	maxVersion, err := strconv.ParseUint(*testMaxVersion, 0, 64)
-	if err != nil {
-		panic(err)
-	}
-	config.MaxVersion = uint16(maxVersion)
+func (test *serverTest) run(t *testing.T, write bool) {
+	var clientConn, serverConn net.Conn
+	var recordingConn *recordingConn
+	var childProcess *exec.Cmd
 
-	suites := strings.Split(*testCipherSuites, ",")
-	config.CipherSuites = make([]uint16, len(suites))
-	for i := range suites {
-		suite, err := strconv.ParseUint(suites[i], 0, 64)
+	if write {
+		var err error
+		recordingConn, childProcess, err = test.connFromCommand()
 		if err != nil {
-			panic(err)
+			t.Fatalf("Failed to start subcommand: %s", err)
 		}
-		config.CipherSuites[i] = uint16(suite)
+		serverConn = recordingConn
+	} else {
+		clientConn, serverConn = net.Pipe()
 	}
-
-	ecdsa := false
-	for _, suite := range config.CipherSuites {
-		switch suite {
-		case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
-			TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
-			TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
-			ecdsa = true
-		}
+	config := test.config
+	if config == nil {
+		config = testConfig
 	}
-	if ecdsa {
-		config.Certificates = nil
-		if !*connect {
-			config.Certificates = make([]Certificate, 1)
-			config.Certificates[0].Certificate = [][]byte{testECDSACertificate}
-			config.Certificates[0].PrivateKey = testECDSAPrivateKey
+	server := Server(serverConn, config)
+	peerCertsChan := make(chan []*x509.Certificate, 1)
+	go func() {
+		if _, err := server.Write([]byte("hello, world\n")); err != nil {
+			t.Logf("Error from Server.Write: %s", err)
 		}
-		config.BuildNameToCertificate()
-	}
-
-	config.ClientAuth = ClientAuthType(*testClientAuth)
-	return &config
-}
-
-func TestRunServer(t *testing.T) {
-	if !*serve {
-		return
-	}
-
-	config := GetTestConfig()
-
-	const addr = ":10443"
-	l, err := net.Listen("tcp", addr)
-	if err != nil {
-		t.Fatal(err)
-	}
-	log.Printf("Now listening for connections on %s", addr)
+		server.Close()
+		serverConn.Close()
+		peerCertsChan <- server.ConnectionState().PeerCertificates
+	}()
 
-	for {
-		tcpConn, err := l.Accept()
+	if !write {
+		flows, err := test.loadData()
 		if err != nil {
-			log.Printf("error accepting connection: %s", err)
-			break
+			t.Fatalf("%s: failed to load data from %s", test.name, test.dataPath())
 		}
-
-		record := &recordingConn{
-			Conn: tcpConn,
+		for i, b := range flows {
+			if i%2 == 0 {
+				clientConn.Write(b)
+				continue
+			}
+			bb := make([]byte, len(b))
+			n, err := io.ReadFull(clientConn, bb)
+			if err != nil {
+				t.Fatalf("%s #%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", test.name, i+1, err, n, len(bb), bb[:n], b)
+			}
+			if !bytes.Equal(b, bb) {
+				t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", test.name, i+1, bb, b)
+			}
 		}
+		clientConn.Close()
+	}
 
-		conn := Server(record, config)
-		if err := conn.Handshake(); err != nil {
-			log.Printf("error from TLS handshake: %s", err)
-			break
+	peerCerts := <-peerCertsChan
+	if len(peerCerts) == len(test.expectedPeerCerts) {
+		for i, peerCert := range peerCerts {
+			block, _ := pem.Decode([]byte(test.expectedPeerCerts[i]))
+			if !bytes.Equal(block.Bytes, peerCert.Raw) {
+				t.Fatalf("%s: mismatch on peer cert %d", test.name, i+1)
+			}
 		}
+	} else {
+		t.Fatalf("%s: mismatch on peer list length: %d (wanted) != %d (got)", test.name, len(test.expectedPeerCerts), len(peerCerts))
+	}
 
-		_, err = conn.Write([]byte("hello, world\n"))
+	if write {
+		path := test.dataPath()
+		out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
 		if err != nil {
-			log.Printf("error from Write: %s", err)
-			continue
+			t.Fatalf("Failed to create output file: %s", err)
 		}
-
-		conn.Close()
-
-		record.WriteTo(os.Stdout)
+		defer out.Close()
+		recordingConn.Close()
+		if len(recordingConn.flows) < 3 {
+			childProcess.Stdout.(*bytes.Buffer).WriteTo(os.Stdout)
+			t.Fatalf("Handshake failed")
+		}
+		recordingConn.WriteTo(out)
+		fmt.Printf("Wrote %s\n", path)
+		childProcess.Wait()
 	}
 }
 
-func bigFromString(s string) *big.Int {
-	ret := new(big.Int)
-	ret.SetString(s, 10)
-	return ret
+func runServerTestForVersion(t *testing.T, template *serverTest, prefix, option string) {
+	test := *template
+	test.name = prefix + test.name
+	if len(test.command) == 0 {
+		test.command = defaultClientCommand
+	}
+	test.command = append([]string(nil), test.command...)
+	test.command = append(test.command, option)
+	test.run(t, *update)
 }
 
-func fromHex(s string) []byte {
-	b, _ := hex.DecodeString(s)
-	return b
+func runServerTestSSLv3(t *testing.T, template *serverTest) {
+	runServerTestForVersion(t, template, "SSLv3-", "-ssl3")
 }
 
-var testRSACertificate = fromHex("308202b030820219a00302010202090085b0bba48a7fb8ca300d06092a864886f70d01010505003045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3130303432343039303933385a170d3131303432343039303933385a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819f300d06092a864886f70d010101 [...]
-
-var testECDSACertificate = fromHex("3082020030820162020900b8bf2d47a0d2ebf4300906072a8648ce3d04013045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3132313132323135303633325a170d3232313132303135303633325a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819b301006072a8648ce3d020106052b81040023038186 [...]
-
-var testSNICertificate = fromHex("308201f23082015da003020102020100300b06092a864886f70d01010530283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d301e170d3132303431313137343033355a170d3133303431313137343533355a30283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d30819d300b06092a864886f70d01010103818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a [...]
+func runServerTestTLS10(t *testing.T, template *serverTest) {
+	runServerTestForVersion(t, template, "TLSv10-", "-tls1")
+}
 
-var testRSAPrivateKey = &rsa.PrivateKey{
-	PublicKey: rsa.PublicKey{
-		N: bigFromString("131650079503776001033793877885499001334664249354723305978524647182322416328664556247316495448366990052837680518067798333412266673813370895702118944398081598789828837447552603077848001020611640547221687072142537202428102790818451901395596882588063427854225330436740647715202971973145151161964464812406232198521"),
-		E: 65537,
-	},
-	D: bigFromString("29354450337804273969007277378287027274721892607543397931919078829901848876371746653677097639302788129485893852488285045793268732234230875671682624082413996177431586734171663258657462237320300610850244186316880055243099640544518318093544057213190320837094958164973959123058337475052510833916491060913053867729"),
-	Primes: []*big.Int{
-		bigFromString("11969277782311800166562047708379380720136961987713178380670422671426759650127150688426177829077494755200794297055316163155755835813760102405344560929062149"),
-		bigFromString("10998999429884441391899182616418192492905073053684657075974935218461686523870125521822756579792315215543092255516093840728890783887287417039645833477273829"),
-	},
+func runServerTestTLS11(t *testing.T, template *serverTest) {
+	runServerTestForVersion(t, template, "TLSv11-", "-tls1_1")
 }
 
-var testECDSAPrivateKey = &ecdsa.PrivateKey{
-	PublicKey: ecdsa.PublicKey{
-		Curve: &elliptic.CurveParams{
-			P:       bigFromString("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"),
-			N:       bigFromString("6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449"),
-			B:       bigFromString("1093849038073734274511112390766805569936207598951683748994586394495953116150735016013708737573759623248592132296706313309438452531591012912142327488478985984"),
-			Gx:      bigFromString("2661740802050217063228768716723360960729859168756973147706671368418802944996427808491545080627771902352094241225065558662157113545570916814161637315895999846"),
-			Gy:      bigFromString("3757180025770020463545507224491183603594455134769762486694567779615544477440556316691234405012945539562144444537289428522585666729196580810124344277578376784"),
-			BitSize: 521,
-		},
-		X: bigFromString("2636411247892461147287360222306590634450676461695221912739908880441342231985950069527906976759812296359387337367668045707086543273113073382714101597903639351"),
-		Y: bigFromString("3204695818431246682253994090650952614555094516658732116404513121125038617915183037601737180082382202488628239201196033284060130040574800684774115478859677243"),
-	},
-	D: bigFromString("5477294338614160138026852784385529180817726002953041720191098180813046231640184669647735805135001309477695746518160084669446643325196003346204701381388769751"),
+func runServerTestTLS12(t *testing.T, template *serverTest) {
+	runServerTestForVersion(t, template, "TLSv12-", "-tls1_2")
 }
 
-func loadPEMCert(in string) *x509.Certificate {
-	block, _ := pem.Decode([]byte(in))
-	if block.Type == "CERTIFICATE" && len(block.Headers) == 0 {
-		cert, err := x509.ParseCertificate(block.Bytes)
-		if err == nil {
-			return cert
-		}
-		panic("error parsing cert")
+func TestHandshakeServerRSARC4(t *testing.T) {
+	test := &serverTest{
+		name:    "RSA-RC4",
+		command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA"},
 	}
-	panic("error parsing PEM")
+	runServerTestSSLv3(t, test)
+	runServerTestTLS10(t, test)
+	runServerTestTLS11(t, test)
+	runServerTestTLS12(t, test)
 }
 
-// Script of interaction with gnutls implementation.
-// The values for this test are obtained by building and running in server mode:
-//   % go test -test.run "TestRunServer" -serve
-// The recorded bytes are written to stdout.
-var rsaRC4ServerScript = [][]byte{
-	{
-		0x16, 0x03, 0x01, 0x00, 0x54, 0x01, 0x00, 0x00,
-		0x50, 0x03, 0x01, 0x50, 0x77, 0x3d, 0xbd, 0x32,
-		0x13, 0xd7, 0xea, 0x33, 0x65, 0x02, 0xb8, 0x70,
-		0xb7, 0x84, 0xc4, 0x05, 0x1f, 0xa4, 0x24, 0xc4,
-		0x91, 0x69, 0x04, 0x32, 0x96, 0xfe, 0x5b, 0x49,
-		0x71, 0x60, 0x9a, 0x00, 0x00, 0x28, 0x00, 0x39,
-		0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13,
-		0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f,
-		0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
-		0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08,
-		0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01,
-		0x00,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
-		0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16,
-		0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba,
-		0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82,
-		0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03,
-		0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0,
-		0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d,
-		0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
-		0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
-		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
-		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
-		0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
-		0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
-		0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
-		0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
-		0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
-		0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
-		0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
-		0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31,
-		0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30,
-		0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b,
-		0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
-		0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
-		0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
-		0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
-		0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
-		0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
-		0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
-		0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
-		0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d,
-		0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
-		0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
-		0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
-		0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf,
-		0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b,
-		0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a,
-		0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65,
-		0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4,
-		0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62,
-		0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c,
-		0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58,
-		0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0,
-		0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f,
-		0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18,
-		0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1,
-		0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9,
-		0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01,
-		0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d,
-		0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79,
-		0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7,
-		0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55,
-		0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad,
-		0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69,
-		0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18,
-		0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d,
-		0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1,
-		0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
-		0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
-		0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30,
-		0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
-		0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
-		0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
-		0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
-		0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
-		0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
-		0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
-		0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
-		0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09,
-		0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8,
-		0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
-		0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
-		0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
-		0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
-		0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b,
-		0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0,
-		0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5,
-		0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae,
-		0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e,
-		0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5,
-		0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30,
-		0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7,
-		0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78,
-		0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d,
-		0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75,
-		0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd,
-		0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c,
-		0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57,
-		0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b,
-		0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7,
-		0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e,
-		0x00, 0x00, 0x00,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
-		0x82, 0x00, 0x80, 0x2d, 0x09, 0x7c, 0x7f, 0xfc,
-		0x84, 0xce, 0xb3, 0x30, 0x9b, 0xf9, 0xb7, 0xc8,
-		0xc3, 0xff, 0xee, 0x6f, 0x20, 0x8a, 0xf4, 0xfb,
-		0x86, 0x55, 0x1f, 0x6a, 0xb4, 0x81, 0x50, 0x3a,
-		0x46, 0x1b, 0xd3, 0xca, 0x4b, 0x11, 0xff, 0xef,
-		0x02, 0xbc, 0x18, 0xb8, 0x4a, 0x7d, 0x43, 0x23,
-		0x96, 0x92, 0x27, 0x7c, 0xca, 0xcf, 0xe6, 0x91,
-		0xe8, 0x14, 0x97, 0x68, 0xb4, 0xe5, 0xc0, 0xc9,
-		0x23, 0xdd, 0x54, 0x07, 0xa6, 0x2e, 0x8c, 0x98,
-		0xfc, 0xc6, 0x8c, 0x04, 0x6b, 0x1b, 0x5f, 0xd5,
-		0x3d, 0x8b, 0x6c, 0x55, 0x4f, 0x7a, 0xe6, 0x6c,
-		0x74, 0x2c, 0x1e, 0x34, 0xdb, 0xfb, 0x00, 0xb1,
-		0x4e, 0x10, 0x21, 0x16, 0xe0, 0x3e, 0xc5, 0x64,
-		0x84, 0x28, 0x2b, 0x2b, 0x29, 0x47, 0x51, 0x34,
-		0x76, 0x15, 0x20, 0x71, 0x0b, 0x30, 0xa1, 0x85,
-		0xd5, 0x15, 0x18, 0x14, 0x64, 0x4b, 0x40, 0x7c,
-		0x4f, 0xb3, 0x7b, 0x14, 0x03, 0x01, 0x00, 0x01,
-		0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xab, 0xee,
-		0xf5, 0x97, 0x5f, 0xc6, 0x78, 0xf3, 0xc6, 0x83,
-		0x5b, 0x55, 0x4f, 0xcb, 0x45, 0x3f, 0xfa, 0xf7,
-		0x05, 0x02, 0xc2, 0x63, 0x87, 0x18, 0xb5, 0x9a,
-		0x62, 0xe2, 0x3f, 0x88, 0x5a, 0x60, 0x61, 0x72,
-		0xfa, 0x9c,
-	},
-	{
-		0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
-		0x01, 0x00, 0x24, 0x72, 0xa4, 0xe4, 0xaa, 0xd2,
-		0xc4, 0x39, 0x7e, 0x2a, 0xc1, 0x6f, 0x34, 0x42,
-		0x28, 0xcb, 0x9d, 0x7a, 0x09, 0xca, 0x96, 0xad,
-		0x0e, 0x11, 0x51, 0x8a, 0x06, 0xb0, 0xe9, 0xca,
-		0xeb, 0xce, 0xe2, 0xd5, 0x2e, 0xc1, 0x8d, 0x17,
-		0x03, 0x01, 0x00, 0x21, 0x2e, 0x61, 0x86, 0x17,
-		0xdb, 0xa6, 0x30, 0xe2, 0x62, 0x06, 0x2a, 0x8b,
-		0x75, 0x2c, 0x2d, 0xcf, 0xf5, 0x01, 0x11, 0x52,
-		0x81, 0x38, 0xcf, 0xd5, 0xf7, 0xdc, 0x52, 0x31,
-		0x1f, 0x97, 0x43, 0xc2, 0x71, 0x15, 0x03, 0x01,
-		0x00, 0x16, 0xe0, 0x21, 0xfe, 0x36, 0x2e, 0x68,
-		0x2c, 0xf1, 0xbe, 0x04, 0xec, 0xd4, 0xc6, 0xdd,
-		0xac, 0x6f, 0x4c, 0x85, 0x32, 0x3f, 0x87, 0x1b,
-	},
+func TestHandshakeServerRSA3DES(t *testing.T) {
+	test := &serverTest{
+		name:    "RSA-3DES",
+		command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "DES-CBC3-SHA"},
+	}
+	runServerTestSSLv3(t, test)
+	runServerTestTLS10(t, test)
+	runServerTestTLS12(t, test)
 }
 
-var rsaDES3ServerScript = [][]byte{
-	{
-		0x16, 0x03, 0x00, 0x00, 0xc5, 0x01, 0x00, 0x00,
-		0xc1, 0x03, 0x03, 0x50, 0xae, 0x5d, 0x38, 0xec,
-		0xaa, 0x2f, 0x41, 0xf9, 0xd2, 0x7b, 0xa1, 0xfd,
-		0x0f, 0xff, 0x4e, 0x54, 0x0e, 0x15, 0x57, 0xaf,
-		0x2c, 0x91, 0xb5, 0x35, 0x5b, 0x2e, 0xb0, 0xec,
-		0x20, 0xe5, 0xd2, 0x00, 0x00, 0x50, 0xc0, 0x09,
-		0xc0, 0x23, 0xc0, 0x2b, 0xc0, 0x0a, 0xc0, 0x24,
-		0xc0, 0x2c, 0xc0, 0x08, 0xc0, 0x13, 0xc0, 0x27,
-		0xc0, 0x2f, 0xc0, 0x14, 0xc0, 0x30, 0xc0, 0x12,
-		0x00, 0x33, 0x00, 0x67, 0x00, 0x45, 0x00, 0x9e,
-		0x00, 0x39, 0x00, 0x6b, 0x00, 0x88, 0x00, 0x16,
-		0x00, 0x32, 0x00, 0x40, 0x00, 0x44, 0x00, 0xa2,
-		0x00, 0x38, 0x00, 0x6a, 0x00, 0x87, 0x00, 0x13,
-		0x00, 0x66, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x41,
-		0x00, 0x9c, 0x00, 0x35, 0x00, 0x3d, 0x00, 0x84,
-		0x00, 0x0a, 0x00, 0x05, 0x00, 0x04, 0x01, 0x00,
-		0x00, 0x48, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00,
-		0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00,
-		0x00, 0x23, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c,
-		0x00, 0x0a, 0x00, 0x13, 0x00, 0x15, 0x00, 0x17,
-		0x00, 0x18, 0x00, 0x19, 0x00, 0x0b, 0x00, 0x02,
-		0x01, 0x00, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x1a,
-		0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x05, 0x01,
-		0x05, 0x03, 0x06, 0x01, 0x06, 0x03, 0x03, 0x01,
-		0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02,
-		0x02, 0x03,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
-		0x2c, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00,
-		0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
-		0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
-		0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
-		0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
-		0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
-		0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
-		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-		0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
-		0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
-		0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
-		0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
-		0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
-		0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
-		0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
-		0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
-		0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
-		0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
-		0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
-		0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
-		0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
-		0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
-		0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
-		0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
-		0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
-		0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
-		0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
-		0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
-		0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
-		0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
-		0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
-		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-		0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
-		0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
-		0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
-		0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
-		0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
-		0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
-		0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
-		0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
-		0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
-		0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
-		0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
-		0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
-		0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
-		0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
-		0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
-		0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
-		0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
-		0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
-		0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
-		0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
-		0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
-		0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
-		0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
-		0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
-		0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
-		0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
-		0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
-		0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
-		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
-		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
-		0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
-		0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
-		0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
-		0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
-		0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
-		0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
-		0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
-		0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
-		0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
-		0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-		0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
-		0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
-		0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
-		0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
-		0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
-		0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
-		0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
-		0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
-		0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
-		0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
-		0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
-		0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
-		0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
-		0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
-		0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
-		0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
-		0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
-		0x16, 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00,
-		0x00,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
-		0x82, 0x00, 0x80, 0x51, 0x04, 0xf1, 0x7a, 0xbf,
-		0xe8, 0xa5, 0x86, 0x09, 0xa7, 0xf3, 0xcc, 0x93,
-		0x00, 0x10, 0x5b, 0xb8, 0xc1, 0x51, 0x0d, 0x5b,
-		0xcd, 0xed, 0x26, 0x01, 0x69, 0x73, 0xf4, 0x05,
-		0x8a, 0x6a, 0xc3, 0xb1, 0x9e, 0x84, 0x4e, 0x39,
-		0xcf, 0x5e, 0x55, 0xa9, 0x70, 0x19, 0x96, 0x91,
-		0xcd, 0x2c, 0x78, 0x3c, 0xa2, 0x6d, 0xb0, 0x49,
-		0x86, 0xf6, 0xd1, 0x3a, 0xde, 0x00, 0x4b, 0xa6,
-		0x25, 0xbf, 0x85, 0x39, 0xce, 0xb1, 0xcf, 0xbc,
-		0x16, 0xc7, 0x66, 0xac, 0xf8, 0xd2, 0x3b, 0xd1,
-		0xcc, 0x16, 0xac, 0x63, 0x3c, 0xbe, 0xd9, 0xb6,
-		0x6a, 0xe4, 0x13, 0x8a, 0xf4, 0x56, 0x2f, 0x92,
-		0x54, 0xd8, 0xf0, 0x84, 0x01, 0x32, 0x1a, 0xa9,
-		0x2d, 0xaf, 0x82, 0x0e, 0x00, 0xfa, 0x07, 0x88,
-		0xd9, 0x87, 0xe7, 0xdc, 0x9e, 0xe9, 0x72, 0x49,
-		0xb8, 0xfa, 0x8c, 0x7b, 0x07, 0x0b, 0x03, 0x7c,
-		0x10, 0x8c, 0x8a, 0x14, 0x03, 0x01, 0x00, 0x01,
-		0x01, 0x16, 0x03, 0x01, 0x00, 0xa8, 0x61, 0xa4,
-		0xf4, 0x5f, 0x8a, 0x1f, 0x5c, 0x92, 0x3f, 0x8c,
-		0xdb, 0xd6, 0x10, 0xcd, 0x9e, 0xe7, 0xf0, 0xc4,
-		0x3c, 0xb6, 0x1c, 0x9a, 0x56, 0x73, 0x7f, 0xa6,
-		0x14, 0x24, 0xcb, 0x96, 0x1f, 0xe0, 0xaf, 0xcd,
-		0x3c, 0x66, 0x43, 0xb7, 0x37, 0x65, 0x34, 0x47,
-		0xf8, 0x43, 0xf1, 0xcc, 0x15, 0xb8, 0xdc, 0x35,
-		0xe0, 0xa4, 0x2d, 0x78, 0x94, 0xe0, 0x02, 0xf3,
-		0x76, 0x46, 0xf7, 0x9b, 0x8d, 0x0d, 0x5d, 0x0b,
-		0xd3, 0xdd, 0x9a, 0x9e, 0x62, 0x2e, 0xc5, 0x98,
-		0x75, 0x63, 0x0c, 0xbf, 0x8e, 0x49, 0x33, 0x23,
-		0x7c, 0x00, 0xcf, 0xfb, 0xcf, 0xba, 0x0f, 0x41,
-		0x39, 0x89, 0xb9, 0xcc, 0x59, 0xd0, 0x2b, 0xb6,
-		0xec, 0x04, 0xe2, 0xc0, 0x52, 0xc7, 0xcf, 0x71,
-		0x47, 0xff, 0x70, 0x7e, 0xa9, 0xbd, 0x1c, 0xdd,
-		0x17, 0xa5, 0x6c, 0xb7, 0x10, 0x4f, 0x42, 0x18,
-		0x37, 0x69, 0xa9, 0xd2, 0xb3, 0x18, 0x84, 0x92,
-		0xa7, 0x47, 0x21, 0xf6, 0x95, 0x63, 0x29, 0xd6,
-		0xa5, 0xb6, 0xda, 0x65, 0x67, 0x69, 0xc4, 0x26,
-		0xac, 0x8b, 0x08, 0x58, 0xdd, 0x3c, 0x31, 0x20,
-		0xd5, 0x0c, 0x88, 0x72, 0x18, 0x16, 0x88, 0x1e,
-		0x4a, 0x0f, 0xe1, 0xcf, 0x95, 0x24,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x72, 0x04, 0x00, 0x00,
-		0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
-		0xe8, 0x4b, 0xde, 0xef, 0xba, 0x3e, 0x18, 0x1c,
-		0x1e, 0x5e, 0xbc, 0x87, 0xf1, 0x87, 0x8d, 0x72,
-		0xe3, 0xbe, 0x0f, 0xdf, 0xfd, 0xd0, 0xb2, 0x89,
-		0xf8, 0x05, 0x9a, 0x52, 0x47, 0x77, 0x9e, 0xe8,
-		0xb1, 0x1d, 0x18, 0xed, 0x6a, 0x4b, 0x63, 0x1d,
-		0xf1, 0x62, 0xd2, 0x65, 0x21, 0x26, 0x73, 0xd4,
-		0x35, 0x5b, 0x95, 0x89, 0x12, 0x59, 0x23, 0x8c,
-		0xc3, 0xfc, 0xf9, 0x4d, 0x21, 0x79, 0xa0, 0xbd,
-		0xff, 0x33, 0xa2, 0x3d, 0x0b, 0x6f, 0x89, 0xc9,
-		0x23, 0xe4, 0xe7, 0x9f, 0x1d, 0x98, 0xf6, 0xed,
-		0x02, 0x8d, 0xac, 0x1a, 0xf9, 0xcb, 0xa5, 0x14,
-		0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
-		0x00, 0x28, 0x91, 0x56, 0x80, 0xe2, 0x6d, 0x51,
-		0x88, 0x03, 0xf8, 0x49, 0xe6, 0x6a, 0x5a, 0xfb,
-		0x2f, 0x0b, 0xb5, 0xa1, 0x0d, 0x63, 0x83, 0xae,
-		0xb9, 0xbc, 0x05, 0xf0, 0x81, 0x00, 0x61, 0x83,
-		0x38, 0xda, 0x14, 0xf6, 0xea, 0xd8, 0x78, 0x65,
-		0xc7, 0x26, 0x17, 0x03, 0x01, 0x00, 0x18, 0x81,
-		0x30, 0x8b, 0x22, 0x5a, 0xd3, 0x7f, 0xc8, 0xf2,
-		0x8a, 0x6b, 0xa3, 0xba, 0x4d, 0xe7, 0x6e, 0xd2,
-		0xfd, 0xbf, 0xf2, 0xc5, 0x28, 0xa0, 0x62, 0x17,
-		0x03, 0x01, 0x00, 0x28, 0x17, 0x83, 0x3c, 0x78,
-		0x18, 0xfa, 0x8d, 0x58, 0x5c, 0xaa, 0x05, 0x7d,
-		0x67, 0x96, 0x11, 0x60, 0x11, 0xc0, 0x1e, 0x0d,
-		0x6a, 0x6e, 0x5f, 0x1d, 0x98, 0x4b, 0xff, 0x82,
-		0xee, 0x21, 0x06, 0x29, 0xd3, 0x8b, 0x80, 0x78,
-		0x39, 0x05, 0x34, 0x9b, 0x15, 0x03, 0x01, 0x00,
-		0x18, 0xa9, 0x38, 0x18, 0x4f, 0x9d, 0x84, 0x75,
-		0x88, 0x53, 0xd6, 0x85, 0xc2, 0x15, 0x4b, 0xe3,
-		0xe3, 0x35, 0x9a, 0x74, 0xc9, 0x3e, 0x13, 0xc1,
-		0x8c,
-	},
+func TestHandshakeServerRSAAES(t *testing.T) {
+	test := &serverTest{
+		name:    "RSA-AES",
+		command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA"},
+	}
+	runServerTestSSLv3(t, test)
+	runServerTestTLS10(t, test)
+	runServerTestTLS12(t, test)
 }
 
-var rsaAESServerScript = [][]byte{
-	{
-		0x16, 0x03, 0x00, 0x00, 0xc5, 0x01, 0x00, 0x00,
-		0xc1, 0x03, 0x03, 0x50, 0xae, 0x5c, 0xe9, 0x5e,
-		0x31, 0x93, 0x82, 0xa5, 0x6f, 0x51, 0x82, 0xc8,
-		0x55, 0x4f, 0x1f, 0x2e, 0x90, 0x98, 0x81, 0x13,
-		0x27, 0x80, 0x68, 0xb4, 0x2d, 0xba, 0x3a, 0x76,
-		0xd8, 0xd7, 0x2c, 0x00, 0x00, 0x50, 0xc0, 0x09,
-		0xc0, 0x23, 0xc0, 0x2b, 0xc0, 0x0a, 0xc0, 0x24,
-		0xc0, 0x2c, 0xc0, 0x08, 0xc0, 0x13, 0xc0, 0x27,
-		0xc0, 0x2f, 0xc0, 0x14, 0xc0, 0x30, 0xc0, 0x12,
-		0x00, 0x33, 0x00, 0x67, 0x00, 0x45, 0x00, 0x9e,
-		0x00, 0x39, 0x00, 0x6b, 0x00, 0x88, 0x00, 0x16,
-		0x00, 0x32, 0x00, 0x40, 0x00, 0x44, 0x00, 0xa2,
-		0x00, 0x38, 0x00, 0x6a, 0x00, 0x87, 0x00, 0x13,
-		0x00, 0x66, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x41,
-		0x00, 0x9c, 0x00, 0x35, 0x00, 0x3d, 0x00, 0x84,
-		0x00, 0x0a, 0x00, 0x05, 0x00, 0x04, 0x01, 0x00,
-		0x00, 0x48, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00,
-		0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00,
-		0x00, 0x23, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c,
-		0x00, 0x0a, 0x00, 0x13, 0x00, 0x15, 0x00, 0x17,
-		0x00, 0x18, 0x00, 0x19, 0x00, 0x0b, 0x00, 0x02,
-		0x01, 0x00, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x1a,
-		0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x05, 0x01,
-		0x05, 0x03, 0x06, 0x01, 0x06, 0x03, 0x03, 0x01,
-		0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02,
-		0x02, 0x03,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
-		0x2c, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00,
-		0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
-		0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
-		0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
-		0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
-		0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
-		0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
-		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-		0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
-		0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
-		0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
-		0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
-		0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
-		0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
-		0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
-		0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
-		0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
-		0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
-		0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
-		0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
-		0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
-		0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
-		0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
-		0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
-		0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
-		0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
-		0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
-		0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
-		0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
-		0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
-		0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
-		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-		0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
-		0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
-		0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
-		0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
-		0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
-		0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
-		0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
-		0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
-		0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
-		0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
-		0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
-		0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
-		0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
-		0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
-		0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
-		0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
-		0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
-		0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
-		0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
-		0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
-		0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
-		0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
-		0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
-		0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
-		0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
-		0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
-		0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
-		0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
-		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
-		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
-		0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
-		0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
-		0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
-		0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
-		0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
-		0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
-		0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
-		0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
-		0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
-		0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-		0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
-		0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
-		0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
-		0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
-		0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
-		0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
-		0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
-		0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
-		0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
-		0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
-		0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
-		0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
-		0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
-		0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
-		0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
-		0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
-		0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
-		0x16, 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00,
-		0x00,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
-		0x82, 0x00, 0x80, 0x51, 0x2e, 0xec, 0x0d, 0x86,
-		0xf3, 0x9f, 0xf2, 0x77, 0x04, 0x27, 0x2b, 0x0e,
-		0x9c, 0xab, 0x35, 0x84, 0x65, 0xff, 0x36, 0xef,
-		0xc0, 0x08, 0xc9, 0x1d, 0x9f, 0x29, 0xae, 0x8d,
-		0xc5, 0x66, 0x81, 0x31, 0x92, 0x5e, 0x3d, 0xac,
-		0xaa, 0x37, 0x28, 0x2c, 0x06, 0x91, 0xa6, 0xc2,
-		0xd0, 0x83, 0x34, 0x24, 0x1c, 0x88, 0xfc, 0x0a,
-		0xcf, 0xbf, 0xc2, 0x94, 0xe2, 0xed, 0xa7, 0x6a,
-		0xa8, 0x8d, 0x3d, 0xf7, 0x06, 0x7d, 0x69, 0xf8,
-		0x0d, 0xb2, 0xf7, 0xe4, 0x45, 0xcb, 0x0a, 0x25,
-		0xcb, 0xb2, 0x2e, 0x38, 0x9a, 0x84, 0x75, 0xe8,
-		0xe1, 0x42, 0x39, 0xa2, 0x18, 0x0e, 0x48, 0xca,
-		0x33, 0x16, 0x4e, 0xf6, 0x2f, 0xec, 0x07, 0xe7,
-		0x57, 0xe1, 0x20, 0x40, 0x40, 0x6d, 0x4e, 0x29,
-		0x04, 0x1a, 0x8c, 0x99, 0xfb, 0x19, 0x3c, 0xaa,
-		0x75, 0x64, 0xd3, 0xa6, 0xe6, 0xed, 0x3f, 0x5a,
-		0xd2, 0xc9, 0x80, 0x14, 0x03, 0x01, 0x00, 0x01,
-		0x01, 0x16, 0x03, 0x01, 0x01, 0x10, 0xe9, 0x9e,
-		0x06, 0x92, 0x18, 0xbf, 0x5e, 0xaf, 0x33, 0xc1,
-		0xbf, 0x0e, 0x12, 0x07, 0x48, 0x4f, 0x6b, 0x6c,
-		0xf5, 0x23, 0x5e, 0x87, 0xa7, 0xd3, 0x50, 0x79,
-		0x38, 0xdc, 0xe0, 0x49, 0xd3, 0x81, 0x21, 0x12,
-		0xd0, 0x3d, 0x9a, 0xfb, 0x83, 0xc1, 0x8b, 0xfc,
-		0x14, 0xd5, 0xd5, 0xa7, 0xa3, 0x34, 0x14, 0x71,
-		0xbe, 0xea, 0x37, 0x18, 0x12, 0x7f, 0x41, 0xfb,
-		0xc5, 0x51, 0x17, 0x9d, 0x96, 0x58, 0x14, 0xfb,
-		0x4f, 0xd7, 0xd3, 0x15, 0x0f, 0xec, 0x5a, 0x0d,
-		0x35, 0xbb, 0x3c, 0x81, 0x5b, 0x3f, 0xdf, 0x52,
-		0xa4, 0x4c, 0xcd, 0x13, 0xe1, 0x10, 0x37, 0x34,
-		0xbf, 0xb4, 0x80, 0x1e, 0x8d, 0xe2, 0xc3, 0x7a,
-		0x0f, 0x7b, 0x7d, 0x23, 0xeb, 0xd0, 0x99, 0x69,
-		0xad, 0x0a, 0x2d, 0xb3, 0x6c, 0xd6, 0x80, 0x11,
-		0x7f, 0x6c, 0xed, 0x1b, 0xcd, 0x08, 0x22, 0x56,
-		0x90, 0x0e, 0xa4, 0xc3, 0x29, 0x33, 0x96, 0x30,
-		0x34, 0x94, 0xa1, 0xeb, 0x9c, 0x1b, 0x5a, 0xd1,
-		0x03, 0x61, 0xf9, 0xdd, 0xf3, 0x64, 0x8a, 0xfd,
-		0x5f, 0x44, 0xdb, 0x2e, 0xa7, 0xfd, 0xe1, 0x1a,
-		0x66, 0xc5, 0x01, 0x9c, 0xc7, 0xd1, 0xc4, 0xd3,
-		0xea, 0x14, 0x3c, 0xed, 0x74, 0xbb, 0x1b, 0x97,
-		0x8f, 0xf1, 0x29, 0x39, 0x33, 0x92, 0x93, 0x4e,
-		0xf5, 0x87, 0x91, 0x61, 0x65, 0x8d, 0x27, 0x8d,
-		0x76, 0xc1, 0xfa, 0x6a, 0x99, 0x80, 0xb1, 0x9b,
-		0x29, 0x53, 0xce, 0x3e, 0xb6, 0x9a, 0xce, 0x3c,
-		0x19, 0x5e, 0x48, 0x83, 0xaa, 0xa7, 0x66, 0x98,
-		0x59, 0xf4, 0xbb, 0xf2, 0xbc, 0xd9, 0xc5, 0x9a,
-		0xc8, 0x2c, 0x63, 0x58, 0xd5, 0xd4, 0xbc, 0x03,
-		0xa9, 0x06, 0xa9, 0x80, 0x0d, 0xb3, 0x46, 0x2d,
-		0xe3, 0xc6, 0xaf, 0x1a, 0x39, 0x18, 0x7e, 0x1e,
-		0x83, 0x80, 0x46, 0x11, 0xd2, 0x13, 0x9f, 0xda,
-		0xfc, 0x2d, 0x42, 0xaa, 0x5a, 0x1d, 0x4c, 0x31,
-		0xe5, 0x58, 0x78, 0x5e, 0xe2, 0x04, 0xd6, 0x23,
-		0x7f, 0x3f, 0x06, 0xc0, 0x54, 0xf8,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x72, 0x04, 0x00, 0x00,
-		0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
-		0xe8, 0x4b, 0xfb, 0xef, 0xba, 0xed, 0xc5, 0x36,
-		0xc8, 0x5a, 0x41, 0x3f, 0x05, 0xfa, 0xfe, 0x48,
-		0xc3, 0x91, 0x12, 0x8b, 0xe8, 0x32, 0x6a, 0x9f,
-		0xdc, 0x97, 0xe2, 0x77, 0xb9, 0x96, 0x2d, 0xd4,
-		0xe5, 0xbd, 0xa1, 0xfd, 0x94, 0xbb, 0x74, 0x63,
-		0xb1, 0x0c, 0x38, 0xbc, 0x6f, 0x69, 0xaf, 0xa3,
-		0x46, 0x9c, 0x96, 0x41, 0xde, 0x59, 0x23, 0xff,
-		0x15, 0x6b, 0x3a, 0xef, 0x91, 0x6d, 0x92, 0x44,
-		0xdc, 0x72, 0x1f, 0x40, 0x3d, 0xb5, 0x34, 0x8f,
-		0x2a, 0xac, 0x21, 0x69, 0x05, 0x6f, 0xb2, 0x60,
-		0x32, 0x5d, 0x3d, 0x97, 0xb4, 0x24, 0x99, 0x14,
-		0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
-		0x00, 0x30, 0x68, 0x27, 0x97, 0xca, 0x63, 0x09,
-		0x22, 0xed, 0x0e, 0x61, 0x7c, 0x76, 0x31, 0x9c,
-		0xbe, 0x27, 0xc9, 0xe6, 0x09, 0xc3, 0xc3, 0xc2,
-		0xf4, 0xa2, 0x32, 0xba, 0x7c, 0xf2, 0x0f, 0xb8,
-		0x3d, 0xcb, 0xe2, 0x4c, 0xc0, 0x7d, 0x8e, 0x5b,
-		0x5a, 0xed, 0x05, 0x5c, 0x15, 0x96, 0x69, 0xc2,
-		0x6f, 0x5f, 0x17, 0x03, 0x01, 0x00, 0x20, 0x5a,
-		0xfe, 0x0b, 0xe1, 0x6f, 0xa8, 0x54, 0x19, 0x78,
-		0xca, 0xba, 0x2e, 0x1e, 0x2e, 0xe1, 0x5d, 0x17,
-		0xe5, 0x97, 0x05, 0x2c, 0x08, 0x0c, 0xff, 0xa8,
-		0x59, 0xa9, 0xde, 0x5e, 0x21, 0x34, 0x04, 0x17,
-		0x03, 0x01, 0x00, 0x30, 0x86, 0xb1, 0x3f, 0x88,
-		0x43, 0xf0, 0x07, 0xee, 0xa8, 0xf4, 0xbc, 0xe7,
-		0x5f, 0xc6, 0x8c, 0x86, 0x4c, 0xca, 0x70, 0x88,
-		0xcc, 0x6a, 0xb4, 0x3d, 0x40, 0xe8, 0x54, 0x89,
-		0x19, 0x43, 0x1f, 0x76, 0xe2, 0xac, 0xb2, 0x5b,
-		0x92, 0xf8, 0x57, 0x39, 0x2a, 0xc3, 0x6d, 0x13,
-		0x45, 0xfa, 0x36, 0x9e, 0x15, 0x03, 0x01, 0x00,
-		0x20, 0x6d, 0xed, 0x7b, 0x59, 0x28, 0x2a, 0x27,
-		0x04, 0x15, 0x07, 0x4e, 0xeb, 0x13, 0x00, 0xe3,
-		0x3a, 0x3f, 0xf8, 0xaa, 0x2b, 0x3b, 0x1a, 0x8c,
-		0x12, 0xd6, 0x4c, 0xec, 0x2a, 0xaf, 0x33, 0x60,
-		0xaf,
-	},
+func TestHandshakeServerAESGCM(t *testing.T) {
+	test := &serverTest{
+		name:    "RSA-AES-GCM",
+		command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-AES128-GCM-SHA256"},
+	}
+	runServerTestTLS12(t, test)
 }
 
-// Generated using:
-// $ go test -test.run TestRunServer -serve -ciphersuites=0xc00a
-// $ openssl s_client -host 127.0.0.1 -port 10443 -cipher ECDHE-ECDSA-AES256-SHA
-var ecdheECDSAAESServerScript = [][]byte{
-	{
-		0x16, 0x03, 0x01, 0x00, 0xa0, 0x01, 0x00, 0x00,
-		0x9c, 0x03, 0x03, 0x50, 0xd7, 0x18, 0x31, 0x49,
-		0xde, 0x19, 0x8d, 0x08, 0x5c, 0x4b, 0x60, 0x67,
-		0x0f, 0xfe, 0xd0, 0x62, 0xf9, 0x31, 0x48, 0x17,
-		0x9e, 0x50, 0xc1, 0xd8, 0x35, 0x24, 0x0e, 0xa6,
-		0x09, 0x06, 0x51, 0x00, 0x00, 0x04, 0xc0, 0x0a,
-		0x00, 0xff, 0x01, 0x00, 0x00, 0x6f, 0x00, 0x0b,
-		0x00, 0x04, 0x03, 0x00, 0x01, 0x02, 0x00, 0x0a,
-		0x00, 0x34, 0x00, 0x32, 0x00, 0x0e, 0x00, 0x0d,
-		0x00, 0x19, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x18,
-		0x00, 0x09, 0x00, 0x0a, 0x00, 0x16, 0x00, 0x17,
-		0x00, 0x08, 0x00, 0x06, 0x00, 0x07, 0x00, 0x14,
-		0x00, 0x15, 0x00, 0x04, 0x00, 0x05, 0x00, 0x12,
-		0x00, 0x13, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03,
-		0x00, 0x0f, 0x00, 0x10, 0x00, 0x11, 0x00, 0x23,
-		0x00, 0x00, 0x00, 0x0d, 0x00, 0x22, 0x00, 0x20,
-		0x06, 0x01, 0x06, 0x02, 0x06, 0x03, 0x05, 0x01,
-		0x05, 0x02, 0x05, 0x03, 0x04, 0x01, 0x04, 0x02,
-		0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03,
-		0x02, 0x01, 0x02, 0x02, 0x02, 0x03, 0x01, 0x01,
-		0x00, 0x0f, 0x00, 0x01, 0x01,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
-		0x2c, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0xc0, 0x0a, 0x00, 0x00,
-		0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
-		0x02, 0x0e, 0x0b, 0x00, 0x02, 0x0a, 0x00, 0x02,
-		0x07, 0x00, 0x02, 0x04, 0x30, 0x82, 0x02, 0x00,
-		0x30, 0x82, 0x01, 0x62, 0x02, 0x09, 0x00, 0xb8,
-		0xbf, 0x2d, 0x47, 0xa0, 0xd2, 0xeb, 0xf4, 0x30,
-		0x09, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d,
-		0x04, 0x01, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
-		0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
-		0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
-		0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
-		0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
-		0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
-		0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
-		0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
-		0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
-		0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x31,
-		0x31, 0x32, 0x32, 0x31, 0x35, 0x30, 0x36, 0x33,
-		0x32, 0x5a, 0x17, 0x0d, 0x32, 0x32, 0x31, 0x31,
-		0x32, 0x30, 0x31, 0x35, 0x30, 0x36, 0x33, 0x32,
-		0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06,
-		0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55,
-		0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
-		0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d,
-		0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30,
-		0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18,
-		0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
-		0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73,
-		0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64,
-		0x30, 0x81, 0x9b, 0x30, 0x10, 0x06, 0x07, 0x2a,
-		0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05,
-		0x2b, 0x81, 0x04, 0x00, 0x23, 0x03, 0x81, 0x86,
-		0x00, 0x04, 0x00, 0xc4, 0xa1, 0xed, 0xbe, 0x98,
-		0xf9, 0x0b, 0x48, 0x73, 0x36, 0x7e, 0xc3, 0x16,
-		0x56, 0x11, 0x22, 0xf2, 0x3d, 0x53, 0xc3, 0x3b,
-		0x4d, 0x21, 0x3d, 0xcd, 0x6b, 0x75, 0xe6, 0xf6,
-		0xb0, 0xdc, 0x9a, 0xdf, 0x26, 0xc1, 0xbc, 0xb2,
-		0x87, 0xf0, 0x72, 0x32, 0x7c, 0xb3, 0x64, 0x2f,
-		0x1c, 0x90, 0xbc, 0xea, 0x68, 0x23, 0x10, 0x7e,
-		0xfe, 0xe3, 0x25, 0xc0, 0x48, 0x3a, 0x69, 0xe0,
-		0x28, 0x6d, 0xd3, 0x37, 0x00, 0xef, 0x04, 0x62,
-		0xdd, 0x0d, 0xa0, 0x9c, 0x70, 0x62, 0x83, 0xd8,
-		0x81, 0xd3, 0x64, 0x31, 0xaa, 0x9e, 0x97, 0x31,
-		0xbd, 0x96, 0xb0, 0x68, 0xc0, 0x9b, 0x23, 0xde,
-		0x76, 0x64, 0x3f, 0x1a, 0x5c, 0x7f, 0xe9, 0x12,
-		0x0e, 0x58, 0x58, 0xb6, 0x5f, 0x70, 0xdd, 0x9b,
-		0xd8, 0xea, 0xd5, 0xd7, 0xf5, 0xd5, 0xcc, 0xb9,
-		0xb6, 0x9f, 0x30, 0x66, 0x5b, 0x66, 0x9a, 0x20,
-		0xe2, 0x27, 0xe5, 0xbf, 0xfe, 0x3b, 0x30, 0x09,
-		0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04,
-		0x01, 0x03, 0x81, 0x8c, 0x00, 0x30, 0x81, 0x88,
-		0x02, 0x42, 0x01, 0x88, 0xa2, 0x4f, 0xeb, 0xe2,
-		0x45, 0xc5, 0x48, 0x7d, 0x1b, 0xac, 0xf5, 0xed,
-		0x98, 0x9d, 0xae, 0x47, 0x70, 0xc0, 0x5e, 0x1b,
-		0xb6, 0x2f, 0xbd, 0xf1, 0xb6, 0x4d, 0xb7, 0x61,
-		0x40, 0xd3, 0x11, 0xa2, 0xce, 0xee, 0x0b, 0x7e,
-		0x92, 0x7e, 0xff, 0x76, 0x9d, 0xc3, 0x3b, 0x7e,
-		0xa5, 0x3f, 0xce, 0xfa, 0x10, 0xe2, 0x59, 0xec,
-		0x47, 0x2d, 0x7c, 0xac, 0xda, 0x4e, 0x97, 0x0e,
-		0x15, 0xa0, 0x6f, 0xd0, 0x02, 0x42, 0x01, 0x4d,
-		0xfc, 0xbe, 0x67, 0x13, 0x9c, 0x2d, 0x05, 0x0e,
-		0xbd, 0x3f, 0xa3, 0x8c, 0x25, 0xc1, 0x33, 0x13,
-		0x83, 0x0d, 0x94, 0x06, 0xbb, 0xd4, 0x37, 0x7a,
-		0xf6, 0xec, 0x7a, 0xc9, 0x86, 0x2e, 0xdd, 0xd7,
-		0x11, 0x69, 0x7f, 0x85, 0x7c, 0x56, 0xde, 0xfb,
-		0x31, 0x78, 0x2b, 0xe4, 0xc7, 0x78, 0x0d, 0xae,
-		0xcb, 0xbe, 0x9e, 0x4e, 0x36, 0x24, 0x31, 0x7b,
-		0x6a, 0x0f, 0x39, 0x95, 0x12, 0x07, 0x8f, 0x2a,
-		0x16, 0x03, 0x01, 0x01, 0x1a, 0x0c, 0x00, 0x01,
-		0x16, 0x03, 0x00, 0x19, 0x85, 0x04, 0x01, 0x39,
-		0xdc, 0xee, 0x44, 0x17, 0x5e, 0xdb, 0xd7, 0x27,
-		0xaf, 0xb6, 0x56, 0xd9, 0xb4, 0x43, 0x5a, 0x99,
-		0xcf, 0xaa, 0x31, 0x37, 0x0c, 0x6f, 0x3a, 0xa0,
-		0xf8, 0x53, 0xc4, 0x74, 0xd1, 0x91, 0x0a, 0x46,
-		0xf5, 0x38, 0x3b, 0x5c, 0x09, 0xd8, 0x97, 0xdc,
-		0x4b, 0xaa, 0x70, 0x26, 0x48, 0xf2, 0xd6, 0x0b,
-		0x31, 0xc9, 0xf8, 0xd4, 0x98, 0x43, 0xe1, 0x6c,
-		0xd5, 0xc7, 0xb2, 0x8e, 0x0b, 0x01, 0xe6, 0xb6,
-		0x00, 0x28, 0x80, 0x7b, 0xfc, 0x96, 0x8f, 0x0d,
-		0xa2, 0x4f, 0xb0, 0x79, 0xaf, 0xdc, 0x61, 0x28,
-		0x63, 0x33, 0x78, 0xf6, 0x31, 0x39, 0xfd, 0x8a,
-		0xf4, 0x15, 0x18, 0x11, 0xfe, 0xdb, 0xd5, 0x07,
-		0xda, 0x2c, 0xed, 0x49, 0xa0, 0x23, 0xbf, 0xd0,
-		0x3a, 0x38, 0x1d, 0x54, 0xae, 0x1c, 0x7b, 0xea,
-		0x29, 0xee, 0xd0, 0x38, 0xc1, 0x76, 0xa7, 0x7f,
-		0x2a, 0xf4, 0xce, 0x1e, 0xac, 0xcc, 0x94, 0x79,
-		0x90, 0x33, 0x00, 0x8b, 0x30, 0x81, 0x88, 0x02,
-		0x42, 0x00, 0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04,
-		0x04, 0xe9, 0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23,
-		0x95, 0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x05,
-		0x3f, 0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b,
-		0x4d, 0x3d, 0xba, 0xa1, 0x4b, 0x5e, 0x77, 0xef,
-		0xe7, 0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2,
-		0xff, 0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85,
-		0x6a, 0x42, 0x9b, 0xf9, 0x7e, 0x7e, 0x31, 0xc2,
-		0xe5, 0xbd, 0x66, 0x02, 0x42, 0x00, 0xad, 0x7d,
-		0x06, 0x35, 0xab, 0xec, 0x8d, 0xac, 0xd4, 0xba,
-		0x1b, 0x49, 0x5e, 0x05, 0x5f, 0xf0, 0x97, 0x93,
-		0x82, 0xb8, 0x2b, 0x8d, 0x91, 0x98, 0x63, 0x8e,
-		0xb4, 0x14, 0x62, 0xdb, 0x1e, 0xc9, 0x2b, 0x30,
-		0xf8, 0x41, 0x9b, 0xa6, 0xe6, 0xbc, 0xde, 0x0e,
-		0x68, 0x30, 0x22, 0x50, 0xe6, 0x98, 0x97, 0x7b,
-		0x69, 0xf7, 0x93, 0xed, 0xcd, 0x19, 0x2f, 0x44,
-		0x6c, 0x2e, 0xdf, 0x25, 0xee, 0xcc, 0x46, 0x16,
-		0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x8a, 0x10, 0x00, 0x00,
-		0x86, 0x85, 0x04, 0x00, 0x1c, 0xc5, 0xe8, 0xb3,
-		0x42, 0xb4, 0xad, 0xca, 0x45, 0xcd, 0x42, 0x7b,
-		0xfb, 0x0c, 0xea, 0x32, 0x26, 0xd4, 0x8a, 0xef,
-		0xdf, 0xc9, 0xff, 0xd2, 0xe0, 0x36, 0xea, 0x4e,
-		0xbb, 0x3e, 0xf4, 0x9c, 0x76, 0x4f, 0x44, 0xbd,
-		0x84, 0x72, 0xdd, 0xcb, 0xe5, 0x28, 0x8d, 0x31,
-		0x72, 0x3b, 0xd3, 0xf2, 0x9a, 0x13, 0xfb, 0x8a,
-		0xa7, 0x72, 0xca, 0x21, 0x6c, 0xea, 0xbf, 0xe9,
-		0x8c, 0x0a, 0xcc, 0x8f, 0xd6, 0x00, 0x20, 0x87,
-		0xf3, 0x7d, 0x18, 0xc5, 0xfd, 0x9e, 0xdd, 0x6b,
-		0x06, 0xdc, 0x52, 0xeb, 0x14, 0xc0, 0x67, 0x5a,
-		0x06, 0xd8, 0x98, 0x19, 0x14, 0xe7, 0xd4, 0x36,
-		0x32, 0xee, 0xb7, 0xfa, 0xe2, 0x85, 0x4a, 0x16,
-		0x42, 0x0c, 0xa6, 0x21, 0xcf, 0x1f, 0xae, 0x10,
-		0x8b, 0x28, 0x32, 0x19, 0xa4, 0x0a, 0xd7, 0xce,
-		0xe6, 0xe1, 0x93, 0xfb, 0x5f, 0x08, 0x8b, 0x42,
-		0xa2, 0x20, 0xed, 0x0d, 0x62, 0xca, 0xed, 0x14,
-		0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
-		0x00, 0x30, 0x2e, 0x33, 0xc0, 0x57, 0x6c, 0xb4,
-		0x1b, 0xd2, 0x63, 0xe8, 0x67, 0x10, 0x2d, 0x87,
-		0x71, 0x6e, 0x19, 0x60, 0xf4, 0xa4, 0x10, 0x52,
-		0x73, 0x2d, 0x09, 0x5e, 0xdb, 0x6c, 0xdc, 0xcf,
-		0x2d, 0xff, 0x03, 0x11, 0x95, 0x76, 0x90, 0xd7,
-		0x87, 0x54, 0x43, 0xed, 0xc2, 0x36, 0x69, 0x14,
-		0x72, 0x4a,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x72, 0x04, 0x00, 0x00,
-		0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
-		0xe8, 0x8b, 0xde, 0xef, 0xba, 0xc5, 0x7e, 0x04,
-		0xab, 0xfd, 0x79, 0x56, 0xf3, 0xe1, 0xa5, 0x3e,
-		0x02, 0xdf, 0x69, 0x6d, 0x1f, 0x41, 0x9f, 0xbc,
-		0x93, 0xe2, 0x6c, 0xf1, 0xb1, 0x38, 0xf5, 0x2b,
-		0x8c, 0x4c, 0xf4, 0x74, 0xe1, 0x79, 0x35, 0x34,
-		0x97, 0x9b, 0xd5, 0xba, 0xfd, 0xf7, 0x2f, 0x2d,
-		0x9e, 0x84, 0x54, 0xee, 0x77, 0x59, 0x23, 0x8f,
-		0xc8, 0x84, 0xb4, 0xd6, 0xea, 0x4c, 0x44, 0x8a,
-		0xc6, 0x9c, 0xf9, 0x9b, 0x27, 0xea, 0x4f, 0x28,
-		0x72, 0x33, 0x12, 0x20, 0x7c, 0xd7, 0x3f, 0x56,
-		0xa6, 0x76, 0xc7, 0x48, 0xe4, 0x2d, 0x6f, 0x14,
-		0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
-		0x00, 0x30, 0x36, 0xe3, 0xd4, 0xf7, 0xb1, 0x69,
-		0x18, 0x8d, 0x09, 0xba, 0x52, 0x1e, 0xd5, 0x7d,
-		0x2c, 0x15, 0x3a, 0xd6, 0xe3, 0x99, 0x30, 0x2c,
-		0x99, 0x97, 0xbc, 0x19, 0x3c, 0x63, 0xa1, 0x25,
-		0x68, 0xbc, 0x8a, 0x16, 0x47, 0xec, 0xae, 0x13,
-		0xa4, 0x03, 0x96, 0x29, 0x11, 0x92, 0x90, 0x1a,
-		0xc8, 0xa4, 0x17, 0x03, 0x01, 0x00, 0x20, 0xc1,
-		0x10, 0x1d, 0xa6, 0xf1, 0xe2, 0x8a, 0xcc, 0x37,
-		0x7d, 0x8e, 0x05, 0x00, 0xfb, 0xd1, 0x9f, 0xc7,
-		0x11, 0xd2, 0x00, 0xb4, 0x27, 0x0a, 0x25, 0x14,
-		0xd9, 0x79, 0x1b, 0xcb, 0x4d, 0x81, 0x61, 0x17,
-		0x03, 0x01, 0x00, 0x30, 0x5c, 0x7c, 0x2d, 0xc0,
-		0x9e, 0xa6, 0xc4, 0x8e, 0xfd, 0xf4, 0xe2, 0xe5,
-		0xe4, 0xe6, 0x56, 0x9f, 0x7d, 0x4c, 0x4c, 0x2d,
-		0xb7, 0xa9, 0xac, 0xfa, 0x9f, 0x12, 0x7f, 0x2d,
-		0x30, 0x57, 0xe4, 0x8e, 0x30, 0x86, 0x65, 0x59,
-		0xcd, 0x24, 0xda, 0xe2, 0x8a, 0x7b, 0x0c, 0x5e,
-		0x86, 0x05, 0x06, 0x2a, 0x15, 0x03, 0x01, 0x00,
-		0x20, 0xd6, 0xb7, 0x70, 0xf8, 0x47, 0xbc, 0x0f,
-		0xf4, 0x66, 0x98, 0x1b, 0x1e, 0x8a, 0x8c, 0x0b,
-		0xa1, 0x4a, 0x04, 0x29, 0x60, 0x72, 0x8b, 0xc4,
-		0x73, 0xc1, 0xd6, 0x41, 0x72, 0xb7, 0x17, 0x39,
-		0xda,
-	},
-}
+func TestHandshakeServerECDHEECDSAAES(t *testing.T) {
+	config := *testConfig
+	config.Certificates = make([]Certificate, 1)
+	config.Certificates[0].Certificate = [][]byte{testECDSACertificate}
+	config.Certificates[0].PrivateKey = testECDSAPrivateKey
+	config.BuildNameToCertificate()
 
-var sslv3ServerScript = [][]byte{
-	{
-		0x16, 0x03, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00,
-		0x50, 0x03, 0x00, 0x50, 0x77, 0x3d, 0x42, 0xae,
-		0x84, 0xbd, 0xc5, 0x07, 0xa5, 0xc4, 0xd6, 0x16,
-		0x4e, 0xd5, 0xc5, 0xfa, 0x02, 0x7a, 0x0f, 0x1d,
-		0xc1, 0xe1, 0xaa, 0xe3, 0x3b, 0x4b, 0x6f, 0x11,
-		0xfa, 0x1a, 0xa4, 0x00, 0x00, 0x28, 0x00, 0x39,
-		0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13,
-		0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f,
-		0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
-		0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08,
-		0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01,
-		0x00,
-	},
-	{
-		0x16, 0x03, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00,
-		0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16,
-		0x03, 0x00, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba,
-		0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82,
-		0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03,
-		0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0,
-		0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d,
-		0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
-		0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
-		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
-		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
-		0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
-		0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
-		0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
-		0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
-		0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
-		0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
-		0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
-		0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31,
-		0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30,
-		0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b,
-		0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
-		0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
-		0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
-		0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
-		0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
-		0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
-		0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
-		0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
-		0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d,
-		0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
-		0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
-		0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
-		0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf,
-		0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b,
-		0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a,
-		0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65,
-		0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4,
-		0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62,
-		0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c,
-		0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58,
-		0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0,
-		0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f,
-		0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18,
-		0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1,
-		0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9,
-		0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01,
-		0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d,
-		0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79,
-		0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7,
-		0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55,
-		0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad,
-		0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69,
-		0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18,
-		0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d,
-		0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1,
-		0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
-		0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
-		0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30,
-		0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
-		0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
-		0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
-		0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
-		0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
-		0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
-		0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
-		0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
-		0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09,
-		0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8,
-		0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
-		0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
-		0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
-		0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
-		0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b,
-		0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0,
-		0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5,
-		0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae,
-		0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e,
-		0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5,
-		0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30,
-		0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7,
-		0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78,
-		0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d,
-		0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75,
-		0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd,
-		0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c,
-		0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57,
-		0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b,
-		0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7,
-		0xbd, 0xd9, 0x16, 0x03, 0x00, 0x00, 0x04, 0x0e,
-		0x00, 0x00, 0x00,
-	},
-	{
-		0x16, 0x03, 0x00, 0x00, 0x84, 0x10, 0x00, 0x00,
-		0x80, 0x4a, 0x8d, 0xc4, 0x38, 0x7a, 0x9c, 0xd6,
-		0xe8, 0x72, 0x9e, 0xa3, 0xdf, 0x37, 0xb4, 0x6c,
-		0x58, 0x33, 0x59, 0xd9, 0xc9, 0x4b, 0x50, 0x33,
-		0x6c, 0xed, 0x73, 0x38, 0x2a, 0x46, 0x55, 0x31,
-		0xa9, 0x8e, 0x8e, 0xfc, 0x0b, 0x5d, 0x5f, 0x3c,
-		0x88, 0x28, 0x3f, 0x60, 0x51, 0x13, 0xf1, 0x59,
-		0x0c, 0xa3, 0x5e, 0xe0, 0xa3, 0x35, 0x06, 0xb1,
-		0x71, 0x59, 0x24, 0x4e, 0xed, 0x07, 0x15, 0x88,
-		0x50, 0xef, 0xc2, 0xb2, 0x2a, 0x52, 0x30, 0x6a,
-		0x7c, 0xbe, 0x2f, 0xc6, 0x8f, 0xa8, 0x83, 0xc5,
-		0x80, 0x14, 0x62, 0x74, 0x7f, 0x96, 0x9f, 0x41,
-		0x32, 0x74, 0xdd, 0x76, 0x2d, 0x7b, 0xeb, 0x7b,
-		0xea, 0xd0, 0x4f, 0x0c, 0xcf, 0x9a, 0x9c, 0xc5,
-		0x7a, 0xe4, 0xbc, 0xf8, 0xa6, 0xe1, 0x09, 0x8e,
-		0x7c, 0x53, 0x3a, 0xe3, 0x30, 0x8f, 0x76, 0xee,
-		0x58, 0xbb, 0xfd, 0x0b, 0x06, 0xb8, 0xdf, 0xb7,
-		0x31, 0x14, 0x03, 0x00, 0x00, 0x01, 0x01, 0x16,
-		0x03, 0x00, 0x00, 0x3c, 0x13, 0x91, 0xc6, 0x4a,
-		0x0c, 0x59, 0x25, 0xce, 0x54, 0xc0, 0x1d, 0xb9,
-		0x2a, 0xff, 0x4d, 0xca, 0x26, 0x0c, 0x8c, 0x04,
-		0x98, 0x7c, 0x7c, 0x38, 0xa3, 0xf5, 0xf9, 0x36,
-		0x1c, 0x04, 0x32, 0x47, 0x2d, 0x48, 0x0e, 0x96,
-		0xe8, 0x2b, 0x5e, 0x5a, 0xc6, 0x0a, 0x48, 0x41,
-		0x34, 0x5e, 0x62, 0xd5, 0x68, 0x4e, 0x44, 0x1d,
-		0xb2, 0xa1, 0x11, 0xad, 0x6e, 0x14, 0x85, 0x61,
-	},
-	{
-		0x14, 0x03, 0x00, 0x00, 0x01, 0x01, 0x16, 0x03,
-		0x00, 0x00, 0x3c, 0x88, 0xae, 0xa9, 0xd4, 0xa8,
-		0x10, 0x8d, 0x65, 0xa6, 0x3e, 0x1e, 0xed, 0xd2,
-		0xfc, 0xc4, 0x7c, 0xa8, 0x94, 0x4f, 0x11, 0xaf,
-		0xa6, 0x87, 0x09, 0x37, 0x54, 0xf7, 0x69, 0xd1,
-		0xb5, 0x25, 0x6b, 0xb5, 0xed, 0xcb, 0x25, 0x39,
-		0x73, 0xeb, 0x53, 0x6c, 0xc7, 0xb4, 0x29, 0x8f,
-		0xd6, 0x49, 0xd1, 0x95, 0x59, 0x80, 0x9a, 0x67,
-		0x5c, 0xb2, 0xe0, 0xbd, 0x1e, 0xff, 0xaa, 0x17,
-		0x03, 0x00, 0x00, 0x21, 0x65, 0x7b, 0x99, 0x09,
-		0x02, 0xc3, 0x9d, 0x54, 0xd6, 0xe7, 0x32, 0x62,
-		0xab, 0xc1, 0x09, 0x91, 0x30, 0x0a, 0xc9, 0xfa,
-		0x70, 0xec, 0x06, 0x7b, 0xa3, 0xe1, 0x5f, 0xb4,
-		0x63, 0xe6, 0x5c, 0xba, 0x1f, 0x15, 0x03, 0x00,
-		0x00, 0x16, 0x40, 0x70, 0xbe, 0xe6, 0xa6, 0xee,
-		0x8f, 0xd0, 0x87, 0xa0, 0x43, 0xa1, 0x92, 0xd7,
-		0xd0, 0x1a, 0x0c, 0x20, 0x7c, 0xbf, 0xa2, 0xb5,
-	},
+	test := &serverTest{
+		name:    "ECDHE-ECDSA-AES",
+		command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-ECDSA-AES256-SHA"},
+		config:  &config,
+	}
+	runServerTestTLS10(t, test)
+	runServerTestTLS12(t, test)
 }
 
-var selectCertificateBySNIScript = [][]byte{
-	{
-		0x16, 0x03, 0x01, 0x00, 0x6a, 0x01, 0x00, 0x00,
-		0x66, 0x03, 0x01, 0x50, 0x77, 0x3d, 0xfe, 0xfb,
-		0x8d, 0xc2, 0x68, 0xeb, 0xf9, 0xfa, 0x54, 0x97,
-		0x86, 0x45, 0xa2, 0xa3, 0xed, 0xb1, 0x91, 0xb8,
-		0x28, 0xc0, 0x47, 0xaf, 0xfb, 0xcd, 0xdc, 0x0e,
-		0xb3, 0xea, 0xa5, 0x00, 0x00, 0x28, 0x00, 0x39,
-		0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13,
-		0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f,
-		0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
-		0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08,
-		0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01,
-		0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00,
-		0x0e, 0x00, 0x00, 0x0b, 0x73, 0x6e, 0x69, 0x74,
-		0x65, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
-		0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16,
-		0x03, 0x01, 0x02, 0x00, 0x0b, 0x00, 0x01, 0xfc,
-		0x00, 0x01, 0xf9, 0x00, 0x01, 0xf6, 0x30, 0x82,
-		0x01, 0xf2, 0x30, 0x82, 0x01, 0x5d, 0xa0, 0x03,
-		0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x30, 0x0b,
-		0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
-		0x01, 0x01, 0x05, 0x30, 0x28, 0x31, 0x10, 0x30,
-		0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07,
-		0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f, 0x31,
-		0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x03,
-		0x13, 0x0b, 0x73, 0x6e, 0x69, 0x74, 0x65, 0x73,
-		0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17,
-		0x0d, 0x31, 0x32, 0x30, 0x34, 0x31, 0x31, 0x31,
-		0x37, 0x34, 0x30, 0x33, 0x35, 0x5a, 0x17, 0x0d,
-		0x31, 0x33, 0x30, 0x34, 0x31, 0x31, 0x31, 0x37,
-		0x34, 0x35, 0x33, 0x35, 0x5a, 0x30, 0x28, 0x31,
-		0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a,
-		0x13, 0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43,
-		0x6f, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55,
-		0x04, 0x03, 0x13, 0x0b, 0x73, 0x6e, 0x69, 0x74,
-		0x65, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30,
-		0x81, 0x9d, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86,
-		0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x03,
-		0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81,
-		0x81, 0x00, 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5,
-		0xe5, 0xbf, 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe,
-		0xe6, 0x2b, 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d,
-		0x8a, 0x7a, 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7,
-		0xa5, 0x65, 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c,
-		0xb5, 0xb4, 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b,
-		0x7e, 0x62, 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe,
-		0x12, 0x5c, 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf,
-		0xfa, 0x58, 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04,
-		0xd3, 0xd0, 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4,
-		0x54, 0x9f, 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00,
-		0xfe, 0x18, 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d,
-		0x7d, 0xf1, 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb,
-		0x51, 0xc9, 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32,
-		0x66, 0x01, 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71,
-		0x9a, 0x1d, 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda,
-		0x2d, 0x79, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
-		0x32, 0x30, 0x30, 0x30, 0x0e, 0x06, 0x03, 0x55,
-		0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
-		0x02, 0x00, 0xa0, 0x30, 0x0d, 0x06, 0x03, 0x55,
-		0x1d, 0x0e, 0x04, 0x06, 0x04, 0x04, 0x01, 0x02,
-		0x03, 0x04, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d,
-		0x23, 0x04, 0x08, 0x30, 0x06, 0x80, 0x04, 0x01,
-		0x02, 0x03, 0x04, 0x30, 0x0b, 0x06, 0x09, 0x2a,
-		0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
-		0x03, 0x81, 0x81, 0x00, 0x89, 0xc6, 0x45, 0x5f,
-		0x1c, 0x1f, 0x5e, 0xf8, 0xeb, 0x1a, 0xb1, 0x74,
-		0xee, 0x24, 0x39, 0x05, 0x9f, 0x5c, 0x42, 0x59,
-		0xbb, 0x1a, 0x8d, 0x86, 0xcd, 0xb1, 0xd0, 0x56,
-		0xf5, 0x6a, 0x71, 0x7d, 0xa4, 0x0e, 0x95, 0xab,
-		0x90, 0xf5, 0x9e, 0x8d, 0xea, 0xf6, 0x27, 0xc1,
-		0x57, 0x99, 0x50, 0x94, 0xdb, 0x08, 0x02, 0x26,
-		0x6e, 0xb3, 0x4f, 0xc6, 0x84, 0x2d, 0xea, 0x8a,
-		0x4b, 0x68, 0xd9, 0xc1, 0x38, 0x91, 0x03, 0xab,
-		0x84, 0xfb, 0x9e, 0x1f, 0x85, 0xd9, 0xb5, 0xd2,
-		0x3f, 0xf2, 0x31, 0x2c, 0x86, 0x70, 0xfb, 0xb5,
-		0x40, 0x14, 0x82, 0x45, 0xa4, 0xeb, 0xaf, 0xe2,
-		0x64, 0xd9, 0x0c, 0x8a, 0x4c, 0xf4, 0xf8, 0x5b,
-		0x0f, 0xac, 0x12, 0xac, 0x2f, 0xc4, 0xa3, 0x15,
-		0x4b, 0xad, 0x52, 0x46, 0x28, 0x68, 0xaf, 0x96,
-		0xc6, 0x2c, 0x65, 0x25, 0xd6, 0x52, 0xb6, 0xe3,
-		0x18, 0x45, 0xbd, 0xcc, 0x16, 0x03, 0x01, 0x00,
-		0x04, 0x0e, 0x00, 0x00, 0x00,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
-		0x82, 0x00, 0x80, 0x69, 0xc3, 0xd4, 0x0e, 0xcc,
-		0xdc, 0xbc, 0x5e, 0xc2, 0x64, 0xa6, 0xde, 0x3c,
-		0x0c, 0x7e, 0x0c, 0x6b, 0x80, 0x0f, 0xd4, 0x8f,
-		0x02, 0x4b, 0xb2, 0xba, 0x8d, 0x01, 0xeb, 0x6b,
-		0xa1, 0x2e, 0x79, 0x37, 0xba, 0xae, 0x24, 0xc2,
-		0x26, 0x72, 0x51, 0xe1, 0x82, 0x8e, 0x51, 0x41,
-		0x1c, 0x54, 0xa4, 0x26, 0xbe, 0x13, 0xcd, 0x1b,
-		0xc6, 0xed, 0x3d, 0x1f, 0xfd, 0x72, 0x80, 0x90,
-		0xdb, 0xbf, 0xd6, 0x39, 0x94, 0x5f, 0x48, 0xfb,
-		0x25, 0x5a, 0xc9, 0x60, 0x9b, 0xd7, 0xc6, 0x20,
-		0xa8, 0x66, 0x64, 0x13, 0xf3, 0x65, 0xc8, 0xb1,
-		0xd5, 0x33, 0x21, 0x0e, 0x73, 0x41, 0xc0, 0x18,
-		0x1a, 0x37, 0xfe, 0xcf, 0x28, 0x2a, 0xcd, 0xe4,
-		0x0b, 0xac, 0xdd, 0x25, 0x5e, 0xcb, 0x17, 0x51,
-		0x69, 0xd5, 0x8c, 0xf4, 0xb6, 0x21, 0x98, 0xef,
-		0x20, 0xdb, 0x14, 0x67, 0xf3, 0x7c, 0x95, 0x6a,
-		0x48, 0x2a, 0x6a, 0x14, 0x03, 0x01, 0x00, 0x01,
-		0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0x36, 0x1b,
-		0x09, 0xe5, 0xb9, 0xb9, 0x4d, 0x7d, 0xae, 0x87,
-		0xb6, 0x0f, 0xaf, 0xec, 0x22, 0xba, 0x0d, 0xa5,
-		0x96, 0x5e, 0x64, 0x65, 0xe7, 0xfb, 0xe3, 0xf3,
-		0x6b, 0x72, 0xa8, 0xdb, 0xed, 0xd8, 0x69, 0x9c,
-		0x08, 0xd8,
-	},
-	{
-		0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
-		0x01, 0x00, 0x24, 0x60, 0xf7, 0x09, 0x5f, 0xd1,
-		0xcb, 0xc9, 0xe1, 0x22, 0xb5, 0x2a, 0xcc, 0xde,
-		0x7c, 0xa7, 0xb8, 0x85, 0x00, 0xbc, 0xfd, 0x85,
-		0xe1, 0x91, 0x36, 0xbb, 0x07, 0x42, 0xad, 0x3d,
-		0x29, 0x62, 0x69, 0xc1, 0x45, 0x92, 0x6f, 0x17,
-		0x03, 0x01, 0x00, 0x21, 0x0d, 0xf9, 0xd5, 0x87,
-		0xb9, 0x57, 0x3c, 0x50, 0x19, 0xe4, 0x3a, 0x50,
-		0x45, 0xcc, 0x86, 0x89, 0xd4, 0x32, 0x79, 0x45,
-		0x7c, 0x9f, 0x96, 0xd4, 0x54, 0x56, 0x0c, 0x63,
-		0x72, 0x81, 0xc3, 0xd3, 0xe3, 0x15, 0x03, 0x01,
-		0x00, 0x16, 0x84, 0xec, 0x2e, 0xf6, 0xaf, 0x4f,
-		0xee, 0x48, 0x0f, 0xbe, 0xcd, 0x82, 0x5c, 0x56,
-		0x16, 0xe4, 0xfb, 0x89, 0xc5, 0x57, 0x3e, 0x91,
-	},
+// TestHandshakeServerSNI involves a client sending an SNI extension of
+// "snitest.com", which happens to match the CN of testSNICertificate. The test
+// verifies that the server correctly selects that certificate.
+func TestHandshakeServerSNI(t *testing.T) {
+	test := &serverTest{
+		name:    "SNI",
+		command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
+	}
+	runServerTestTLS12(t, test)
 }
 
-var issueSessionTicketTest = [][]byte{
-	{
-		0x16, 0x03, 0x01, 0x00, 0x5a, 0x01, 0x00, 0x00,
-		0x56, 0x03, 0x01, 0x50, 0x77, 0x3e, 0x49, 0x7a,
-		0xb7, 0x86, 0x5c, 0x27, 0xd2, 0x97, 0x61, 0xe3,
-		0x49, 0x41, 0x48, 0xe7, 0x0e, 0xaa, 0x7e, 0x4d,
-		0xb8, 0xdc, 0x01, 0x97, 0xfb, 0xab, 0x53, 0xb2,
-		0x5e, 0x36, 0xf6, 0x00, 0x00, 0x28, 0x00, 0x39,
-		0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13,
-		0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f,
-		0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
-		0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08,
-		0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01,
-		0x00, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
-		0x2c, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
-		0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
-		0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
-		0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
-		0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
-		0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
-		0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
-		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-		0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
-		0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
-		0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
-		0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
-		0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
-		0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
-		0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
-		0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
-		0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
-		0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
-		0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
-		0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
-		0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
-		0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
-		0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
-		0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
-		0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
-		0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
-		0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
-		0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
-		0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
-		0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
-		0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
-		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-		0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
-		0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
-		0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
-		0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
-		0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
-		0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
-		0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
-		0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
-		0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
-		0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
-		0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
-		0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
-		0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
-		0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
-		0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
-		0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
-		0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
-		0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
-		0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
-		0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
-		0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
-		0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
-		0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
-		0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
-		0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
-		0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
-		0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
-		0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
-		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
-		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
-		0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
-		0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
-		0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
-		0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
-		0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
-		0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
-		0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
-		0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
-		0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
-		0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-		0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
-		0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
-		0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
-		0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
-		0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
-		0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
-		0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
-		0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
-		0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
-		0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
-		0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
-		0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
-		0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
-		0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
-		0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
-		0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
-		0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
-		0x16, 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00,
-		0x00,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
-		0x82, 0x00, 0x80, 0x68, 0x10, 0xdc, 0x80, 0xbc,
-		0xb3, 0x5a, 0x10, 0x75, 0x89, 0xcc, 0xe5, 0x9f,
-		0xbf, 0xe2, 0xce, 0xa4, 0x9f, 0x7f, 0x60, 0xc4,
-		0xfe, 0x5c, 0xb5, 0x02, 0x2d, 0xa5, 0xa9, 0x1e,
-		0x2c, 0x10, 0x79, 0x15, 0x0f, 0xed, 0x96, 0xb3,
-		0xa8, 0x5e, 0x21, 0xbc, 0x5b, 0xdc, 0x58, 0x04,
-		0x7d, 0x37, 0xdb, 0xa0, 0x31, 0xe8, 0x4f, 0x04,
-		0xbc, 0x46, 0x7c, 0xdb, 0x2e, 0x93, 0x07, 0xaf,
-		0xa6, 0x36, 0xd3, 0x39, 0x8d, 0x1d, 0x95, 0xa8,
-		0x50, 0x4b, 0xc4, 0x2b, 0xde, 0xd7, 0x04, 0x6d,
-		0x77, 0x6c, 0x4d, 0x70, 0x51, 0x88, 0x16, 0x31,
-		0x40, 0xb5, 0xba, 0x90, 0x47, 0x64, 0x0c, 0x87,
-		0xa5, 0x19, 0xf9, 0x89, 0x24, 0x3c, 0x5e, 0x4b,
-		0xaa, 0xe0, 0x60, 0x47, 0x0f, 0x2e, 0xcc, 0xc2,
-		0xd5, 0x21, 0xed, 0x72, 0xd0, 0xa9, 0xdd, 0x2a,
-		0x2b, 0xef, 0x08, 0x3a, 0x65, 0xea, 0x8b, 0x52,
-		0x77, 0x2d, 0xcc, 0x14, 0x03, 0x01, 0x00, 0x01,
-		0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xe2, 0x95,
-		0x62, 0x3c, 0x18, 0xe5, 0xc7, 0x2c, 0xda, 0x16,
-		0x9b, 0x28, 0x0d, 0xf7, 0x88, 0x7b, 0x5d, 0x33,
-		0x55, 0x3b, 0x01, 0x73, 0xf2, 0xc6, 0x4e, 0x96,
-		0x01, 0x01, 0x83, 0x65, 0xd4, 0xef, 0x12, 0x13,
-		0x1d, 0x42,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x72, 0x04, 0x00, 0x00,
-		0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
-		0xe8, 0x4b, 0xd1, 0xef, 0xba, 0xfb, 0x41, 0x92,
-		0x6d, 0x37, 0x5f, 0xf8, 0x7d, 0x90, 0x0f, 0x01,
-		0xf8, 0x8c, 0xee, 0xbc, 0xd9, 0x0c, 0x97, 0x7e,
-		0x23, 0x46, 0xe2, 0x6b, 0x52, 0xc6, 0xc6, 0x97,
-		0x1d, 0xab, 0xde, 0xa0, 0x86, 0x94, 0xc8, 0x2e,
-		0x8b, 0x2e, 0x42, 0x5f, 0xc2, 0x70, 0x35, 0xc9,
-		0xee, 0x37, 0xeb, 0x70, 0xaa, 0x59, 0x23, 0x6c,
-		0xc8, 0xc1, 0x84, 0x89, 0x39, 0x87, 0x73, 0x0a,
-		0x7e, 0xba, 0xca, 0xed, 0x63, 0xba, 0x4e, 0x4f,
-		0xf3, 0x31, 0x4b, 0xf0, 0xee, 0x91, 0xa5, 0xb4,
-		0x62, 0x01, 0x9e, 0xbd, 0xbc, 0xb3, 0x35, 0x14,
-		0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
-		0x00, 0x24, 0x3f, 0x66, 0xe4, 0x98, 0xc1, 0x3f,
-		0xc6, 0x2c, 0x81, 0xfb, 0xa9, 0x9f, 0x27, 0xe9,
-		0x63, 0x20, 0x1e, 0x0e, 0x4f, 0xfc, 0x5d, 0x12,
-		0xee, 0x77, 0x73, 0xc6, 0x96, 0x51, 0xf2, 0x26,
-		0x35, 0x3f, 0xce, 0x6a, 0xa9, 0xfd, 0x17, 0x03,
-		0x01, 0x00, 0x21, 0x8d, 0xd5, 0x67, 0x60, 0x5d,
-		0xa7, 0x93, 0xcc, 0x39, 0x78, 0x59, 0xab, 0xdb,
-		0x10, 0x96, 0xf2, 0xad, 0xa2, 0x85, 0xe2, 0x93,
-		0x43, 0x43, 0xcf, 0x82, 0xbd, 0x1f, 0xdc, 0x7a,
-		0x72, 0xd6, 0x83, 0x3b, 0x15, 0x03, 0x01, 0x00,
-		0x16, 0x89, 0x55, 0xf6, 0x42, 0x71, 0xa9, 0xe9,
-		0x05, 0x68, 0xe8, 0xce, 0x0d, 0x21, 0xe9, 0xec,
-		0xf2, 0x27, 0x67, 0xa7, 0x94, 0xf8, 0x34,
-	},
-}
-var serverResumeTest = [][]byte{
-	{
-		0x16, 0x03, 0x01, 0x00, 0xc2, 0x01, 0x00, 0x00,
-		0xbe, 0x03, 0x01, 0x50, 0x77, 0x3e, 0x4f, 0x1f,
-		0x6f, 0xa5, 0x81, 0xeb, 0xb8, 0x80, 0x55, 0xa4,
-		0x76, 0xc2, 0x7f, 0x27, 0xf2, 0xe7, 0xc9, 0x7a,
-		0x01, 0x3c, 0xd8, 0xc1, 0xde, 0x99, 0x1f, 0x7c,
-		0xab, 0x35, 0x98, 0x00, 0x00, 0x28, 0x00, 0x39,
-		0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13,
-		0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f,
-		0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
-		0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08,
-		0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01,
-		0x00, 0x00, 0x6c, 0x00, 0x23, 0x00, 0x68, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
-		0xe8, 0x4b, 0xd1, 0xef, 0xba, 0xfb, 0x41, 0x92,
-		0x6d, 0x37, 0x5f, 0xf8, 0x7d, 0x90, 0x0f, 0x01,
-		0xf8, 0x8c, 0xee, 0xbc, 0xd9, 0x0c, 0x97, 0x7e,
-		0x23, 0x46, 0xe2, 0x6b, 0x52, 0xc6, 0xc6, 0x97,
-		0x1d, 0xab, 0xde, 0xa0, 0x86, 0x94, 0xc8, 0x2e,
-		0x8b, 0x2e, 0x42, 0x5f, 0xc2, 0x70, 0x35, 0xc9,
-		0xee, 0x37, 0xeb, 0x70, 0xaa, 0x59, 0x23, 0x6c,
-		0xc8, 0xc1, 0x84, 0x89, 0x39, 0x87, 0x73, 0x0a,
-		0x7e, 0xba, 0xca, 0xed, 0x63, 0xba, 0x4e, 0x4f,
-		0xf3, 0x31, 0x4b, 0xf0, 0xee, 0x91, 0xa5, 0xb4,
-		0x62, 0x01, 0x9e, 0xbd, 0xbc, 0xb3, 0x35,
-	},
-	{
-		0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
-		0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x14,
-		0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
-		0x00, 0x24, 0xc5, 0x35, 0x74, 0x19, 0x05, 0xc5,
-		0x85, 0x68, 0x48, 0xe8, 0xb5, 0xe9, 0xaf, 0x78,
-		0xbd, 0x35, 0x6f, 0xe9, 0x79, 0x34, 0x1b, 0xf0,
-		0x35, 0xd4, 0x4e, 0x55, 0x2e, 0x3c, 0xd5, 0xaf,
-		0xfc, 0xba, 0xf5, 0x1e, 0x83, 0x32,
-	},
-	{
-		0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
-		0x01, 0x00, 0x24, 0x27, 0x28, 0x88, 0xe1, 0x7e,
-		0x0d, 0x9c, 0x12, 0x50, 0xf6, 0x7a, 0xa7, 0x32,
-		0x21, 0x68, 0xba, 0xd8, 0x0a, 0xdc, 0x39, 0xef,
-		0x68, 0x95, 0x82, 0xae, 0xbd, 0x12, 0x79, 0xa1,
-		0x99, 0xfd, 0xd0, 0x10, 0x8e, 0x4b, 0xd8,
-	},
-	{
-		0x17, 0x03, 0x01, 0x00, 0x21, 0xc5, 0x7e, 0x0a,
-		0x52, 0x6a, 0xb9, 0xaa, 0x1d, 0xae, 0x9e, 0x24,
-		0x9c, 0x34, 0x1e, 0xdb, 0x50, 0x95, 0xee, 0x76,
-		0xd7, 0x28, 0x88, 0x08, 0xe3, 0x2e, 0x58, 0xf7,
-		0xdb, 0x34, 0x75, 0xa5, 0x7f, 0x9d, 0x15, 0x03,
-		0x01, 0x00, 0x16, 0x2c, 0xc1, 0x29, 0x5f, 0x12,
-		0x1d, 0x19, 0xab, 0xb3, 0xf4, 0x35, 0x1c, 0x62,
-		0x6a, 0x80, 0x29, 0x0d, 0x0e, 0xef, 0x7d, 0x6e,
-		0x50,
-	},
-}
+// TestCipherSuiteCertPreferance ensures that we select an RSA ciphersuite with
+// an RSA certificate and an ECDSA ciphersuite with an ECDSA certificate.
+func TestCipherSuiteCertPreferenceECDSA(t *testing.T) {
+	config := *testConfig
+	config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}
+	config.PreferServerCipherSuites = true
 
-var clientauthRSATests = []clientauthTest{
-	// Server asks for cert with empty CA list, client doesn't give it.
-	// go test -run "TestRunServer" -serve -clientauth 1
-	{"RequestClientCert, none given", RequestClientCert, nil, [][]byte{
-		{
-			0x16, 0x03, 0x01, 0x01, 0x1e, 0x01, 0x00, 0x01,
-			0x1a, 0x03, 0x03, 0x51, 0xe5, 0x6c, 0xb5, 0x5a,
-			0xc2, 0xf5, 0xf0, 0x92, 0x94, 0x8a, 0x64, 0x18,
-			0xa4, 0x2b, 0x82, 0x07, 0xbc, 0xd9, 0xd9, 0xf9,
-			0x7b, 0xd2, 0xd0, 0xee, 0xa2, 0x70, 0x4e, 0x23,
-			0x88, 0x7c, 0x95, 0x00, 0x00, 0x82, 0xc0, 0x30,
-			0xc0, 0x2c, 0xc0, 0x28, 0xc0, 0x24, 0xc0, 0x14,
-			0xc0, 0x0a, 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x6b,
-			0x00, 0x6a, 0x00, 0x39, 0x00, 0x38, 0xc0, 0x32,
-			0xc0, 0x2e, 0xc0, 0x2a, 0xc0, 0x26, 0xc0, 0x0f,
-			0xc0, 0x05, 0x00, 0x9d, 0x00, 0x3d, 0x00, 0x35,
-			0xc0, 0x12, 0xc0, 0x08, 0x00, 0x16, 0x00, 0x13,
-			0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a, 0xc0, 0x2f,
-			0xc0, 0x2b, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x13,
-			0xc0, 0x09, 0x00, 0xa2, 0x00, 0x9e, 0x00, 0x67,
-			0x00, 0x40, 0x00, 0x33, 0x00, 0x32, 0xc0, 0x31,
-			0xc0, 0x2d, 0xc0, 0x29, 0xc0, 0x25, 0xc0, 0x0e,
-			0xc0, 0x04, 0x00, 0x9c, 0x00, 0x3c, 0x00, 0x2f,
-			0x00, 0x07, 0xc0, 0x11, 0xc0, 0x07, 0xc0, 0x0c,
-			0xc0, 0x02, 0x00, 0x05, 0x00, 0x04, 0x00, 0x15,
-			0x00, 0x12, 0x00, 0x09, 0x00, 0x14, 0x00, 0x11,
-			0x00, 0x08, 0x00, 0x06, 0x00, 0x03, 0x00, 0xff,
-			0x01, 0x00, 0x00, 0x6f, 0x00, 0x0b, 0x00, 0x04,
-			0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, 0x34,
-			0x00, 0x32, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x19,
-			0x00, 0x0b, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x09,
-			0x00, 0x0a, 0x00, 0x16, 0x00, 0x17, 0x00, 0x08,
-			0x00, 0x06, 0x00, 0x07, 0x00, 0x14, 0x00, 0x15,
-			0x00, 0x04, 0x00, 0x05, 0x00, 0x12, 0x00, 0x13,
-			0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x0f,
-			0x00, 0x10, 0x00, 0x11, 0x00, 0x23, 0x00, 0x00,
-			0x00, 0x0d, 0x00, 0x22, 0x00, 0x20, 0x06, 0x01,
-			0x06, 0x02, 0x06, 0x03, 0x05, 0x01, 0x05, 0x02,
-			0x05, 0x03, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03,
-			0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x02, 0x01,
-			0x02, 0x02, 0x02, 0x03, 0x01, 0x01, 0x00, 0x0f,
-			0x00, 0x01, 0x01,
-		},
-		{
-			0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
-			0x2c, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-			0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
-			0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
-			0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
-			0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
-			0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
-			0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
-			0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
-			0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-			0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
-			0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
-			0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
-			0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
-			0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
-			0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
-			0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
-			0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
-			0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
-			0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
-			0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
-			0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
-			0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
-			0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
-			0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
-			0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
-			0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
-			0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
-			0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
-			0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
-			0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
-			0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
-			0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
-			0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-			0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
-			0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
-			0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
-			0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
-			0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
-			0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
-			0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
-			0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
-			0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
-			0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
-			0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
-			0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
-			0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
-			0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
-			0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
-			0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
-			0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
-			0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
-			0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
-			0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
-			0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
-			0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
-			0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
-			0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
-			0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
-			0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
-			0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
-			0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
-			0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-			0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
-			0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
-			0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
-			0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
-			0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
-			0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
-			0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
-			0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
-			0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
-			0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
-			0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
-			0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-			0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
-			0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
-			0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
-			0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
-			0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
-			0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
-			0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
-			0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
-			0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
-			0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
-			0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
-			0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
-			0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
-			0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
-			0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
-			0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
-			0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
-			0x16, 0x03, 0x01, 0x00, 0x09, 0x0d, 0x00, 0x00,
-			0x05, 0x02, 0x01, 0x40, 0x00, 0x00, 0x16, 0x03,
-			0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
-		},
-		{
-			0x16, 0x03, 0x01, 0x00, 0x07, 0x0b, 0x00, 0x00,
-			0x03, 0x00, 0x00, 0x00, 0x16, 0x03, 0x01, 0x00,
-			0x86, 0x10, 0x00, 0x00, 0x82, 0x00, 0x80, 0x36,
-			0xfc, 0xd8, 0xc8, 0xa2, 0x67, 0xc8, 0xc6, 0xf4,
-			0x28, 0x70, 0xe1, 0x5a, 0x02, 0x8f, 0xef, 0x42,
-			0xe0, 0xd3, 0xb8, 0xd6, 0x6b, 0xe4, 0xee, 0x5c,
-			0xcf, 0x42, 0xc4, 0xfa, 0xcd, 0x0f, 0xfe, 0xf4,
-			0x76, 0x76, 0x47, 0x73, 0xa8, 0x72, 0x8f, 0xa2,
-			0x56, 0x81, 0x83, 0xb8, 0x84, 0x72, 0x67, 0xdd,
-			0xbe, 0x05, 0x4b, 0x84, 0xd9, 0xd2, 0xb6, 0xc2,
-			0xe7, 0x20, 0xac, 0x1f, 0x46, 0x9d, 0x05, 0x47,
-			0x8e, 0x89, 0xc0, 0x42, 0x57, 0x4a, 0xa2, 0x98,
-			0xe5, 0x39, 0x4f, 0xc4, 0x27, 0x6d, 0x43, 0xa8,
-			0x83, 0x76, 0xe6, 0xad, 0xe3, 0x17, 0x68, 0x31,
-			0xcb, 0x7e, 0xfc, 0xe7, 0x4b, 0x76, 0x3d, 0x3c,
-			0xfa, 0x77, 0x65, 0xc9, 0x4c, 0x5b, 0xce, 0x5e,
-			0xf7, 0x8b, 0xa8, 0xa6, 0xdd, 0xb2, 0xef, 0x0b,
-			0x46, 0x83, 0xdf, 0x0a, 0x8c, 0x22, 0x12, 0x6e,
-			0xe1, 0x45, 0x54, 0x88, 0xd1, 0xe8, 0xd2, 0x14,
-			0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
-			0x00, 0x24, 0x30, 0x8c, 0x7d, 0x40, 0xfc, 0x5e,
-			0x80, 0x9c, 0xc4, 0x7c, 0x62, 0x01, 0xa1, 0x37,
-			0xcf, 0x1a, 0x75, 0x28, 0x8d, 0xeb, 0x63, 0xcc,
-			0x02, 0xa6, 0x66, 0xdf, 0x36, 0x01, 0xb3, 0x9d,
-			0x38, 0x42, 0x16, 0x91, 0xf0, 0x02,
-		},
-		{
-			0x16, 0x03, 0x01, 0x00, 0x72, 0x04, 0x00, 0x00,
-			0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
-			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
-			0xe8, 0x4b, 0xd1, 0xef, 0xba, 0x96, 0x9a, 0x2a,
-			0x6c, 0x8c, 0x7e, 0x38, 0x10, 0x46, 0x86, 0x1d,
-			0x19, 0x1d, 0x62, 0x29, 0x3f, 0x58, 0xfb, 0x6d,
-			0x89, 0xd2, 0x81, 0x9a, 0x1c, 0xb3, 0x58, 0xb3,
-			0x19, 0x39, 0x17, 0x47, 0x49, 0xc9, 0xfe, 0x4a,
-			0x7a, 0x32, 0xac, 0x2c, 0x43, 0xf9, 0xa9, 0xea,
-			0xec, 0x51, 0x46, 0xf1, 0xb8, 0x59, 0x23, 0x70,
-			0xce, 0x7c, 0xb9, 0x47, 0x70, 0xa3, 0xc9, 0xae,
-			0x47, 0x7b, 0x7e, 0xc7, 0xcf, 0x76, 0x12, 0x76,
-			0x18, 0x90, 0x12, 0xcd, 0xf3, 0xd4, 0x27, 0x81,
-			0xfc, 0x46, 0x03, 0x3e, 0x05, 0x87, 0x6f, 0x14,
-			0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01,
-			0x00, 0x24, 0xc3, 0xa0, 0x29, 0xb1, 0x52, 0x82,
-			0xef, 0x85, 0xa1, 0x64, 0x0f, 0xe4, 0xa3, 0xfb,
-			0xa7, 0x1d, 0x22, 0x4c, 0xcb, 0xd6, 0x5b, 0x18,
-			0x61, 0xc7, 0x7c, 0xf2, 0x67, 0x4a, 0xc7, 0x11,
-			0x9d, 0x8e, 0x0e, 0x15, 0x22, 0xcf, 0x17, 0x03,
-			0x01, 0x00, 0x21, 0xfd, 0xbb, 0xf1, 0xa9, 0x7c,
-			0xbf, 0x92, 0xb3, 0xfa, 0x2c, 0x08, 0x6f, 0x22,
-			0x78, 0x80, 0xf2, 0x2e, 0x86, 0x26, 0x21, 0x36,
-			0x3f, 0x32, 0xdf, 0xb6, 0x47, 0xa5, 0xf8, 0x27,
-			0xc1, 0xe9, 0x53, 0x90, 0x15, 0x03, 0x01, 0x00,
-			0x16, 0xfe, 0xef, 0x2e, 0xa0, 0x5d, 0xe0, 0xce,
-			0x94, 0x20, 0x56, 0x61, 0x6e, 0xe5, 0x62, 0xce,
-			0x27, 0x57, 0x3e, 0x30, 0x32, 0x77, 0x53,
-		},
-	}},
-
-	// Server asks for cert with empty CA list, client gives one
-	// go test -run "TestRunServer" -serve -clientauth 1
-	{"RequestClientCert, client gives it", RequestClientCert, []*x509.Certificate{clientCertificate}, [][]byte{
-		{
-			0x16, 0x03, 0x01, 0x01, 0x1e, 0x01, 0x00, 0x01,
-			0x1a, 0x03, 0x03, 0x51, 0xe5, 0x74, 0x0e, 0x95,
-			0x6f, 0x4f, 0x4a, 0xbf, 0xb7, 0xc0, 0x6c, 0xac,
-			0xd9, 0xfe, 0x7d, 0xd0, 0x51, 0x19, 0x62, 0x62,
-			0x1c, 0x6e, 0x57, 0x77, 0xd2, 0x31, 0xaf, 0x88,
-			0xb9, 0xc0, 0x1d, 0x00, 0x00, 0x82, 0xc0, 0x30,
-			0xc0, 0x2c, 0xc0, 0x28, 0xc0, 0x24, 0xc0, 0x14,
-			0xc0, 0x0a, 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x6b,
-			0x00, 0x6a, 0x00, 0x39, 0x00, 0x38, 0xc0, 0x32,
-			0xc0, 0x2e, 0xc0, 0x2a, 0xc0, 0x26, 0xc0, 0x0f,
-			0xc0, 0x05, 0x00, 0x9d, 0x00, 0x3d, 0x00, 0x35,
-			0xc0, 0x12, 0xc0, 0x08, 0x00, 0x16, 0x00, 0x13,
-			0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a, 0xc0, 0x2f,
-			0xc0, 0x2b, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x13,
-			0xc0, 0x09, 0x00, 0xa2, 0x00, 0x9e, 0x00, 0x67,
-			0x00, 0x40, 0x00, 0x33, 0x00, 0x32, 0xc0, 0x31,
-			0xc0, 0x2d, 0xc0, 0x29, 0xc0, 0x25, 0xc0, 0x0e,
-			0xc0, 0x04, 0x00, 0x9c, 0x00, 0x3c, 0x00, 0x2f,
-			0x00, 0x07, 0xc0, 0x11, 0xc0, 0x07, 0xc0, 0x0c,
-			0xc0, 0x02, 0x00, 0x05, 0x00, 0x04, 0x00, 0x15,
-			0x00, 0x12, 0x00, 0x09, 0x00, 0x14, 0x00, 0x11,
-			0x00, 0x08, 0x00, 0x06, 0x00, 0x03, 0x00, 0xff,
-			0x01, 0x00, 0x00, 0x6f, 0x00, 0x0b, 0x00, 0x04,
-			0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, 0x34,
-			0x00, 0x32, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x19,
-			0x00, 0x0b, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x09,
-			0x00, 0x0a, 0x00, 0x16, 0x00, 0x17, 0x00, 0x08,
-			0x00, 0x06, 0x00, 0x07, 0x00, 0x14, 0x00, 0x15,
-			0x00, 0x04, 0x00, 0x05, 0x00, 0x12, 0x00, 0x13,
-			0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x0f,
-			0x00, 0x10, 0x00, 0x11, 0x00, 0x23, 0x00, 0x00,
-			0x00, 0x0d, 0x00, 0x22, 0x00, 0x20, 0x06, 0x01,
-			0x06, 0x02, 0x06, 0x03, 0x05, 0x01, 0x05, 0x02,
-			0x05, 0x03, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03,
-			0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x02, 0x01,
-			0x02, 0x02, 0x02, 0x03, 0x01, 0x01, 0x00, 0x0f,
-			0x00, 0x01, 0x01,
-		},
-		{
-			0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
-			0x2c, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-			0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
-			0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
-			0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
-			0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
-			0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
-			0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
-			0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
-			0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-			0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
-			0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
-			0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
-			0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
-			0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
-			0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
-			0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
-			0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
-			0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
-			0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
-			0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
-			0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
-			0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
-			0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
-			0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
-			0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
-			0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
-			0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
-			0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
-			0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
-			0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
-			0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
-			0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
-			0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-			0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
-			0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
-			0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
-			0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
-			0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
-			0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
-			0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
-			0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
-			0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
-			0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
-			0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
-			0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
-			0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
-			0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
-			0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
-			0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
-			0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
-			0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
-			0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
-			0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
-			0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
-			0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
-			0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
-			0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
-			0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
-			0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
-			0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
-			0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
-			0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-			0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
-			0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
-			0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
-			0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
-			0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
-			0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
-			0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
-			0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
-			0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
-			0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
-			0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
-			0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-			0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
-			0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
-			0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
-			0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
-			0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
-			0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
-			0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
-			0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
-			0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
-			0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
-			0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
-			0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
-			0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
-			0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
-			0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
-			0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
-			0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
-			0x16, 0x03, 0x01, 0x00, 0x09, 0x0d, 0x00, 0x00,
-			0x05, 0x02, 0x01, 0x40, 0x00, 0x00, 0x16, 0x03,
-			0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
-		},
-		{
-			0x16, 0x03, 0x01, 0x01, 0xfb, 0x0b, 0x00, 0x01,
-			0xf7, 0x00, 0x01, 0xf4, 0x00, 0x01, 0xf1, 0x30,
-			0x82, 0x01, 0xed, 0x30, 0x82, 0x01, 0x58, 0xa0,
-			0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x30,
-			0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
-			0x0d, 0x01, 0x01, 0x05, 0x30, 0x26, 0x31, 0x10,
-			0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
-			0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f,
-			0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
-			0x03, 0x13, 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30,
-			0x2e, 0x30, 0x2e, 0x31, 0x30, 0x1e, 0x17, 0x0d,
-			0x31, 0x31, 0x31, 0x32, 0x30, 0x38, 0x30, 0x37,
-			0x35, 0x35, 0x31, 0x32, 0x5a, 0x17, 0x0d, 0x31,
-			0x32, 0x31, 0x32, 0x30, 0x37, 0x30, 0x38, 0x30,
-			0x30, 0x31, 0x32, 0x5a, 0x30, 0x26, 0x31, 0x10,
-			0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
-			0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f,
-			0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
-			0x03, 0x13, 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30,
-			0x2e, 0x30, 0x2e, 0x31, 0x30, 0x81, 0x9c, 0x30,
-			0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
-			0x0d, 0x01, 0x01, 0x01, 0x03, 0x81, 0x8c, 0x00,
-			0x30, 0x81, 0x88, 0x02, 0x81, 0x80, 0x4e, 0xd0,
-			0x7b, 0x31, 0xe3, 0x82, 0x64, 0xd9, 0x59, 0xc0,
-			0xc2, 0x87, 0xa4, 0x5e, 0x1e, 0x8b, 0x73, 0x33,
-			0xc7, 0x63, 0x53, 0xdf, 0x66, 0x92, 0x06, 0x84,
-			0xf6, 0x64, 0xd5, 0x8f, 0xe4, 0x36, 0xa7, 0x1d,
-			0x2b, 0xe8, 0xb3, 0x20, 0x36, 0x45, 0x23, 0xb5,
-			0xe3, 0x95, 0xae, 0xed, 0xe0, 0xf5, 0x20, 0x9c,
-			0x8d, 0x95, 0xdf, 0x7f, 0x5a, 0x12, 0xef, 0x87,
-			0xe4, 0x5b, 0x68, 0xe4, 0xe9, 0x0e, 0x74, 0xec,
-			0x04, 0x8a, 0x7f, 0xde, 0x93, 0x27, 0xc4, 0x01,
-			0x19, 0x7a, 0xbd, 0xf2, 0xdc, 0x3d, 0x14, 0xab,
-			0xd0, 0x54, 0xca, 0x21, 0x0c, 0xd0, 0x4d, 0x6e,
-			0x87, 0x2e, 0x5c, 0xc5, 0xd2, 0xbb, 0x4d, 0x4b,
-			0x4f, 0xce, 0xb6, 0x2c, 0xf7, 0x7e, 0x88, 0xec,
-			0x7c, 0xd7, 0x02, 0x91, 0x74, 0xa6, 0x1e, 0x0c,
-			0x1a, 0xda, 0xe3, 0x4a, 0x5a, 0x2e, 0xde, 0x13,
-			0x9c, 0x4c, 0x40, 0x88, 0x59, 0x93, 0x02, 0x03,
-			0x01, 0x00, 0x01, 0xa3, 0x32, 0x30, 0x30, 0x30,
-			0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01,
-			0xff, 0x04, 0x04, 0x03, 0x02, 0x00, 0xa0, 0x30,
-			0x0d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x06,
-			0x04, 0x04, 0x01, 0x02, 0x03, 0x04, 0x30, 0x0f,
-			0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x08, 0x30,
-			0x06, 0x80, 0x04, 0x01, 0x02, 0x03, 0x04, 0x30,
-			0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
-			0x0d, 0x01, 0x01, 0x05, 0x03, 0x81, 0x81, 0x00,
-			0x36, 0x1f, 0xb3, 0x7a, 0x0c, 0x75, 0xc9, 0x6e,
-			0x37, 0x46, 0x61, 0x2b, 0xd5, 0xbd, 0xc0, 0xa7,
-			0x4b, 0xcc, 0x46, 0x9a, 0x81, 0x58, 0x7c, 0x85,
-			0x79, 0x29, 0xc8, 0xc8, 0xc6, 0x67, 0xdd, 0x32,
-			0x56, 0x45, 0x2b, 0x75, 0xb6, 0xe9, 0x24, 0xa9,
-			0x50, 0x9a, 0xbe, 0x1f, 0x5a, 0xfa, 0x1a, 0x15,
-			0xd9, 0xcc, 0x55, 0x95, 0x72, 0x16, 0x83, 0xb9,
-			0xc2, 0xb6, 0x8f, 0xfd, 0x88, 0x8c, 0x38, 0x84,
-			0x1d, 0xab, 0x5d, 0x92, 0x31, 0x13, 0x4f, 0xfd,
-			0x83, 0x3b, 0xc6, 0x9d, 0xf1, 0x11, 0x62, 0xb6,
-			0x8b, 0xec, 0xab, 0x67, 0xbe, 0xc8, 0x64, 0xb0,
-			0x11, 0x50, 0x46, 0x58, 0x17, 0x6b, 0x99, 0x1c,
-			0xd3, 0x1d, 0xfc, 0x06, 0xf1, 0x0e, 0xe5, 0x96,
-			0xa8, 0x0c, 0xf9, 0x78, 0x20, 0xb7, 0x44, 0x18,
-			0x51, 0x8d, 0x10, 0x7e, 0x4f, 0x94, 0x67, 0xdf,
-			0xa3, 0x4e, 0x70, 0x73, 0x8e, 0x90, 0x91, 0x85,
-			0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
-			0x82, 0x00, 0x80, 0x0a, 0x4e, 0x89, 0xdf, 0x3a,
-			0x3f, 0xf0, 0x4f, 0xef, 0x1a, 0x90, 0xd4, 0x3c,
-			0xaf, 0x10, 0x57, 0xb0, 0xa1, 0x5f, 0xcd, 0x62,
-			0x01, 0xe9, 0x0c, 0x36, 0x42, 0xfd, 0xaf, 0x23,
-			0xf9, 0x14, 0xa6, 0x72, 0x26, 0x4e, 0x01, 0xdb,
-			0xac, 0xb7, 0x4c, 0xe6, 0xa9, 0x52, 0xe2, 0xec,
-			0x26, 0x8c, 0x7a, 0x64, 0xf8, 0x0b, 0x4c, 0x2f,
-			0xa9, 0xcb, 0x75, 0xaf, 0x60, 0xd4, 0xb4, 0xe6,
-			0xe8, 0xdb, 0x78, 0x78, 0x85, 0xf6, 0x0c, 0x95,
-			0xcc, 0xb6, 0x55, 0xb9, 0xba, 0x9e, 0x91, 0xbc,
-			0x66, 0xdb, 0x1e, 0x28, 0xab, 0x73, 0xce, 0x8b,
-			0xd0, 0xd3, 0xe8, 0xbc, 0xd0, 0x21, 0x28, 0xbd,
-			0xfb, 0x74, 0x64, 0xde, 0x3b, 0x3b, 0xd3, 0x4c,
-			0x32, 0x40, 0x82, 0xba, 0x91, 0x1e, 0xe8, 0x47,
-			0xc2, 0x09, 0xb7, 0x16, 0xaa, 0x25, 0xa9, 0x3c,
-			0x6c, 0xa7, 0xf8, 0xc9, 0x54, 0x84, 0xc6, 0xf7,
-			0x56, 0x05, 0xa4, 0x16, 0x03, 0x01, 0x00, 0x86,
-			0x0f, 0x00, 0x00, 0x82, 0x00, 0x80, 0x4b, 0xab,
-			0xda, 0xac, 0x2a, 0xb3, 0xe6, 0x34, 0x55, 0xcd,
-			0xf2, 0x4b, 0x67, 0xe3, 0xd3, 0xff, 0xa3, 0xf4,
-			0x79, 0x82, 0x01, 0x47, 0x8a, 0xe3, 0x9f, 0x89,
-			0x70, 0xbe, 0x24, 0x24, 0xb7, 0x69, 0x60, 0xed,
-			0x55, 0xa0, 0xca, 0x72, 0xb6, 0x4a, 0xbc, 0x1d,
-			0xe2, 0x3f, 0xb5, 0x31, 0xda, 0x02, 0xf6, 0x37,
-			0x51, 0xf8, 0x4c, 0x88, 0x2e, 0xb3, 0x8a, 0xe8,
-			0x7b, 0x4a, 0x90, 0x36, 0xe4, 0xa6, 0x31, 0x95,
-			0x8b, 0xa0, 0xc6, 0x91, 0x12, 0xb9, 0x35, 0x4e,
-			0x72, 0xeb, 0x5c, 0xa2, 0xe8, 0x4c, 0x68, 0xf9,
-			0x69, 0xfa, 0x70, 0x60, 0x6c, 0x7f, 0x32, 0x99,
-			0xf1, 0xc3, 0x2d, 0xb4, 0x59, 0x58, 0x87, 0xaf,
-			0x67, 0x62, 0x90, 0xe7, 0x8d, 0xd0, 0xa3, 0x77,
-			0x33, 0xc2, 0x9b, 0xd5, 0x9c, 0xc7, 0xea, 0x25,
-			0x98, 0x76, 0x9c, 0xe0, 0x6a, 0x03, 0x3a, 0x10,
-			0xfd, 0x10, 0x3d, 0x55, 0x53, 0xa0, 0x14, 0x03,
-			0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01, 0x00,
-			0x24, 0xd5, 0x12, 0xfc, 0xb9, 0x5a, 0xe3, 0x27,
-			0x01, 0xbe, 0xc3, 0x77, 0x17, 0x1a, 0xbb, 0x4f,
-			0xae, 0xd5, 0xa7, 0xee, 0x56, 0x61, 0x0d, 0x40,
-			0xf4, 0xa4, 0xb5, 0xcc, 0x76, 0xfd, 0xbd, 0x13,
-			0x04, 0xe1, 0xb8, 0xc7, 0x36,
-		},
-		{
-			0x16, 0x03, 0x01, 0x02, 0x67, 0x04, 0x00, 0x02,
-			0x63, 0x00, 0x00, 0x00, 0x00, 0x02, 0x5d, 0x00,
-			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
-			0xe8, 0x4b, 0xd1, 0xef, 0xba, 0x1f, 0xe2, 0x69,
-			0x07, 0x7f, 0x85, 0x2d, 0x4e, 0x2a, 0x2e, 0xbd,
-			0x05, 0xe9, 0xc1, 0x6c, 0x9e, 0xbf, 0x47, 0x18,
-			0x91, 0x77, 0xf7, 0xe8, 0xb6, 0x27, 0x37, 0xa6,
-			0x6b, 0x87, 0x29, 0xbb, 0x3b, 0xe5, 0x68, 0x62,
-			0x04, 0x3e, 0xad, 0x4d, 0xff, 0xad, 0xf1, 0x22,
-			0x87, 0x8d, 0xf6, 0x04, 0x3b, 0x59, 0x22, 0xf7,
-			0xfd, 0x88, 0x0e, 0xa4, 0x09, 0xc0, 0x0d, 0x10,
-			0x80, 0x10, 0x79, 0xee, 0x70, 0x96, 0xdb, 0x22,
-			0x8b, 0xb7, 0xac, 0xe0, 0x98, 0xad, 0xe9, 0xe3,
-			0xcb, 0xea, 0x9f, 0xe6, 0x83, 0x28, 0x7c, 0x7e,
-			0x4e, 0x9a, 0x8d, 0xd9, 0xf3, 0x86, 0xf4, 0x89,
-			0x8b, 0x79, 0x8f, 0xbb, 0xe9, 0x74, 0x02, 0x02,
-			0x14, 0x04, 0xea, 0xba, 0x16, 0x10, 0xa1, 0x85,
-			0xbe, 0x4e, 0x4e, 0x92, 0xc5, 0x83, 0xf6, 0x1e,
-			0x1f, 0xd4, 0x25, 0xc2, 0xc2, 0xb9, 0xce, 0x33,
-			0x63, 0x66, 0x79, 0x1f, 0x54, 0x35, 0xc1, 0xe8,
-			0x89, 0x34, 0x78, 0x94, 0x36, 0x14, 0xef, 0x01,
-			0x1f, 0xf1, 0xbd, 0x77, 0x2c, 0x4d, 0xac, 0x5c,
-			0x5c, 0x4a, 0xc6, 0xed, 0xd8, 0x0e, 0x72, 0x84,
-			0x83, 0xdc, 0x56, 0x84, 0xc8, 0xf3, 0x89, 0x56,
-			0xfd, 0x89, 0xc1, 0xc9, 0x9a, 0x29, 0x91, 0x7e,
-			0x19, 0xe9, 0x8b, 0x5b, 0x11, 0x15, 0x4e, 0x6c,
-			0xf4, 0x89, 0xe7, 0x6d, 0x68, 0x1e, 0xf9, 0x6c,
-			0x23, 0x72, 0x05, 0x68, 0x82, 0x60, 0x84, 0x1f,
-			0x83, 0x20, 0x09, 0x86, 0x10, 0x81, 0xec, 0xec,
-			0xdc, 0x25, 0x53, 0x20, 0xfa, 0xa9, 0x41, 0x64,
-			0xd6, 0x20, 0xf3, 0xf4, 0x52, 0xf2, 0x80, 0x62,
-			0x83, 0xc9, 0x23, 0x66, 0x44, 0x95, 0x5a, 0x99,
-			0x8a, 0xe1, 0x26, 0x63, 0xc1, 0x8b, 0x31, 0xf9,
-			0x21, 0x06, 0x77, 0x04, 0x27, 0xf2, 0x0c, 0x63,
-			0x83, 0x45, 0xa0, 0xa9, 0x7b, 0xcf, 0xdf, 0xd7,
-			0x56, 0x75, 0xbc, 0xdd, 0x95, 0x36, 0xb1, 0x75,
-			0x39, 0x05, 0x00, 0x3c, 0x8a, 0x79, 0xd6, 0xe9,
-			0xf0, 0x4b, 0xdc, 0x51, 0x6b, 0x01, 0x94, 0x16,
-			0x87, 0x12, 0x92, 0x6c, 0x07, 0xc1, 0xf5, 0x58,
-			0xb7, 0x2a, 0x81, 0xf5, 0xa0, 0x37, 0x8b, 0xa6,
-			0x22, 0xfe, 0x28, 0x0a, 0x7e, 0x68, 0xe2, 0xda,
-			0x6c, 0x53, 0xee, 0x0e, 0x8d, 0x2d, 0x8b, 0x0b,
-			0xda, 0xf8, 0x99, 0x3e, 0x0e, 0xed, 0x9f, 0xc1,
-			0x2b, 0xf6, 0xfe, 0xe9, 0x52, 0x38, 0x7b, 0x83,
-			0x9a, 0x50, 0xa6, 0xd7, 0x49, 0x83, 0x43, 0x7e,
-			0x82, 0xec, 0xc7, 0x09, 0x3d, 0x3d, 0xb1, 0xee,
-			0xe8, 0xc5, 0x6a, 0xc3, 0x3d, 0x4b, 0x4c, 0x6a,
-			0xbb, 0x0b, 0x2c, 0x24, 0x2e, 0xdb, 0x7d, 0x57,
-			0x87, 0xb4, 0x80, 0xa5, 0xae, 0xff, 0x54, 0xa8,
-			0xa5, 0x27, 0x69, 0x95, 0xc8, 0xe7, 0x79, 0xc7,
-			0x89, 0x2a, 0x73, 0x49, 0xcb, 0xf5, 0xc5, 0xbc,
-			0x4a, 0xe0, 0x73, 0xa9, 0xbc, 0x88, 0x64, 0x96,
-			0x98, 0xa5, 0x1e, 0xe3, 0x43, 0xc1, 0x7d, 0x78,
-			0xc7, 0x94, 0x72, 0xd4, 0x2c, 0x6e, 0x85, 0x39,
-			0x9a, 0xaf, 0xdb, 0xa1, 0xe9, 0xe2, 0xcb, 0x37,
-			0x04, 0xc6, 0x8c, 0x81, 0xd3, 0x2a, 0xb7, 0xbe,
-			0x6c, 0x07, 0x1f, 0x5e, 0xd9, 0x00, 0xd2, 0xf7,
-			0xe1, 0xa7, 0xbc, 0x0c, 0xb6, 0x6d, 0xfb, 0x3f,
-			0x3d, 0x24, 0xaa, 0xfb, 0x7e, 0xe1, 0xb5, 0x1b,
-			0xff, 0x38, 0xaa, 0x69, 0x59, 0x38, 0x52, 0x9a,
-			0x0e, 0x6d, 0xbc, 0xde, 0x4f, 0x13, 0x09, 0x17,
-			0xc4, 0xa9, 0x05, 0x84, 0xbc, 0x50, 0xef, 0x40,
-			0xb0, 0x4c, 0x24, 0x32, 0xed, 0x94, 0x2c, 0xdd,
-			0xda, 0x20, 0x24, 0x67, 0xe2, 0xea, 0x71, 0x3d,
-			0x4a, 0x04, 0x0d, 0x98, 0x29, 0x20, 0x4c, 0xeb,
-			0x70, 0xce, 0x45, 0x9e, 0x5a, 0xaf, 0xb6, 0xa3,
-			0x92, 0xc8, 0x28, 0xf2, 0xe3, 0xe8, 0x8a, 0x5d,
-			0x0a, 0x33, 0x79, 0x9b, 0x6a, 0xf3, 0x30, 0x01,
-			0x1d, 0x47, 0xbd, 0x01, 0xcc, 0x4d, 0x71, 0xc0,
-			0x56, 0xfa, 0xfd, 0x37, 0xed, 0x0f, 0x27, 0xc0,
-			0xbb, 0xa0, 0xee, 0xc3, 0x79, 0x8b, 0xe7, 0x41,
-			0x8f, 0xfa, 0x3a, 0xcb, 0x45, 0x3b, 0x85, 0x9f,
-			0x06, 0x90, 0xb2, 0x51, 0x7a, 0xc3, 0x11, 0x41,
-			0x4b, 0xe3, 0x26, 0x94, 0x3e, 0xa2, 0xfd, 0x0a,
-			0xda, 0x50, 0xf6, 0x50, 0x78, 0x19, 0x6c, 0x52,
-			0xd1, 0x12, 0x76, 0xc2, 0x50, 0x2f, 0x0b, 0xca,
-			0x33, 0xe5, 0x79, 0x93, 0x14, 0x03, 0x01, 0x00,
-			0x01, 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0x2b,
-			0x51, 0x42, 0x95, 0x6b, 0xca, 0x9f, 0x42, 0x5d,
-			0xd2, 0xd9, 0x67, 0xf9, 0x49, 0x30, 0xfd, 0x2a,
-			0x46, 0xd3, 0x04, 0xf4, 0x86, 0xf9, 0x11, 0x34,
-			0x82, 0xac, 0xe2, 0xc2, 0x2d, 0xc4, 0xd0, 0xfe,
-			0xa9, 0xc9, 0x4b, 0x17, 0x03, 0x01, 0x00, 0x21,
-			0x65, 0x1c, 0xe9, 0x5c, 0xb6, 0xe2, 0x7c, 0x8e,
-			0x49, 0x12, 0x1b, 0xe6, 0x40, 0xd3, 0x97, 0x21,
-			0x76, 0x01, 0xe5, 0x80, 0x5e, 0xf3, 0x11, 0x47,
-			0x25, 0x02, 0x78, 0x8e, 0x6b, 0xae, 0xb3, 0xf3,
-			0x59, 0x15, 0x03, 0x01, 0x00, 0x16, 0x38, 0xc1,
-			0x99, 0x2e, 0xf8, 0x6f, 0x45, 0xa4, 0x10, 0x79,
-			0x5b, 0xc1, 0x47, 0x9a, 0xf6, 0x5c, 0x90, 0xeb,
-			0xa6, 0xe3, 0x1a, 0x24,
+	test := &serverTest{
+		name:   "CipherSuiteCertPreferenceRSA",
+		config: &config,
+	}
+	runServerTestTLS12(t, test)
+
+	config = *testConfig
+	config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}
+	config.Certificates = []Certificate{
+		Certificate{
+			Certificate: [][]byte{testECDSACertificate},
+			PrivateKey:  testECDSAPrivateKey,
 		},
-	}},
-}
+	}
+	config.BuildNameToCertificate()
+	config.PreferServerCipherSuites = true
 
-var tls11ECDHEAESServerScript = [][]byte{
-	{
-		0x16, 0x03, 0x01, 0x01, 0x46, 0x01, 0x00, 0x01,
-		0x42, 0x03, 0x03, 0x51, 0x9f, 0xa3, 0xb0, 0xb7,
-		0x1d, 0x26, 0x93, 0x36, 0xc0, 0x8d, 0x7e, 0xf8,
-		0x4f, 0x6f, 0xc9, 0x3c, 0x31, 0x1e, 0x7f, 0xb1,
-		0xf0, 0xc1, 0x0f, 0xf9, 0x0c, 0xa2, 0xd5, 0xca,
-		0x48, 0xe5, 0x35, 0x00, 0x00, 0xd0, 0xc0, 0x30,
-		0xc0, 0x2c, 0xc0, 0x28, 0xc0, 0x24, 0xc0, 0x14,
-		0xc0, 0x0a, 0xc0, 0x22, 0xc0, 0x21, 0x00, 0xa5,
-		0x00, 0xa3, 0x00, 0xa1, 0x00, 0x9f, 0x00, 0x6b,
-		0x00, 0x6a, 0x00, 0x69, 0x00, 0x68, 0x00, 0x39,
-		0x00, 0x38, 0x00, 0x37, 0x00, 0x36, 0x00, 0x88,
-		0x00, 0x87, 0x00, 0x86, 0x00, 0x85, 0xc0, 0x32,
-		0xc0, 0x2e, 0xc0, 0x2a, 0xc0, 0x26, 0xc0, 0x0f,
-		0xc0, 0x05, 0x00, 0x9d, 0x00, 0x3d, 0x00, 0x35,
-		0x00, 0x84, 0xc0, 0x12, 0xc0, 0x08, 0xc0, 0x1c,
-		0xc0, 0x1b, 0x00, 0x16, 0x00, 0x13, 0x00, 0x10,
-		0x00, 0x0d, 0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a,
-		0xc0, 0x2f, 0xc0, 0x2b, 0xc0, 0x27, 0xc0, 0x23,
-		0xc0, 0x13, 0xc0, 0x09, 0xc0, 0x1f, 0xc0, 0x1e,
-		0x00, 0xa4, 0x00, 0xa2, 0x00, 0xa0, 0x00, 0x9e,
-		0x00, 0x67, 0x00, 0x40, 0x00, 0x3f, 0x00, 0x3e,
-		0x00, 0x33, 0x00, 0x32, 0x00, 0x31, 0x00, 0x30,
-		0x00, 0x9a, 0x00, 0x99, 0x00, 0x98, 0x00, 0x97,
-		0x00, 0x45, 0x00, 0x44, 0x00, 0x43, 0x00, 0x42,
-		0xc0, 0x31, 0xc0, 0x2d, 0xc0, 0x29, 0xc0, 0x25,
-		0xc0, 0x0e, 0xc0, 0x04, 0x00, 0x9c, 0x00, 0x3c,
-		0x00, 0x2f, 0x00, 0x96, 0x00, 0x41, 0x00, 0x07,
-		0xc0, 0x11, 0xc0, 0x07, 0xc0, 0x0c, 0xc0, 0x02,
-		0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
-		0x00, 0x0f, 0x00, 0x0c, 0x00, 0x09, 0x00, 0x14,
-		0x00, 0x11, 0x00, 0x0e, 0x00, 0x0b, 0x00, 0x08,
-		0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x01, 0x00,
-		0x00, 0x49, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00,
-		0x01, 0x02, 0x00, 0x0a, 0x00, 0x34, 0x00, 0x32,
-		0x00, 0x0e, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x0b,
-		0x00, 0x0c, 0x00, 0x18, 0x00, 0x09, 0x00, 0x0a,
-		0x00, 0x16, 0x00, 0x17, 0x00, 0x08, 0x00, 0x06,
-		0x00, 0x07, 0x00, 0x14, 0x00, 0x15, 0x00, 0x04,
-		0x00, 0x05, 0x00, 0x12, 0x00, 0x13, 0x00, 0x01,
-		0x00, 0x02, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x10,
-		0x00, 0x11, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0f,
-		0x00, 0x01, 0x01,
-	},
-	{
-		0x16, 0x03, 0x02, 0x00, 0x30, 0x02, 0x00, 0x00,
-		0x2c, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0xc0, 0x13, 0x00, 0x00,
-		0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x02,
-		0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
-		0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
-		0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
-		0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
-		0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
-		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-		0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
-		0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
-		0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
-		0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
-		0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
-		0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
-		0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
-		0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
-		0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
-		0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
-		0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
-		0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
-		0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
-		0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
-		0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
-		0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
-		0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
-		0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
-		0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
-		0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
-		0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
-		0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
-		0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
-		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-		0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
-		0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
-		0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
-		0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
-		0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
-		0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
-		0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
-		0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
-		0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
-		0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
-		0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
-		0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
-		0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
-		0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
-		0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
-		0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
-		0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
-		0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
-		0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
-		0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
-		0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
-		0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
-		0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
-		0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
-		0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
-		0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
-		0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
-		0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
-		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
-		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
-		0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
-		0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
-		0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
-		0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
-		0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
-		0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
-		0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
-		0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
-		0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
-		0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-		0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
-		0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
-		0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
-		0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
-		0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
-		0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
-		0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
-		0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
-		0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
-		0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
-		0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
-		0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
-		0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
-		0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
-		0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
-		0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
-		0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
-		0x16, 0x03, 0x02, 0x01, 0x0f, 0x0c, 0x00, 0x01,
-		0x0b, 0x03, 0x00, 0x19, 0x85, 0x04, 0x01, 0x39,
-		0xdc, 0xee, 0x44, 0x17, 0x5e, 0xdb, 0xd7, 0x27,
-		0xaf, 0xb6, 0x56, 0xd9, 0xb4, 0x43, 0x5a, 0x99,
-		0xcf, 0xaa, 0x31, 0x37, 0x0c, 0x6f, 0x3a, 0xa0,
-		0xf8, 0x53, 0xc4, 0x74, 0xd1, 0x91, 0x0a, 0x46,
-		0xf5, 0x38, 0x3b, 0x5c, 0x09, 0xd8, 0x97, 0xdc,
-		0x4b, 0xaa, 0x70, 0x26, 0x48, 0xf2, 0xd6, 0x0b,
-		0x31, 0xc9, 0xf8, 0xd4, 0x98, 0x43, 0xe1, 0x6c,
-		0xd5, 0xc7, 0xb2, 0x8e, 0x0b, 0x01, 0xe6, 0xb6,
-		0x00, 0x28, 0x80, 0x7b, 0xfc, 0x96, 0x8f, 0x0d,
-		0xa2, 0x4f, 0xb0, 0x79, 0xaf, 0xdc, 0x61, 0x28,
-		0x63, 0x33, 0x78, 0xf6, 0x31, 0x39, 0xfd, 0x8a,
-		0xf4, 0x15, 0x18, 0x11, 0xfe, 0xdb, 0xd5, 0x07,
-		0xda, 0x2c, 0xed, 0x49, 0xa0, 0x23, 0xbf, 0xd0,
-		0x3a, 0x38, 0x1d, 0x54, 0xae, 0x1c, 0x7b, 0xea,
-		0x29, 0xee, 0xd0, 0x38, 0xc1, 0x76, 0xa7, 0x7f,
-		0x2a, 0xf4, 0xce, 0x1e, 0xac, 0xcc, 0x94, 0x79,
-		0x90, 0x33, 0x00, 0x80, 0x16, 0x83, 0x9b, 0xf9,
-		0x72, 0xdb, 0x9f, 0x55, 0x02, 0xe1, 0x04, 0xf7,
-		0xb5, 0x3f, 0x4c, 0x71, 0x13, 0x5a, 0x91, 0xe9,
-		0x1d, 0xeb, 0x9d, 0x9c, 0xfb, 0x88, 0xef, 0xca,
-		0xec, 0x7d, 0x9b, 0xdd, 0xd9, 0xee, 0x2b, 0x8e,
-		0xef, 0xf8, 0xb6, 0xc7, 0x7d, 0xfe, 0xda, 0x7f,
-		0x90, 0x2e, 0x53, 0xf1, 0x64, 0x95, 0xfc, 0x66,
-		0xfc, 0x87, 0x27, 0xb6, 0x9f, 0xc8, 0x3a, 0x95,
-		0x68, 0x17, 0xe1, 0x7d, 0xf1, 0x88, 0xe8, 0x17,
-		0x5f, 0x99, 0x90, 0x3f, 0x47, 0x47, 0x81, 0x06,
-		0xe2, 0x8e, 0x22, 0x56, 0x8f, 0xc2, 0x14, 0xe5,
-		0x62, 0xa7, 0x0d, 0x41, 0x3c, 0xc7, 0x4a, 0x0a,
-		0x74, 0x4b, 0xda, 0x00, 0x8e, 0x4f, 0x90, 0xe6,
-		0xd7, 0x68, 0xe5, 0x8b, 0xf2, 0x3f, 0x53, 0x1d,
-		0x7a, 0xe6, 0xb3, 0xe9, 0x8a, 0xc9, 0x4d, 0x19,
-		0xa6, 0xcf, 0xf9, 0xed, 0x5e, 0x26, 0xdc, 0x90,
-		0x1c, 0x41, 0xad, 0x7c, 0x16, 0x03, 0x02, 0x00,
-		0x04, 0x0e, 0x00, 0x00, 0x00,
-	},
-	{
-		0x16, 0x03, 0x02, 0x00, 0x8a, 0x10, 0x00, 0x00,
-		0x86, 0x85, 0x04, 0x01, 0x11, 0xf2, 0xa4, 0x2d,
-		0x1a, 0x75, 0x6c, 0xbc, 0x2d, 0x91, 0x95, 0x07,
-		0xbe, 0xd6, 0x41, 0x7a, 0xbb, 0xc2, 0x7b, 0xa6,
-		0x9b, 0xe3, 0xdc, 0x41, 0x7f, 0x1e, 0x2e, 0xcc,
-		0x6d, 0xa3, 0x85, 0x53, 0x98, 0x9f, 0x2d, 0xe6,
-		0x3c, 0xb9, 0x82, 0xa6, 0x80, 0x53, 0x9b, 0x71,
-		0xfd, 0x27, 0xe5, 0xe5, 0xdf, 0x13, 0xba, 0x56,
-		0x62, 0x30, 0x4a, 0x57, 0x27, 0xa7, 0xcc, 0x26,
-		0x54, 0xe8, 0x65, 0x6e, 0x4d, 0x00, 0xbf, 0x8a,
-		0xcc, 0x89, 0x6a, 0x6c, 0x88, 0xda, 0x79, 0x4f,
-		0xc5, 0xad, 0x6d, 0x1d, 0x7c, 0x53, 0x7b, 0x1a,
-		0x96, 0xf2, 0xf8, 0x30, 0x01, 0x0b, 0xc2, 0xf0,
-		0x78, 0x41, 0xf4, 0x0d, 0xe0, 0xbe, 0xb9, 0x36,
-		0xe0, 0xb7, 0xee, 0x16, 0xeb, 0x25, 0x67, 0x04,
-		0xc0, 0x2e, 0xd8, 0x34, 0x4a, 0x65, 0xa5, 0xf1,
-		0x95, 0x75, 0xc7, 0x39, 0xa9, 0x68, 0xa9, 0x53,
-		0x93, 0x5b, 0xca, 0x7b, 0x7f, 0xc0, 0x63, 0x14,
-		0x03, 0x02, 0x00, 0x01, 0x01, 0x16, 0x03, 0x02,
-		0x00, 0x40, 0x01, 0xb1, 0xae, 0x1b, 0x8a, 0x65,
-		0xf8, 0x37, 0x50, 0x39, 0x76, 0xef, 0xaa, 0xda,
-		0x84, 0xc9, 0x5f, 0x80, 0xdc, 0xfa, 0xe0, 0x46,
-		0x5a, 0xc7, 0x77, 0x9d, 0x76, 0x03, 0xa6, 0xd5,
-		0x0e, 0xbf, 0x25, 0x30, 0x5c, 0x99, 0x7d, 0xcd,
-		0x2b, 0xaa, 0x2e, 0x8c, 0xdd, 0xda, 0xaa, 0xd7,
-		0xf1, 0xf6, 0x33, 0x47, 0x51, 0x1e, 0x83, 0xa1,
-		0x83, 0x04, 0xd2, 0xb2, 0xc8, 0xbc, 0x11, 0xc5,
-		0x1a, 0x87,
-	},
-	{
-		0x16, 0x03, 0x02, 0x00, 0x72, 0x04, 0x00, 0x00,
-		0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
-		0xeb, 0x8b, 0xc7, 0xef, 0xba, 0xe8, 0x0f, 0x69,
-		0xfe, 0xfb, 0xc3, 0x3d, 0x90, 0x5d, 0xd7, 0xb2,
-		0x51, 0x64, 0xac, 0xc3, 0xae, 0x33, 0x03, 0x42,
-		0x45, 0x2d, 0xa7, 0x57, 0xbd, 0xa3, 0x85, 0x64,
-		0xa6, 0xfe, 0x5c, 0x33, 0x04, 0x93, 0xf2, 0x7c,
-		0x06, 0x6d, 0xd7, 0xd7, 0xcf, 0x4a, 0xaf, 0xb2,
-		0xdd, 0x06, 0xdc, 0x28, 0x14, 0x59, 0x23, 0x02,
-		0xef, 0x97, 0x6a, 0xe8, 0xec, 0xca, 0x10, 0x44,
-		0xcd, 0xb8, 0x50, 0x16, 0x46, 0x5a, 0x05, 0xda,
-		0x04, 0xb3, 0x0e, 0xe9, 0xf0, 0x74, 0xc5, 0x23,
-		0xc2, 0x0e, 0xa1, 0x54, 0x66, 0x7b, 0xe8, 0x14,
-		0x03, 0x02, 0x00, 0x01, 0x01, 0x16, 0x03, 0x02,
-		0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x6b, 0x43, 0x1c, 0x58, 0xbc, 0x85,
-		0xf7, 0xc1, 0x76, 0xbc, 0x72, 0x33, 0x41, 0x6b,
-		0xb8, 0xf8, 0xfd, 0x53, 0x21, 0xc2, 0x41, 0x1b,
-		0x72, 0x4f, 0xce, 0x97, 0xca, 0x14, 0x23, 0x4d,
-		0xbc, 0x44, 0xd6, 0xd7, 0xfc, 0xbc, 0xfd, 0xfd,
-		0x5d, 0x33, 0x42, 0x1b, 0x52, 0x40, 0x0a, 0x2b,
-		0x6c, 0x98, 0x17, 0x03, 0x02, 0x00, 0x40, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d,
-		0x31, 0xef, 0x03, 0x7d, 0xa5, 0x74, 0x92, 0x24,
-		0x34, 0xae, 0x4e, 0xc9, 0xfc, 0x59, 0xcb, 0x64,
-		0xf4, 0x45, 0xb1, 0xac, 0x02, 0xf2, 0x87, 0xe7,
-		0x2f, 0xfd, 0x01, 0xca, 0x78, 0x02, 0x2e, 0x3a,
-		0x38, 0xcd, 0xb1, 0xe0, 0xf2, 0x2e, 0xf6, 0x27,
-		0xa0, 0xac, 0x1f, 0x91, 0x43, 0xc2, 0x3d, 0x15,
-		0x03, 0x02, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x9f, 0x30, 0x24, 0x56,
-		0x2c, 0xde, 0xa0, 0xe6, 0x44, 0x35, 0x30, 0x51,
-		0xec, 0xd4, 0x69, 0x2d, 0x46, 0x64, 0x04, 0x21,
-		0xfe, 0x7c, 0x4d, 0xc5, 0xd0, 0x8c, 0xf9, 0xd2,
-		0x3f, 0x88, 0x69, 0xd5,
-	},
+	test = &serverTest{
+		name:   "CipherSuiteCertPreferenceECDSA",
+		config: &config,
+	}
+	runServerTestTLS12(t, test)
 }
 
-// $ go test -run TestRunServer -serve -clientauth 1 \
-//     -ciphersuites=0xc011 -minversion=0x0303 -maxversion=0x0303
-var tls12ServerScript = [][]byte{
-	{
-		0x16, 0x03, 0x01, 0x01, 0x1e, 0x01, 0x00, 0x01,
-		0x1a, 0x03, 0x03, 0x51, 0xe5, 0x76, 0x84, 0x0e,
-		0xb9, 0x17, 0xca, 0x08, 0x47, 0xd9, 0xbd, 0xd0,
-		0x94, 0xd1, 0x97, 0xca, 0x5b, 0xe7, 0x20, 0xac,
-		0x8e, 0xbb, 0xc7, 0x29, 0xe9, 0x26, 0xcf, 0x7d,
-		0xb3, 0xdc, 0x99, 0x00, 0x00, 0x82, 0xc0, 0x30,
-		0xc0, 0x2c, 0xc0, 0x28, 0xc0, 0x24, 0xc0, 0x14,
-		0xc0, 0x0a, 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x6b,
-		0x00, 0x6a, 0x00, 0x39, 0x00, 0x38, 0xc0, 0x32,
-		0xc0, 0x2e, 0xc0, 0x2a, 0xc0, 0x26, 0xc0, 0x0f,
-		0xc0, 0x05, 0x00, 0x9d, 0x00, 0x3d, 0x00, 0x35,
-		0xc0, 0x12, 0xc0, 0x08, 0x00, 0x16, 0x00, 0x13,
-		0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a, 0xc0, 0x2f,
-		0xc0, 0x2b, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x13,
-		0xc0, 0x09, 0x00, 0xa2, 0x00, 0x9e, 0x00, 0x67,
-		0x00, 0x40, 0x00, 0x33, 0x00, 0x32, 0xc0, 0x31,
-		0xc0, 0x2d, 0xc0, 0x29, 0xc0, 0x25, 0xc0, 0x0e,
-		0xc0, 0x04, 0x00, 0x9c, 0x00, 0x3c, 0x00, 0x2f,
-		0x00, 0x07, 0xc0, 0x11, 0xc0, 0x07, 0xc0, 0x0c,
-		0xc0, 0x02, 0x00, 0x05, 0x00, 0x04, 0x00, 0x15,
-		0x00, 0x12, 0x00, 0x09, 0x00, 0x14, 0x00, 0x11,
-		0x00, 0x08, 0x00, 0x06, 0x00, 0x03, 0x00, 0xff,
-		0x01, 0x00, 0x00, 0x6f, 0x00, 0x0b, 0x00, 0x04,
-		0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, 0x34,
-		0x00, 0x32, 0x00, 0x0e, 0x00, 0x0d, 0x00, 0x19,
-		0x00, 0x0b, 0x00, 0x0c, 0x00, 0x18, 0x00, 0x09,
-		0x00, 0x0a, 0x00, 0x16, 0x00, 0x17, 0x00, 0x08,
-		0x00, 0x06, 0x00, 0x07, 0x00, 0x14, 0x00, 0x15,
-		0x00, 0x04, 0x00, 0x05, 0x00, 0x12, 0x00, 0x13,
-		0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x0f,
-		0x00, 0x10, 0x00, 0x11, 0x00, 0x23, 0x00, 0x00,
-		0x00, 0x0d, 0x00, 0x22, 0x00, 0x20, 0x06, 0x01,
-		0x06, 0x02, 0x06, 0x03, 0x05, 0x01, 0x05, 0x02,
-		0x05, 0x03, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03,
-		0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x02, 0x01,
-		0x02, 0x02, 0x02, 0x03, 0x01, 0x01, 0x00, 0x0f,
-		0x00, 0x01, 0x01,
-	},
-	{
-		0x16, 0x03, 0x03, 0x00, 0x30, 0x02, 0x00, 0x00,
-		0x2c, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0xc0, 0x11, 0x00, 0x00,
-		0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x03,
-		0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
-		0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
-		0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
-		0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
-		0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
-		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-		0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
-		0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
-		0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
-		0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
-		0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
-		0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
-		0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
-		0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
-		0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
-		0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
-		0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
-		0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
-		0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
-		0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
-		0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
-		0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
-		0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
-		0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
-		0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
-		0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
-		0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
-		0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
-		0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
-		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-		0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
-		0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
-		0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
-		0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
-		0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
-		0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
-		0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
-		0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
-		0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
-		0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
-		0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
-		0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
-		0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
-		0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
-		0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
-		0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
-		0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
-		0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
-		0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
-		0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
-		0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
-		0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
-		0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
-		0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
-		0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
-		0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
-		0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
-		0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
-		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
-		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
-		0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
-		0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
-		0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
-		0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
-		0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
-		0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
-		0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
-		0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
-		0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
-		0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-		0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
-		0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
-		0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
-		0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
-		0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
-		0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
-		0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
-		0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
-		0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
-		0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
-		0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
-		0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
-		0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
-		0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
-		0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
-		0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
-		0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
-		0x16, 0x03, 0x03, 0x01, 0x11, 0x0c, 0x00, 0x01,
-		0x0d, 0x03, 0x00, 0x19, 0x85, 0x04, 0x01, 0x39,
-		0xdc, 0xee, 0x44, 0x17, 0x5e, 0xdb, 0xd7, 0x27,
-		0xaf, 0xb6, 0x56, 0xd9, 0xb4, 0x43, 0x5a, 0x99,
-		0xcf, 0xaa, 0x31, 0x37, 0x0c, 0x6f, 0x3a, 0xa0,
-		0xf8, 0x53, 0xc4, 0x74, 0xd1, 0x91, 0x0a, 0x46,
-		0xf5, 0x38, 0x3b, 0x5c, 0x09, 0xd8, 0x97, 0xdc,
-		0x4b, 0xaa, 0x70, 0x26, 0x48, 0xf2, 0xd6, 0x0b,
-		0x31, 0xc9, 0xf8, 0xd4, 0x98, 0x43, 0xe1, 0x6c,
-		0xd5, 0xc7, 0xb2, 0x8e, 0x0b, 0x01, 0xe6, 0xb6,
-		0x00, 0x28, 0x80, 0x7b, 0xfc, 0x96, 0x8f, 0x0d,
-		0xa2, 0x4f, 0xb0, 0x79, 0xaf, 0xdc, 0x61, 0x28,
-		0x63, 0x33, 0x78, 0xf6, 0x31, 0x39, 0xfd, 0x8a,
-		0xf4, 0x15, 0x18, 0x11, 0xfe, 0xdb, 0xd5, 0x07,
-		0xda, 0x2c, 0xed, 0x49, 0xa0, 0x23, 0xbf, 0xd0,
-		0x3a, 0x38, 0x1d, 0x54, 0xae, 0x1c, 0x7b, 0xea,
-		0x29, 0xee, 0xd0, 0x38, 0xc1, 0x76, 0xa7, 0x7f,
-		0x2a, 0xf4, 0xce, 0x1e, 0xac, 0xcc, 0x94, 0x79,
-		0x90, 0x33, 0x04, 0x01, 0x00, 0x80, 0x4a, 0xf9,
-		0xf5, 0x0a, 0x61, 0x37, 0x7e, 0x4e, 0x92, 0xb5,
-		0x1c, 0x91, 0x21, 0xb2, 0xb5, 0x17, 0x00, 0xbf,
-		0x01, 0x5f, 0x30, 0xec, 0x62, 0x08, 0xd6, 0x9d,
-		0x1a, 0x08, 0x05, 0x72, 0x8b, 0xf4, 0x49, 0x85,
-		0xa7, 0xbf, 0x3f, 0x75, 0x58, 0x3e, 0x26, 0x82,
-		0xc3, 0x28, 0x07, 0xf9, 0x41, 0x7d, 0x03, 0x14,
-		0x3b, 0xc3, 0x05, 0x64, 0xff, 0x52, 0xf4, 0x75,
-		0x6a, 0x87, 0xcd, 0xdf, 0x93, 0x31, 0x0a, 0x71,
-		0x60, 0x17, 0xc6, 0x33, 0xf0, 0x79, 0xb6, 0x7b,
-		0xd0, 0x9c, 0xa0, 0x5f, 0x74, 0x14, 0x2c, 0x5a,
-		0xb4, 0x3f, 0x39, 0xf5, 0xe4, 0x9f, 0xbe, 0x6d,
-		0x21, 0xd2, 0xa9, 0x42, 0xf7, 0xdc, 0xa6, 0x65,
-		0xb7, 0x6a, 0x7e, 0x2e, 0x14, 0xd3, 0xf6, 0xf3,
-		0x4b, 0x4c, 0x5b, 0x1a, 0x70, 0x7a, 0xbc, 0xb0,
-		0x12, 0xf3, 0x6e, 0x0c, 0xcf, 0x43, 0x22, 0xae,
-		0x5b, 0xba, 0x00, 0xf8, 0xfd, 0xaf, 0x16, 0x03,
-		0x03, 0x00, 0x0f, 0x0d, 0x00, 0x00, 0x0b, 0x02,
-		0x01, 0x40, 0x00, 0x04, 0x04, 0x01, 0x04, 0x03,
-		0x00, 0x00, 0x16, 0x03, 0x03, 0x00, 0x04, 0x0e,
-		0x00, 0x00, 0x00,
-	},
-	{
-		0x16, 0x03, 0x03, 0x01, 0xfb, 0x0b, 0x00, 0x01,
-		0xf7, 0x00, 0x01, 0xf4, 0x00, 0x01, 0xf1, 0x30,
-		0x82, 0x01, 0xed, 0x30, 0x82, 0x01, 0x58, 0xa0,
-		0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x30,
-		0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
-		0x0d, 0x01, 0x01, 0x05, 0x30, 0x26, 0x31, 0x10,
-		0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
-		0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f,
-		0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
-		0x03, 0x13, 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30,
-		0x2e, 0x30, 0x2e, 0x31, 0x30, 0x1e, 0x17, 0x0d,
-		0x31, 0x31, 0x31, 0x32, 0x30, 0x38, 0x30, 0x37,
-		0x35, 0x35, 0x31, 0x32, 0x5a, 0x17, 0x0d, 0x31,
-		0x32, 0x31, 0x32, 0x30, 0x37, 0x30, 0x38, 0x30,
-		0x30, 0x31, 0x32, 0x5a, 0x30, 0x26, 0x31, 0x10,
-		0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
-		0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f,
-		0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
-		0x03, 0x13, 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30,
-		0x2e, 0x30, 0x2e, 0x31, 0x30, 0x81, 0x9c, 0x30,
-		0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
-		0x0d, 0x01, 0x01, 0x01, 0x03, 0x81, 0x8c, 0x00,
-		0x30, 0x81, 0x88, 0x02, 0x81, 0x80, 0x4e, 0xd0,
-		0x7b, 0x31, 0xe3, 0x82, 0x64, 0xd9, 0x59, 0xc0,
-		0xc2, 0x87, 0xa4, 0x5e, 0x1e, 0x8b, 0x73, 0x33,
-		0xc7, 0x63, 0x53, 0xdf, 0x66, 0x92, 0x06, 0x84,
-		0xf6, 0x64, 0xd5, 0x8f, 0xe4, 0x36, 0xa7, 0x1d,
-		0x2b, 0xe8, 0xb3, 0x20, 0x36, 0x45, 0x23, 0xb5,
-		0xe3, 0x95, 0xae, 0xed, 0xe0, 0xf5, 0x20, 0x9c,
-		0x8d, 0x95, 0xdf, 0x7f, 0x5a, 0x12, 0xef, 0x87,
-		0xe4, 0x5b, 0x68, 0xe4, 0xe9, 0x0e, 0x74, 0xec,
-		0x04, 0x8a, 0x7f, 0xde, 0x93, 0x27, 0xc4, 0x01,
-		0x19, 0x7a, 0xbd, 0xf2, 0xdc, 0x3d, 0x14, 0xab,
-		0xd0, 0x54, 0xca, 0x21, 0x0c, 0xd0, 0x4d, 0x6e,
-		0x87, 0x2e, 0x5c, 0xc5, 0xd2, 0xbb, 0x4d, 0x4b,
-		0x4f, 0xce, 0xb6, 0x2c, 0xf7, 0x7e, 0x88, 0xec,
-		0x7c, 0xd7, 0x02, 0x91, 0x74, 0xa6, 0x1e, 0x0c,
-		0x1a, 0xda, 0xe3, 0x4a, 0x5a, 0x2e, 0xde, 0x13,
-		0x9c, 0x4c, 0x40, 0x88, 0x59, 0x93, 0x02, 0x03,
-		0x01, 0x00, 0x01, 0xa3, 0x32, 0x30, 0x30, 0x30,
-		0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01,
-		0xff, 0x04, 0x04, 0x03, 0x02, 0x00, 0xa0, 0x30,
-		0x0d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x06,
-		0x04, 0x04, 0x01, 0x02, 0x03, 0x04, 0x30, 0x0f,
-		0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x08, 0x30,
-		0x06, 0x80, 0x04, 0x01, 0x02, 0x03, 0x04, 0x30,
-		0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
-		0x0d, 0x01, 0x01, 0x05, 0x03, 0x81, 0x81, 0x00,
-		0x36, 0x1f, 0xb3, 0x7a, 0x0c, 0x75, 0xc9, 0x6e,
-		0x37, 0x46, 0x61, 0x2b, 0xd5, 0xbd, 0xc0, 0xa7,
-		0x4b, 0xcc, 0x46, 0x9a, 0x81, 0x58, 0x7c, 0x85,
-		0x79, 0x29, 0xc8, 0xc8, 0xc6, 0x67, 0xdd, 0x32,
-		0x56, 0x45, 0x2b, 0x75, 0xb6, 0xe9, 0x24, 0xa9,
-		0x50, 0x9a, 0xbe, 0x1f, 0x5a, 0xfa, 0x1a, 0x15,
-		0xd9, 0xcc, 0x55, 0x95, 0x72, 0x16, 0x83, 0xb9,
-		0xc2, 0xb6, 0x8f, 0xfd, 0x88, 0x8c, 0x38, 0x84,
-		0x1d, 0xab, 0x5d, 0x92, 0x31, 0x13, 0x4f, 0xfd,
-		0x83, 0x3b, 0xc6, 0x9d, 0xf1, 0x11, 0x62, 0xb6,
-		0x8b, 0xec, 0xab, 0x67, 0xbe, 0xc8, 0x64, 0xb0,
-		0x11, 0x50, 0x46, 0x58, 0x17, 0x6b, 0x99, 0x1c,
-		0xd3, 0x1d, 0xfc, 0x06, 0xf1, 0x0e, 0xe5, 0x96,
-		0xa8, 0x0c, 0xf9, 0x78, 0x20, 0xb7, 0x44, 0x18,
-		0x51, 0x8d, 0x10, 0x7e, 0x4f, 0x94, 0x67, 0xdf,
-		0xa3, 0x4e, 0x70, 0x73, 0x8e, 0x90, 0x91, 0x85,
-		0x16, 0x03, 0x03, 0x00, 0x8a, 0x10, 0x00, 0x00,
-		0x86, 0x85, 0x04, 0x01, 0x5d, 0x3a, 0x92, 0x59,
-		0x7f, 0x9a, 0x22, 0x36, 0x0e, 0x1b, 0x1d, 0x2a,
-		0x05, 0xb7, 0xa4, 0xb6, 0x5d, 0xfc, 0x51, 0x6e,
-		0x15, 0xe5, 0x89, 0x7c, 0xe2, 0xfa, 0x87, 0x38,
-		0x05, 0x79, 0x15, 0x92, 0xb4, 0x8f, 0x88, 0x8f,
-		0x9d, 0x5d, 0xa0, 0xaf, 0xf8, 0xce, 0xf9, 0x6f,
-		0x83, 0xf4, 0x08, 0x69, 0xe4, 0x91, 0xc5, 0xed,
-		0xb9, 0xc5, 0xa8, 0x1f, 0x4b, 0xec, 0xef, 0x91,
-		0xc1, 0xa3, 0x34, 0x24, 0x18, 0x00, 0x2d, 0xcd,
-		0xe6, 0x44, 0xef, 0x5a, 0x3e, 0x52, 0x63, 0x5b,
-		0x36, 0x1f, 0x7e, 0xce, 0x9e, 0xaa, 0xda, 0x8d,
-		0xb5, 0xc9, 0xea, 0xd8, 0x1b, 0xd1, 0x1c, 0x7c,
-		0x07, 0xfc, 0x3c, 0x2d, 0x70, 0x1f, 0xf9, 0x4d,
-		0xcb, 0xaa, 0xad, 0x07, 0xd5, 0x6d, 0xbd, 0xa6,
-		0x61, 0xf3, 0x2f, 0xa3, 0x9c, 0x45, 0x02, 0x4a,
-		0xac, 0x6c, 0xb6, 0x37, 0x95, 0xb1, 0x4a, 0xb5,
-		0x0a, 0x4e, 0x60, 0x67, 0xd7, 0xe0, 0x04, 0x16,
-		0x03, 0x03, 0x00, 0x88, 0x0f, 0x00, 0x00, 0x84,
-		0x04, 0x01, 0x00, 0x80, 0x08, 0x83, 0x53, 0xf0,
-		0xf8, 0x14, 0xf5, 0xc2, 0xd1, 0x8b, 0xf0, 0xa5,
-		0xc1, 0xd8, 0x1a, 0x36, 0x4b, 0x75, 0x77, 0x02,
-		0x19, 0xd8, 0x11, 0x3f, 0x5a, 0x36, 0xfc, 0xe9,
-		0x2b, 0x4b, 0xf9, 0xfe, 0xda, 0x8a, 0x0f, 0x6e,
-		0x3d, 0xd3, 0x52, 0x87, 0xf7, 0x9c, 0x78, 0x39,
-		0xa8, 0xf1, 0xd7, 0xf7, 0x4e, 0x35, 0x33, 0xf9,
-		0xc5, 0x76, 0xa8, 0x12, 0xc4, 0x91, 0x33, 0x1d,
-		0x93, 0x8c, 0xbf, 0xb1, 0x83, 0x00, 0x90, 0xc5,
-		0x52, 0x3e, 0xe0, 0x0a, 0xe8, 0x92, 0x75, 0xdf,
-		0x54, 0x5f, 0x9f, 0x95, 0x76, 0x62, 0xb5, 0x85,
-		0x69, 0xa4, 0x86, 0x85, 0x6c, 0xf3, 0x6b, 0x2a,
-		0x72, 0x7b, 0x4d, 0x42, 0x33, 0x67, 0x4a, 0xce,
-		0xb5, 0xdb, 0x9b, 0xae, 0xc0, 0xb0, 0x10, 0xeb,
-		0x3b, 0xf4, 0xc2, 0x9a, 0x64, 0x47, 0x4c, 0x1e,
-		0xa5, 0x91, 0x7f, 0x6d, 0xd1, 0x03, 0xf5, 0x4a,
-		0x90, 0x69, 0x18, 0xb1, 0x14, 0x03, 0x03, 0x00,
-		0x01, 0x01, 0x16, 0x03, 0x03, 0x00, 0x24, 0x59,
-		0xfc, 0x7e, 0xae, 0xb3, 0xbf, 0xab, 0x4d, 0xdb,
-		0x4e, 0xab, 0xa9, 0x6d, 0x6b, 0x4c, 0x60, 0xb6,
-		0x16, 0xe0, 0xab, 0x7f, 0x52, 0x2d, 0xa1, 0xfc,
-		0xe1, 0x80, 0xd2, 0x8a, 0xa1, 0xe5, 0x8f, 0xa1,
-		0x70, 0x93, 0x23,
-	},
-	{
-		0x16, 0x03, 0x03, 0x02, 0x67, 0x04, 0x00, 0x02,
-		0x63, 0x00, 0x00, 0x00, 0x00, 0x02, 0x5d, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
-		0xea, 0x8b, 0xc5, 0xef, 0xba, 0x64, 0xb7, 0x23,
-		0x08, 0x86, 0x4f, 0x37, 0xe0, 0x8f, 0xbd, 0x75,
-		0x71, 0x2b, 0xcb, 0x20, 0x75, 0x11, 0x3b, 0xa2,
-		0x9e, 0x39, 0x3c, 0x03, 0xef, 0x6e, 0x41, 0xd7,
-		0xcf, 0x1a, 0x2c, 0xf2, 0xfe, 0xc2, 0xd3, 0x65,
-		0x59, 0x00, 0x9d, 0x03, 0xb4, 0xf2, 0x20, 0xe4,
-		0x33, 0x80, 0xcd, 0xf6, 0xe4, 0x59, 0x22, 0xf7,
-		0xfd, 0x88, 0x0e, 0xa4, 0x09, 0xc0, 0x0d, 0x10,
-		0x80, 0x10, 0x79, 0xee, 0x70, 0x96, 0xdb, 0x22,
-		0x8b, 0xb7, 0xac, 0xe0, 0x98, 0xad, 0xe9, 0xe3,
-		0xcb, 0xea, 0x9f, 0xe6, 0x83, 0x28, 0x7c, 0x7e,
-		0x4e, 0x9a, 0x8d, 0xd9, 0xf3, 0x86, 0xf4, 0x89,
-		0x8b, 0x79, 0x8f, 0xbb, 0xe9, 0x74, 0x02, 0x02,
-		0x14, 0x04, 0xea, 0xba, 0x16, 0x10, 0xa1, 0x85,
-		0xbe, 0x4e, 0x4e, 0x92, 0xc5, 0x83, 0xf6, 0x1e,
-		0x1f, 0xd4, 0x25, 0xc2, 0xc2, 0xb9, 0xce, 0x33,
-		0x63, 0x66, 0x79, 0x1f, 0x54, 0x35, 0xc1, 0xe8,
-		0x89, 0x34, 0x78, 0x94, 0x36, 0x14, 0xef, 0x01,
-		0x1f, 0xf1, 0xbd, 0x77, 0x2c, 0x4d, 0xac, 0x5c,
-		0x5c, 0x4a, 0xc6, 0xed, 0xd8, 0x0e, 0x72, 0x84,
-		0x83, 0xdc, 0x56, 0x84, 0xc8, 0xf3, 0x89, 0x56,
-		0xfd, 0x89, 0xc1, 0xc9, 0x9a, 0x29, 0x91, 0x7e,
-		0x19, 0xe9, 0x8b, 0x5b, 0x11, 0x15, 0x4e, 0x6c,
-		0xf4, 0x89, 0xe7, 0x6d, 0x68, 0x1e, 0xf9, 0x6c,
-		0x23, 0x72, 0x05, 0x68, 0x82, 0x60, 0x84, 0x1f,
-		0x83, 0x20, 0x09, 0x86, 0x10, 0x81, 0xec, 0xec,
-		0xdc, 0x25, 0x53, 0x20, 0xfa, 0xa9, 0x41, 0x64,
-		0xd6, 0x20, 0xf3, 0xf4, 0x52, 0xf2, 0x80, 0x62,
-		0x83, 0xc9, 0x23, 0x66, 0x44, 0x95, 0x5a, 0x99,
-		0x8a, 0xe1, 0x26, 0x63, 0xc1, 0x8b, 0x31, 0xf9,
-		0x21, 0x06, 0x77, 0x04, 0x27, 0xf2, 0x0c, 0x63,
-		0x83, 0x45, 0xa0, 0xa9, 0x7b, 0xcf, 0xdf, 0xd7,
-		0x56, 0x75, 0xbc, 0xdd, 0x95, 0x36, 0xb1, 0x75,
-		0x39, 0x05, 0x00, 0x3c, 0x8a, 0x79, 0xd6, 0xe9,
-		0xf0, 0x4b, 0xdc, 0x51, 0x6b, 0x01, 0x94, 0x16,
-		0x87, 0x12, 0x92, 0x6c, 0x07, 0xc1, 0xf5, 0x58,
-		0xb7, 0x2a, 0x81, 0xf5, 0xa0, 0x37, 0x8b, 0xa6,
-		0x22, 0xfe, 0x28, 0x0a, 0x7e, 0x68, 0xe2, 0xda,
-		0x6c, 0x53, 0xee, 0x0e, 0x8d, 0x2d, 0x8b, 0x0b,
-		0xda, 0xf8, 0x99, 0x3e, 0x0e, 0xed, 0x9f, 0xc1,
-		0x2b, 0xf6, 0xfe, 0xe9, 0x52, 0x38, 0x7b, 0x83,
-		0x9a, 0x50, 0xa6, 0xd7, 0x49, 0x83, 0x43, 0x7e,
-		0x82, 0xec, 0xc7, 0x09, 0x3d, 0x3d, 0xb1, 0xee,
-		0xe8, 0xc5, 0x6a, 0xc3, 0x3d, 0x4b, 0x4c, 0x6a,
-		0xbb, 0x0b, 0x2c, 0x24, 0x2e, 0xdb, 0x7d, 0x57,
-		0x87, 0xb4, 0x80, 0xa5, 0xae, 0xff, 0x54, 0xa8,
-		0xa5, 0x27, 0x69, 0x95, 0xc8, 0xe7, 0x79, 0xc7,
-		0x89, 0x2a, 0x73, 0x49, 0xcb, 0xf5, 0xc5, 0xbc,
-		0x4a, 0xe0, 0x73, 0xa9, 0xbc, 0x88, 0x64, 0x96,
-		0x98, 0xa5, 0x1e, 0xe3, 0x43, 0xc1, 0x7d, 0x78,
-		0xc7, 0x94, 0x72, 0xd4, 0x2c, 0x6e, 0x85, 0x39,
-		0x9a, 0xaf, 0xdb, 0xa1, 0xe9, 0xe2, 0xcb, 0x37,
-		0x04, 0xc6, 0x8c, 0x81, 0xd3, 0x2a, 0xb7, 0xbe,
-		0x6c, 0x07, 0x1f, 0x5e, 0xd9, 0x00, 0xd2, 0xf7,
-		0xe1, 0xa7, 0xbc, 0x0c, 0xb6, 0x6d, 0xfb, 0x3f,
-		0x3d, 0x24, 0xaa, 0xfb, 0x7e, 0xe1, 0xb5, 0x1b,
-		0xff, 0x38, 0xaa, 0x69, 0x59, 0x38, 0x52, 0x9a,
-		0x0e, 0x6d, 0xbc, 0xde, 0x4f, 0x13, 0x09, 0x17,
-		0xc4, 0xa9, 0x05, 0x84, 0xbc, 0x50, 0xef, 0x40,
-		0xb0, 0x4c, 0x24, 0x32, 0xed, 0x94, 0x2c, 0xdd,
-		0xda, 0x20, 0x24, 0x67, 0xe2, 0xea, 0x71, 0x3d,
-		0x4a, 0x04, 0x0d, 0x98, 0x29, 0x20, 0x4c, 0xeb,
-		0x70, 0xce, 0x45, 0x9e, 0x5a, 0xaf, 0xb6, 0xa3,
-		0x92, 0xc8, 0x28, 0xf2, 0xe3, 0xe8, 0x8a, 0x5d,
-		0x0a, 0x33, 0x79, 0x9b, 0x6a, 0xf3, 0x30, 0x01,
-		0x1d, 0x47, 0xbd, 0x01, 0xcc, 0x4d, 0x71, 0xc0,
-		0x56, 0xfa, 0xfd, 0x37, 0xed, 0x0f, 0x27, 0xc0,
-		0xbb, 0xa0, 0xee, 0xc3, 0x79, 0x8b, 0xe7, 0x41,
-		0x8f, 0xfa, 0x3a, 0xcb, 0x45, 0x3b, 0x85, 0x9f,
-		0x06, 0x90, 0xb2, 0x51, 0xc0, 0x48, 0x10, 0xac,
-		0x2a, 0xec, 0xec, 0x48, 0x7a, 0x19, 0x47, 0xc4,
-		0x2a, 0xeb, 0xb3, 0xa2, 0x07, 0x22, 0x32, 0x78,
-		0xf4, 0x73, 0x5e, 0x92, 0x42, 0x15, 0xa1, 0x90,
-		0x91, 0xd0, 0xeb, 0x12, 0x14, 0x03, 0x03, 0x00,
-		0x01, 0x01, 0x16, 0x03, 0x03, 0x00, 0x24, 0x45,
-		0x4b, 0x80, 0x42, 0x46, 0xde, 0xbb, 0xe7, 0x76,
-		0xd1, 0x33, 0x92, 0xfc, 0x46, 0x17, 0x6d, 0x21,
-		0xf6, 0x0e, 0x16, 0xca, 0x9b, 0x9b, 0x04, 0x65,
-		0x16, 0x40, 0x44, 0x64, 0xbc, 0x58, 0xfa, 0x2a,
-		0x49, 0xe9, 0xed, 0x17, 0x03, 0x03, 0x00, 0x21,
-		0x89, 0x71, 0xcd, 0x56, 0x54, 0xbf, 0x73, 0xde,
-		0xfb, 0x4b, 0x4e, 0xf1, 0x7f, 0xc6, 0x75, 0xa6,
-		0xbd, 0x6b, 0x6c, 0xd9, 0xdc, 0x0c, 0x71, 0xb4,
-		0xb9, 0xbb, 0x6e, 0xfa, 0x9e, 0xc7, 0xc7, 0x4c,
-		0x24, 0x15, 0x03, 0x03, 0x00, 0x16, 0x62, 0xea,
-		0x65, 0x69, 0x68, 0x4a, 0xce, 0xa7, 0x9e, 0xce,
-		0xc0, 0xf1, 0x5c, 0x96, 0xd9, 0x1f, 0x49, 0xac,
-		0x2d, 0x05, 0x89, 0x94,
-	},
+func TestResumption(t *testing.T) {
+	sessionFilePath := tempFile("")
+	defer os.Remove(sessionFilePath)
+
+	test := &serverTest{
+		name:    "IssueTicket",
+		command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_out", sessionFilePath},
+	}
+	runServerTestTLS12(t, test)
+
+	test = &serverTest{
+		name:    "Resume",
+		command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_in", sessionFilePath},
+	}
+	runServerTestTLS12(t, test)
 }
 
 // cert.pem and key.pem were generated with generate_cert.go
 // Thus, they have no ExtKeyUsage fields and trigger an error
 // when verification is turned on.
 
-var clientCertificate = loadPEMCert(`
+const clientCertificatePEM = `
 -----BEGIN CERTIFICATE-----
 MIIB7TCCAVigAwIBAgIBADALBgkqhkiG9w0BAQUwJjEQMA4GA1UEChMHQWNtZSBD
 bzESMBAGA1UEAxMJMTI3LjAuMC4xMB4XDTExMTIwODA3NTUxMloXDTEyMTIwNzA4
@@ -3147,10 +574,9 @@ DwYDVR0jBAgwBoAEAQIDBDALBgkqhkiG9w0BAQUDgYEANh+zegx1yW43RmEr1b3A
 p0vMRpqBWHyFeSnIyMZn3TJWRSt1tukkqVCavh9a+hoV2cxVlXIWg7nCto/9iIw4
 hB2rXZIxE0/9gzvGnfERYraL7KtnvshksBFQRlgXa5kc0x38BvEO5ZaoDPl4ILdE
 GFGNEH5PlGffo05wc46QkYU=
------END CERTIFICATE-----
-`)
+-----END CERTIFICATE-----`
 
-/* corresponding key.pem for cert.pem is:
+const clientKeyPEM = `
 -----BEGIN RSA PRIVATE KEY-----
 MIICWgIBAAKBgE7QezHjgmTZWcDCh6ReHotzM8djU99mkgaE9mTVj+Q2px0r6LMg
 NkUjteOVru3g9SCcjZXff1oS74fkW2jk6Q507ASKf96TJ8QBGXq98tw9FKvQVMoh
@@ -3165,10 +591,9 @@ saG9sF+UEhRt9AxUfW/U/tIQ9V0ZHHcSg1XaCM5Nvp934brdKdvTOKnJAkBD5h/3
 Rybatlvg/fzBEaJFyq09zhngkxlZOUtBVTqzl17RVvY2orgH02U4HbCHy4phxOn7
 qTdQRYlHRftgnWK1AkANibn9PRYJ7mJyJ9Dyj2QeNcSkSTzrt0tPvUMf4+meJymN
 1Ntu5+S1DLLzfxlaljWG6ylW6DNxujCyuXIV2rvA
------END RSA PRIVATE KEY-----
-*/
+-----END RSA PRIVATE KEY-----`
 
-var clientECDSACertificate = loadPEMCert(`
+const clientECDSACertificatePEM = `
 -----BEGIN CERTIFICATE-----
 MIIB/DCCAV4CCQCaMIRsJjXZFzAJBgcqhkjOPQQBMEUxCzAJBgNVBAYTAkFVMRMw
 EQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0
@@ -3181,10 +606,9 @@ ixgnTy5w/hOWusPTQBbNZU6sER7m8TAJBgcqhkjOPQQBA4GMADCBiAJCAOAUxGBg
 C3JosDJdYUoCdFzCgbkWqD8pyDbHgf9stlvZcPE4O1BIKJTLCRpS8V3ujfK58PDa
 2RU6+b0DeoeiIzXsAkIBo9SKeDUcSpoj0gq+KxAxnZxfvuiRs9oa9V2jI/Umi0Vw
 jWVim34BmT0Y9hCaOGGbLlfk+syxis7iI6CH8OFnUes=
------END CERTIFICATE-----
-`)
+-----END CERTIFICATE-----`
 
-/* corresponding key for cert is:
+const clientECDSAKeyPEM = `
 -----BEGIN EC PARAMETERS-----
 BgUrgQQAIw==
 -----END EC PARAMETERS-----
@@ -3194,603 +618,83 @@ k+wLWoqizS3NpQyMtrU8JFdWfj+C57UNkOugBwYFK4EEACOhgYkDgYYABACVjJF1
 FMBexFe01MNvja5oHt1vzobhfm6ySD6B5U7ixohLZNz1MLvT/2XMW/TdtWo+PtAd
 3kfDdq0Z9kUsjLzYHQFMH3CQRnZIi4+DzEpcj0B22uCJ7B0rxE4wdihBsmKo+1vx
 +U56jb0JuK7qixgnTy5w/hOWusPTQBbNZU6sER7m8Q==
------END EC PRIVATE KEY-----
-*/
-var clientauthECDSATests = []clientauthTest{
-	// Server asks for cert with empty CA list, client gives one
-	//   go test -run "TestRunServer" -serve \
-	//     -clientauth 1 -ciphersuites=0xc00a
-	//   openssl s_client -host 127.0.0.1 -port 10443 \
-	//     -cipher ECDHE-ECDSA-AES256-SHA -key client.key -cert client.crt
-	{"RequestClientCert, client gives it", RequestClientCert, []*x509.Certificate{clientECDSACertificate}, [][]byte{
-		{
-			0x16, 0x03, 0x01, 0x00, 0xa0, 0x01, 0x00, 0x00,
-			0x9c, 0x03, 0x03, 0x51, 0xe5, 0x73, 0xc5, 0xae,
-			0x51, 0x94, 0xb4, 0xf2, 0xe8, 0xf6, 0x03, 0x0e,
-			0x3b, 0x34, 0xaf, 0xf0, 0xdc, 0x1b, 0xcc, 0xd8,
-			0x0c, 0x45, 0x82, 0xd4, 0xd6, 0x76, 0x04, 0x6e,
-			0x4f, 0x7a, 0x24, 0x00, 0x00, 0x04, 0xc0, 0x0a,
-			0x00, 0xff, 0x01, 0x00, 0x00, 0x6f, 0x00, 0x0b,
-			0x00, 0x04, 0x03, 0x00, 0x01, 0x02, 0x00, 0x0a,
-			0x00, 0x34, 0x00, 0x32, 0x00, 0x0e, 0x00, 0x0d,
-			0x00, 0x19, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x18,
-			0x00, 0x09, 0x00, 0x0a, 0x00, 0x16, 0x00, 0x17,
-			0x00, 0x08, 0x00, 0x06, 0x00, 0x07, 0x00, 0x14,
-			0x00, 0x15, 0x00, 0x04, 0x00, 0x05, 0x00, 0x12,
-			0x00, 0x13, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03,
-			0x00, 0x0f, 0x00, 0x10, 0x00, 0x11, 0x00, 0x23,
-			0x00, 0x00, 0x00, 0x0d, 0x00, 0x22, 0x00, 0x20,
-			0x06, 0x01, 0x06, 0x02, 0x06, 0x03, 0x05, 0x01,
-			0x05, 0x02, 0x05, 0x03, 0x04, 0x01, 0x04, 0x02,
-			0x04, 0x03, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03,
-			0x02, 0x01, 0x02, 0x02, 0x02, 0x03, 0x01, 0x01,
-			0x00, 0x0f, 0x00, 0x01, 0x01,
-		},
-		{
-			0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00,
-			0x2c, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-			0x00, 0x00, 0x00, 0x00, 0xc0, 0x0a, 0x00, 0x00,
-			0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01,
-			0x02, 0x0e, 0x0b, 0x00, 0x02, 0x0a, 0x00, 0x02,
-			0x07, 0x00, 0x02, 0x04, 0x30, 0x82, 0x02, 0x00,
-			0x30, 0x82, 0x01, 0x62, 0x02, 0x09, 0x00, 0xb8,
-			0xbf, 0x2d, 0x47, 0xa0, 0xd2, 0xeb, 0xf4, 0x30,
-			0x09, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d,
-			0x04, 0x01, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
-			0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
-			0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
-			0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
-			0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
-			0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
-			0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
-			0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
-			0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
-			0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x31,
-			0x31, 0x32, 0x32, 0x31, 0x35, 0x30, 0x36, 0x33,
-			0x32, 0x5a, 0x17, 0x0d, 0x32, 0x32, 0x31, 0x31,
-			0x32, 0x30, 0x31, 0x35, 0x30, 0x36, 0x33, 0x32,
-			0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06,
-			0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55,
-			0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
-			0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d,
-			0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30,
-			0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18,
-			0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
-			0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73,
-			0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64,
-			0x30, 0x81, 0x9b, 0x30, 0x10, 0x06, 0x07, 0x2a,
-			0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05,
-			0x2b, 0x81, 0x04, 0x00, 0x23, 0x03, 0x81, 0x86,
-			0x00, 0x04, 0x00, 0xc4, 0xa1, 0xed, 0xbe, 0x98,
-			0xf9, 0x0b, 0x48, 0x73, 0x36, 0x7e, 0xc3, 0x16,
-			0x56, 0x11, 0x22, 0xf2, 0x3d, 0x53, 0xc3, 0x3b,
-			0x4d, 0x21, 0x3d, 0xcd, 0x6b, 0x75, 0xe6, 0xf6,
-			0xb0, 0xdc, 0x9a, 0xdf, 0x26, 0xc1, 0xbc, 0xb2,
-			0x87, 0xf0, 0x72, 0x32, 0x7c, 0xb3, 0x64, 0x2f,
-			0x1c, 0x90, 0xbc, 0xea, 0x68, 0x23, 0x10, 0x7e,
-			0xfe, 0xe3, 0x25, 0xc0, 0x48, 0x3a, 0x69, 0xe0,
-			0x28, 0x6d, 0xd3, 0x37, 0x00, 0xef, 0x04, 0x62,
-			0xdd, 0x0d, 0xa0, 0x9c, 0x70, 0x62, 0x83, 0xd8,
-			0x81, 0xd3, 0x64, 0x31, 0xaa, 0x9e, 0x97, 0x31,
-			0xbd, 0x96, 0xb0, 0x68, 0xc0, 0x9b, 0x23, 0xde,
-			0x76, 0x64, 0x3f, 0x1a, 0x5c, 0x7f, 0xe9, 0x12,
-			0x0e, 0x58, 0x58, 0xb6, 0x5f, 0x70, 0xdd, 0x9b,
-			0xd8, 0xea, 0xd5, 0xd7, 0xf5, 0xd5, 0xcc, 0xb9,
-			0xb6, 0x9f, 0x30, 0x66, 0x5b, 0x66, 0x9a, 0x20,
-			0xe2, 0x27, 0xe5, 0xbf, 0xfe, 0x3b, 0x30, 0x09,
-			0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04,
-			0x01, 0x03, 0x81, 0x8c, 0x00, 0x30, 0x81, 0x88,
-			0x02, 0x42, 0x01, 0x88, 0xa2, 0x4f, 0xeb, 0xe2,
-			0x45, 0xc5, 0x48, 0x7d, 0x1b, 0xac, 0xf5, 0xed,
-			0x98, 0x9d, 0xae, 0x47, 0x70, 0xc0, 0x5e, 0x1b,
-			0xb6, 0x2f, 0xbd, 0xf1, 0xb6, 0x4d, 0xb7, 0x61,
-			0x40, 0xd3, 0x11, 0xa2, 0xce, 0xee, 0x0b, 0x7e,
-			0x92, 0x7e, 0xff, 0x76, 0x9d, 0xc3, 0x3b, 0x7e,
-			0xa5, 0x3f, 0xce, 0xfa, 0x10, 0xe2, 0x59, 0xec,
-			0x47, 0x2d, 0x7c, 0xac, 0xda, 0x4e, 0x97, 0x0e,
-			0x15, 0xa0, 0x6f, 0xd0, 0x02, 0x42, 0x01, 0x4d,
-			0xfc, 0xbe, 0x67, 0x13, 0x9c, 0x2d, 0x05, 0x0e,
-			0xbd, 0x3f, 0xa3, 0x8c, 0x25, 0xc1, 0x33, 0x13,
-			0x83, 0x0d, 0x94, 0x06, 0xbb, 0xd4, 0x37, 0x7a,
-			0xf6, 0xec, 0x7a, 0xc9, 0x86, 0x2e, 0xdd, 0xd7,
-			0x11, 0x69, 0x7f, 0x85, 0x7c, 0x56, 0xde, 0xfb,
-			0x31, 0x78, 0x2b, 0xe4, 0xc7, 0x78, 0x0d, 0xae,
-			0xcb, 0xbe, 0x9e, 0x4e, 0x36, 0x24, 0x31, 0x7b,
-			0x6a, 0x0f, 0x39, 0x95, 0x12, 0x07, 0x8f, 0x2a,
-			0x16, 0x03, 0x01, 0x01, 0x1a, 0x0c, 0x00, 0x01,
-			0x16, 0x03, 0x00, 0x19, 0x85, 0x04, 0x01, 0x39,
-			0xdc, 0xee, 0x44, 0x17, 0x5e, 0xdb, 0xd7, 0x27,
-			0xaf, 0xb6, 0x56, 0xd9, 0xb4, 0x43, 0x5a, 0x99,
-			0xcf, 0xaa, 0x31, 0x37, 0x0c, 0x6f, 0x3a, 0xa0,
-			0xf8, 0x53, 0xc4, 0x74, 0xd1, 0x91, 0x0a, 0x46,
-			0xf5, 0x38, 0x3b, 0x5c, 0x09, 0xd8, 0x97, 0xdc,
-			0x4b, 0xaa, 0x70, 0x26, 0x48, 0xf2, 0xd6, 0x0b,
-			0x31, 0xc9, 0xf8, 0xd4, 0x98, 0x43, 0xe1, 0x6c,
-			0xd5, 0xc7, 0xb2, 0x8e, 0x0b, 0x01, 0xe6, 0xb6,
-			0x00, 0x28, 0x80, 0x7b, 0xfc, 0x96, 0x8f, 0x0d,
-			0xa2, 0x4f, 0xb0, 0x79, 0xaf, 0xdc, 0x61, 0x28,
-			0x63, 0x33, 0x78, 0xf6, 0x31, 0x39, 0xfd, 0x8a,
-			0xf4, 0x15, 0x18, 0x11, 0xfe, 0xdb, 0xd5, 0x07,
-			0xda, 0x2c, 0xed, 0x49, 0xa0, 0x23, 0xbf, 0xd0,
-			0x3a, 0x38, 0x1d, 0x54, 0xae, 0x1c, 0x7b, 0xea,
-			0x29, 0xee, 0xd0, 0x38, 0xc1, 0x76, 0xa7, 0x7f,
-			0x2a, 0xf4, 0xce, 0x1e, 0xac, 0xcc, 0x94, 0x79,
-			0x90, 0x33, 0x00, 0x8b, 0x30, 0x81, 0x88, 0x02,
-			0x42, 0x00, 0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04,
-			0x04, 0xe9, 0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23,
-			0x95, 0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x05,
-			0x3f, 0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b,
-			0x4d, 0x3d, 0xba, 0xa1, 0x4b, 0x5e, 0x77, 0xef,
-			0xe7, 0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2,
-			0xff, 0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85,
-			0x6a, 0x42, 0x9b, 0xf9, 0x7e, 0x7e, 0x31, 0xc2,
-			0xe5, 0xbd, 0x66, 0x02, 0x42, 0x00, 0xad, 0x7d,
-			0x06, 0x35, 0xab, 0xec, 0x8d, 0xac, 0xd4, 0xba,
-			0x1b, 0x49, 0x5e, 0x05, 0x5f, 0xf0, 0x97, 0x93,
-			0x82, 0xb8, 0x2b, 0x8d, 0x91, 0x98, 0x63, 0x8e,
-			0xb4, 0x14, 0x62, 0xdb, 0x1e, 0xc9, 0x2b, 0x30,
-			0xf8, 0x41, 0x9b, 0xa6, 0xe6, 0xbc, 0xde, 0x0e,
-			0x68, 0x30, 0x21, 0xf4, 0xa8, 0xa9, 0x1b, 0xec,
-			0x44, 0x4f, 0x5d, 0x02, 0x2f, 0x60, 0x45, 0x60,
-			0xba, 0xe0, 0x4e, 0xc0, 0xd4, 0x3b, 0x01, 0x16,
-			0x03, 0x01, 0x00, 0x09, 0x0d, 0x00, 0x00, 0x05,
-			0x02, 0x01, 0x40, 0x00, 0x00, 0x16, 0x03, 0x01,
-			0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
-		},
-		{
-			0x16, 0x03, 0x01, 0x02, 0x0a, 0x0b, 0x00, 0x02,
-			0x06, 0x00, 0x02, 0x03, 0x00, 0x02, 0x00, 0x30,
-			0x82, 0x01, 0xfc, 0x30, 0x82, 0x01, 0x5e, 0x02,
-			0x09, 0x00, 0x9a, 0x30, 0x84, 0x6c, 0x26, 0x35,
-			0xd9, 0x17, 0x30, 0x09, 0x06, 0x07, 0x2a, 0x86,
-			0x48, 0xce, 0x3d, 0x04, 0x01, 0x30, 0x45, 0x31,
-			0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-			0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
-			0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
-			0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
-			0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
-			0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
-			0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
-			0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
-			0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
-			0x31, 0x32, 0x31, 0x31, 0x31, 0x34, 0x31, 0x33,
-			0x32, 0x35, 0x35, 0x33, 0x5a, 0x17, 0x0d, 0x32,
-			0x32, 0x31, 0x31, 0x31, 0x32, 0x31, 0x33, 0x32,
-			0x35, 0x35, 0x33, 0x5a, 0x30, 0x41, 0x31, 0x0b,
-			0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
-			0x02, 0x41, 0x55, 0x31, 0x0c, 0x30, 0x0a, 0x06,
-			0x03, 0x55, 0x04, 0x08, 0x13, 0x03, 0x4e, 0x53,
-			0x57, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
-			0x04, 0x07, 0x13, 0x07, 0x50, 0x79, 0x72, 0x6d,
-			0x6f, 0x6e, 0x74, 0x31, 0x12, 0x30, 0x10, 0x06,
-			0x03, 0x55, 0x04, 0x03, 0x13, 0x09, 0x4a, 0x6f,
-			0x65, 0x6c, 0x20, 0x53, 0x69, 0x6e, 0x67, 0x30,
-			0x81, 0x9b, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86,
-			0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b,
-			0x81, 0x04, 0x00, 0x23, 0x03, 0x81, 0x86, 0x00,
-			0x04, 0x00, 0x95, 0x8c, 0x91, 0x75, 0x14, 0xc0,
-			0x5e, 0xc4, 0x57, 0xb4, 0xd4, 0xc3, 0x6f, 0x8d,
-			0xae, 0x68, 0x1e, 0xdd, 0x6f, 0xce, 0x86, 0xe1,
-			0x7e, 0x6e, 0xb2, 0x48, 0x3e, 0x81, 0xe5, 0x4e,
-			0xe2, 0xc6, 0x88, 0x4b, 0x64, 0xdc, 0xf5, 0x30,
-			0xbb, 0xd3, 0xff, 0x65, 0xcc, 0x5b, 0xf4, 0xdd,
-			0xb5, 0x6a, 0x3e, 0x3e, 0xd0, 0x1d, 0xde, 0x47,
-			0xc3, 0x76, 0xad, 0x19, 0xf6, 0x45, 0x2c, 0x8c,
-			0xbc, 0xd8, 0x1d, 0x01, 0x4c, 0x1f, 0x70, 0x90,
-			0x46, 0x76, 0x48, 0x8b, 0x8f, 0x83, 0xcc, 0x4a,
-			0x5c, 0x8f, 0x40, 0x76, 0xda, 0xe0, 0x89, 0xec,
-			0x1d, 0x2b, 0xc4, 0x4e, 0x30, 0x76, 0x28, 0x41,
-			0xb2, 0x62, 0xa8, 0xfb, 0x5b, 0xf1, 0xf9, 0x4e,
-			0x7a, 0x8d, 0xbd, 0x09, 0xb8, 0xae, 0xea, 0x8b,
-			0x18, 0x27, 0x4f, 0x2e, 0x70, 0xfe, 0x13, 0x96,
-			0xba, 0xc3, 0xd3, 0x40, 0x16, 0xcd, 0x65, 0x4e,
-			0xac, 0x11, 0x1e, 0xe6, 0xf1, 0x30, 0x09, 0x06,
-			0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01,
-			0x03, 0x81, 0x8c, 0x00, 0x30, 0x81, 0x88, 0x02,
-			0x42, 0x00, 0xe0, 0x14, 0xc4, 0x60, 0x60, 0x0b,
-			0x72, 0x68, 0xb0, 0x32, 0x5d, 0x61, 0x4a, 0x02,
-			0x74, 0x5c, 0xc2, 0x81, 0xb9, 0x16, 0xa8, 0x3f,
-			0x29, 0xc8, 0x36, 0xc7, 0x81, 0xff, 0x6c, 0xb6,
-			0x5b, 0xd9, 0x70, 0xf1, 0x38, 0x3b, 0x50, 0x48,
-			0x28, 0x94, 0xcb, 0x09, 0x1a, 0x52, 0xf1, 0x5d,
-			0xee, 0x8d, 0xf2, 0xb9, 0xf0, 0xf0, 0xda, 0xd9,
-			0x15, 0x3a, 0xf9, 0xbd, 0x03, 0x7a, 0x87, 0xa2,
-			0x23, 0x35, 0xec, 0x02, 0x42, 0x01, 0xa3, 0xd4,
-			0x8a, 0x78, 0x35, 0x1c, 0x4a, 0x9a, 0x23, 0xd2,
-			0x0a, 0xbe, 0x2b, 0x10, 0x31, 0x9d, 0x9c, 0x5f,
-			0xbe, 0xe8, 0x91, 0xb3, 0xda, 0x1a, 0xf5, 0x5d,
-			0xa3, 0x23, 0xf5, 0x26, 0x8b, 0x45, 0x70, 0x8d,
-			0x65, 0x62, 0x9b, 0x7e, 0x01, 0x99, 0x3d, 0x18,
-			0xf6, 0x10, 0x9a, 0x38, 0x61, 0x9b, 0x2e, 0x57,
-			0xe4, 0xfa, 0xcc, 0xb1, 0x8a, 0xce, 0xe2, 0x23,
-			0xa0, 0x87, 0xf0, 0xe1, 0x67, 0x51, 0xeb, 0x16,
-			0x03, 0x01, 0x00, 0x8a, 0x10, 0x00, 0x00, 0x86,
-			0x85, 0x04, 0x00, 0xcd, 0x1c, 0xe8, 0x66, 0x5b,
-			0xa8, 0x9d, 0x83, 0x2f, 0x7e, 0x1d, 0x0b, 0x59,
-			0x23, 0xbc, 0x30, 0xcf, 0xa3, 0xaf, 0x21, 0xdc,
-			0xf2, 0x57, 0x49, 0x56, 0x30, 0x25, 0x7c, 0x84,
-			0x5d, 0xad, 0xaa, 0x9c, 0x7b, 0x2a, 0x95, 0x58,
-			0x3d, 0x30, 0x87, 0x01, 0x3b, 0xb7, 0xea, 0xcb,
-			0xc4, 0xa3, 0xeb, 0x22, 0xbf, 0x2d, 0x61, 0x17,
-			0x8c, 0x9b, 0xe8, 0x1b, 0xb2, 0x87, 0x16, 0x78,
-			0xd5, 0xfd, 0x8b, 0xdd, 0x00, 0x0f, 0xda, 0x8e,
-			0xfd, 0x28, 0x36, 0xeb, 0xe4, 0xc5, 0x42, 0x14,
-			0xc7, 0xbd, 0x29, 0x5e, 0x9a, 0xed, 0x5e, 0xc1,
-			0xf7, 0xf4, 0xbd, 0xbd, 0x15, 0x9c, 0xe8, 0x44,
-			0x71, 0xa7, 0xb6, 0xe9, 0xfa, 0x7e, 0x97, 0xcb,
-			0x96, 0x3e, 0x53, 0x76, 0xfb, 0x11, 0x1f, 0x36,
-			0x8f, 0x30, 0xfb, 0x71, 0x3a, 0x75, 0x3a, 0x25,
-			0x7b, 0xa2, 0xc1, 0xf9, 0x3e, 0x58, 0x5f, 0x07,
-			0x16, 0xed, 0xe1, 0xf7, 0xc1, 0xb1, 0x16, 0x03,
-			0x01, 0x00, 0x90, 0x0f, 0x00, 0x00, 0x8c, 0x00,
-			0x8a, 0x30, 0x81, 0x87, 0x02, 0x42, 0x00, 0xb2,
-			0xd3, 0x91, 0xe6, 0xd5, 0x9b, 0xb2, 0xb8, 0x03,
-			0xf4, 0x85, 0x4d, 0x43, 0x79, 0x1f, 0xb6, 0x6f,
-			0x0c, 0xcd, 0x67, 0x5f, 0x5e, 0xca, 0xee, 0xb3,
-			0xe4, 0xab, 0x1e, 0x58, 0xc3, 0x04, 0xa9, 0x8a,
-			0xa7, 0xcf, 0xaa, 0x33, 0x88, 0xd5, 0x35, 0xd2,
-			0x80, 0x8f, 0xfa, 0x1b, 0x3c, 0x3d, 0xf7, 0x80,
-			0x50, 0xde, 0x80, 0x30, 0x64, 0xee, 0xc0, 0xb3,
-			0x91, 0x6e, 0x5d, 0x1e, 0xc0, 0xdc, 0x3a, 0x93,
-			0x02, 0x41, 0x4e, 0xca, 0x98, 0x41, 0x8c, 0x36,
-			0xf2, 0x12, 0xbf, 0x8e, 0x0f, 0x69, 0x8e, 0xf8,
-			0x7b, 0x9d, 0xba, 0x9c, 0x5c, 0x48, 0x79, 0xf4,
-			0xba, 0x3d, 0x06, 0xa5, 0xab, 0x47, 0xe0, 0x1a,
-			0x45, 0x28, 0x3a, 0x8f, 0xbf, 0x14, 0x24, 0x36,
-			0xd1, 0x1d, 0x29, 0xdc, 0xde, 0x72, 0x5b, 0x76,
-			0x41, 0x67, 0xe8, 0xe5, 0x71, 0x4a, 0x77, 0xe9,
-			0xed, 0x02, 0x19, 0xdd, 0xe4, 0xaa, 0xe9, 0x2d,
-			0xe7, 0x47, 0x32, 0x14, 0x03, 0x01, 0x00, 0x01,
-			0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0xfa, 0xc3,
-			0xf2, 0x35, 0xd0, 0x6d, 0x32, 0x78, 0x6a, 0xd6,
-			0xe6, 0x70, 0x5e, 0x00, 0x4c, 0x35, 0xf1, 0xe0,
-			0x21, 0xcf, 0xc3, 0x78, 0xcd, 0xe0, 0x2b, 0x0b,
-			0xf4, 0xeb, 0xf9, 0xc0, 0x38, 0xf2, 0x9a, 0x31,
-			0x55, 0x07, 0x2b, 0x8d, 0x68, 0x40, 0x31, 0x08,
-			0xaa, 0xe3, 0x16, 0xcf, 0x4b, 0xd4,
-		},
-		{
-			0x16, 0x03, 0x01, 0x02, 0x76, 0x04, 0x00, 0x02,
-			0x72, 0x00, 0x00, 0x00, 0x00, 0x02, 0x6c, 0x00,
-			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
-			0xe8, 0x8b, 0xde, 0xef, 0xba, 0xf9, 0xdb, 0x95,
-			0x24, 0xa5, 0x49, 0xb3, 0x23, 0xd8, 0x73, 0x88,
-			0x50, 0x42, 0xed, 0xeb, 0xa3, 0xd8, 0xab, 0x31,
-			0x9c, 0xd0, 0x00, 0x01, 0xef, 0xc0, 0xbf, 0xab,
-			0x59, 0x55, 0xb5, 0xb9, 0xef, 0xa5, 0xa6, 0xec,
-			0x69, 0xed, 0x00, 0x2f, 0x47, 0xdb, 0x75, 0x52,
-			0x0c, 0xe5, 0x86, 0xb7, 0x02, 0x59, 0x22, 0xf7,
-			0xfd, 0x8b, 0xff, 0xa4, 0x09, 0xc0, 0x1c, 0x10,
-			0x80, 0x10, 0x7f, 0x4c, 0x7a, 0x94, 0x40, 0x10,
-			0x0d, 0xda, 0x8a, 0xe5, 0x4a, 0xbc, 0xd0, 0xc0,
-			0x4b, 0xa5, 0x33, 0x97, 0xc6, 0xe7, 0x40, 0x7f,
-			0x7f, 0x8c, 0xf9, 0xf8, 0xc8, 0xb8, 0xfb, 0x8c,
-			0xdd, 0x28, 0x81, 0xae, 0xfd, 0x37, 0x20, 0x3a,
-			0x40, 0x37, 0x99, 0xc4, 0x21, 0x01, 0xc4, 0x91,
-			0xb0, 0x5e, 0x11, 0xc5, 0xa9, 0xfd, 0x9a, 0x02,
-			0x7e, 0x97, 0x6a, 0x86, 0x89, 0xb8, 0xc1, 0x32,
-			0x4c, 0x7e, 0x6d, 0x47, 0x61, 0x0e, 0xe3, 0xc2,
-			0xf0, 0x62, 0x3c, 0xc6, 0x71, 0x4f, 0xbb, 0x47,
-			0x65, 0xb1, 0xd9, 0x22, 0x79, 0x15, 0xea, 0x1f,
-			0x4b, 0x2a, 0x8a, 0xa4, 0xc8, 0x73, 0x34, 0xba,
-			0x83, 0xe4, 0x70, 0x99, 0xc9, 0xcf, 0xbe, 0x64,
-			0x99, 0xb9, 0xfa, 0xe9, 0xaf, 0x5d, 0xc7, 0x20,
-			0x26, 0xde, 0xc5, 0x06, 0x12, 0x36, 0x4f, 0x4d,
-			0xc0, 0xbb, 0x81, 0x5b, 0x5e, 0x38, 0xc3, 0x07,
-			0x21, 0x04, 0x1a, 0x53, 0x9c, 0x59, 0xac, 0x2d,
-			0xe6, 0xa5, 0x93, 0xa5, 0x19, 0xc6, 0xb0, 0xf7,
-			0x56, 0x5d, 0xdf, 0xd1, 0xf4, 0xfd, 0x44, 0x6d,
-			0xc6, 0xa2, 0x31, 0xa7, 0x35, 0x42, 0x18, 0x50,
-			0x0c, 0x4f, 0x6e, 0xe3, 0x3b, 0xa3, 0xaa, 0x1c,
-			0xbe, 0x41, 0x0d, 0xce, 0x6c, 0x62, 0xe1, 0x96,
-			0x2d, 0xbd, 0x14, 0x31, 0xe3, 0xc4, 0x5b, 0xbf,
-			0xf6, 0xde, 0xec, 0x42, 0xe8, 0xc7, 0x2a, 0x0b,
-			0xdb, 0x2d, 0x7c, 0xf0, 0x3f, 0x45, 0x32, 0x45,
-			0x09, 0x47, 0x09, 0x0f, 0x21, 0x22, 0x45, 0x06,
-			0x11, 0xb8, 0xf9, 0xe6, 0x67, 0x90, 0x4b, 0x4a,
-			0xde, 0x81, 0xfb, 0xeb, 0xe7, 0x9a, 0x08, 0x30,
-			0xcf, 0x51, 0xe1, 0xd9, 0xfa, 0x79, 0xa3, 0xcc,
-			0x65, 0x1a, 0x83, 0x86, 0xc9, 0x7a, 0x41, 0xf5,
-			0xdf, 0xa0, 0x7c, 0x44, 0x23, 0x17, 0xf3, 0x62,
-			0xe8, 0xa9, 0x31, 0x1e, 0x6b, 0x05, 0x4b, 0x4f,
-			0x9d, 0x91, 0x46, 0x92, 0xa6, 0x25, 0x32, 0xca,
-			0xa1, 0x75, 0xda, 0xe6, 0x80, 0x3e, 0x7f, 0xd1,
-			0x26, 0x57, 0x07, 0x42, 0xe4, 0x91, 0xff, 0xbd,
-			0x44, 0xae, 0x98, 0x5c, 0x1d, 0xdf, 0x11, 0xe3,
-			0xae, 0x87, 0x5e, 0xb7, 0x69, 0xad, 0x34, 0x7f,
-			0x3a, 0x07, 0x7c, 0xdf, 0xfc, 0x76, 0x17, 0x8b,
-			0x62, 0xc8, 0xe1, 0x78, 0x2a, 0xc8, 0xb9, 0x8a,
-			0xbb, 0x5c, 0xfb, 0x38, 0x74, 0x91, 0x6e, 0x12,
-			0x0c, 0x1f, 0x8e, 0xe1, 0xc2, 0x01, 0xd8, 0x9d,
-			0x23, 0x0f, 0xc4, 0x67, 0x5d, 0xe5, 0x67, 0x4b,
-			0x94, 0x6e, 0x69, 0x72, 0x90, 0x2d, 0x52, 0x78,
-			0x8e, 0x61, 0xba, 0xdf, 0x4e, 0xf5, 0xdc, 0xfb,
-			0x73, 0xbe, 0x03, 0x70, 0xd9, 0x01, 0x30, 0xf3,
-			0xa1, 0xbb, 0x9a, 0x5f, 0xec, 0x9e, 0xed, 0x8d,
-			0xdd, 0x53, 0xfd, 0x60, 0xc3, 0x2b, 0x7a, 0x00,
-			0x2c, 0xf9, 0x0a, 0x57, 0x47, 0x45, 0x43, 0xb3,
-			0x23, 0x01, 0x9c, 0xee, 0x54, 0x4d, 0x58, 0xd3,
-			0x71, 0x1c, 0xc9, 0xd3, 0x30, 0x9e, 0x14, 0xa5,
-			0xf3, 0xbf, 0x4d, 0x9b, 0xb7, 0x13, 0x21, 0xae,
-			0xd2, 0x8d, 0x6e, 0x6f, 0x1c, 0xcc, 0xb2, 0x41,
-			0xb2, 0x64, 0x56, 0x83, 0xce, 0xd1, 0x0c, 0x79,
-			0x32, 0x78, 0xef, 0xc5, 0x21, 0xb1, 0xe8, 0xc4,
-			0x42, 0xa7, 0x8d, 0xc1, 0xfa, 0xa1, 0x9c, 0x3c,
-			0x21, 0xd8, 0xe9, 0x90, 0xe2, 0x7c, 0x14, 0x26,
-			0xfe, 0x61, 0x3e, 0xf9, 0x71, 0x1d, 0x5d, 0x49,
-			0x3b, 0xb1, 0xb8, 0x42, 0xa1, 0xb8, 0x1c, 0x75,
-			0x7d, 0xee, 0xed, 0xfc, 0xe6, 0x20, 0x2b, 0x9e,
-			0x10, 0x52, 0xda, 0x56, 0x4d, 0x64, 0x6c, 0x41,
-			0xc1, 0xf7, 0x60, 0x0c, 0x10, 0x65, 0x6f, 0xd4,
-			0xe9, 0x9b, 0x0d, 0x83, 0x13, 0xc8, 0x5a, 0xa3,
-			0x56, 0x2a, 0x42, 0xc6, 0x1c, 0xfe, 0xdb, 0xba,
-			0x3d, 0x04, 0x12, 0xfd, 0x28, 0xeb, 0x78, 0xdd,
-			0xbc, 0xc8, 0x0d, 0xa1, 0xce, 0xd4, 0x54, 0xbf,
-			0xaf, 0xe1, 0x60, 0x0c, 0xa3, 0xc3, 0xc3, 0x62,
-			0x58, 0xc1, 0x79, 0xa7, 0x95, 0x41, 0x09, 0x24,
-			0xc6, 0x9a, 0x50, 0x14, 0x03, 0x01, 0x00, 0x01,
-			0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0x4d, 0x7b,
-			0x5f, 0x28, 0x5e, 0x68, 0x6c, 0xa3, 0x65, 0xc7,
-			0x7e, 0x49, 0x6c, 0xb3, 0x67, 0xbb, 0xd0, 0x75,
-			0xa2, 0x9e, 0x8c, 0x92, 0x4f, 0x8c, 0x33, 0x14,
-			0x7c, 0x6c, 0xf1, 0x74, 0x97, 0xc3, 0xe0, 0x10,
-			0xe9, 0x0d, 0xc2, 0x30, 0x5c, 0x23, 0xee, 0x1d,
-			0x16, 0x2e, 0xb9, 0x96, 0x2b, 0x2d, 0x17, 0x03,
-			0x01, 0x00, 0x20, 0xf2, 0xc8, 0xa7, 0x1b, 0x60,
-			0x46, 0xee, 0xe5, 0x7e, 0xc9, 0x35, 0xb3, 0xf1,
-			0x7c, 0x32, 0x0c, 0x85, 0x94, 0x59, 0x57, 0x27,
-			0xb0, 0xbd, 0x52, 0x86, 0x90, 0xf1, 0xb7, 0x4d,
-			0x1e, 0xc1, 0x16, 0x17, 0x03, 0x01, 0x00, 0x30,
-			0xff, 0x85, 0x50, 0xdf, 0x3f, 0xfc, 0xa2, 0x61,
-			0x1a, 0x12, 0xc0, 0x1e, 0x10, 0x32, 0x88, 0x50,
-			0xa0, 0x2c, 0x80, 0xda, 0x77, 0xea, 0x09, 0x47,
-			0xe0, 0x85, 0x07, 0x29, 0x45, 0x65, 0x19, 0xa3,
-			0x8d, 0x99, 0xb8, 0xbf, 0xb6, 0xbc, 0x76, 0xe2,
-			0x50, 0x24, 0x82, 0x0a, 0xfd, 0xdd, 0x35, 0x09,
-			0x15, 0x03, 0x01, 0x00, 0x20, 0xe7, 0x36, 0xf6,
-			0x61, 0xd2, 0x95, 0x3c, 0xb6, 0x65, 0x7b, 0xb2,
-			0xb8, 0xdf, 0x03, 0x53, 0xeb, 0xf7, 0x16, 0xe0,
-			0xe0, 0x15, 0x22, 0x71, 0x70, 0x62, 0x73, 0xad,
-			0xb5, 0x1a, 0x77, 0x44, 0x57,
-		},
-	}},
+-----END EC PRIVATE KEY-----`
+
+func TestClientAuth(t *testing.T) {
+	var certPath, keyPath, ecdsaCertPath, ecdsaKeyPath string
+
+	if *update {
+		certPath = tempFile(clientCertificatePEM)
+		defer os.Remove(certPath)
+		keyPath = tempFile(clientKeyPEM)
+		defer os.Remove(keyPath)
+		ecdsaCertPath = tempFile(clientECDSACertificatePEM)
+		defer os.Remove(ecdsaCertPath)
+		ecdsaKeyPath = tempFile(clientECDSAKeyPEM)
+		defer os.Remove(ecdsaKeyPath)
+	}
+
+	config := *testConfig
+	config.ClientAuth = RequestClientCert
+
+	test := &serverTest{
+		name:    "ClientAuthRequestedNotGiven",
+		command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA"},
+		config:  &config,
+	}
+	runServerTestTLS12(t, test)
+
+	test = &serverTest{
+		name:              "ClientAuthRequestedAndGiven",
+		command:           []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA", "-cert", certPath, "-key", keyPath},
+		config:            &config,
+		expectedPeerCerts: []string{clientCertificatePEM},
+	}
+	runServerTestTLS12(t, test)
+
+	test = &serverTest{
+		name:              "ClientAuthRequestedAndECDSAGiven",
+		command:           []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA", "-cert", ecdsaCertPath, "-key", ecdsaKeyPath},
+		config:            &config,
+		expectedPeerCerts: []string{clientECDSACertificatePEM},
+	}
+	runServerTestTLS12(t, test)
 }
 
-var aesGCMServerScript = [][]byte{
-	{
-		0x16, 0x03, 0x01, 0x01, 0x1c, 0x01, 0x00, 0x01,
-		0x18, 0x03, 0x03, 0x52, 0x1e, 0x74, 0xf0, 0xb0,
-		0xc1, 0x8b, 0x16, 0xf9, 0x74, 0xfc, 0x16, 0xc4,
-		0x11, 0x18, 0x96, 0x08, 0x25, 0x38, 0x4f, 0x98,
-		0x98, 0xbe, 0xb5, 0x61, 0xdf, 0x94, 0x15, 0xcc,
-		0x9b, 0x61, 0xef, 0x00, 0x00, 0x80, 0xc0, 0x30,
-		0xc0, 0x2c, 0xc0, 0x28, 0xc0, 0x24, 0xc0, 0x14,
-		0xc0, 0x0a, 0x00, 0xa3, 0x00, 0x9f, 0x00, 0x6b,
-		0x00, 0x6a, 0x00, 0x39, 0x00, 0x38, 0xc0, 0x32,
-		0xc0, 0x2e, 0xc0, 0x2a, 0xc0, 0x26, 0xc0, 0x0f,
-		0xc0, 0x05, 0x00, 0x9d, 0x00, 0x3d, 0x00, 0x35,
-		0xc0, 0x12, 0xc0, 0x08, 0x00, 0x16, 0x00, 0x13,
-		0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a, 0xc0, 0x2f,
-		0xc0, 0x2b, 0xc0, 0x27, 0xc0, 0x23, 0xc0, 0x13,
-		0xc0, 0x09, 0x00, 0xa2, 0x00, 0x9e, 0x00, 0x67,
-		0x00, 0x40, 0x00, 0x33, 0x00, 0x32, 0xc0, 0x31,
-		0xc0, 0x2d, 0xc0, 0x29, 0xc0, 0x25, 0xc0, 0x0e,
-		0xc0, 0x04, 0x00, 0x9c, 0x00, 0x3c, 0x00, 0x2f,
-		0xc0, 0x11, 0xc0, 0x07, 0xc0, 0x0c, 0xc0, 0x02,
-		0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,
-		0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08,
-		0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x01, 0x00,
-		0x00, 0x6f, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00,
-		0x01, 0x02, 0x00, 0x0a, 0x00, 0x34, 0x00, 0x32,
-		0x00, 0x0e, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x0b,
-		0x00, 0x0c, 0x00, 0x18, 0x00, 0x09, 0x00, 0x0a,
-		0x00, 0x16, 0x00, 0x17, 0x00, 0x08, 0x00, 0x06,
-		0x00, 0x07, 0x00, 0x14, 0x00, 0x15, 0x00, 0x04,
-		0x00, 0x05, 0x00, 0x12, 0x00, 0x13, 0x00, 0x01,
-		0x00, 0x02, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x10,
-		0x00, 0x11, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d,
-		0x00, 0x22, 0x00, 0x20, 0x06, 0x01, 0x06, 0x02,
-		0x06, 0x03, 0x05, 0x01, 0x05, 0x02, 0x05, 0x03,
-		0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x03, 0x01,
-		0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02,
-		0x02, 0x03, 0x01, 0x01, 0x00, 0x0f, 0x00, 0x01,
-		0x01,
-	},
-	{
-		0x16, 0x03, 0x03, 0x00, 0x30, 0x02, 0x00, 0x00,
-		0x2c, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0xc0, 0x2f, 0x00, 0x00,
-		0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x03,
-		0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02,
-		0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0,
-		0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
-		0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4,
-		0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09,
-		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-		0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30,
-		0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
-		0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
-		0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d,
-		0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31,
-		0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
-		0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
-		0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69,
-		0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
-		0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30,
-		0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39,
-		0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
-		0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33,
-		0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09,
-		0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41,
-		0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
-		0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65,
-		0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21,
-		0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
-		0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
-		0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
-		0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
-		0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
-		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-		0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
-		0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79,
-		0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10,
-		0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43,
-		0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85,
-		0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c,
-		0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5,
-		0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c,
-		0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56,
-		0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26,
-		0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21,
-		0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf,
-		0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07,
-		0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39,
-		0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3,
-		0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf,
-		0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb,
-		0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03,
-		0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81,
-		0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
-		0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85,
-		0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23,
-		0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39,
-		0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
-		0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2,
-		0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce,
-		0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88,
-		0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,
-		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
-		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
-		0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
-		0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
-		0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
-		0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
-		0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
-		0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85,
-		0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30,
-		0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05,
-		0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06,
-		0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-		0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
-		0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59,
-		0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7,
-		0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95,
-		0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66,
-		0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3,
-		0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13,
-		0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba,
-		0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31,
-		0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50,
-		0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f,
-		0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96,
-		0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f,
-		0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b,
-		0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70,
-		0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e,
-		0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9,
-		0x16, 0x03, 0x03, 0x01, 0x11, 0x0c, 0x00, 0x01,
-		0x0d, 0x03, 0x00, 0x19, 0x85, 0x04, 0x01, 0x39,
-		0xdc, 0xee, 0x44, 0x17, 0x5e, 0xdb, 0xd7, 0x27,
-		0xaf, 0xb6, 0x56, 0xd9, 0xb4, 0x43, 0x5a, 0x99,
-		0xcf, 0xaa, 0x31, 0x37, 0x0c, 0x6f, 0x3a, 0xa0,
-		0xf8, 0x53, 0xc4, 0x74, 0xd1, 0x91, 0x0a, 0x46,
-		0xf5, 0x38, 0x3b, 0x5c, 0x09, 0xd8, 0x97, 0xdc,
-		0x4b, 0xaa, 0x70, 0x26, 0x48, 0xf2, 0xd6, 0x0b,
-		0x31, 0xc9, 0xf8, 0xd4, 0x98, 0x43, 0xe1, 0x6c,
-		0xd5, 0xc7, 0xb2, 0x8e, 0x0b, 0x01, 0xe6, 0xb6,
-		0x00, 0x28, 0x80, 0x7b, 0xfc, 0x96, 0x8f, 0x0d,
-		0xa2, 0x4f, 0xb0, 0x79, 0xaf, 0xdc, 0x61, 0x28,
-		0x63, 0x33, 0x78, 0xf6, 0x31, 0x39, 0xfd, 0x8a,
-		0xf4, 0x15, 0x18, 0x11, 0xfe, 0xdb, 0xd5, 0x07,
-		0xda, 0x2c, 0xed, 0x49, 0xa0, 0x23, 0xbf, 0xd0,
-		0x3a, 0x38, 0x1d, 0x54, 0xae, 0x1c, 0x7b, 0xea,
-		0x29, 0xee, 0xd0, 0x38, 0xc1, 0x76, 0xa7, 0x7f,
-		0x2a, 0xf4, 0xce, 0x1e, 0xac, 0xcc, 0x94, 0x79,
-		0x90, 0x33, 0x04, 0x01, 0x00, 0x80, 0x0d, 0x8e,
-		0x79, 0xe6, 0x86, 0xf6, 0xb6, 0xfb, 0x6b, 0x6a,
-		0xcc, 0x55, 0xe4, 0x80, 0x4d, 0xc5, 0x0c, 0xc6,
-		0xa3, 0x9f, 0x1d, 0x39, 0xd2, 0x98, 0x57, 0x31,
-		0xa2, 0x90, 0x73, 0xe8, 0xd2, 0xcd, 0xb0, 0x93,
-		0x1a, 0x60, 0x0f, 0x38, 0x02, 0x3b, 0x1b, 0x25,
-		0x56, 0xec, 0x44, 0xab, 0xbe, 0x2e, 0x0c, 0xc0,
-		0x6e, 0x54, 0x91, 0x50, 0xd6, 0xb1, 0xa2, 0x98,
-		0x14, 0xa8, 0x35, 0x62, 0x9d, 0xca, 0xfb, 0x0f,
-		0x64, 0x2b, 0x05, 0xa0, 0xa0, 0x57, 0xef, 0xcd,
-		0x95, 0x45, 0x13, 0x5a, 0x9b, 0x3d, 0xdb, 0x42,
-		0x54, 0x7f, 0xb9, 0x17, 0x08, 0x7f, 0xb2, 0xf0,
-		0xb1, 0xc3, 0xdf, 0x67, 0x95, 0xe2, 0x73, 0xf2,
-		0x76, 0xa3, 0x97, 0xfd, 0x9c, 0x92, 0x4a, 0xdb,
-		0x95, 0x1e, 0x91, 0x95, 0xae, 0x3d, 0xae, 0x58,
-		0xb5, 0x03, 0x6f, 0x5c, 0x3a, 0x19, 0xab, 0x92,
-		0xa5, 0x09, 0x6b, 0x40, 0x61, 0xb0, 0x16, 0x03,
-		0x03, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,
+func bigFromString(s string) *big.Int {
+	ret := new(big.Int)
+	ret.SetString(s, 10)
+	return ret
+}
+
+func fromHex(s string) []byte {
+	b, _ := hex.DecodeString(s)
+	return b
+}
+
+var testRSACertificate = fromHex("308202b030820219a00302010202090085b0bba48a7fb8ca300d06092a864886f70d01010505003045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3130303432343039303933385a170d3131303432343039303933385a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819f300d06092a864886f70d010101 [...]
+
+var testECDSACertificate = fromHex("3082020030820162020900b8bf2d47a0d2ebf4300906072a8648ce3d04013045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3132313132323135303633325a170d3232313132303135303633325a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819b301006072a8648ce3d020106052b81040023038186 [...]
+
+var testSNICertificate = fromHex("308201f23082015da003020102020100300b06092a864886f70d01010530283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d301e170d3132303431313137343033355a170d3133303431313137343533355a30283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d30819d300b06092a864886f70d01010103818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a [...]
+
+var testRSAPrivateKey = &rsa.PrivateKey{
+	PublicKey: rsa.PublicKey{
+		N: bigFromString("131650079503776001033793877885499001334664249354723305978524647182322416328664556247316495448366990052837680518067798333412266673813370895702118944398081598789828837447552603077848001020611640547221687072142537202428102790818451901395596882588063427854225330436740647715202971973145151161964464812406232198521"),
+		E: 65537,
 	},
-	{
-		0x16, 0x03, 0x03, 0x00, 0x8a, 0x10, 0x00, 0x00,
-		0x86, 0x85, 0x04, 0x01, 0xba, 0xb8, 0xad, 0x69,
-		0x20, 0x5e, 0xc1, 0x61, 0xc3, 0x0f, 0xb4, 0x30,
-		0x64, 0x66, 0x70, 0x96, 0x33, 0x3c, 0x8e, 0x12,
-		0x56, 0xbf, 0x6d, 0xb8, 0x6d, 0xc6, 0xba, 0xea,
-		0xfc, 0x38, 0xc0, 0x8b, 0x87, 0xa8, 0xf3, 0x87,
-		0xa1, 0xd5, 0xb6, 0xb0, 0x72, 0xc7, 0xd4, 0x19,
-		0x56, 0xa0, 0x91, 0xe1, 0x45, 0xc7, 0xf1, 0x7d,
-		0xb0, 0x1d, 0x78, 0x18, 0xf6, 0x3d, 0xbf, 0x1a,
-		0x23, 0x93, 0x0b, 0x19, 0xb1, 0x00, 0x56, 0xc9,
-		0x5e, 0x89, 0xd4, 0x9d, 0xd9, 0x5b, 0xe0, 0xb8,
-		0xff, 0x2f, 0x7d, 0x93, 0xae, 0x5b, 0xa5, 0x1f,
-		0x1f, 0x2b, 0x09, 0xe5, 0xf6, 0x07, 0x26, 0xa3,
-		0xed, 0xcb, 0x6a, 0x1a, 0xd6, 0x14, 0x83, 0x9b,
-		0xd3, 0x9d, 0x47, 0x1b, 0xf3, 0x72, 0x5f, 0x69,
-		0x21, 0x8f, 0xfa, 0x09, 0x38, 0x1a, 0x6b, 0x91,
-		0xcf, 0x19, 0x32, 0x54, 0x58, 0x8e, 0xee, 0xaf,
-		0xeb, 0x06, 0x9b, 0x3a, 0x34, 0x16, 0x66, 0x14,
-		0x03, 0x03, 0x00, 0x01, 0x01, 0x16, 0x03, 0x03,
-		0x00, 0x28, 0xc6, 0x96, 0x67, 0x62, 0xcc, 0x47,
-		0x01, 0xb5, 0xbd, 0xb7, 0x24, 0xd3, 0xb6, 0xfd,
-		0xb8, 0x46, 0xce, 0x82, 0x6d, 0x31, 0x1f, 0x15,
-		0x11, 0x8f, 0xed, 0x62, 0x71, 0x5f, 0xae, 0xb6,
-		0xa9, 0x0c, 0x24, 0x1d, 0xe8, 0x26, 0x51, 0xca,
-		0x7c, 0x42,
+	D: bigFromString("29354450337804273969007277378287027274721892607543397931919078829901848876371746653677097639302788129485893852488285045793268732234230875671682624082413996177431586734171663258657462237320300610850244186316880055243099640544518318093544057213190320837094958164973959123058337475052510833916491060913053867729"),
+	Primes: []*big.Int{
+		bigFromString("11969277782311800166562047708379380720136961987713178380670422671426759650127150688426177829077494755200794297055316163155755835813760102405344560929062149"),
+		bigFromString("10998999429884441391899182616418192492905073053684657075974935218461686523870125521822756579792315215543092255516093840728890783887287417039645833477273829"),
 	},
-	{
-		0x16, 0x03, 0x03, 0x00, 0x72, 0x04, 0x00, 0x00,
-		0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
-		0xea, 0x8b, 0xfb, 0xef, 0xba, 0xc8, 0x88, 0x94,
-		0x44, 0x99, 0x5f, 0x02, 0x68, 0x3a, 0x12, 0x67,
-		0x7f, 0xb9, 0x39, 0x71, 0x84, 0xe0, 0x30, 0xe6,
-		0x90, 0x6c, 0xcf, 0x32, 0x29, 0x29, 0x5c, 0x5a,
-		0x8b, 0x7d, 0xaa, 0x11, 0x28, 0x26, 0xb5, 0xce,
-		0xd2, 0x88, 0xd5, 0xb0, 0x5f, 0x94, 0x37, 0xa2,
-		0x48, 0xd9, 0x53, 0xb2, 0xab, 0x59, 0x23, 0x3d,
-		0x81, 0x6e, 0x64, 0x89, 0xca, 0x1a, 0x84, 0x16,
-		0xdf, 0x31, 0x10, 0xde, 0x52, 0x7f, 0x50, 0xf3,
-		0xd9, 0x27, 0xa0, 0xe8, 0x34, 0x15, 0x9e, 0x11,
-		0xdd, 0xba, 0xce, 0x40, 0x17, 0xf3, 0x67, 0x14,
-		0x03, 0x03, 0x00, 0x01, 0x01, 0x16, 0x03, 0x03,
-		0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x35, 0xcb, 0x17, 0x66, 0xee, 0xfd,
-		0x27, 0xdb, 0xb8, 0xa8, 0x8a, 0xf1, 0x56, 0x67,
-		0x89, 0x0d, 0x13, 0xac, 0xe2, 0x31, 0xb9, 0xa2,
-		0x26, 0xbb, 0x1c, 0xcf, 0xd1, 0xb2, 0x48, 0x1d,
-		0x0d, 0xb1, 0x17, 0x03, 0x03, 0x00, 0x25, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0,
-		0x89, 0x7c, 0x58, 0x6a, 0x9b, 0x00, 0x05, 0x8c,
-		0x7f, 0x28, 0x54, 0x61, 0x44, 0x10, 0xee, 0x85,
-		0x26, 0xa8, 0x04, 0xcd, 0xca, 0x85, 0x60, 0xf2,
-		0xeb, 0x22, 0xbd, 0x9e, 0x15, 0x03, 0x03, 0x00,
-		0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x02, 0x10, 0xe4, 0xe5, 0xf9, 0x85, 0xe3, 0xb0,
-		0xec, 0x84, 0x29, 0x91, 0x05, 0x7d, 0x86, 0xe3,
-		0x97, 0xeb, 0xb2,
+}
+
+var testECDSAPrivateKey = &ecdsa.PrivateKey{
+	PublicKey: ecdsa.PublicKey{
+		Curve: elliptic.P521(),
+		X:     bigFromString("2636411247892461147287360222306590634450676461695221912739908880441342231985950069527906976759812296359387337367668045707086543273113073382714101597903639351"),
+		Y:     bigFromString("3204695818431246682253994090650952614555094516658732116404513121125038617915183037601737180082382202488628239201196033284060130040574800684774115478859677243"),
 	},
+	D: bigFromString("5477294338614160138026852784385529180817726002953041720191098180813046231640184669647735805135001309477695746518160084669446643325196003346204701381388769751"),
 }
diff --git a/src/pkg/crypto/tls/handshake_test.go b/src/pkg/crypto/tls/handshake_test.go
new file mode 100644
index 0000000..f95f274
--- /dev/null
+++ b/src/pkg/crypto/tls/handshake_test.go
@@ -0,0 +1,167 @@
+// 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 tls
+
+import (
+	"bufio"
+	"encoding/hex"
+	"errors"
+	"flag"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net"
+	"strconv"
+	"strings"
+	"sync"
+)
+
+// TLS reference tests run a connection against a reference implementation
+// (OpenSSL) of TLS and record the bytes of the resulting connection. The Go
+// code, during a test, is configured with deterministic randomness and so the
+// reference test can be reproduced exactly in the future.
+//
+// In order to save everyone who wishes to run the tests from needing the
+// reference implementation installed, the reference connections are saved in
+// files in the testdata directory. Thus running the tests involves nothing
+// external, but creating and updating them requires the reference
+// implementation.
+//
+// Tests can be updated by running them with the -update flag. This will cause
+// the test files. Generally one should combine the -update flag with -test.run
+// to updated a specific test. Since the reference implementation will always
+// generate fresh random numbers, large parts of the reference connection will
+// always change.
+
+var update = flag.Bool("update", false, "update golden files on disk")
+
+// recordingConn is a net.Conn that records the traffic that passes through it.
+// WriteTo can be used to produce output that can be later be loaded with
+// ParseTestData.
+type recordingConn struct {
+	net.Conn
+	sync.Mutex
+	flows   [][]byte
+	reading bool
+}
+
+func (r *recordingConn) Read(b []byte) (n int, err error) {
+	if n, err = r.Conn.Read(b); n == 0 {
+		return
+	}
+	b = b[:n]
+
+	r.Lock()
+	defer r.Unlock()
+
+	if l := len(r.flows); l == 0 || !r.reading {
+		buf := make([]byte, len(b))
+		copy(buf, b)
+		r.flows = append(r.flows, buf)
+	} else {
+		r.flows[l-1] = append(r.flows[l-1], b[:n]...)
+	}
+	r.reading = true
+	return
+}
+
+func (r *recordingConn) Write(b []byte) (n int, err error) {
+	if n, err = r.Conn.Write(b); n == 0 {
+		return
+	}
+	b = b[:n]
+
+	r.Lock()
+	defer r.Unlock()
+
+	if l := len(r.flows); l == 0 || r.reading {
+		buf := make([]byte, len(b))
+		copy(buf, b)
+		r.flows = append(r.flows, buf)
+	} else {
+		r.flows[l-1] = append(r.flows[l-1], b[:n]...)
+	}
+	r.reading = false
+	return
+}
+
+// WriteTo writes Go source code to w that contains the recorded traffic.
+func (r *recordingConn) WriteTo(w io.Writer) {
+	// TLS always starts with a client to server flow.
+	clientToServer := true
+
+	for i, flow := range r.flows {
+		source, dest := "client", "server"
+		if !clientToServer {
+			source, dest = dest, source
+		}
+		fmt.Fprintf(w, ">>> Flow %d (%s to %s)\n", i+1, source, dest)
+		dumper := hex.Dumper(w)
+		dumper.Write(flow)
+		dumper.Close()
+		clientToServer = !clientToServer
+	}
+}
+
+func parseTestData(r io.Reader) (flows [][]byte, err error) {
+	var currentFlow []byte
+
+	scanner := bufio.NewScanner(r)
+	for scanner.Scan() {
+		line := scanner.Text()
+		// If the line starts with ">>> " then it marks the beginning
+		// of a new flow.
+		if strings.HasPrefix(line, ">>> ") {
+			if len(currentFlow) > 0 || len(flows) > 0 {
+				flows = append(flows, currentFlow)
+				currentFlow = nil
+			}
+			continue
+		}
+
+		// Otherwise the line is a line of hex dump that looks like:
+		// 00000170  fc f5 06 bf (...)  |.....X{&?......!|
+		// (Some bytes have been omitted from the middle section.)
+
+		if i := strings.IndexByte(line, ' '); i >= 0 {
+			line = line[i:]
+		} else {
+			return nil, errors.New("invalid test data")
+		}
+
+		if i := strings.IndexByte(line, '|'); i >= 0 {
+			line = line[:i]
+		} else {
+			return nil, errors.New("invalid test data")
+		}
+
+		hexBytes := strings.Fields(line)
+		for _, hexByte := range hexBytes {
+			val, err := strconv.ParseUint(hexByte, 16, 8)
+			if err != nil {
+				return nil, errors.New("invalid hex byte in test data: " + err.Error())
+			}
+			currentFlow = append(currentFlow, byte(val))
+		}
+	}
+
+	if len(currentFlow) > 0 {
+		flows = append(flows, currentFlow)
+	}
+
+	return flows, nil
+}
+
+// tempFile creates a temp file containing contents and returns its path.
+func tempFile(contents string) string {
+	file, err := ioutil.TempFile("", "go-tls-test")
+	if err != nil {
+		panic("failed to create temp file: " + err.Error())
+	}
+	path := file.Name()
+	file.WriteString(contents)
+	file.Close()
+	return path
+}
diff --git a/src/pkg/crypto/tls/key_agreement.go b/src/pkg/crypto/tls/key_agreement.go
index 7e820c1..f38b701 100644
--- a/src/pkg/crypto/tls/key_agreement.go
+++ b/src/pkg/crypto/tls/key_agreement.go
@@ -19,6 +19,9 @@ import (
 	"math/big"
 )
 
+var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message")
+var errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message")
+
 // rsaKeyAgreement implements the standard TLS key agreement where the client
 // encrypts the pre-master secret to the server's public key.
 type rsaKeyAgreement struct{}
@@ -35,14 +38,14 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certifi
 	}
 
 	if len(ckx.ciphertext) < 2 {
-		return nil, errors.New("bad ClientKeyExchange")
+		return nil, errClientKeyExchange
 	}
 
 	ciphertext := ckx.ciphertext
 	if version != VersionSSL30 {
 		ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
 		if ciphertextLen != len(ckx.ciphertext)-2 {
-			return nil, errors.New("bad ClientKeyExchange")
+			return nil, errClientKeyExchange
 		}
 		ciphertext = ckx.ciphertext[2:]
 	}
@@ -61,7 +64,7 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certifi
 }
 
 func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
-	return errors.New("unexpected ServerKeyExchange")
+	return errors.New("tls: unexpected ServerKeyExchange")
 }
 
 func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
@@ -138,7 +141,7 @@ func hashForServerKeyExchange(sigType, hashFunc uint8, version uint16, slices ..
 
 // pickTLS12HashForSignature returns a TLS 1.2 hash identifier for signing a
 // ServerKeyExchange given the signature type being used and the client's
-// advertized list of supported signature and hash combinations.
+// advertised list of supported signature and hash combinations.
 func pickTLS12HashForSignature(sigType uint8, clientSignatureAndHashes []signatureAndHash) (uint8, error) {
 	if len(clientSignatureAndHashes) == 0 {
 		// If the client didn't specify any signature_algorithms
@@ -160,6 +163,20 @@ func pickTLS12HashForSignature(sigType uint8, clientSignatureAndHashes []signatu
 	return 0, errors.New("tls: client doesn't support any common hash functions")
 }
 
+func curveForCurveID(id CurveID) (elliptic.Curve, bool) {
+	switch id {
+	case CurveP256:
+		return elliptic.P256(), true
+	case CurveP384:
+		return elliptic.P384(), true
+	case CurveP521:
+		return elliptic.P521(), true
+	default:
+		return nil, false
+	}
+
+}
+
 // ecdheRSAKeyAgreement implements a TLS key agreement where the server
 // generates a ephemeral EC public/private key pair and signs it. The
 // pre-master secret is then calculated using ECDH. The signature may
@@ -173,23 +190,16 @@ type ecdheKeyAgreement struct {
 }
 
 func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
-	var curveid uint16
-
-Curve:
-	for _, c := range clientHello.supportedCurves {
-		switch c {
-		case curveP256:
-			ka.curve = elliptic.P256()
-			curveid = c
-			break Curve
-		case curveP384:
-			ka.curve = elliptic.P384()
-			curveid = c
-			break Curve
-		case curveP521:
-			ka.curve = elliptic.P521()
-			curveid = c
-			break Curve
+	var curveid CurveID
+	preferredCurves := config.curvePreferences()
+
+NextCandidate:
+	for _, candidate := range preferredCurves {
+		for _, c := range clientHello.supportedCurves {
+			if candidate == c {
+				curveid = c
+				break NextCandidate
+			}
 		}
 	}
 
@@ -197,6 +207,11 @@ Curve:
 		return nil, errors.New("tls: no supported elliptic curves offered")
 	}
 
+	var ok bool
+	if ka.curve, ok = curveForCurveID(curveid); !ok {
+		return nil, errors.New("tls: preferredCurves includes unsupported curve")
+	}
+
 	var x, y *big.Int
 	var err error
 	ka.privateKey, x, y, err = elliptic.GenerateKey(ka.curve, config.rand())
@@ -271,11 +286,11 @@ Curve:
 
 func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
 	if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
-		return nil, errors.New("bad ClientKeyExchange")
+		return nil, errClientKeyExchange
 	}
 	x, y := elliptic.Unmarshal(ka.curve, ckx.ciphertext[1:])
 	if x == nil {
-		return nil, errors.New("bad ClientKeyExchange")
+		return nil, errClientKeyExchange
 	}
 	x, _ = ka.curve.ScalarMult(x, y, ka.privateKey)
 	preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3)
@@ -285,26 +300,18 @@ func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Cert
 	return preMasterSecret, nil
 }
 
-var errServerKeyExchange = errors.New("invalid ServerKeyExchange")
-
 func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
 	if len(skx.key) < 4 {
 		return errServerKeyExchange
 	}
 	if skx.key[0] != 3 { // named curve
-		return errors.New("server selected unsupported curve")
+		return errors.New("tls: server selected unsupported curve")
 	}
-	curveid := uint16(skx.key[1])<<8 | uint16(skx.key[2])
+	curveid := CurveID(skx.key[1])<<8 | CurveID(skx.key[2])
 
-	switch curveid {
-	case curveP256:
-		ka.curve = elliptic.P256()
-	case curveP384:
-		ka.curve = elliptic.P384()
-	case curveP521:
-		ka.curve = elliptic.P521()
-	default:
-		return errors.New("server selected unsupported curve")
+	var ok bool
+	if ka.curve, ok = curveForCurveID(curveid); !ok {
+		return errors.New("tls: server selected unsupported curve")
 	}
 
 	publicLen := int(skx.key[3])
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA b/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
new file mode 100644
index 0000000..00722cb
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
@@ -0,0 +1,129 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
+00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
+00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
+00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
+00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
+00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 01 00 59 02 00 00  55 03 01 53 04 f1 03 46  |....Y...U..S...F|
+00000010  0f 84 c4 cb 55 ef 85 f6  4f d7 0e e1 4b 10 d4 bb  |....U...O...K...|
+00000020  35 87 2d f3 d7 18 ec 4e  95 4b f4 20 28 82 94 d9  |5.-....N.K. (...|
+00000030  df c4 fc ee 21 23 c1 e2  76 3e 7b 09 af 2c 39 23  |....!#..v>{..,9#|
+00000040  f8 46 6c 31 88 42 f0 79  de 37 2b 00 c0 09 00 00  |.Fl1.B.y.7+.....|
+00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
+00000060  01 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
+00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
+00000080  30 09 06 07 2a 86 48 ce  3d 04 01 30 45 31 0b 30  |0...*.H.=..0E1.0|
+00000090  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
+000000a0  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
+000000b0  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
+000000c0  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
+000000d0  74 64 30 1e 17 0d 31 32  31 31 32 32 31 35 30 36  |td0...1211221506|
+000000e0  33 32 5a 17 0d 32 32 31  31 32 30 31 35 30 36 33  |32Z..22112015063|
+000000f0  32 5a 30 45 31 0b 30 09  06 03 55 04 06 13 02 41  |2Z0E1.0...U....A|
+00000100  55 31 13 30 11 06 03 55  04 08 13 0a 53 6f 6d 65  |U1.0...U....Some|
+00000110  2d 53 74 61 74 65 31 21  30 1f 06 03 55 04 0a 13  |-State1!0...U...|
+00000120  18 49 6e 74 65 72 6e 65  74 20 57 69 64 67 69 74  |.Internet Widgit|
+00000130  73 20 50 74 79 20 4c 74  64 30 81 9b 30 10 06 07  |s Pty Ltd0..0...|
+00000140  2a 86 48 ce 3d 02 01 06  05 2b 81 04 00 23 03 81  |*.H.=....+...#..|
+00000150  86 00 04 00 c4 a1 ed be  98 f9 0b 48 73 36 7e c3  |...........Hs6~.|
+00000160  16 56 11 22 f2 3d 53 c3  3b 4d 21 3d cd 6b 75 e6  |.V.".=S.;M!=.ku.|
+00000170  f6 b0 dc 9a df 26 c1 bc  b2 87 f0 72 32 7c b3 64  |.....&.....r2|.d|
+00000180  2f 1c 90 bc ea 68 23 10  7e fe e3 25 c0 48 3a 69  |/....h#.~..%.H:i|
+00000190  e0 28 6d d3 37 00 ef 04  62 dd 0d a0 9c 70 62 83  |.(m.7...b....pb.|
+000001a0  d8 81 d3 64 31 aa 9e 97  31 bd 96 b0 68 c0 9b 23  |...d1...1...h..#|
+000001b0  de 76 64 3f 1a 5c 7f e9  12 0e 58 58 b6 5f 70 dd  |.vd?.\....XX._p.|
+000001c0  9b d8 ea d5 d7 f5 d5 cc  b9 b6 9f 30 66 5b 66 9a  |...........0f[f.|
+000001d0  20 e2 27 e5 bf fe 3b 30  09 06 07 2a 86 48 ce 3d  | .'...;0...*.H.=|
+000001e0  04 01 03 81 8c 00 30 81  88 02 42 01 88 a2 4f eb  |......0...B...O.|
+000001f0  e2 45 c5 48 7d 1b ac f5  ed 98 9d ae 47 70 c0 5e  |.E.H}.......Gp.^|
+00000200  1b b6 2f bd f1 b6 4d b7  61 40 d3 11 a2 ce ee 0b  |../...M.a at ......|
+00000210  7e 92 7e ff 76 9d c3 3b  7e a5 3f ce fa 10 e2 59  |~.~.v..;~.?....Y|
+00000220  ec 47 2d 7c ac da 4e 97  0e 15 a0 6f d0 02 42 01  |.G-|..N....o..B.|
+00000230  4d fc be 67 13 9c 2d 05  0e bd 3f a3 8c 25 c1 33  |M..g..-...?..%.3|
+00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
+00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
+00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
+00000270  2a 16 03 01 00 d5 0c 00  00 d1 03 00 17 41 04 4f  |*............A.O|
+00000280  47 16 72 98 9e 9f 2e 8e  78 e9 0f fe 95 83 7b aa  |G.r.....x.....{.|
+00000290  e5 3d c0 7d cf 83 bd 22  0b fd 48 f1 a7 49 a5 7d  |.=.}..."..H..I.}|
+000002a0  8e 0c 83 7f e1 2d 71 03  cc 90 09 ab f7 35 81 48  |.....-q......5.H|
+000002b0  a4 1e 7d 87 21 23 12 58  2c 47 f3 af c7 6c 71 00  |..}.!#.X,G...lq.|
+000002c0  8a 30 81 87 02 42 00 b4  03 38 60 43 d9 32 ef 64  |.0...B...8`C.2.d|
+000002d0  5a 9c 91 95 0d 10 21 53  c7 78 f8 bf 50 ed 13 5d  |Z.....!S.x..P..]|
+000002e0  c3 e7 71 d6 11 04 f1 e4  9d ce 17 99 8d 1a 87 1f  |..q.............|
+000002f0  cb dd f8 1b ae cd bc 4a  77 ab 7c 50 bf 73 c3 ea  |.......Jw.|P.s..|
+00000300  d6 df 88 56 f6 b1 03 83  02 41 66 3d fb 4e 7e af  |...V.....Af=.N~.|
+00000310  4e c1 60 fe 09 fa 7e 74  99 66 7f de b4 b2 74 89  |N.`...~t.f....t.|
+00000320  1c a4 cf 74 1a 55 a5 be  74 f9 36 21 3d ae c8 c3  |...t.U..t.6!=...|
+00000330  24 8e ad db a3 26 67 8f  98 27 e3 93 ee d9 5c fb  |$....&g..'....\.|
+00000340  85 82 e2 13 c3 50 ab e9  f6 39 2b 16 03 01 00 0e  |.....P...9+.....|
+00000350  0d 00 00 06 03 01 02 40  00 00 0e 00 00 00        |....... at ......|
+>>> Flow 3 (client to server)
+00000000  16 03 01 02 0a 0b 00 02  06 00 02 03 00 02 00 30  |...............0|
+00000010  82 01 fc 30 82 01 5e 02  09 00 9a 30 84 6c 26 35  |...0..^....0.l&5|
+00000020  d9 17 30 09 06 07 2a 86  48 ce 3d 04 01 30 45 31  |..0...*.H.=..0E1|
+00000030  0b 30 09 06 03 55 04 06  13 02 41 55 31 13 30 11  |.0...U....AU1.0.|
+00000040  06 03 55 04 08 13 0a 53  6f 6d 65 2d 53 74 61 74  |..U....Some-Stat|
+00000050  65 31 21 30 1f 06 03 55  04 0a 13 18 49 6e 74 65  |e1!0...U....Inte|
+00000060  72 6e 65 74 20 57 69 64  67 69 74 73 20 50 74 79  |rnet Widgits Pty|
+00000070  20 4c 74 64 30 1e 17 0d  31 32 31 31 31 34 31 33  | Ltd0...12111413|
+00000080  32 35 35 33 5a 17 0d 32  32 31 31 31 32 31 33 32  |2553Z..221112132|
+00000090  35 35 33 5a 30 41 31 0b  30 09 06 03 55 04 06 13  |553Z0A1.0...U...|
+000000a0  02 41 55 31 0c 30 0a 06  03 55 04 08 13 03 4e 53  |.AU1.0...U....NS|
+000000b0  57 31 10 30 0e 06 03 55  04 07 13 07 50 79 72 6d  |W1.0...U....Pyrm|
+000000c0  6f 6e 74 31 12 30 10 06  03 55 04 03 13 09 4a 6f  |ont1.0...U....Jo|
+000000d0  65 6c 20 53 69 6e 67 30  81 9b 30 10 06 07 2a 86  |el Sing0..0...*.|
+000000e0  48 ce 3d 02 01 06 05 2b  81 04 00 23 03 81 86 00  |H.=....+...#....|
+000000f0  04 00 95 8c 91 75 14 c0  5e c4 57 b4 d4 c3 6f 8d  |.....u..^.W...o.|
+00000100  ae 68 1e dd 6f ce 86 e1  7e 6e b2 48 3e 81 e5 4e  |.h..o...~n.H>..N|
+00000110  e2 c6 88 4b 64 dc f5 30  bb d3 ff 65 cc 5b f4 dd  |...Kd..0...e.[..|
+00000120  b5 6a 3e 3e d0 1d de 47  c3 76 ad 19 f6 45 2c 8c  |.j>>...G.v...E,.|
+00000130  bc d8 1d 01 4c 1f 70 90  46 76 48 8b 8f 83 cc 4a  |....L.p.FvH....J|
+00000140  5c 8f 40 76 da e0 89 ec  1d 2b c4 4e 30 76 28 41  |\. at v.....+.N0v(A|
+00000150  b2 62 a8 fb 5b f1 f9 4e  7a 8d bd 09 b8 ae ea 8b  |.b..[..Nz.......|
+00000160  18 27 4f 2e 70 fe 13 96  ba c3 d3 40 16 cd 65 4e  |.'O.p...... at ..eN|
+00000170  ac 11 1e e6 f1 30 09 06  07 2a 86 48 ce 3d 04 01  |.....0...*.H.=..|
+00000180  03 81 8c 00 30 81 88 02  42 00 e0 14 c4 60 60 0b  |....0...B....``.|
+00000190  72 68 b0 32 5d 61 4a 02  74 5c c2 81 b9 16 a8 3f  |rh.2]aJ.t\.....?|
+000001a0  29 c8 36 c7 81 ff 6c b6  5b d9 70 f1 38 3b 50 48  |).6...l.[.p.8;PH|
+000001b0  28 94 cb 09 1a 52 f1 5d  ee 8d f2 b9 f0 f0 da d9  |(....R.]........|
+000001c0  15 3a f9 bd 03 7a 87 a2  23 35 ec 02 42 01 a3 d4  |.:...z..#5..B...|
+000001d0  8a 78 35 1c 4a 9a 23 d2  0a be 2b 10 31 9d 9c 5f  |.x5.J.#...+.1.._|
+000001e0  be e8 91 b3 da 1a f5 5d  a3 23 f5 26 8b 45 70 8d  |.......].#.&.Ep.|
+000001f0  65 62 9b 7e 01 99 3d 18  f6 10 9a 38 61 9b 2e 57  |eb.~..=....8a..W|
+00000200  e4 fa cc b1 8a ce e2 23  a0 87 f0 e1 67 51 eb 16  |.......#....gQ..|
+00000210  03 01 00 46 10 00 00 42  41 04 1e 18 37 ef 0d 19  |...F...BA...7...|
+00000220  51 88 35 75 71 b5 e5 54  5b 12 2e 8f 09 67 fd a7  |Q.5uq..T[....g..|
+00000230  24 20 3e b2 56 1c ce 97  28 5e f8 2b 2d 4f 9e f1  |$ >.V...(^.+-O..|
+00000240  07 9f 6c 4b 5b 83 56 e2  32 42 e9 58 b6 d7 49 a6  |..lK[.V.2B.X..I.|
+00000250  b5 68 1a 41 03 56 6b dc  5a 89 16 03 01 00 90 0f  |.h.A.Vk.Z.......|
+00000260  00 00 8c 00 8a 30 81 87  02 42 00 c6 85 8e 06 b7  |.....0...B......|
+00000270  04 04 e9 cd 9e 3e cb 66  23 95 b4 42 9c 64 81 39  |.....>.f#..B.d.9|
+00000280  05 3f b5 21 f8 28 af 60  6b 4d 3d ba a1 4b 5e 77  |.?.!.(.`kM=..K^w|
+00000290  ef e7 59 28 fe 1d c1 27  a2 ff a8 de 33 48 b3 c1  |..Y(...'....3H..|
+000002a0  85 6a 42 9b f9 7e 7e 31  c2 e5 bd 66 02 41 4b 49  |.jB..~~1...f.AKI|
+000002b0  c6 cd 02 e3 83 f7 03 50  18 6d b4 c9 51 02 c0 ab  |.......P.m..Q...|
+000002c0  87 bc e0 3e 4b 89 53 3a  e2 65 89 97 02 c1 87 f1  |...>K.S:.e......|
+000002d0  67 d0 f2 06 28 4e 51 4e  fd f0 01 be 41 3c 52 42  |g...(NQN....A<RB|
+000002e0  10 44 73 88 3e 44 24 bb  2e 77 01 77 6f a8 ac 14  |.Ds.>D$..w.wo...|
+000002f0  03 01 00 01 01 16 03 01  00 30 a3 da 45 22 96 83  |.........0..E"..|
+00000300  59 90 e9 6b ec 3b 77 50  05 89 e6 0c 61 d1 1d 2b  |Y..k.;wP....a..+|
+00000310  da d4 49 bf b9 c6 dd ad  c3 9c 82 bd 53 62 e8 57  |..I.........Sb.W|
+00000320  a4 6a e7 9f b1 d5 39 77  88 6d                    |.j....9w.m|
+>>> Flow 4 (server to client)
+00000000  14 03 01 00 01 01 16 03  01 00 30 a4 45 dd 99 df  |..........0.E...|
+00000010  66 ae f5 c7 bd 1a eb 6a  ff ac a6 38 14 81 b5 07  |f......j...8....|
+00000020  86 24 80 f1 09 59 ad 33  3d 43 ed 9e 43 b1 1e 9f  |.$...Y.3=C..C...|
+00000030  bd 8c b3 e0 41 83 a1 34  91 c5 a1                 |....A..4...|
+>>> Flow 5 (client to server)
+00000000  17 03 01 00 20 ae e3 ae  7f 2d e3 a2 f7 1b 4e 69  |.... ....-....Ni|
+00000010  cb 18 c6 68 42 f8 de 61  92 4c fa d6 19 7c 8c 09  |...hB..a.L...|..|
+00000020  82 e2 f2 32 19 17 03 01  00 20 2a 77 65 1f c1 fd  |...2..... *we...|
+00000030  5e 37 b7 15 f6 1f 4c 7f  5f 89 52 b4 32 27 4d 17  |^7....L._.R.2'M.|
+00000040  33 c6 e8 50 ac 70 c8 b9  2d 0a 15 03 01 00 20 e0  |3..P.p..-..... .|
+00000050  cb ce 07 80 55 a0 46 ca  a7 25 4c 5f 9d 7c 73 37  |....U.F..%L_.|s7|
+00000060  de 72 6d 36 a8 e4 be fd  2a e7 f8 8d 14 80 b7     |.rm6....*......|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA b/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
new file mode 100644
index 0000000..c0be824
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
@@ -0,0 +1,125 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
+00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
+00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
+00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
+00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
+00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 01 00 51 02 00 00  4d 03 01 53 04 f1 02 ed  |....Q...M..S....|
+00000010  86 9c 56 84 5a d3 7d d7  f3 4e 6f 2c 69 0d f0 59  |..V.Z.}..No,i..Y|
+00000020  a5 d1 de 2d 03 2f dd 63  c3 ab fa 20 30 d6 5a 24  |...-./.c... 0.Z$|
+00000030  5c 31 67 36 8d 4c 43 e1  64 c4 8a 2c a5 fd 39 92  |\1g6.LC.d..,..9.|
+00000040  c5 6f 58 47 a3 fe 63 14  98 92 11 90 00 05 00 00  |.oXG..c.........|
+00000050  05 ff 01 00 01 00 16 03  01 02 be 0b 00 02 ba 00  |................|
+00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000080  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000090  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+000000a0  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+000000b0  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000c0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000d0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000e0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000f0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+00000100  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+00000110  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000120  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000130  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000140  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000150  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000160  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000170  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000180  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000190  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+000001a0  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+000001b0  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001c0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001d0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001e0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001f0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+00000200  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+00000210  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000220  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000230  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000240  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000250  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000260  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000270  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000280  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000290  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+000002a0  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+000002b0  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002c0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002d0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002e0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002f0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+00000300  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 01 00 0e 0d 00  |n8P)l...........|
+00000320  00 06 03 01 02 40 00 00  0e 00 00 00              |..... at ......|
+>>> Flow 3 (client to server)
+00000000  16 03 01 02 0a 0b 00 02  06 00 02 03 00 02 00 30  |...............0|
+00000010  82 01 fc 30 82 01 5e 02  09 00 9a 30 84 6c 26 35  |...0..^....0.l&5|
+00000020  d9 17 30 09 06 07 2a 86  48 ce 3d 04 01 30 45 31  |..0...*.H.=..0E1|
+00000030  0b 30 09 06 03 55 04 06  13 02 41 55 31 13 30 11  |.0...U....AU1.0.|
+00000040  06 03 55 04 08 13 0a 53  6f 6d 65 2d 53 74 61 74  |..U....Some-Stat|
+00000050  65 31 21 30 1f 06 03 55  04 0a 13 18 49 6e 74 65  |e1!0...U....Inte|
+00000060  72 6e 65 74 20 57 69 64  67 69 74 73 20 50 74 79  |rnet Widgits Pty|
+00000070  20 4c 74 64 30 1e 17 0d  31 32 31 31 31 34 31 33  | Ltd0...12111413|
+00000080  32 35 35 33 5a 17 0d 32  32 31 31 31 32 31 33 32  |2553Z..221112132|
+00000090  35 35 33 5a 30 41 31 0b  30 09 06 03 55 04 06 13  |553Z0A1.0...U...|
+000000a0  02 41 55 31 0c 30 0a 06  03 55 04 08 13 03 4e 53  |.AU1.0...U....NS|
+000000b0  57 31 10 30 0e 06 03 55  04 07 13 07 50 79 72 6d  |W1.0...U....Pyrm|
+000000c0  6f 6e 74 31 12 30 10 06  03 55 04 03 13 09 4a 6f  |ont1.0...U....Jo|
+000000d0  65 6c 20 53 69 6e 67 30  81 9b 30 10 06 07 2a 86  |el Sing0..0...*.|
+000000e0  48 ce 3d 02 01 06 05 2b  81 04 00 23 03 81 86 00  |H.=....+...#....|
+000000f0  04 00 95 8c 91 75 14 c0  5e c4 57 b4 d4 c3 6f 8d  |.....u..^.W...o.|
+00000100  ae 68 1e dd 6f ce 86 e1  7e 6e b2 48 3e 81 e5 4e  |.h..o...~n.H>..N|
+00000110  e2 c6 88 4b 64 dc f5 30  bb d3 ff 65 cc 5b f4 dd  |...Kd..0...e.[..|
+00000120  b5 6a 3e 3e d0 1d de 47  c3 76 ad 19 f6 45 2c 8c  |.j>>...G.v...E,.|
+00000130  bc d8 1d 01 4c 1f 70 90  46 76 48 8b 8f 83 cc 4a  |....L.p.FvH....J|
+00000140  5c 8f 40 76 da e0 89 ec  1d 2b c4 4e 30 76 28 41  |\. at v.....+.N0v(A|
+00000150  b2 62 a8 fb 5b f1 f9 4e  7a 8d bd 09 b8 ae ea 8b  |.b..[..Nz.......|
+00000160  18 27 4f 2e 70 fe 13 96  ba c3 d3 40 16 cd 65 4e  |.'O.p...... at ..eN|
+00000170  ac 11 1e e6 f1 30 09 06  07 2a 86 48 ce 3d 04 01  |.....0...*.H.=..|
+00000180  03 81 8c 00 30 81 88 02  42 00 e0 14 c4 60 60 0b  |....0...B....``.|
+00000190  72 68 b0 32 5d 61 4a 02  74 5c c2 81 b9 16 a8 3f  |rh.2]aJ.t\.....?|
+000001a0  29 c8 36 c7 81 ff 6c b6  5b d9 70 f1 38 3b 50 48  |).6...l.[.p.8;PH|
+000001b0  28 94 cb 09 1a 52 f1 5d  ee 8d f2 b9 f0 f0 da d9  |(....R.]........|
+000001c0  15 3a f9 bd 03 7a 87 a2  23 35 ec 02 42 01 a3 d4  |.:...z..#5..B...|
+000001d0  8a 78 35 1c 4a 9a 23 d2  0a be 2b 10 31 9d 9c 5f  |.x5.J.#...+.1.._|
+000001e0  be e8 91 b3 da 1a f5 5d  a3 23 f5 26 8b 45 70 8d  |.......].#.&.Ep.|
+000001f0  65 62 9b 7e 01 99 3d 18  f6 10 9a 38 61 9b 2e 57  |eb.~..=....8a..W|
+00000200  e4 fa cc b1 8a ce e2 23  a0 87 f0 e1 67 51 eb 16  |.......#....gQ..|
+00000210  03 01 00 86 10 00 00 82  00 80 6d 51 f3 7f f9 3e  |..........mQ...>|
+00000220  fb 75 82 41 36 83 e8 6a  ee 2a 2e 25 90 67 4c 8e  |.u.A6..j.*.%.gL.|
+00000230  62 2f 30 81 17 e0 85 09  0c 2b b7 23 d7 b0 e2 1d  |b/0......+.#....|
+00000240  f7 3b d7 f5 a1 27 b6 ee  24 b6 1b cc 5b ea 66 0d  |.;...'..$...[.f.|
+00000250  6a f4 e5 85 f9 da 43 b4  0e 86 85 e1 f5 aa be c8  |j.....C.........|
+00000260  ce 39 4c 9c 86 00 08 c2  4b e2 c6 ec 2f f7 ce e6  |.9L.....K.../...|
+00000270  bd 77 82 6f 23 b6 e0 bd  a2 92 b7 3a ac e8 56 f1  |.w.o#......:..V.|
+00000280  af 54 5e 46 87 e9 3b 33  e7 b8 28 b7 d6 c8 90 35  |.T^F..;3..(....5|
+00000290  d4 1c 43 d1 30 6f 55 4e  0a 70 16 03 01 00 90 0f  |..C.0oUN.p......|
+000002a0  00 00 8c 00 8a 30 81 87  02 42 00 c6 85 8e 06 b7  |.....0...B......|
+000002b0  04 04 e9 cd 9e 3e cb 66  23 95 b4 42 9c 64 81 39  |.....>.f#..B.d.9|
+000002c0  05 3f b5 21 f8 28 af 60  6b 4d 3d ba a1 4b 5e 77  |.?.!.(.`kM=..K^w|
+000002d0  ef e7 59 28 fe 1d c1 27  a2 ff a8 de 33 48 b3 c1  |..Y(...'....3H..|
+000002e0  85 6a 42 9b f9 7e 7e 31  c2 e5 bd 66 02 41 4b 49  |.jB..~~1...f.AKI|
+000002f0  c6 cd 02 e3 83 f7 03 50  18 6d b4 c9 51 02 c0 ab  |.......P.m..Q...|
+00000300  87 bc e0 3e 4b 89 53 3a  e2 65 89 97 02 c1 87 f1  |...>K.S:.e......|
+00000310  67 d0 f2 06 28 4e 51 4e  fd f0 01 47 e7 c9 d9 23  |g...(NQN...G...#|
+00000320  21 6b 87 d2 55 e3 c9 f7  eb 86 d5 1e 50 df d5 14  |!k..U.......P...|
+00000330  03 01 00 01 01 16 03 01  00 24 95 62 42 be 90 39  |.........$.bB..9|
+00000340  68 ae f5 77 47 21 14 b9  ac ee 81 2d e3 9e c7 34  |h..wG!.....-...4|
+00000350  3a 00 5c c9 12 1d c0 5a  7c e7 ef e0 cd fd        |:.\....Z|.....|
+>>> Flow 4 (server to client)
+00000000  14 03 01 00 01 01 16 03  01 00 24 ea 98 c0 fb 86  |..........$.....|
+00000010  87 7a 2e e1 c7 68 61 3e  5b cc da 1f d6 7b ab 5a  |.z...ha>[....{.Z|
+00000020  a0 ae a2 cf d0 54 44 19  12 db 75 2b 8c 73 8c     |.....TD...u+.s.|
+>>> Flow 5 (client to server)
+00000000  17 03 01 00 1a f3 28 77  31 33 4c b3 7c 4b 75 61  |......(w13L.|Kua|
+00000010  38 69 6b ae c9 36 ab 2e  56 16 29 6a 9a 00 2f 15  |8ik..6..V.)j../.|
+00000020  03 01 00 16 6b ed 68 18  ed ff 44 39 9b 4a e4 a2  |....k.h...D9.J..|
+00000030  cd 79 ef 2a 3e 5a 4d b1  5d 56                    |.y.*>ZM.]V|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA b/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
new file mode 100644
index 0000000..3e6dbc2
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
@@ -0,0 +1,128 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
+00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
+00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
+00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
+00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
+00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 01 00 59 02 00 00  55 03 01 53 04 f1 02 4f  |....Y...U..S...O|
+00000010  73 06 2d 72 41 36 a1 b2  d3 50 97 55 8c c5 f1 43  |s.-rA6...P.U...C|
+00000020  37 1f 1a 2a fe 51 70 0b  2f 25 9e 20 50 61 86 80  |7..*.Qp./%. Pa..|
+00000030  9a 9c 6d 6f c9 ea 5c ce  0c b7 7c ce e3 be d0 e5  |..mo..\...|.....|
+00000040  be d0 c4 80 78 c3 c7 17  0c 2d 8e c8 c0 09 00 00  |....x....-......|
+00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
+00000060  01 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
+00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
+00000080  30 09 06 07 2a 86 48 ce  3d 04 01 30 45 31 0b 30  |0...*.H.=..0E1.0|
+00000090  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
+000000a0  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
+000000b0  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
+000000c0  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
+000000d0  74 64 30 1e 17 0d 31 32  31 31 32 32 31 35 30 36  |td0...1211221506|
+000000e0  33 32 5a 17 0d 32 32 31  31 32 30 31 35 30 36 33  |32Z..22112015063|
+000000f0  32 5a 30 45 31 0b 30 09  06 03 55 04 06 13 02 41  |2Z0E1.0...U....A|
+00000100  55 31 13 30 11 06 03 55  04 08 13 0a 53 6f 6d 65  |U1.0...U....Some|
+00000110  2d 53 74 61 74 65 31 21  30 1f 06 03 55 04 0a 13  |-State1!0...U...|
+00000120  18 49 6e 74 65 72 6e 65  74 20 57 69 64 67 69 74  |.Internet Widgit|
+00000130  73 20 50 74 79 20 4c 74  64 30 81 9b 30 10 06 07  |s Pty Ltd0..0...|
+00000140  2a 86 48 ce 3d 02 01 06  05 2b 81 04 00 23 03 81  |*.H.=....+...#..|
+00000150  86 00 04 00 c4 a1 ed be  98 f9 0b 48 73 36 7e c3  |...........Hs6~.|
+00000160  16 56 11 22 f2 3d 53 c3  3b 4d 21 3d cd 6b 75 e6  |.V.".=S.;M!=.ku.|
+00000170  f6 b0 dc 9a df 26 c1 bc  b2 87 f0 72 32 7c b3 64  |.....&.....r2|.d|
+00000180  2f 1c 90 bc ea 68 23 10  7e fe e3 25 c0 48 3a 69  |/....h#.~..%.H:i|
+00000190  e0 28 6d d3 37 00 ef 04  62 dd 0d a0 9c 70 62 83  |.(m.7...b....pb.|
+000001a0  d8 81 d3 64 31 aa 9e 97  31 bd 96 b0 68 c0 9b 23  |...d1...1...h..#|
+000001b0  de 76 64 3f 1a 5c 7f e9  12 0e 58 58 b6 5f 70 dd  |.vd?.\....XX._p.|
+000001c0  9b d8 ea d5 d7 f5 d5 cc  b9 b6 9f 30 66 5b 66 9a  |...........0f[f.|
+000001d0  20 e2 27 e5 bf fe 3b 30  09 06 07 2a 86 48 ce 3d  | .'...;0...*.H.=|
+000001e0  04 01 03 81 8c 00 30 81  88 02 42 01 88 a2 4f eb  |......0...B...O.|
+000001f0  e2 45 c5 48 7d 1b ac f5  ed 98 9d ae 47 70 c0 5e  |.E.H}.......Gp.^|
+00000200  1b b6 2f bd f1 b6 4d b7  61 40 d3 11 a2 ce ee 0b  |../...M.a at ......|
+00000210  7e 92 7e ff 76 9d c3 3b  7e a5 3f ce fa 10 e2 59  |~.~.v..;~.?....Y|
+00000220  ec 47 2d 7c ac da 4e 97  0e 15 a0 6f d0 02 42 01  |.G-|..N....o..B.|
+00000230  4d fc be 67 13 9c 2d 05  0e bd 3f a3 8c 25 c1 33  |M..g..-...?..%.3|
+00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
+00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
+00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
+00000270  2a 16 03 01 00 d6 0c 00  00 d2 03 00 17 41 04 b1  |*............A..|
+00000280  0f 0f 4a 18 ed 25 32 b3  a3 19 ed 4b 61 b6 eb e4  |..J..%2....Ka...|
+00000290  d3 f7 77 13 ac 9f 60 c7  8d 6d cb f1 ee 99 1a 71  |..w...`..m.....q|
+000002a0  68 aa d3 a7 70 7f 38 d0  f6 23 ab 9a f6 dd 19 4f  |h...p.8..#.....O|
+000002b0  ce 10 ef d5 cf 64 85 2f  75 f6 20 06 4b f0 b9 00  |.....d./u. .K...|
+000002c0  8b 30 81 88 02 42 01 00  b9 6b 80 91 59 0a 48 3f  |.0...B...k..Y.H?|
+000002d0  72 16 96 8f 21 2c 28 e4  6d 03 74 66 35 16 7d ec  |r...!,(.m.tf5.}.|
+000002e0  c7 08 9b 52 b5 05 d9 38  d8 b7 51 42 a7 4a 9f 9b  |...R...8..QB.J..|
+000002f0  1a 37 14 de c5 f5 16 96  83 81 58 d3 a6 1e ce 8a  |.7........X.....|
+00000300  bc 19 47 30 fe c5 85 55  02 42 01 4f 61 59 68 85  |..G0...U.B.OaYh.|
+00000310  c7 64 23 22 f6 83 53 cc  58 38 25 b5 ce 74 c1 68  |.d#"..S.X8%..t.h|
+00000320  9f 32 72 33 ea c9 62 e0  26 63 92 e3 5f 34 10 0b  |.2r3..b.&c.._4..|
+00000330  3c d5 83 fe 9f 67 69 ef  33 6b 19 c1 ec d6 6c 35  |<....gi.3k....l5|
+00000340  89 33 17 d3 9d 93 e2 e5  6e 89 9a a1 16 03 01 00  |.3......n.......|
+00000350  0e 0d 00 00 06 03 01 02  40 00 00 0e 00 00 00     |........ at ......|
+>>> Flow 3 (client to server)
+00000000  16 03 01 01 fb 0b 00 01  f7 00 01 f4 00 01 f1 30  |...............0|
+00000010  82 01 ed 30 82 01 58 a0  03 02 01 02 02 01 00 30  |...0..X........0|
+00000020  0b 06 09 2a 86 48 86 f7  0d 01 01 05 30 26 31 10  |...*.H......0&1.|
+00000030  30 0e 06 03 55 04 0a 13  07 41 63 6d 65 20 43 6f  |0...U....Acme Co|
+00000040  31 12 30 10 06 03 55 04  03 13 09 31 32 37 2e 30  |1.0...U....127.0|
+00000050  2e 30 2e 31 30 1e 17 0d  31 31 31 32 30 38 30 37  |.0.10...11120807|
+00000060  35 35 31 32 5a 17 0d 31  32 31 32 30 37 30 38 30  |5512Z..121207080|
+00000070  30 31 32 5a 30 26 31 10  30 0e 06 03 55 04 0a 13  |012Z0&1.0...U...|
+00000080  07 41 63 6d 65 20 43 6f  31 12 30 10 06 03 55 04  |.Acme Co1.0...U.|
+00000090  03 13 09 31 32 37 2e 30  2e 30 2e 31 30 81 9c 30  |...127.0.0.10..0|
+000000a0  0b 06 09 2a 86 48 86 f7  0d 01 01 01 03 81 8c 00  |...*.H..........|
+000000b0  30 81 88 02 81 80 4e d0  7b 31 e3 82 64 d9 59 c0  |0.....N.{1..d.Y.|
+000000c0  c2 87 a4 5e 1e 8b 73 33  c7 63 53 df 66 92 06 84  |...^..s3.cS.f...|
+000000d0  f6 64 d5 8f e4 36 a7 1d  2b e8 b3 20 36 45 23 b5  |.d...6..+.. 6E#.|
+000000e0  e3 95 ae ed e0 f5 20 9c  8d 95 df 7f 5a 12 ef 87  |...... .....Z...|
+000000f0  e4 5b 68 e4 e9 0e 74 ec  04 8a 7f de 93 27 c4 01  |.[h...t......'..|
+00000100  19 7a bd f2 dc 3d 14 ab  d0 54 ca 21 0c d0 4d 6e  |.z...=...T.!..Mn|
+00000110  87 2e 5c c5 d2 bb 4d 4b  4f ce b6 2c f7 7e 88 ec  |..\...MKO..,.~..|
+00000120  7c d7 02 91 74 a6 1e 0c  1a da e3 4a 5a 2e de 13  ||...t......JZ...|
+00000130  9c 4c 40 88 59 93 02 03  01 00 01 a3 32 30 30 30  |.L at .Y.......2000|
+00000140  0e 06 03 55 1d 0f 01 01  ff 04 04 03 02 00 a0 30  |...U...........0|
+00000150  0d 06 03 55 1d 0e 04 06  04 04 01 02 03 04 30 0f  |...U..........0.|
+00000160  06 03 55 1d 23 04 08 30  06 80 04 01 02 03 04 30  |..U.#..0.......0|
+00000170  0b 06 09 2a 86 48 86 f7  0d 01 01 05 03 81 81 00  |...*.H..........|
+00000180  36 1f b3 7a 0c 75 c9 6e  37 46 61 2b d5 bd c0 a7  |6..z.u.n7Fa+....|
+00000190  4b cc 46 9a 81 58 7c 85  79 29 c8 c8 c6 67 dd 32  |K.F..X|.y)...g.2|
+000001a0  56 45 2b 75 b6 e9 24 a9  50 9a be 1f 5a fa 1a 15  |VE+u..$.P...Z...|
+000001b0  d9 cc 55 95 72 16 83 b9  c2 b6 8f fd 88 8c 38 84  |..U.r.........8.|
+000001c0  1d ab 5d 92 31 13 4f fd  83 3b c6 9d f1 11 62 b6  |..].1.O..;....b.|
+000001d0  8b ec ab 67 be c8 64 b0  11 50 46 58 17 6b 99 1c  |...g..d..PFX.k..|
+000001e0  d3 1d fc 06 f1 0e e5 96  a8 0c f9 78 20 b7 44 18  |...........x .D.|
+000001f0  51 8d 10 7e 4f 94 67 df  a3 4e 70 73 8e 90 91 85  |Q..~O.g..Nps....|
+00000200  16 03 01 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
+00000210  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
+00000220  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
+00000230  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
+00000240  a6 b5 68 1a 41 03 56 6b  dc 5a 89 16 03 01 00 86  |..h.A.Vk.Z......|
+00000250  0f 00 00 82 00 80 20 2c  5a 08 3a 00 33 50 19 b2  |...... ,Z.:.3P..|
+00000260  0f ba 6c 76 7f 5c 92 e2  78 55 3e 32 32 bb 33 bc  |..lv.\..xU>22.3.|
+00000270  ab a9 34 e0 83 cf 82 cd  9e 6b 3f 9d e6 49 61 29  |..4......k?..Ia)|
+00000280  8b b4 ed e8 12 cd a9 52  86 11 48 64 08 61 72 8d  |.......R..Hd.ar.|
+00000290  d6 6a ac 42 cc e4 07 5f  08 56 9f 2f c5 35 d3 9b  |.j.B..._.V./.5..|
+000002a0  e9 0d 91 82 c0 e9 bb 9f  a9 8f df 96 85 08 9a 69  |...............i|
+000002b0  a4 93 b3 72 37 ba f9 b1  a4 0b b0 9f 43 6a 15 ec  |...r7.......Cj..|
+000002c0  79 b8 fd 9c 1f 5f 0d 2c  56 33 c7 15 d5 4a b7 82  |y...._.,V3...J..|
+000002d0  ea 44 80 20 c5 80 14 03  01 00 01 01 16 03 01 00  |.D. ............|
+000002e0  30 c9 c0 7c d7 57 d3 00  ab 87 eb 78 56 6b a1 69  |0..|.W.....xVk.i|
+000002f0  1d fa ec ae 38 f3 ef 5d  49 19 0d 4b f0 73 63 af  |....8..]I..K.sc.|
+00000300  89 b6 cb 76 cf fb b9 c1  99 98 06 0a 54 67 a0 6e  |...v........Tg.n|
+00000310  e7                                                |.|
+>>> Flow 4 (server to client)
+00000000  14 03 01 00 01 01 16 03  01 00 30 20 db fd ed ed  |..........0 ....|
+00000010  7c d5 bf 8f 06 3b 86 1b  c1 60 7d a4 74 e9 a6 c9  ||....;...`}.t...|
+00000020  f5 7c c7 f4 65 91 06 d5  53 88 d7 57 a4 22 b6 1f  |.|..e...S..W."..|
+00000030  f1 02 e9 79 36 e6 a1 22  51 3a 4c                 |...y6.."Q:L|
+>>> Flow 5 (client to server)
+00000000  17 03 01 00 20 00 66 51  6a 14 ca ea e2 21 48 74  |.... .fQj....!Ht|
+00000010  c4 c1 6e b9 8b 23 af 7c  33 c9 00 f8 0b ec ab 35  |..n..#.|3......5|
+00000020  e7 42 0a d1 ae 17 03 01  00 20 00 1c 6d 60 75 5d  |.B....... ..m`u]|
+00000030  b3 fb 40 2e e0 b7 0d 48  f4 87 ac d4 bf ea 01 0d  |.. at ....H........|
+00000040  fe 10 0d 05 04 43 6b 19  ed f2 15 03 01 00 20 f8  |.....Ck....... .|
+00000050  03 ac 62 4b 1f db 2e d2  4e 00 c3 a4 57 3c 0a 62  |..bK....N...W<.b|
+00000060  05 a0 ef bd 2b 9b 9a 63  27 72 d7 d8 f1 8d 84     |....+..c'r.....|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA b/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
new file mode 100644
index 0000000..94e6860
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
@@ -0,0 +1,124 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
+00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
+00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
+00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
+00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
+00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 01 00 51 02 00 00  4d 03 01 53 04 f1 02 73  |....Q...M..S...s|
+00000010  ee 5f 70 a4 aa 0d be d7  46 a3 25 3f e3 5d ef 7b  |._p.....F.%?.].{|
+00000020  73 49 7c b6 82 4d 99 2f  31 fc 8b 20 2d a3 33 7c  |sI|..M./1.. -.3||
+00000030  a5 c3 85 86 ba 61 4d 05  b0 5e d3 5e 88 6e c3 4b  |.....aM..^.^.n.K|
+00000040  95 d3 e9 67 f1 96 24 58  7a 6f e6 c5 00 05 00 00  |...g..$Xzo......|
+00000050  05 ff 01 00 01 00 16 03  01 02 be 0b 00 02 ba 00  |................|
+00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000080  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000090  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+000000a0  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+000000b0  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000c0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000d0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000e0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000f0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+00000100  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+00000110  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000120  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000130  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000140  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000150  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000160  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000170  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000180  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000190  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+000001a0  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+000001b0  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001c0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001d0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001e0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001f0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+00000200  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+00000210  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000220  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000230  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000240  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000250  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000260  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000270  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000280  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000290  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+000002a0  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+000002b0  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002c0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002d0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002e0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002f0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+00000300  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 01 00 0e 0d 00  |n8P)l...........|
+00000320  00 06 03 01 02 40 00 00  0e 00 00 00              |..... at ......|
+>>> Flow 3 (client to server)
+00000000  16 03 01 01 fb 0b 00 01  f7 00 01 f4 00 01 f1 30  |...............0|
+00000010  82 01 ed 30 82 01 58 a0  03 02 01 02 02 01 00 30  |...0..X........0|
+00000020  0b 06 09 2a 86 48 86 f7  0d 01 01 05 30 26 31 10  |...*.H......0&1.|
+00000030  30 0e 06 03 55 04 0a 13  07 41 63 6d 65 20 43 6f  |0...U....Acme Co|
+00000040  31 12 30 10 06 03 55 04  03 13 09 31 32 37 2e 30  |1.0...U....127.0|
+00000050  2e 30 2e 31 30 1e 17 0d  31 31 31 32 30 38 30 37  |.0.10...11120807|
+00000060  35 35 31 32 5a 17 0d 31  32 31 32 30 37 30 38 30  |5512Z..121207080|
+00000070  30 31 32 5a 30 26 31 10  30 0e 06 03 55 04 0a 13  |012Z0&1.0...U...|
+00000080  07 41 63 6d 65 20 43 6f  31 12 30 10 06 03 55 04  |.Acme Co1.0...U.|
+00000090  03 13 09 31 32 37 2e 30  2e 30 2e 31 30 81 9c 30  |...127.0.0.10..0|
+000000a0  0b 06 09 2a 86 48 86 f7  0d 01 01 01 03 81 8c 00  |...*.H..........|
+000000b0  30 81 88 02 81 80 4e d0  7b 31 e3 82 64 d9 59 c0  |0.....N.{1..d.Y.|
+000000c0  c2 87 a4 5e 1e 8b 73 33  c7 63 53 df 66 92 06 84  |...^..s3.cS.f...|
+000000d0  f6 64 d5 8f e4 36 a7 1d  2b e8 b3 20 36 45 23 b5  |.d...6..+.. 6E#.|
+000000e0  e3 95 ae ed e0 f5 20 9c  8d 95 df 7f 5a 12 ef 87  |...... .....Z...|
+000000f0  e4 5b 68 e4 e9 0e 74 ec  04 8a 7f de 93 27 c4 01  |.[h...t......'..|
+00000100  19 7a bd f2 dc 3d 14 ab  d0 54 ca 21 0c d0 4d 6e  |.z...=...T.!..Mn|
+00000110  87 2e 5c c5 d2 bb 4d 4b  4f ce b6 2c f7 7e 88 ec  |..\...MKO..,.~..|
+00000120  7c d7 02 91 74 a6 1e 0c  1a da e3 4a 5a 2e de 13  ||...t......JZ...|
+00000130  9c 4c 40 88 59 93 02 03  01 00 01 a3 32 30 30 30  |.L at .Y.......2000|
+00000140  0e 06 03 55 1d 0f 01 01  ff 04 04 03 02 00 a0 30  |...U...........0|
+00000150  0d 06 03 55 1d 0e 04 06  04 04 01 02 03 04 30 0f  |...U..........0.|
+00000160  06 03 55 1d 23 04 08 30  06 80 04 01 02 03 04 30  |..U.#..0.......0|
+00000170  0b 06 09 2a 86 48 86 f7  0d 01 01 05 03 81 81 00  |...*.H..........|
+00000180  36 1f b3 7a 0c 75 c9 6e  37 46 61 2b d5 bd c0 a7  |6..z.u.n7Fa+....|
+00000190  4b cc 46 9a 81 58 7c 85  79 29 c8 c8 c6 67 dd 32  |K.F..X|.y)...g.2|
+000001a0  56 45 2b 75 b6 e9 24 a9  50 9a be 1f 5a fa 1a 15  |VE+u..$.P...Z...|
+000001b0  d9 cc 55 95 72 16 83 b9  c2 b6 8f fd 88 8c 38 84  |..U.r.........8.|
+000001c0  1d ab 5d 92 31 13 4f fd  83 3b c6 9d f1 11 62 b6  |..].1.O..;....b.|
+000001d0  8b ec ab 67 be c8 64 b0  11 50 46 58 17 6b 99 1c  |...g..d..PFX.k..|
+000001e0  d3 1d fc 06 f1 0e e5 96  a8 0c f9 78 20 b7 44 18  |...........x .D.|
+000001f0  51 8d 10 7e 4f 94 67 df  a3 4e 70 73 8e 90 91 85  |Q..~O.g..Nps....|
+00000200  16 03 01 00 86 10 00 00  82 00 80 6d 51 f3 7f f9  |...........mQ...|
+00000210  3e fb 75 82 41 36 83 e8  6a ee 2a 2e 25 90 67 4c  |>.u.A6..j.*.%.gL|
+00000220  8e 62 2f 30 81 17 e0 85  09 0c 2b b7 23 d7 b0 e2  |.b/0......+.#...|
+00000230  1d f7 3b d7 f5 a1 27 b6  ee 24 b6 1b cc 5b ea 66  |..;...'..$...[.f|
+00000240  0d 6a f4 e5 85 f9 da 43  b4 0e 86 85 e1 f5 aa be  |.j.....C........|
+00000250  c8 ce 39 4c 9c 86 00 08  c2 4b e2 c6 ec 2f f7 ce  |..9L.....K.../..|
+00000260  e6 bd 77 82 6f 23 b6 e0  bd a2 92 b7 3a ac e8 56  |..w.o#......:..V|
+00000270  f1 af 54 5e 46 87 e9 3b  33 e7 b8 28 b7 d6 c8 90  |..T^F..;3..(....|
+00000280  35 d4 1c 43 d1 30 6f 55  4e 0a 70 16 03 01 00 86  |5..C.0oUN.p.....|
+00000290  0f 00 00 82 00 80 0f 4c  d2 b2 f0 94 6d 61 d1 2c  |.......L....ma.,|
+000002a0  db 6f 79 03 bd 40 b2 d2  1d 61 ef 83 1b 4a 0c 7b  |.oy.. at ...a...J.{|
+000002b0  c5 73 1e 1a 81 e7 67 0a  d6 aa 2d 04 04 cc 0e 4b  |.s....g...-....K|
+000002c0  2e da 96 7f 15 6c 05 ee  c4 53 7e 33 89 28 7d db  |.....l...S~3.(}.|
+000002d0  a1 77 43 ba a3 51 a9 1c  b9 f5 ec 9a 8d eb 2c 46  |.wC..Q........,F|
+000002e0  5c 33 59 6b 16 af de f4  9b 80 76 a3 22 30 5d bb  |\3Yk......v."0].|
+000002f0  02 b9 77 96 8a db 36 9f  54 95 00 d8 58 e1 aa 04  |..w...6.T...X...|
+00000300  98 c9 0c 32 ae 62 81 12  0c f6 1b 76 c6 58 a7 8c  |...2.b.....v.X..|
+00000310  0e d8 b7 8e ed 0f 14 03  01 00 01 01 16 03 01 00  |................|
+00000320  24 1d c0 20 02 2d da 69  54 29 8c ff af 5c 56 a8  |$.. .-.iT)...\V.|
+00000330  eb d0 09 95 29 8f 52 8c  e2 7b 9f 36 3e 47 a0 33  |....).R..{.6>G.3|
+00000340  2e 63 a2 24 93                                    |.c.$.|
+>>> Flow 4 (server to client)
+00000000  14 03 01 00 01 01 16 03  01 00 24 99 e8 fb 65 f4  |..........$...e.|
+00000010  95 ae 8b 71 cc 5d a4 95  a7 27 98 fd 16 3f 7a 1a  |...q.]...'...?z.|
+00000020  b6 bd bf 0a 58 72 77 97  1f 8e b1 dd 4b 12 12     |....Xrw.....K..|
+>>> Flow 5 (client to server)
+00000000  17 03 01 00 1a 42 70 c0  89 78 12 5c 91 7e 88 2d  |.....Bp..x.\.~.-|
+00000010  2f 8f be f2 f2 12 9d 81  ae 78 08 38 5e 6d 1b 15  |/........x.8^m..|
+00000020  03 01 00 16 1a 64 b1 6f  8a ff d3 63 6a c7 b8 95  |.....d.o...cj...|
+00000030  3d b0 87 bc 62 e9 88 5b  26 bd                    |=...b..[&.|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES b/src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
new file mode 100644
index 0000000..30c4c6b
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
@@ -0,0 +1,87 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
+00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
+00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
+00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
+00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
+00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 01 00 59 02 00 00  55 03 01 53 04 f1 02 b2  |....Y...U..S....|
+00000010  e0 f6 f6 b5 c9 5b 28 d0  5d 58 1b 6f 4e 2b 9d 05  |.....[(.]X.oN+..|
+00000020  2a b9 b4 da 45 cf f3 10  b2 23 44 20 f8 4d 59 05  |*...E....#D .MY.|
+00000030  ad 27 f2 a0 ee 7f ec cc  20 dc e7 a2 1b 07 b3 a5  |.'...... .......|
+00000040  37 7e 61 3d d6 5c 03 cf  cc f5 9b ca c0 09 00 00  |7~a=.\..........|
+00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
+00000060  01 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
+00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
+00000080  30 09 06 07 2a 86 48 ce  3d 04 01 30 45 31 0b 30  |0...*.H.=..0E1.0|
+00000090  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
+000000a0  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
+000000b0  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
+000000c0  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
+000000d0  74 64 30 1e 17 0d 31 32  31 31 32 32 31 35 30 36  |td0...1211221506|
+000000e0  33 32 5a 17 0d 32 32 31  31 32 30 31 35 30 36 33  |32Z..22112015063|
+000000f0  32 5a 30 45 31 0b 30 09  06 03 55 04 06 13 02 41  |2Z0E1.0...U....A|
+00000100  55 31 13 30 11 06 03 55  04 08 13 0a 53 6f 6d 65  |U1.0...U....Some|
+00000110  2d 53 74 61 74 65 31 21  30 1f 06 03 55 04 0a 13  |-State1!0...U...|
+00000120  18 49 6e 74 65 72 6e 65  74 20 57 69 64 67 69 74  |.Internet Widgit|
+00000130  73 20 50 74 79 20 4c 74  64 30 81 9b 30 10 06 07  |s Pty Ltd0..0...|
+00000140  2a 86 48 ce 3d 02 01 06  05 2b 81 04 00 23 03 81  |*.H.=....+...#..|
+00000150  86 00 04 00 c4 a1 ed be  98 f9 0b 48 73 36 7e c3  |...........Hs6~.|
+00000160  16 56 11 22 f2 3d 53 c3  3b 4d 21 3d cd 6b 75 e6  |.V.".=S.;M!=.ku.|
+00000170  f6 b0 dc 9a df 26 c1 bc  b2 87 f0 72 32 7c b3 64  |.....&.....r2|.d|
+00000180  2f 1c 90 bc ea 68 23 10  7e fe e3 25 c0 48 3a 69  |/....h#.~..%.H:i|
+00000190  e0 28 6d d3 37 00 ef 04  62 dd 0d a0 9c 70 62 83  |.(m.7...b....pb.|
+000001a0  d8 81 d3 64 31 aa 9e 97  31 bd 96 b0 68 c0 9b 23  |...d1...1...h..#|
+000001b0  de 76 64 3f 1a 5c 7f e9  12 0e 58 58 b6 5f 70 dd  |.vd?.\....XX._p.|
+000001c0  9b d8 ea d5 d7 f5 d5 cc  b9 b6 9f 30 66 5b 66 9a  |...........0f[f.|
+000001d0  20 e2 27 e5 bf fe 3b 30  09 06 07 2a 86 48 ce 3d  | .'...;0...*.H.=|
+000001e0  04 01 03 81 8c 00 30 81  88 02 42 01 88 a2 4f eb  |......0...B...O.|
+000001f0  e2 45 c5 48 7d 1b ac f5  ed 98 9d ae 47 70 c0 5e  |.E.H}.......Gp.^|
+00000200  1b b6 2f bd f1 b6 4d b7  61 40 d3 11 a2 ce ee 0b  |../...M.a at ......|
+00000210  7e 92 7e ff 76 9d c3 3b  7e a5 3f ce fa 10 e2 59  |~.~.v..;~.?....Y|
+00000220  ec 47 2d 7c ac da 4e 97  0e 15 a0 6f d0 02 42 01  |.G-|..N....o..B.|
+00000230  4d fc be 67 13 9c 2d 05  0e bd 3f a3 8c 25 c1 33  |M..g..-...?..%.3|
+00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
+00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
+00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
+00000270  2a 16 03 01 00 d5 0c 00  00 d1 03 00 17 41 04 da  |*............A..|
+00000280  5a fd 09 e5 d6 c0 70 41  5e 3a 87 eb df 0c ad 90  |Z.....pA^:......|
+00000290  22 8a 2f 90 81 0c 24 00  68 92 f3 d5 95 2f 93 43  |"./...$.h..../.C|
+000002a0  e9 58 2d 18 28 62 ee 33  5b 21 2e 49 87 21 4d 32  |.X-.(b.3[!.I.!M2|
+000002b0  32 19 b3 ba fe 2d 9a 85  12 0e a1 77 08 06 75 00  |2....-.....w..u.|
+000002c0  8a 30 81 87 02 42 01 91  14 fc 68 74 95 10 4b d4  |.0...B....ht..K.|
+000002d0  67 60 12 46 bb b0 f6 98  77 a3 41 b8 01 5c 49 54  |g`.F....w.A..\IT|
+000002e0  9e 3e 81 e7 97 a3 b9 73  6e 15 74 67 be e5 d9 eb  |.>.....sn.tg....|
+000002f0  8b 87 c5 22 ab ab 58 28  4f d1 b6 80 94 1b f5 f7  |..."..X(O.......|
+00000300  12 43 ef 0a c7 3e 1a 76  02 41 7a 00 49 cb 9f 3b  |.C...>.v.Az.I..;|
+00000310  91 6e 38 58 0a d3 d0 d1  ee 67 f0 b6 5d cd fa 23  |.n8X.....g..]..#|
+00000320  b6 98 43 af 9c 71 90 1e  1d 50 a2 6e 61 5b f2 92  |..C..q...P.na[..|
+00000330  b4 69 73 f2 3b 54 bf 1c  9d 05 19 97 e4 4e 41 9e  |.is.;T.......NA.|
+00000340  f2 9a 76 77 9a 86 43 1f  1f 30 a2 16 03 01 00 04  |..vw..C..0......|
+00000350  0e 00 00 00                                       |....|
+>>> Flow 3 (client to server)
+00000000  16 03 01 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
+00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
+00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
+00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
+00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 01 00 01  |..h.A.Vk.Z......|
+00000050  01 16 03 01 00 30 88 60  65 b2 d7 51 1f ad 96 56  |.....0.`e..Q...V|
+00000060  4e 0a 20 eb b5 b0 1a dd  4c f6 1a cf d4 5c 47 c4  |N. .....L....\G.|
+00000070  9c 7c a0 36 dd d1 1b 96  91 99 c0 a7 2d 9a 7c 42  |.|.6........-.|B|
+00000080  51 d1 de 87 2b a4                                 |Q...+.|
+>>> Flow 4 (server to client)
+00000000  14 03 01 00 01 01 16 03  01 00 30 86 6c b5 94 69  |..........0.l..i|
+00000010  2e e0 55 a2 4d a8 63 f2  5b 1f ae 34 21 c8 21 6a  |..U.M.c.[..4!.!j|
+00000020  00 b6 56 ed 4e 2a b0 ff  01 2f da ce a1 c0 41 03  |..V.N*.../....A.|
+00000030  a9 1b 6e 2e e1 88 50 ba  62 14 88                 |..n...P.b..|
+>>> Flow 5 (client to server)
+00000000  17 03 01 00 20 a6 63 0a  2f a5 dc e1 fb cb 7b 1f  |.... .c./.....{.|
+00000010  f2 da 74 c3 ff e9 f5 8b  9c 5f 0c d3 f7 1f 44 e6  |..t......_....D.|
+00000020  90 13 5c 48 50 17 03 01  00 20 c7 75 b5 ff bc 09  |..\HP.... .u....|
+00000030  34 f2 45 db 0d 22 08 8e  f1 35 cd b6 0f b0 eb 2a  |4.E.."...5.....*|
+00000040  b7 1a d0 8e 14 a4 54 84  f9 dc 15 03 01 00 20 e0  |......T....... .|
+00000050  36 3d aa b3 a9 b4 20 23  ca 9e 8c 5d fc a8 c8 b7  |6=.... #...]....|
+00000060  f5 c2 b6 d0 5a e2 ce a5  7b 68 a0 48 86 95 6a     |....Z...{h.H..j|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES b/src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
new file mode 100644
index 0000000..868f0ce
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
@@ -0,0 +1,97 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
+00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
+00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
+00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
+00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
+00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 01 00 59 02 00 00  55 03 01 53 04 f1 02 21  |....Y...U..S...!|
+00000010  67 b5 2b 34 fb 62 d7 36  4f cf 68 2e 29 39 d0 28  |g.+4.b.6O.h.)9.(|
+00000020  3a 02 32 82 8f 95 de 62  d6 03 77 20 e6 98 56 cd  |:.2....b..w ..V.|
+00000030  96 24 d1 b9 4d eb 51 19  bb b7 71 f4 9c 29 32 d4  |.$..M.Q...q..)2.|
+00000040  e5 c6 0a 54 e0 4a 20 29  3e bd 06 0d c0 13 00 00  |...T.J )>.......|
+00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
+00000060  01 02 be 0b 00 02 ba 00  02 b7 00 02 b4 30 82 02  |.............0..|
+00000070  b0 30 82 02 19 a0 03 02  01 02 02 09 00 85 b0 bb  |.0..............|
+00000080  a4 8a 7f b8 ca 30 0d 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
+00000090  01 05 05 00 30 45 31 0b  30 09 06 03 55 04 06 13  |....0E1.0...U...|
+000000a0  02 41 55 31 13 30 11 06  03 55 04 08 13 0a 53 6f  |.AU1.0...U....So|
+000000b0  6d 65 2d 53 74 61 74 65  31 21 30 1f 06 03 55 04  |me-State1!0...U.|
+000000c0  0a 13 18 49 6e 74 65 72  6e 65 74 20 57 69 64 67  |...Internet Widg|
+000000d0  69 74 73 20 50 74 79 20  4c 74 64 30 1e 17 0d 31  |its Pty Ltd0...1|
+000000e0  30 30 34 32 34 30 39 30  39 33 38 5a 17 0d 31 31  |00424090938Z..11|
+000000f0  30 34 32 34 30 39 30 39  33 38 5a 30 45 31 0b 30  |0424090938Z0E1.0|
+00000100  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
+00000110  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
+00000120  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
+00000130  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
+00000140  74 64 30 81 9f 30 0d 06  09 2a 86 48 86 f7 0d 01  |td0..0...*.H....|
+00000150  01 01 05 00 03 81 8d 00  30 81 89 02 81 81 00 bb  |........0.......|
+00000160  79 d6 f5 17 b5 e5 bf 46  10 d0 dc 69 be e6 2b 07  |y......F...i..+.|
+00000170  43 5a d0 03 2d 8a 7a 43  85 b7 14 52 e7 a5 65 4c  |CZ..-.zC...R..eL|
+00000180  2c 78 b8 23 8c b5 b4 82  e5 de 1f 95 3b 7e 62 a5  |,x.#........;~b.|
+00000190  2c a5 33 d6 fe 12 5c 7a  56 fc f5 06 bf fa 58 7b  |,.3...\zV.....X{|
+000001a0  26 3f b5 cd 04 d3 d0 c9  21 96 4a c7 f4 54 9f 5a  |&?......!.J..T.Z|
+000001b0  bf ef 42 71 00 fe 18 99  07 7f 7e 88 7d 7d f1 04  |..Bq......~.}}..|
+000001c0  39 c4 a2 2e db 51 c9 7c  e3 c0 4c 3b 32 66 01 cf  |9....Q.|..L;2f..|
+000001d0  af b1 1d b8 71 9a 1d db  db 89 6b ae da 2d 79 02  |....q.....k..-y.|
+000001e0  03 01 00 01 a3 81 a7 30  81 a4 30 1d 06 03 55 1d  |.......0..0...U.|
+000001f0  0e 04 16 04 14 b1 ad e2  85 5a cf cb 28 db 69 ce  |.........Z..(.i.|
+00000200  23 69 de d3 26 8e 18 88  39 30 75 06 03 55 1d 23  |#i..&...90u..U.#|
+00000210  04 6e 30 6c 80 14 b1 ad  e2 85 5a cf cb 28 db 69  |.n0l......Z..(.i|
+00000220  ce 23 69 de d3 26 8e 18  88 39 a1 49 a4 47 30 45  |.#i..&...9.I.G0E|
+00000230  31 0b 30 09 06 03 55 04  06 13 02 41 55 31 13 30  |1.0...U....AU1.0|
+00000240  11 06 03 55 04 08 13 0a  53 6f 6d 65 2d 53 74 61  |...U....Some-Sta|
+00000250  74 65 31 21 30 1f 06 03  55 04 0a 13 18 49 6e 74  |te1!0...U....Int|
+00000260  65 72 6e 65 74 20 57 69  64 67 69 74 73 20 50 74  |ernet Widgits Pt|
+00000270  79 20 4c 74 64 82 09 00  85 b0 bb a4 8a 7f b8 ca  |y Ltd...........|
+00000280  30 0c 06 03 55 1d 13 04  05 30 03 01 01 ff 30 0d  |0...U....0....0.|
+00000290  06 09 2a 86 48 86 f7 0d  01 01 05 05 00 03 81 81  |..*.H...........|
+000002a0  00 08 6c 45 24 c7 6b b1  59 ab 0c 52 cc f2 b0 14  |..lE$.k.Y..R....|
+000002b0  d7 87 9d 7a 64 75 b5 5a  95 66 e4 c5 2b 8e ae 12  |...zdu.Z.f..+...|
+000002c0  66 1f eb 4f 38 b3 6e 60  d3 92 fd f7 41 08 b5 25  |f..O8.n`....A..%|
+000002d0  13 b1 18 7a 24 fb 30 1d  ba ed 98 b9 17 ec e7 d7  |...z$.0.........|
+000002e0  31 59 db 95 d3 1d 78 ea  50 56 5c d5 82 5a 2d 5a  |1Y....x.PV\..Z-Z|
+000002f0  5f 33 c4 b6 d8 c9 75 90  96 8c 0f 52 98 b5 cd 98  |_3....u....R....|
+00000300  1f 89 20 5f f2 a0 1c a3  1b 96 94 dd a9 fd 57 e9  |.. _..........W.|
+00000310  70 e8 26 6d 71 99 9b 26  6e 38 50 29 6c 90 a7 bd  |p.&mq..&n8P)l...|
+00000320  d9 16 03 01 00 cb 0c 00  00 c7 03 00 17 41 04 05  |.............A..|
+00000330  45 33 f8 4b e9 96 0e 4a  fd ec 54 76 21 9b 24 8a  |E3.K...J..Tv!.$.|
+00000340  75 0b 80 84 c7 30 2b 22  f0 85 57 a4 a9 79 d6 f6  |u....0+"..W..y..|
+00000350  6d 80 b0 71 d9 66 c9 6c  dd 76 fc 32 d0 c6 bc 52  |m..q.f.l.v.2...R|
+00000360  2f f1 c9 62 17 53 76 ec  be a6 1c 93 f2 b4 5d 00  |/..b.Sv.......].|
+00000370  80 72 d9 20 52 70 7c 03  b1 33 fa 51 23 cd 05 97  |.r. Rp|..3.Q#...|
+00000380  6f d6 89 2f 8d 2e 3a 17  32 eb f2 ff 6b 39 70 5e  |o../..:.2...k9p^|
+00000390  21 41 8d 69 02 c8 9a 17  19 e4 48 9b 51 c3 7f 9b  |!A.i......H.Q...|
+000003a0  8d 4a 83 97 07 0e 30 f1  8b 6b e9 92 12 01 d6 96  |.J....0..k......|
+000003b0  f2 1a a2 10 7f 59 87 16  1a fb 55 67 68 fc 78 c6  |.....Y....Ugh.x.|
+000003c0  57 ac 05 dd f3 6f 77 84  eb ae b0 33 2d 19 2c ba  |W....ow....3-.,.|
+000003d0  b8 ae 9f 95 69 85 95 45  5e 37 f4 17 17 9b 03 c1  |....i..E^7......|
+000003e0  50 b1 36 42 bd 60 5c 8b  d8 b6 f3 c8 34 c8 9d 9d  |P.6B.`\.....4...|
+000003f0  75 16 03 01 00 04 0e 00  00 00                    |u.........|
+>>> Flow 3 (client to server)
+00000000  16 03 01 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
+00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
+00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
+00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
+00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 01 00 01  |..h.A.Vk.Z......|
+00000050  01 16 03 01 00 30 ca d1  1b 08 27 9b 44 e7 e9 b4  |.....0....'.D...|
+00000060  90 16 4d 30 4e 65 5c 0d  47 ba 46 86 cf c9 80 e7  |..M0Ne\.G.F.....|
+00000070  64 31 f5 a1 9e dc 39 15  d3 be 16 4f c7 90 b6 62  |d1....9....O...b|
+00000080  5d 6d 7f 41 4e 3e                                 |]m.AN>|
+>>> Flow 4 (server to client)
+00000000  14 03 01 00 01 01 16 03  01 00 30 98 81 24 8e cd  |..........0..$..|
+00000010  b6 48 2f 80 de 8e 24 3c  cd 02 67 80 34 97 d7 92  |.H/...$<..g.4...|
+00000020  78 c2 44 3d 5d 05 eb 88  76 79 46 7a c3 fa ca 73  |x.D=]...vyFz...s|
+00000030  45 82 ad c1 81 00 ca 40  c1 2f 13                 |E...... at ./.|
+>>> Flow 5 (client to server)
+00000000  17 03 01 00 20 ee 19 59  67 67 a9 8b db 99 87 50  |.... ..Ygg.....P|
+00000010  01 e2 02 c1 d5 6d 36 79  af aa ec 1b 80 0e b6 5e  |.....m6y.......^|
+00000020  5f fa 03 01 cc 17 03 01  00 20 ec e2 04 b7 3b a5  |_........ ....;.|
+00000030  f2 e0 13 1f 17 48 e7 6e  d3 eb f0 fa 36 ef 6e 2e  |.....H.n....6.n.|
+00000040  fb ea c8 39 c4 5f 4b 28  d4 50 15 03 01 00 20 c7  |...9._K(.P.... .|
+00000050  45 ff fb c7 07 0c d8 0e  35 a3 c5 31 47 b7 03 0e  |E.......5..1G...|
+00000060  14 c8 29 fd 53 70 5f 15  ac d2 1c 4c 69 fb d6     |..).Sp_....Li..|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv10-RSA-RC4 b/src/pkg/crypto/tls/testdata/Client-TLSv10-RSA-RC4
new file mode 100644
index 0000000..395d53b
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv10-RSA-RC4
@@ -0,0 +1,83 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
+00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
+00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
+00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
+00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
+00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 01 00 51 02 00 00  4d 03 01 53 04 f1 02 76  |....Q...M..S...v|
+00000010  e8 45 7f 57 f3 42 4b 33  0b 06 fa a6 fa c4 3d 84  |.E.W.BK3......=.|
+00000020  5a 45 dc 93 41 a5 8d 79  6e 8f 11 20 e7 c6 29 2b  |ZE..A..yn.. ..)+|
+00000030  ff 4a 6e 63 67 a6 10 cb  49 19 46 1e 5e 0a d5 70  |.Jncg...I.F.^..p|
+00000040  96 88 9a 32 48 ef c3 4a  45 4c 6d e0 00 05 00 00  |...2H..JELm.....|
+00000050  05 ff 01 00 01 00 16 03  01 02 be 0b 00 02 ba 00  |................|
+00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000080  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000090  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+000000a0  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+000000b0  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000c0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000d0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000e0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000f0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+00000100  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+00000110  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000120  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000130  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000140  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000150  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000160  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000170  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000180  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000190  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+000001a0  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+000001b0  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001c0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001d0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001e0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001f0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+00000200  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+00000210  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000220  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000230  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000240  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000250  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000260  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000270  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000280  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000290  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+000002a0  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+000002b0  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002c0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002d0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002e0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002f0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+00000300  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 01 00 04 0e 00  |n8P)l...........|
+00000320  00 00                                             |..|
+>>> Flow 3 (client to server)
+00000000  16 03 01 00 86 10 00 00  82 00 80 6d 51 f3 7f f9  |...........mQ...|
+00000010  3e fb 75 82 41 36 83 e8  6a ee 2a 2e 25 90 67 4c  |>.u.A6..j.*.%.gL|
+00000020  8e 62 2f 30 81 17 e0 85  09 0c 2b b7 23 d7 b0 e2  |.b/0......+.#...|
+00000030  1d f7 3b d7 f5 a1 27 b6  ee 24 b6 1b cc 5b ea 66  |..;...'..$...[.f|
+00000040  0d 6a f4 e5 85 f9 da 43  b4 0e 86 85 e1 f5 aa be  |.j.....C........|
+00000050  c8 ce 39 4c 9c 86 00 08  c2 4b e2 c6 ec 2f f7 ce  |..9L.....K.../..|
+00000060  e6 bd 77 82 6f 23 b6 e0  bd a2 92 b7 3a ac e8 56  |..w.o#......:..V|
+00000070  f1 af 54 5e 46 87 e9 3b  33 e7 b8 28 b7 d6 c8 90  |..T^F..;3..(....|
+00000080  35 d4 1c 43 d1 30 6f 55  4e 0a 70 14 03 01 00 01  |5..C.0oUN.p.....|
+00000090  01 16 03 01 00 24 cd c0  68 dc 2e 69 cc c7 5b c5  |.....$..h..i..[.|
+000000a0  3f bd 40 cf a0 0f 41 34  ce 16 37 10 26 c8 3f d1  |?. at ...A4..7.&.?.|
+000000b0  46 3b ad 7b b0 31 f3 c5  36 e7                    |F;.{.1..6.|
+>>> Flow 4 (server to client)
+00000000  14 03 01 00 01 01 16 03  01 00 24 ea 77 6f 3c 42  |..........$.wo<B|
+00000010  12 16 51 de e8 b6 f9 85  06 d9 6d 05 75 50 2b 27  |..Q.......m.uP+'|
+00000020  93 b7 6b 65 e9 14 99 48  53 3e be e4 be 03 5d     |..ke...HS>....]|
+>>> Flow 5 (client to server)
+00000000  17 03 01 00 1a 9e ae ca  55 df c4 d9 47 04 55 dd  |........U...G.U.|
+00000010  3b 33 e1 a6 16 6f a1 94  b1 9b 4d 0d cb 6c 3b 15  |;3...o....M..l;.|
+00000020  03 01 00 16 92 5d 76 07  e9 b7 31 29 09 c5 b1 09  |.....]v...1)....|
+00000030  2d 64 3d 85 8d f1 d1 40  54 b8                    |-d=.... at T.|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES b/src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
new file mode 100644
index 0000000..9f941f8
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
@@ -0,0 +1,89 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
+00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
+00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
+00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
+00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
+00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 02 00 59 02 00 00  55 03 02 53 04 f1 02 1c  |....Y...U..S....|
+00000010  d1 1c 6a 5f 7a 5c 26 69  92 cd ee c3 57 ed 96 90  |..j_z\&i....W...|
+00000020  e3 c5 f1 ee 8b ee 99 5f  46 2c e6 20 c8 50 6a a4  |......._F,. .Pj.|
+00000030  4b 93 e6 da ba 6d d4 87  f6 75 a8 9d 44 db b5 43  |K....m...u..D..C|
+00000040  df 12 57 de a4 f1 bc fb  b8 7a 3f 6a c0 09 00 00  |..W......z?j....|
+00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
+00000060  02 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
+00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
+00000080  30 09 06 07 2a 86 48 ce  3d 04 01 30 45 31 0b 30  |0...*.H.=..0E1.0|
+00000090  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
+000000a0  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
+000000b0  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
+000000c0  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
+000000d0  74 64 30 1e 17 0d 31 32  31 31 32 32 31 35 30 36  |td0...1211221506|
+000000e0  33 32 5a 17 0d 32 32 31  31 32 30 31 35 30 36 33  |32Z..22112015063|
+000000f0  32 5a 30 45 31 0b 30 09  06 03 55 04 06 13 02 41  |2Z0E1.0...U....A|
+00000100  55 31 13 30 11 06 03 55  04 08 13 0a 53 6f 6d 65  |U1.0...U....Some|
+00000110  2d 53 74 61 74 65 31 21  30 1f 06 03 55 04 0a 13  |-State1!0...U...|
+00000120  18 49 6e 74 65 72 6e 65  74 20 57 69 64 67 69 74  |.Internet Widgit|
+00000130  73 20 50 74 79 20 4c 74  64 30 81 9b 30 10 06 07  |s Pty Ltd0..0...|
+00000140  2a 86 48 ce 3d 02 01 06  05 2b 81 04 00 23 03 81  |*.H.=....+...#..|
+00000150  86 00 04 00 c4 a1 ed be  98 f9 0b 48 73 36 7e c3  |...........Hs6~.|
+00000160  16 56 11 22 f2 3d 53 c3  3b 4d 21 3d cd 6b 75 e6  |.V.".=S.;M!=.ku.|
+00000170  f6 b0 dc 9a df 26 c1 bc  b2 87 f0 72 32 7c b3 64  |.....&.....r2|.d|
+00000180  2f 1c 90 bc ea 68 23 10  7e fe e3 25 c0 48 3a 69  |/....h#.~..%.H:i|
+00000190  e0 28 6d d3 37 00 ef 04  62 dd 0d a0 9c 70 62 83  |.(m.7...b....pb.|
+000001a0  d8 81 d3 64 31 aa 9e 97  31 bd 96 b0 68 c0 9b 23  |...d1...1...h..#|
+000001b0  de 76 64 3f 1a 5c 7f e9  12 0e 58 58 b6 5f 70 dd  |.vd?.\....XX._p.|
+000001c0  9b d8 ea d5 d7 f5 d5 cc  b9 b6 9f 30 66 5b 66 9a  |...........0f[f.|
+000001d0  20 e2 27 e5 bf fe 3b 30  09 06 07 2a 86 48 ce 3d  | .'...;0...*.H.=|
+000001e0  04 01 03 81 8c 00 30 81  88 02 42 01 88 a2 4f eb  |......0...B...O.|
+000001f0  e2 45 c5 48 7d 1b ac f5  ed 98 9d ae 47 70 c0 5e  |.E.H}.......Gp.^|
+00000200  1b b6 2f bd f1 b6 4d b7  61 40 d3 11 a2 ce ee 0b  |../...M.a at ......|
+00000210  7e 92 7e ff 76 9d c3 3b  7e a5 3f ce fa 10 e2 59  |~.~.v..;~.?....Y|
+00000220  ec 47 2d 7c ac da 4e 97  0e 15 a0 6f d0 02 42 01  |.G-|..N....o..B.|
+00000230  4d fc be 67 13 9c 2d 05  0e bd 3f a3 8c 25 c1 33  |M..g..-...?..%.3|
+00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
+00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
+00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
+00000270  2a 16 03 02 00 d4 0c 00  00 d0 03 00 17 41 04 7b  |*............A.{|
+00000280  c4 00 37 35 51 de c3 f2  a4 95 2c 19 21 3e a6 94  |..75Q.....,.!>..|
+00000290  7b fd 04 d7 b7 1c 56 e6  af 3c ee 36 cb 55 e6 f0  |{.....V..<.6.U..|
+000002a0  e6 24 34 6b 8a 02 66 71  f9 e2 f5 a6 c9 d7 6c dc  |.$4k..fq......l.|
+000002b0  65 59 ff 1c c9 ec a9 8b  07 d6 52 2c 01 3c c3 00  |eY........R,.<..|
+000002c0  89 30 81 86 02 41 74 89  1a 31 72 e6 8b c0 4a ce  |.0...At..1r...J.|
+000002d0  8f 5a 49 a7 52 2d 6d b9  8b 50 17 62 2a 99 d6 3b  |.ZI.R-m..P.b*..;|
+000002e0  02 85 41 4d 34 53 b5 09  bd e3 ac 16 c1 9b e9 83  |..AM4S..........|
+000002f0  cc 83 e3 9c 23 34 67 71  72 d4 05 a2 34 f7 08 29  |....#4gqr...4..)|
+00000300  62 43 2e cc bc 08 01 02  41 59 de 5a d0 dd d7 6b  |bC......AY.Z...k|
+00000310  db 9c 35 29 79 f8 96 91  56 74 1f 18 7b ee 25 83  |..5)y...Vt..{.%.|
+00000320  f2 37 0e 77 ab 38 fb 5e  04 0b 09 d9 b4 1f 3f be  |.7.w.8.^......?.|
+00000330  2e e3 60 e3 96 f3 29 c1  6d 8f 56 1b fd 62 14 48  |..`...).m.V..b.H|
+00000340  e3 d9 2a ea 2f be 93 d0  8b 31 16 03 02 00 04 0e  |..*./....1......|
+00000350  00 00 00                                          |...|
+>>> Flow 3 (client to server)
+00000000  16 03 02 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
+00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
+00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
+00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
+00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 02 00 01  |..h.A.Vk.Z......|
+00000050  01 16 03 02 00 40 00 00  00 00 00 00 00 00 00 00  |..... at ..........|
+00000060  00 00 00 00 00 00 b6 98  a2 a9 48 34 12 6b 0a 94  |..........H4.k..|
+00000070  89 fc 38 04 63 5a 6f 63  36 3e d9 35 12 64 8c 28  |..8.cZoc6>.5.d.(|
+00000080  99 a6 cf 2e 57 e3 14 6d  0a 8a ab f0 a6 58 37 7c  |....W..m.....X7||
+00000090  96 04 d3 71 bc d4                                 |...q..|
+>>> Flow 4 (server to client)
+00000000  14 03 02 00 01 01 16 03  02 00 40 c5 01 c9 0a b0  |.......... at .....|
+00000010  d8 ca 5e c1 19 dc 37 6c  2e a0 b3 11 a8 87 65 5a  |..^...7l......eZ|
+00000020  09 41 b9 fe 53 c4 c9 76  97 6d 7f ac c0 be d2 07  |.A..S..v.m......|
+00000030  84 e5 5b 78 37 34 ee da  3b cb 3e 82 52 79 91 44  |..[x74..;.>.Ry.D|
+00000040  b4 e4 1c ec 3a c0 c0 9d  cd ff 13                 |....:......|
+>>> Flow 5 (client to server)
+00000000  17 03 02 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
+00000010  00 00 00 00 00 46 60 13  39 2b 2f 72 95 ed 0e aa  |.....F`.9+/r....|
+00000020  69 6e b4 64 3e 83 43 d0  f9 7f 37 7c 1d b9 ce 11  |in.d>.C...7|....|
+00000030  d9 41 66 60 6d 15 03 02  00 30 00 00 00 00 00 00  |.Af`m....0......|
+00000040  00 00 00 00 00 00 00 00  00 00 b1 26 d0 5d 08 98  |...........&.]..|
+00000050  eb 28 42 74 31 58 42 95  c5 ad 1a 92 0a f5 5f ed  |.(Bt1XB......._.|
+00000060  45 98 e0 90 e5 a3 b6 8b  8d 18                    |E.........|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES b/src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
new file mode 100644
index 0000000..fc72339
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
@@ -0,0 +1,99 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
+00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
+00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
+00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
+00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
+00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 02 00 59 02 00 00  55 03 02 53 04 f1 02 fe  |....Y...U..S....|
+00000010  17 8b 79 ad 93 2e d3 89  66 9b 5d 9b b4 03 3e ba  |..y.....f.]...>.|
+00000020  65 2a f1 55 f9 3c 33 de  2c a7 47 20 fa 4f 82 11  |e*.U.<3.,.G .O..|
+00000030  96 81 d0 70 2e 65 b3 68  2e 3a 6d d7 6c 74 22 33  |...p.e.h.:m.lt"3|
+00000040  d4 ae 6c aa c8 f0 c7 20  8b 10 21 e7 c0 13 00 00  |..l.... ..!.....|
+00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
+00000060  02 02 be 0b 00 02 ba 00  02 b7 00 02 b4 30 82 02  |.............0..|
+00000070  b0 30 82 02 19 a0 03 02  01 02 02 09 00 85 b0 bb  |.0..............|
+00000080  a4 8a 7f b8 ca 30 0d 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
+00000090  01 05 05 00 30 45 31 0b  30 09 06 03 55 04 06 13  |....0E1.0...U...|
+000000a0  02 41 55 31 13 30 11 06  03 55 04 08 13 0a 53 6f  |.AU1.0...U....So|
+000000b0  6d 65 2d 53 74 61 74 65  31 21 30 1f 06 03 55 04  |me-State1!0...U.|
+000000c0  0a 13 18 49 6e 74 65 72  6e 65 74 20 57 69 64 67  |...Internet Widg|
+000000d0  69 74 73 20 50 74 79 20  4c 74 64 30 1e 17 0d 31  |its Pty Ltd0...1|
+000000e0  30 30 34 32 34 30 39 30  39 33 38 5a 17 0d 31 31  |00424090938Z..11|
+000000f0  30 34 32 34 30 39 30 39  33 38 5a 30 45 31 0b 30  |0424090938Z0E1.0|
+00000100  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
+00000110  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
+00000120  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
+00000130  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
+00000140  74 64 30 81 9f 30 0d 06  09 2a 86 48 86 f7 0d 01  |td0..0...*.H....|
+00000150  01 01 05 00 03 81 8d 00  30 81 89 02 81 81 00 bb  |........0.......|
+00000160  79 d6 f5 17 b5 e5 bf 46  10 d0 dc 69 be e6 2b 07  |y......F...i..+.|
+00000170  43 5a d0 03 2d 8a 7a 43  85 b7 14 52 e7 a5 65 4c  |CZ..-.zC...R..eL|
+00000180  2c 78 b8 23 8c b5 b4 82  e5 de 1f 95 3b 7e 62 a5  |,x.#........;~b.|
+00000190  2c a5 33 d6 fe 12 5c 7a  56 fc f5 06 bf fa 58 7b  |,.3...\zV.....X{|
+000001a0  26 3f b5 cd 04 d3 d0 c9  21 96 4a c7 f4 54 9f 5a  |&?......!.J..T.Z|
+000001b0  bf ef 42 71 00 fe 18 99  07 7f 7e 88 7d 7d f1 04  |..Bq......~.}}..|
+000001c0  39 c4 a2 2e db 51 c9 7c  e3 c0 4c 3b 32 66 01 cf  |9....Q.|..L;2f..|
+000001d0  af b1 1d b8 71 9a 1d db  db 89 6b ae da 2d 79 02  |....q.....k..-y.|
+000001e0  03 01 00 01 a3 81 a7 30  81 a4 30 1d 06 03 55 1d  |.......0..0...U.|
+000001f0  0e 04 16 04 14 b1 ad e2  85 5a cf cb 28 db 69 ce  |.........Z..(.i.|
+00000200  23 69 de d3 26 8e 18 88  39 30 75 06 03 55 1d 23  |#i..&...90u..U.#|
+00000210  04 6e 30 6c 80 14 b1 ad  e2 85 5a cf cb 28 db 69  |.n0l......Z..(.i|
+00000220  ce 23 69 de d3 26 8e 18  88 39 a1 49 a4 47 30 45  |.#i..&...9.I.G0E|
+00000230  31 0b 30 09 06 03 55 04  06 13 02 41 55 31 13 30  |1.0...U....AU1.0|
+00000240  11 06 03 55 04 08 13 0a  53 6f 6d 65 2d 53 74 61  |...U....Some-Sta|
+00000250  74 65 31 21 30 1f 06 03  55 04 0a 13 18 49 6e 74  |te1!0...U....Int|
+00000260  65 72 6e 65 74 20 57 69  64 67 69 74 73 20 50 74  |ernet Widgits Pt|
+00000270  79 20 4c 74 64 82 09 00  85 b0 bb a4 8a 7f b8 ca  |y Ltd...........|
+00000280  30 0c 06 03 55 1d 13 04  05 30 03 01 01 ff 30 0d  |0...U....0....0.|
+00000290  06 09 2a 86 48 86 f7 0d  01 01 05 05 00 03 81 81  |..*.H...........|
+000002a0  00 08 6c 45 24 c7 6b b1  59 ab 0c 52 cc f2 b0 14  |..lE$.k.Y..R....|
+000002b0  d7 87 9d 7a 64 75 b5 5a  95 66 e4 c5 2b 8e ae 12  |...zdu.Z.f..+...|
+000002c0  66 1f eb 4f 38 b3 6e 60  d3 92 fd f7 41 08 b5 25  |f..O8.n`....A..%|
+000002d0  13 b1 18 7a 24 fb 30 1d  ba ed 98 b9 17 ec e7 d7  |...z$.0.........|
+000002e0  31 59 db 95 d3 1d 78 ea  50 56 5c d5 82 5a 2d 5a  |1Y....x.PV\..Z-Z|
+000002f0  5f 33 c4 b6 d8 c9 75 90  96 8c 0f 52 98 b5 cd 98  |_3....u....R....|
+00000300  1f 89 20 5f f2 a0 1c a3  1b 96 94 dd a9 fd 57 e9  |.. _..........W.|
+00000310  70 e8 26 6d 71 99 9b 26  6e 38 50 29 6c 90 a7 bd  |p.&mq..&n8P)l...|
+00000320  d9 16 03 02 00 cb 0c 00  00 c7 03 00 17 41 04 26  |.............A.&|
+00000330  56 18 02 e5 66 d4 aa 24  7e ae 39 e5 ca 78 6c c1  |V...f..$~.9..xl.|
+00000340  90 02 c3 c4 ad 79 2c 47  a8 bf 54 e2 8a 22 b6 ef  |.....y,G..T.."..|
+00000350  99 d4 7a 7f 8f 78 6a 78  4e 14 2a 16 0d bb 54 38  |..z..xjxN.*...T8|
+00000360  59 1f 7a 53 1b c7 73 10  89 4b de c3 66 39 7a 00  |Y.zS..s..K..f9z.|
+00000370  80 3a 88 38 c8 15 07 ab  2f 0f 0d cb 19 07 84 ac  |.:.8..../.......|
+00000380  24 fd 8b d2 9d 05 45 c6  11 c3 d6 84 58 95 5a 08  |$.....E.....X.Z.|
+00000390  b9 a4 2c c0 41 4e 34 e0  b2 24 98 94 b7 67 27 50  |..,.AN4..$...g'P|
+000003a0  ba 82 35 28 a9 bf 16 ee  e3 7b 49 9c 4c 81 80 69  |..5(.....{I.L..i|
+000003b0  d7 aa ed 46 ea 9a 68 c4  97 b7 11 d4 35 91 74 5e  |...F..h.....5.t^|
+000003c0  54 10 34 83 cd c4 06 18  49 7d 7a 28 c9 53 06 73  |T.4.....I}z(.S.s|
+000003d0  00 7b 04 b6 d8 36 a7 4b  67 7f 81 30 94 de 40 4d  |.{...6.Kg..0.. at M|
+000003e0  18 f8 c4 b7 02 00 44 8e  bc 72 06 24 53 15 74 72  |......D..r.$S.tr|
+000003f0  8d 16 03 02 00 04 0e 00  00 00                    |..........|
+>>> Flow 3 (client to server)
+00000000  16 03 02 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
+00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
+00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
+00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
+00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 02 00 01  |..h.A.Vk.Z......|
+00000050  01 16 03 02 00 40 00 00  00 00 00 00 00 00 00 00  |..... at ..........|
+00000060  00 00 00 00 00 00 8a 87  81 38 35 c0 4c bb f8 12  |.........85.L...|
+00000070  fa 75 04 cd 1e 3a 61 96  93 c8 fb 07 d1 6d b4 55  |.u...:a......m.U|
+00000080  0f b5 0f 07 35 0a 96 ce  5c 6f 24 62 d3 68 e4 b0  |....5...\o$b.h..|
+00000090  5d be 81 37 c2 9c                                 |]..7..|
+>>> Flow 4 (server to client)
+00000000  14 03 02 00 01 01 16 03  02 00 40 66 36 8d f8 8c  |.......... at f6...|
+00000010  7f db 38 e8 39 df f8 2f  cb 88 9c 14 d9 89 10 b4  |..8.9../........|
+00000020  be 59 88 d7 f3 73 62 af  a3 42 66 6e 74 38 64 9f  |.Y...sb..Bfnt8d.|
+00000030  16 79 09 d7 14 7e 91 8a  70 73 63 28 30 58 fe cc  |.y...~..psc(0X..|
+00000040  42 45 d6 37 fb 9e 8c c1  01 af 34                 |BE.7......4|
+>>> Flow 5 (client to server)
+00000000  17 03 02 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
+00000010  00 00 00 00 00 31 0b e3  9d 2a 05 83 19 7d 10 36  |.....1...*...}.6|
+00000020  23 dc da fe 00 ab d3 aa  8f ce 28 5f 08 fd b7 59  |#.........(_...Y|
+00000030  1e 00 2e 25 5a 15 03 02  00 30 00 00 00 00 00 00  |...%Z....0......|
+00000040  00 00 00 00 00 00 00 00  00 00 10 91 fd fa 59 07  |..............Y.|
+00000050  df 2c 92 25 15 7b 7c 83  44 89 0d 4f 65 43 99 2e  |.,.%.{|.D..OeC..|
+00000060  41 5d 51 c9 09 89 ed 02  08 bc                    |A]Q.......|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv11-RSA-RC4 b/src/pkg/crypto/tls/testdata/Client-TLSv11-RSA-RC4
new file mode 100644
index 0000000..f7be3f7
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv11-RSA-RC4
@@ -0,0 +1,83 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
+00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
+00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
+00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
+00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
+00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 02 00 51 02 00 00  4d 03 02 53 04 f1 02 d4  |....Q...M..S....|
+00000010  69 65 aa 96 3d 42 96 eb  9e 7d 8a 18 af 4c 7c 5d  |ie..=B...}...L|]|
+00000020  fb 97 5f da 94 62 13 69  1f 66 06 20 aa 52 e3 08  |.._..b.i.f. .R..|
+00000030  35 0a 87 d5 ef 93 49 ab  1a 74 dd 90 bd 69 70 d1  |5.....I..t...ip.|
+00000040  e9 f1 44 17 3a dc 33 98  f5 e5 ab 93 00 05 00 00  |..D.:.3.........|
+00000050  05 ff 01 00 01 00 16 03  02 02 be 0b 00 02 ba 00  |................|
+00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000080  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000090  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+000000a0  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+000000b0  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000c0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000d0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000e0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000f0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+00000100  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+00000110  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000120  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000130  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000140  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000150  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000160  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000170  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000180  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000190  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+000001a0  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+000001b0  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001c0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001d0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001e0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001f0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+00000200  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+00000210  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000220  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000230  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000240  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000250  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000260  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000270  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000280  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000290  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+000002a0  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+000002b0  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002c0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002d0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002e0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002f0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+00000300  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 02 00 04 0e 00  |n8P)l...........|
+00000320  00 00                                             |..|
+>>> Flow 3 (client to server)
+00000000  16 03 02 00 86 10 00 00  82 00 80 6d 51 f3 7f f9  |...........mQ...|
+00000010  3e fb 75 82 41 36 83 e8  6a ee 2a 2e 25 90 67 4c  |>.u.A6..j.*.%.gL|
+00000020  8e 62 2f 30 81 17 e0 85  09 0c 2b b7 23 d7 b0 e2  |.b/0......+.#...|
+00000030  1d f7 3b d7 f5 a1 27 b6  ee 24 b6 1b cc 5b ea 66  |..;...'..$...[.f|
+00000040  0d 6a f4 e5 85 f9 da 43  b4 0e 86 85 e1 f5 aa be  |.j.....C........|
+00000050  c8 ce 39 4c 9c 86 00 08  c2 4b e2 c6 ec 2f f7 ce  |..9L.....K.../..|
+00000060  e6 bd 77 82 6f 23 b6 e0  bd a2 92 b7 3a ac e8 56  |..w.o#......:..V|
+00000070  f1 af 54 5e 46 87 e9 3b  33 e7 b8 28 b7 d6 c8 90  |..T^F..;3..(....|
+00000080  35 d4 1c 43 d1 30 6f 55  4e 0a 70 14 03 02 00 01  |5..C.0oUN.p.....|
+00000090  01 16 03 02 00 24 07 9f  dc df 2d c3 a6 88 06 28  |.....$....-....(|
+000000a0  21 e0 e0 d3 31 99 fc 89  b8 82 6e 95 f4 4b 9e e2  |!...1.....n..K..|
+000000b0  d9 36 5c 14 ce d7 db e2  78 4e                    |.6\.....xN|
+>>> Flow 4 (server to client)
+00000000  14 03 02 00 01 01 16 03  02 00 24 81 72 75 80 d4  |..........$.ru..|
+00000010  1b 1a 32 00 89 bf 9e 79  30 b9 6b 67 e0 8e c7 eb  |..2....y0.kg....|
+00000020  73 f2 e4 93 51 65 9b 5f  91 b1 b4 b1 f7 44 76     |s...Qe._.....Dv|
+>>> Flow 5 (client to server)
+00000000  17 03 02 00 1a b2 91 39  63 c0 38 3c 4d 25 fd 14  |.......9c.8<M%..|
+00000010  b9 b6 e1 23 21 b4 8d 17  9e 1f d8 33 92 69 c2 15  |...#!......3.i..|
+00000020  03 02 00 16 4b 10 25 4d  9d 09 c2 11 96 be f7 5b  |....K.%M.......[|
+00000030  c2 9b 99 fd 1f 8e af 0f  2c 51                    |........,Q|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA b/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
new file mode 100644
index 0000000..2073270
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
@@ -0,0 +1,134 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
+00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
+00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
+00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
+00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
+00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 59 02 00 00  55 03 03 53 04 f1 03 6f  |....Y...U..S...o|
+00000010  c6 4b 55 27 fe e8 fe 4d  7c 0e d4 20 98 b8 7c 81  |.KU'...M|.. ..|.|
+00000020  3d 31 f8 35 66 2f 0a 0b  f1 2c e3 20 86 4d 12 32  |=1.5f/...,. .M.2|
+00000030  73 e3 ba be 25 50 a4 a2  a1 7b f1 9a 76 7a 75 fb  |s...%P...{..vzu.|
+00000040  e2 64 a2 12 ec f3 e7 9d  9a 24 6e 94 c0 09 00 00  |.d.......$n.....|
+00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
+00000060  03 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
+00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
+00000080  30 09 06 07 2a 86 48 ce  3d 04 01 30 45 31 0b 30  |0...*.H.=..0E1.0|
+00000090  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
+000000a0  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
+000000b0  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
+000000c0  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
+000000d0  74 64 30 1e 17 0d 31 32  31 31 32 32 31 35 30 36  |td0...1211221506|
+000000e0  33 32 5a 17 0d 32 32 31  31 32 30 31 35 30 36 33  |32Z..22112015063|
+000000f0  32 5a 30 45 31 0b 30 09  06 03 55 04 06 13 02 41  |2Z0E1.0...U....A|
+00000100  55 31 13 30 11 06 03 55  04 08 13 0a 53 6f 6d 65  |U1.0...U....Some|
+00000110  2d 53 74 61 74 65 31 21  30 1f 06 03 55 04 0a 13  |-State1!0...U...|
+00000120  18 49 6e 74 65 72 6e 65  74 20 57 69 64 67 69 74  |.Internet Widgit|
+00000130  73 20 50 74 79 20 4c 74  64 30 81 9b 30 10 06 07  |s Pty Ltd0..0...|
+00000140  2a 86 48 ce 3d 02 01 06  05 2b 81 04 00 23 03 81  |*.H.=....+...#..|
+00000150  86 00 04 00 c4 a1 ed be  98 f9 0b 48 73 36 7e c3  |...........Hs6~.|
+00000160  16 56 11 22 f2 3d 53 c3  3b 4d 21 3d cd 6b 75 e6  |.V.".=S.;M!=.ku.|
+00000170  f6 b0 dc 9a df 26 c1 bc  b2 87 f0 72 32 7c b3 64  |.....&.....r2|.d|
+00000180  2f 1c 90 bc ea 68 23 10  7e fe e3 25 c0 48 3a 69  |/....h#.~..%.H:i|
+00000190  e0 28 6d d3 37 00 ef 04  62 dd 0d a0 9c 70 62 83  |.(m.7...b....pb.|
+000001a0  d8 81 d3 64 31 aa 9e 97  31 bd 96 b0 68 c0 9b 23  |...d1...1...h..#|
+000001b0  de 76 64 3f 1a 5c 7f e9  12 0e 58 58 b6 5f 70 dd  |.vd?.\....XX._p.|
+000001c0  9b d8 ea d5 d7 f5 d5 cc  b9 b6 9f 30 66 5b 66 9a  |...........0f[f.|
+000001d0  20 e2 27 e5 bf fe 3b 30  09 06 07 2a 86 48 ce 3d  | .'...;0...*.H.=|
+000001e0  04 01 03 81 8c 00 30 81  88 02 42 01 88 a2 4f eb  |......0...B...O.|
+000001f0  e2 45 c5 48 7d 1b ac f5  ed 98 9d ae 47 70 c0 5e  |.E.H}.......Gp.^|
+00000200  1b b6 2f bd f1 b6 4d b7  61 40 d3 11 a2 ce ee 0b  |../...M.a at ......|
+00000210  7e 92 7e ff 76 9d c3 3b  7e a5 3f ce fa 10 e2 59  |~.~.v..;~.?....Y|
+00000220  ec 47 2d 7c ac da 4e 97  0e 15 a0 6f d0 02 42 01  |.G-|..N....o..B.|
+00000230  4d fc be 67 13 9c 2d 05  0e bd 3f a3 8c 25 c1 33  |M..g..-...?..%.3|
+00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
+00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
+00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
+00000270  2a 16 03 03 00 d7 0c 00  00 d3 03 00 17 41 04 a3  |*............A..|
+00000280  03 8c de d2 b0 68 c8 25  0e 85 ea d7 ae 13 0d 79  |.....h.%.......y|
+00000290  ec 59 0d b5 4d 51 96 d9  7f 64 36 fb 4c d5 6a 26  |.Y..MQ...d6.L.j&|
+000002a0  ae 0e 48 61 df 5c 2b d4  ff 09 41 15 c4 14 8e 1b  |..Ha.\+...A.....|
+000002b0  84 a8 c8 cd ef 10 97 95  66 67 85 dd fd dc 2a 04  |........fg....*.|
+000002c0  03 00 8a 30 81 87 02 41  11 75 5d bc bd 08 28 d4  |...0...A.u]...(.|
+000002d0  5b 1b 45 7f 9c d3 8d 0b  91 fa f6 82 ba 59 bd 3e  |[.E..........Y.>|
+000002e0  96 01 c6 1d 38 db fe 08  e7 56 89 fc 10 b0 37 6a  |....8....V....7j|
+000002f0  3d d6 c9 50 16 53 f7 c2  a2 60 67 82 1f 74 b8 d5  |=..P.S...`g..t..|
+00000300  bc 02 ec 96 db 82 18 8c  87 02 42 01 0d df f7 b7  |..........B.....|
+00000310  05 3c 8c 56 f0 1d 33 18  cf c5 4c 80 7e 0b d9 f9  |.<.V..3...L.~...|
+00000320  f0 51 69 fe 5d b8 0b 64  c0 c7 0d f4 75 65 ae 07  |.Qi.]..d....ue..|
+00000330  9d cf f4 4b ad 52 f6 b8  10 26 18 bd d6 e2 0d a8  |...K.R...&......|
+00000340  80 10 50 34 15 cd 72 0b  7d a9 94 de 4c 16 03 03  |..P4..r.}...L...|
+00000350  00 30 0d 00 00 28 03 01  02 40 00 20 06 01 06 02  |.0...(... at . ....|
+00000360  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
+00000370  03 02 03 03 02 01 02 02  02 03 01 01 00 00 0e 00  |................|
+00000380  00 00                                             |..|
+>>> Flow 3 (client to server)
+00000000  16 03 03 02 0a 0b 00 02  06 00 02 03 00 02 00 30  |...............0|
+00000010  82 01 fc 30 82 01 5e 02  09 00 9a 30 84 6c 26 35  |...0..^....0.l&5|
+00000020  d9 17 30 09 06 07 2a 86  48 ce 3d 04 01 30 45 31  |..0...*.H.=..0E1|
+00000030  0b 30 09 06 03 55 04 06  13 02 41 55 31 13 30 11  |.0...U....AU1.0.|
+00000040  06 03 55 04 08 13 0a 53  6f 6d 65 2d 53 74 61 74  |..U....Some-Stat|
+00000050  65 31 21 30 1f 06 03 55  04 0a 13 18 49 6e 74 65  |e1!0...U....Inte|
+00000060  72 6e 65 74 20 57 69 64  67 69 74 73 20 50 74 79  |rnet Widgits Pty|
+00000070  20 4c 74 64 30 1e 17 0d  31 32 31 31 31 34 31 33  | Ltd0...12111413|
+00000080  32 35 35 33 5a 17 0d 32  32 31 31 31 32 31 33 32  |2553Z..221112132|
+00000090  35 35 33 5a 30 41 31 0b  30 09 06 03 55 04 06 13  |553Z0A1.0...U...|
+000000a0  02 41 55 31 0c 30 0a 06  03 55 04 08 13 03 4e 53  |.AU1.0...U....NS|
+000000b0  57 31 10 30 0e 06 03 55  04 07 13 07 50 79 72 6d  |W1.0...U....Pyrm|
+000000c0  6f 6e 74 31 12 30 10 06  03 55 04 03 13 09 4a 6f  |ont1.0...U....Jo|
+000000d0  65 6c 20 53 69 6e 67 30  81 9b 30 10 06 07 2a 86  |el Sing0..0...*.|
+000000e0  48 ce 3d 02 01 06 05 2b  81 04 00 23 03 81 86 00  |H.=....+...#....|
+000000f0  04 00 95 8c 91 75 14 c0  5e c4 57 b4 d4 c3 6f 8d  |.....u..^.W...o.|
+00000100  ae 68 1e dd 6f ce 86 e1  7e 6e b2 48 3e 81 e5 4e  |.h..o...~n.H>..N|
+00000110  e2 c6 88 4b 64 dc f5 30  bb d3 ff 65 cc 5b f4 dd  |...Kd..0...e.[..|
+00000120  b5 6a 3e 3e d0 1d de 47  c3 76 ad 19 f6 45 2c 8c  |.j>>...G.v...E,.|
+00000130  bc d8 1d 01 4c 1f 70 90  46 76 48 8b 8f 83 cc 4a  |....L.p.FvH....J|
+00000140  5c 8f 40 76 da e0 89 ec  1d 2b c4 4e 30 76 28 41  |\. at v.....+.N0v(A|
+00000150  b2 62 a8 fb 5b f1 f9 4e  7a 8d bd 09 b8 ae ea 8b  |.b..[..Nz.......|
+00000160  18 27 4f 2e 70 fe 13 96  ba c3 d3 40 16 cd 65 4e  |.'O.p...... at ..eN|
+00000170  ac 11 1e e6 f1 30 09 06  07 2a 86 48 ce 3d 04 01  |.....0...*.H.=..|
+00000180  03 81 8c 00 30 81 88 02  42 00 e0 14 c4 60 60 0b  |....0...B....``.|
+00000190  72 68 b0 32 5d 61 4a 02  74 5c c2 81 b9 16 a8 3f  |rh.2]aJ.t\.....?|
+000001a0  29 c8 36 c7 81 ff 6c b6  5b d9 70 f1 38 3b 50 48  |).6...l.[.p.8;PH|
+000001b0  28 94 cb 09 1a 52 f1 5d  ee 8d f2 b9 f0 f0 da d9  |(....R.]........|
+000001c0  15 3a f9 bd 03 7a 87 a2  23 35 ec 02 42 01 a3 d4  |.:...z..#5..B...|
+000001d0  8a 78 35 1c 4a 9a 23 d2  0a be 2b 10 31 9d 9c 5f  |.x5.J.#...+.1.._|
+000001e0  be e8 91 b3 da 1a f5 5d  a3 23 f5 26 8b 45 70 8d  |.......].#.&.Ep.|
+000001f0  65 62 9b 7e 01 99 3d 18  f6 10 9a 38 61 9b 2e 57  |eb.~..=....8a..W|
+00000200  e4 fa cc b1 8a ce e2 23  a0 87 f0 e1 67 51 eb 16  |.......#....gQ..|
+00000210  03 03 00 46 10 00 00 42  41 04 1e 18 37 ef 0d 19  |...F...BA...7...|
+00000220  51 88 35 75 71 b5 e5 54  5b 12 2e 8f 09 67 fd a7  |Q.5uq..T[....g..|
+00000230  24 20 3e b2 56 1c ce 97  28 5e f8 2b 2d 4f 9e f1  |$ >.V...(^.+-O..|
+00000240  07 9f 6c 4b 5b 83 56 e2  32 42 e9 58 b6 d7 49 a6  |..lK[.V.2B.X..I.|
+00000250  b5 68 1a 41 03 56 6b dc  5a 89 16 03 03 00 92 0f  |.h.A.Vk.Z.......|
+00000260  00 00 8e 04 03 00 8a 30  81 87 02 42 00 c6 85 8e  |.......0...B....|
+00000270  06 b7 04 04 e9 cd 9e 3e  cb 66 23 95 b4 42 9c 64  |.......>.f#..B.d|
+00000280  81 39 05 3f b5 21 f8 28  af 60 6b 4d 3d ba a1 4b  |.9.?.!.(.`kM=..K|
+00000290  5e 77 ef e7 59 28 fe 1d  c1 27 a2 ff a8 de 33 48  |^w..Y(...'....3H|
+000002a0  b3 c1 85 6a 42 9b f9 7e  7e 31 c2 e5 bd 66 02 41  |...jB..~~1...f.A|
+000002b0  4b 49 c6 cd 02 e3 83 f7  03 50 18 6d b4 c9 51 02  |KI.......P.m..Q.|
+000002c0  c0 ab 87 bc e0 3e 4b 89  53 3a e2 65 89 97 02 c1  |.....>K.S:.e....|
+000002d0  88 0d 64 db 8e 4f 73 4e  ea 29 0b ed a0 f5 ce 3d  |..d..OsN.).....=|
+000002e0  5f cc 20 ef 0a 22 02 82  f2 14 2a b7 42 68 bd c7  |_. .."....*.Bh..|
+000002f0  4d 14 03 03 00 01 01 16  03 03 00 40 00 00 00 00  |M.......... at ....|
+00000300  00 00 00 00 00 00 00 00  00 00 00 00 f0 cc 4f c7  |..............O.|
+00000310  b6 0f c9 38 4d 4b 97 2c  4f be 53 08 4c d6 5b 4e  |...8MK.,O.S.L.[N|
+00000320  24 70 30 81 82 3a 7f 62  95 03 4d fc 54 78 ec 13  |$p0..:.b..M.Tx..|
+00000330  b2 a1 00 85 2b 04 e4 1d  7b 6e 87 60              |....+...{n.`|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 40 d5 2a 76 79 1c  |.......... at .*vy.|
+00000010  e7 d5 b1 5c 65 6b d1 45  73 53 4c 05 3a 6c 5d 81  |...\ek.EsSL.:l].|
+00000020  dd 2f f0 74 62 e4 8e f8  ed 21 99 c7 4f d6 28 40  |./.tb....!..O.(@|
+00000030  63 d9 6d e5 b0 04 73 27  7a 1d 08 19 31 10 da ef  |c.m...s'z...1...|
+00000040  79 26 33 fb 45 23 be a4  7c 03 66                 |y&3.E#..|.f|
+>>> Flow 5 (client to server)
+00000000  17 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
+00000010  00 00 00 00 00 e2 53 bd  c0 ef 9e e6 44 94 ea 5d  |......S.....D..]|
+00000020  f5 c5 a9 4b ed eb 1c 49  9f 79 44 f9 cd d7 de 02  |...K...I.yD.....|
+00000030  51 10 ae 87 7d 15 03 03  00 30 00 00 00 00 00 00  |Q...}....0......|
+00000040  00 00 00 00 00 00 00 00  00 00 d3 95 13 7f 5f 58  |.............._X|
+00000050  ab d6 17 ea 01 2c 2a ea  5d 7c 44 61 4a 27 97 52  |.....,*.]|DaJ'.R|
+00000060  cc 9b 86 f6 37 42 2b 94  01 49                    |....7B+..I|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA b/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
new file mode 100644
index 0000000..c3b753a
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
@@ -0,0 +1,127 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
+00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
+00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
+00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
+00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
+00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 51 02 00 00  4d 03 03 53 04 f1 03 b0  |....Q...M..S....|
+00000010  43 00 97 24 a7 a8 ea b2  24 fe 96 24 a1 49 64 fd  |C..$....$..$.Id.|
+00000020  1c a3 30 35 2d 85 a7 40  42 86 6b 20 af 27 7f ac  |..05-.. at B.k .'..|
+00000030  8b 16 89 6c 78 b7 f5 29  02 58 a6 8b 61 43 c2 b0  |...lx..).X..aC..|
+00000040  e0 a8 96 c8 fa 2b 26 ad  9a 5f 2d d6 00 05 00 00  |.....+&.._-.....|
+00000050  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
+00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000080  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000090  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+000000a0  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+000000b0  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000c0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000d0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000e0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000f0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+00000100  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+00000110  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000120  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000130  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000140  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000150  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000160  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000170  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000180  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000190  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+000001a0  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+000001b0  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001c0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001d0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001e0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001f0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+00000200  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+00000210  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000220  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000230  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000240  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000250  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000260  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000270  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000280  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000290  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+000002a0  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+000002b0  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002c0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002d0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002e0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002f0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+00000300  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 30 0d 00  |n8P)l........0..|
+00000320  00 28 03 01 02 40 00 20  06 01 06 02 06 03 05 01  |.(... at . ........|
+00000330  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
+00000340  02 01 02 02 02 03 01 01  00 00 0e 00 00 00        |..............|
+>>> Flow 3 (client to server)
+00000000  16 03 03 02 0a 0b 00 02  06 00 02 03 00 02 00 30  |...............0|
+00000010  82 01 fc 30 82 01 5e 02  09 00 9a 30 84 6c 26 35  |...0..^....0.l&5|
+00000020  d9 17 30 09 06 07 2a 86  48 ce 3d 04 01 30 45 31  |..0...*.H.=..0E1|
+00000030  0b 30 09 06 03 55 04 06  13 02 41 55 31 13 30 11  |.0...U....AU1.0.|
+00000040  06 03 55 04 08 13 0a 53  6f 6d 65 2d 53 74 61 74  |..U....Some-Stat|
+00000050  65 31 21 30 1f 06 03 55  04 0a 13 18 49 6e 74 65  |e1!0...U....Inte|
+00000060  72 6e 65 74 20 57 69 64  67 69 74 73 20 50 74 79  |rnet Widgits Pty|
+00000070  20 4c 74 64 30 1e 17 0d  31 32 31 31 31 34 31 33  | Ltd0...12111413|
+00000080  32 35 35 33 5a 17 0d 32  32 31 31 31 32 31 33 32  |2553Z..221112132|
+00000090  35 35 33 5a 30 41 31 0b  30 09 06 03 55 04 06 13  |553Z0A1.0...U...|
+000000a0  02 41 55 31 0c 30 0a 06  03 55 04 08 13 03 4e 53  |.AU1.0...U....NS|
+000000b0  57 31 10 30 0e 06 03 55  04 07 13 07 50 79 72 6d  |W1.0...U....Pyrm|
+000000c0  6f 6e 74 31 12 30 10 06  03 55 04 03 13 09 4a 6f  |ont1.0...U....Jo|
+000000d0  65 6c 20 53 69 6e 67 30  81 9b 30 10 06 07 2a 86  |el Sing0..0...*.|
+000000e0  48 ce 3d 02 01 06 05 2b  81 04 00 23 03 81 86 00  |H.=....+...#....|
+000000f0  04 00 95 8c 91 75 14 c0  5e c4 57 b4 d4 c3 6f 8d  |.....u..^.W...o.|
+00000100  ae 68 1e dd 6f ce 86 e1  7e 6e b2 48 3e 81 e5 4e  |.h..o...~n.H>..N|
+00000110  e2 c6 88 4b 64 dc f5 30  bb d3 ff 65 cc 5b f4 dd  |...Kd..0...e.[..|
+00000120  b5 6a 3e 3e d0 1d de 47  c3 76 ad 19 f6 45 2c 8c  |.j>>...G.v...E,.|
+00000130  bc d8 1d 01 4c 1f 70 90  46 76 48 8b 8f 83 cc 4a  |....L.p.FvH....J|
+00000140  5c 8f 40 76 da e0 89 ec  1d 2b c4 4e 30 76 28 41  |\. at v.....+.N0v(A|
+00000150  b2 62 a8 fb 5b f1 f9 4e  7a 8d bd 09 b8 ae ea 8b  |.b..[..Nz.......|
+00000160  18 27 4f 2e 70 fe 13 96  ba c3 d3 40 16 cd 65 4e  |.'O.p...... at ..eN|
+00000170  ac 11 1e e6 f1 30 09 06  07 2a 86 48 ce 3d 04 01  |.....0...*.H.=..|
+00000180  03 81 8c 00 30 81 88 02  42 00 e0 14 c4 60 60 0b  |....0...B....``.|
+00000190  72 68 b0 32 5d 61 4a 02  74 5c c2 81 b9 16 a8 3f  |rh.2]aJ.t\.....?|
+000001a0  29 c8 36 c7 81 ff 6c b6  5b d9 70 f1 38 3b 50 48  |).6...l.[.p.8;PH|
+000001b0  28 94 cb 09 1a 52 f1 5d  ee 8d f2 b9 f0 f0 da d9  |(....R.]........|
+000001c0  15 3a f9 bd 03 7a 87 a2  23 35 ec 02 42 01 a3 d4  |.:...z..#5..B...|
+000001d0  8a 78 35 1c 4a 9a 23 d2  0a be 2b 10 31 9d 9c 5f  |.x5.J.#...+.1.._|
+000001e0  be e8 91 b3 da 1a f5 5d  a3 23 f5 26 8b 45 70 8d  |.......].#.&.Ep.|
+000001f0  65 62 9b 7e 01 99 3d 18  f6 10 9a 38 61 9b 2e 57  |eb.~..=....8a..W|
+00000200  e4 fa cc b1 8a ce e2 23  a0 87 f0 e1 67 51 eb 16  |.......#....gQ..|
+00000210  03 03 00 86 10 00 00 82  00 80 6d 51 f3 7f f9 3e  |..........mQ...>|
+00000220  fb 75 82 41 36 83 e8 6a  ee 2a 2e 25 90 67 4c 8e  |.u.A6..j.*.%.gL.|
+00000230  62 2f 30 81 17 e0 85 09  0c 2b b7 23 d7 b0 e2 1d  |b/0......+.#....|
+00000240  f7 3b d7 f5 a1 27 b6 ee  24 b6 1b cc 5b ea 66 0d  |.;...'..$...[.f.|
+00000250  6a f4 e5 85 f9 da 43 b4  0e 86 85 e1 f5 aa be c8  |j.....C.........|
+00000260  ce 39 4c 9c 86 00 08 c2  4b e2 c6 ec 2f f7 ce e6  |.9L.....K.../...|
+00000270  bd 77 82 6f 23 b6 e0 bd  a2 92 b7 3a ac e8 56 f1  |.w.o#......:..V.|
+00000280  af 54 5e 46 87 e9 3b 33  e7 b8 28 b7 d6 c8 90 35  |.T^F..;3..(....5|
+00000290  d4 1c 43 d1 30 6f 55 4e  0a 70 16 03 03 00 92 0f  |..C.0oUN.p......|
+000002a0  00 00 8e 04 03 00 8a 30  81 87 02 42 00 c6 85 8e  |.......0...B....|
+000002b0  06 b7 04 04 e9 cd 9e 3e  cb 66 23 95 b4 42 9c 64  |.......>.f#..B.d|
+000002c0  81 39 05 3f b5 21 f8 28  af 60 6b 4d 3d ba a1 4b  |.9.?.!.(.`kM=..K|
+000002d0  5e 77 ef e7 59 28 fe 1d  c1 27 a2 ff a8 de 33 48  |^w..Y(...'....3H|
+000002e0  b3 c1 85 6a 42 9b f9 7e  7e 31 c2 e5 bd 66 02 41  |...jB..~~1...f.A|
+000002f0  4b 49 c6 cd 02 e3 83 f7  03 50 18 6d b4 c9 51 02  |KI.......P.m..Q.|
+00000300  c0 ab 87 bc e0 3e 4b 89  53 3a e2 65 89 97 02 c1  |.....>K.S:.e....|
+00000310  88 5a 97 82 3e 55 6b 7c  d8 db b8 cc 1b 30 84 0a  |.Z..>Uk|.....0..|
+00000320  7a 97 71 e4 10 bb a4 39  8c 2a cf f5 88 c7 d1 95  |z.q....9.*......|
+00000330  73 14 03 03 00 01 01 16  03 03 00 24 9f 1e f0 72  |s..........$...r|
+00000340  92 ea dc f7 56 96 37 e4  69 db db 66 1d f6 94 c4  |....V.7.i..f....|
+00000350  18 31 4f d0 5d c5 f4 53  21 aa 98 b1 dc 08 94 94  |.1O.]..S!.......|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 24 ee 68 c1 87 9f  |..........$.h...|
+00000010  d7 90 94 f1 3b 6d 26 0b  3d 89 7a 45 3b 52 5d 3c  |....;m&.=.zE;R]<|
+00000020  dd 7c c1 4e 57 3e a9 ee  91 be cf 2b a3 98 9d     |.|.NW>.....+...|
+>>> Flow 5 (client to server)
+00000000  17 03 03 00 1a 88 33 3e  2b 22 6b 92 d0 bb 8a 1e  |......3>+"k.....|
+00000010  9b f4 9e aa 91 8b 2b 95  ea 53 c8 03 0a 93 58 15  |......+..S....X.|
+00000020  03 03 00 16 c4 67 79 ba  ec cf 90 b1 f9 ac ec 64  |.....gy........d|
+00000030  72 01 08 8f 3a 98 aa 66  25 00                    |r...:..f%.|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA b/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
new file mode 100644
index 0000000..0037af6
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
@@ -0,0 +1,133 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
+00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
+00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
+00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
+00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
+00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 59 02 00 00  55 03 03 53 04 f1 02 fd  |....Y...U..S....|
+00000010  41 bd ef ee f3 da fc 1a  31 8c 77 f2 e9 66 54 a0  |A.......1.w..fT.|
+00000020  f4 15 b1 1c 84 0d 6d 74  87 ac 7d 20 78 17 8b 08  |......mt..} x...|
+00000030  10 20 c9 44 e4 8a 43 af  4a c7 b8 3d 99 f2 f7 af  |. .D..C.J..=....|
+00000040  bb a3 21 2f 40 cc ed b6  da a8 a1 d5 c0 09 00 00  |..!/@...........|
+00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
+00000060  03 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
+00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
+00000080  30 09 06 07 2a 86 48 ce  3d 04 01 30 45 31 0b 30  |0...*.H.=..0E1.0|
+00000090  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
+000000a0  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
+000000b0  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
+000000c0  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
+000000d0  74 64 30 1e 17 0d 31 32  31 31 32 32 31 35 30 36  |td0...1211221506|
+000000e0  33 32 5a 17 0d 32 32 31  31 32 30 31 35 30 36 33  |32Z..22112015063|
+000000f0  32 5a 30 45 31 0b 30 09  06 03 55 04 06 13 02 41  |2Z0E1.0...U....A|
+00000100  55 31 13 30 11 06 03 55  04 08 13 0a 53 6f 6d 65  |U1.0...U....Some|
+00000110  2d 53 74 61 74 65 31 21  30 1f 06 03 55 04 0a 13  |-State1!0...U...|
+00000120  18 49 6e 74 65 72 6e 65  74 20 57 69 64 67 69 74  |.Internet Widgit|
+00000130  73 20 50 74 79 20 4c 74  64 30 81 9b 30 10 06 07  |s Pty Ltd0..0...|
+00000140  2a 86 48 ce 3d 02 01 06  05 2b 81 04 00 23 03 81  |*.H.=....+...#..|
+00000150  86 00 04 00 c4 a1 ed be  98 f9 0b 48 73 36 7e c3  |...........Hs6~.|
+00000160  16 56 11 22 f2 3d 53 c3  3b 4d 21 3d cd 6b 75 e6  |.V.".=S.;M!=.ku.|
+00000170  f6 b0 dc 9a df 26 c1 bc  b2 87 f0 72 32 7c b3 64  |.....&.....r2|.d|
+00000180  2f 1c 90 bc ea 68 23 10  7e fe e3 25 c0 48 3a 69  |/....h#.~..%.H:i|
+00000190  e0 28 6d d3 37 00 ef 04  62 dd 0d a0 9c 70 62 83  |.(m.7...b....pb.|
+000001a0  d8 81 d3 64 31 aa 9e 97  31 bd 96 b0 68 c0 9b 23  |...d1...1...h..#|
+000001b0  de 76 64 3f 1a 5c 7f e9  12 0e 58 58 b6 5f 70 dd  |.vd?.\....XX._p.|
+000001c0  9b d8 ea d5 d7 f5 d5 cc  b9 b6 9f 30 66 5b 66 9a  |...........0f[f.|
+000001d0  20 e2 27 e5 bf fe 3b 30  09 06 07 2a 86 48 ce 3d  | .'...;0...*.H.=|
+000001e0  04 01 03 81 8c 00 30 81  88 02 42 01 88 a2 4f eb  |......0...B...O.|
+000001f0  e2 45 c5 48 7d 1b ac f5  ed 98 9d ae 47 70 c0 5e  |.E.H}.......Gp.^|
+00000200  1b b6 2f bd f1 b6 4d b7  61 40 d3 11 a2 ce ee 0b  |../...M.a at ......|
+00000210  7e 92 7e ff 76 9d c3 3b  7e a5 3f ce fa 10 e2 59  |~.~.v..;~.?....Y|
+00000220  ec 47 2d 7c ac da 4e 97  0e 15 a0 6f d0 02 42 01  |.G-|..N....o..B.|
+00000230  4d fc be 67 13 9c 2d 05  0e bd 3f a3 8c 25 c1 33  |M..g..-...?..%.3|
+00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
+00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
+00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
+00000270  2a 16 03 03 00 d8 0c 00  00 d4 03 00 17 41 04 a9  |*............A..|
+00000280  19 8b d9 9b 5c 7c 6a 7d  85 d2 70 4e 89 7e 0b 5b  |....\|j}..pN.~.[|
+00000290  dd 5e a1 63 8d 15 bc 0b  0c 47 3d 4d e8 a7 56 88  |.^.c.....G=M..V.|
+000002a0  2e f6 7f e2 4d fc ed cc  03 ed a1 2d ac ae 81 a5  |....M......-....|
+000002b0  e2 6d 7f 9f a3 93 e9 10  c1 0e 48 1b f3 f4 38 04  |.m........H...8.|
+000002c0  03 00 8b 30 81 88 02 42  00 87 fe 7e 63 82 14 57  |...0...B...~c..W|
+000002d0  dc 7d e2 0f cc 97 2d ba  3c a7 56 4a 17 a8 09 6a  |.}....-.<.VJ...j|
+000002e0  28 2e f2 66 1a 3f 2d 48  2b 6f 79 a1 60 cd 5e 10  |(..f.?-H+oy.`.^.|
+000002f0  0b 0a 28 f2 5f e4 3f 4f  f9 c9 91 34 d9 dc bc fc  |..(._.?O...4....|
+00000300  98 ea 77 0b 99 f8 a2 11  c4 bd 02 42 01 a0 b0 dc  |..w........B....|
+00000310  db 5b c2 09 99 bd ee a0  b9 aa 31 b9 10 84 22 be  |.[........1...".|
+00000320  5a 63 12 5a 43 00 8e c1  33 cc 91 bb c2 70 7a 63  |Zc.ZC...3....pzc|
+00000330  19 82 c0 74 48 a1 c7 3d  1f f1 6f 4a 6f 6a 8c 3f  |...tH..=..oJoj.?|
+00000340  28 31 a8 0c 65 19 26 62  4b 7a 7c 4b ea 1a 16 03  |(1..e.&bKz|K....|
+00000350  03 00 30 0d 00 00 28 03  01 02 40 00 20 06 01 06  |..0...(... at . ...|
+00000360  02 06 03 05 01 05 02 05  03 04 01 04 02 04 03 03  |................|
+00000370  01 03 02 03 03 02 01 02  02 02 03 01 01 00 00 0e  |................|
+00000380  00 00 00                                          |...|
+>>> Flow 3 (client to server)
+00000000  16 03 03 01 fb 0b 00 01  f7 00 01 f4 00 01 f1 30  |...............0|
+00000010  82 01 ed 30 82 01 58 a0  03 02 01 02 02 01 00 30  |...0..X........0|
+00000020  0b 06 09 2a 86 48 86 f7  0d 01 01 05 30 26 31 10  |...*.H......0&1.|
+00000030  30 0e 06 03 55 04 0a 13  07 41 63 6d 65 20 43 6f  |0...U....Acme Co|
+00000040  31 12 30 10 06 03 55 04  03 13 09 31 32 37 2e 30  |1.0...U....127.0|
+00000050  2e 30 2e 31 30 1e 17 0d  31 31 31 32 30 38 30 37  |.0.10...11120807|
+00000060  35 35 31 32 5a 17 0d 31  32 31 32 30 37 30 38 30  |5512Z..121207080|
+00000070  30 31 32 5a 30 26 31 10  30 0e 06 03 55 04 0a 13  |012Z0&1.0...U...|
+00000080  07 41 63 6d 65 20 43 6f  31 12 30 10 06 03 55 04  |.Acme Co1.0...U.|
+00000090  03 13 09 31 32 37 2e 30  2e 30 2e 31 30 81 9c 30  |...127.0.0.10..0|
+000000a0  0b 06 09 2a 86 48 86 f7  0d 01 01 01 03 81 8c 00  |...*.H..........|
+000000b0  30 81 88 02 81 80 4e d0  7b 31 e3 82 64 d9 59 c0  |0.....N.{1..d.Y.|
+000000c0  c2 87 a4 5e 1e 8b 73 33  c7 63 53 df 66 92 06 84  |...^..s3.cS.f...|
+000000d0  f6 64 d5 8f e4 36 a7 1d  2b e8 b3 20 36 45 23 b5  |.d...6..+.. 6E#.|
+000000e0  e3 95 ae ed e0 f5 20 9c  8d 95 df 7f 5a 12 ef 87  |...... .....Z...|
+000000f0  e4 5b 68 e4 e9 0e 74 ec  04 8a 7f de 93 27 c4 01  |.[h...t......'..|
+00000100  19 7a bd f2 dc 3d 14 ab  d0 54 ca 21 0c d0 4d 6e  |.z...=...T.!..Mn|
+00000110  87 2e 5c c5 d2 bb 4d 4b  4f ce b6 2c f7 7e 88 ec  |..\...MKO..,.~..|
+00000120  7c d7 02 91 74 a6 1e 0c  1a da e3 4a 5a 2e de 13  ||...t......JZ...|
+00000130  9c 4c 40 88 59 93 02 03  01 00 01 a3 32 30 30 30  |.L at .Y.......2000|
+00000140  0e 06 03 55 1d 0f 01 01  ff 04 04 03 02 00 a0 30  |...U...........0|
+00000150  0d 06 03 55 1d 0e 04 06  04 04 01 02 03 04 30 0f  |...U..........0.|
+00000160  06 03 55 1d 23 04 08 30  06 80 04 01 02 03 04 30  |..U.#..0.......0|
+00000170  0b 06 09 2a 86 48 86 f7  0d 01 01 05 03 81 81 00  |...*.H..........|
+00000180  36 1f b3 7a 0c 75 c9 6e  37 46 61 2b d5 bd c0 a7  |6..z.u.n7Fa+....|
+00000190  4b cc 46 9a 81 58 7c 85  79 29 c8 c8 c6 67 dd 32  |K.F..X|.y)...g.2|
+000001a0  56 45 2b 75 b6 e9 24 a9  50 9a be 1f 5a fa 1a 15  |VE+u..$.P...Z...|
+000001b0  d9 cc 55 95 72 16 83 b9  c2 b6 8f fd 88 8c 38 84  |..U.r.........8.|
+000001c0  1d ab 5d 92 31 13 4f fd  83 3b c6 9d f1 11 62 b6  |..].1.O..;....b.|
+000001d0  8b ec ab 67 be c8 64 b0  11 50 46 58 17 6b 99 1c  |...g..d..PFX.k..|
+000001e0  d3 1d fc 06 f1 0e e5 96  a8 0c f9 78 20 b7 44 18  |...........x .D.|
+000001f0  51 8d 10 7e 4f 94 67 df  a3 4e 70 73 8e 90 91 85  |Q..~O.g..Nps....|
+00000200  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
+00000210  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
+00000220  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
+00000230  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
+00000240  a6 b5 68 1a 41 03 56 6b  dc 5a 89 16 03 03 00 88  |..h.A.Vk.Z......|
+00000250  0f 00 00 84 04 01 00 80  38 f2 16 e5 b5 86 16 62  |........8......b|
+00000260  86 e1 7d 01 f1 a8 e1 f7  e7 85 b1 a0 17 ee 84 25  |..}............%|
+00000270  cb 3c 46 61 1a 78 7b 1e  ee 32 bc d9 6c fa 6b 76  |.<Fa.x{..2..l.kv|
+00000280  67 a7 9e c8 7a 4c e8 79  0d 22 27 ad e7 98 6a 98  |g...zL.y."'...j.|
+00000290  89 88 8b a9 69 5b 6f c6  00 48 9a 21 77 a9 7c 15  |....i[o..H.!w.|.|
+000002a0  ba 47 16 74 8d 6c 67 dc  6d f1 98 b6 61 e8 bc 08  |.G.t.lg.m...a...|
+000002b0  18 53 a6 93 bf fc 27 5e  b7 4d d2 eb 68 e9 23 ee  |.S....'^.M..h.#.|
+000002c0  d2 70 d2 55 2c c7 99 7d  c0 66 b5 1c ea 38 71 5c  |.p.U,..}.f...8q\|
+000002d0  a6 57 1f 52 e4 8e e8 51  14 03 03 00 01 01 16 03  |.W.R...Q........|
+000002e0  03 00 40 00 00 00 00 00  00 00 00 00 00 00 00 00  |.. at .............|
+000002f0  00 00 00 5e e7 6e 1c a2  02 24 34 f0 a6 b6 27 ea  |...^.n...$4...'.|
+00000300  69 d5 0e 2e a8 ad 5c ad  6c 06 78 68 39 92 27 f1  |i.....\.l.xh9.'.|
+00000310  e8 35 49 67 4d fb 5d 8a  31 2e 4e 3f 19 ed ea 30  |.5IgM.].1.N?...0|
+00000320  20 60 e1                                          | `.|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 40 ee a8 82 bc 3f  |.......... at ....?|
+00000010  bf ab a6 e4 30 e0 3d f1  2f 19 a2 ac 7a 81 57 f1  |....0.=./...z.W.|
+00000020  ee 67 3f 55 2b 30 fa 72  b5 10 03 ec 8d 0a 8f bb  |.g?U+0.r........|
+00000030  24 f5 45 f5 4e 53 4b 93  a5 0d 42 6c 46 69 98 fb  |$.E.NSK...BlFi..|
+00000040  63 c5 9f 95 65 d1 b6 f0  a4 15 bd                 |c...e......|
+>>> Flow 5 (client to server)
+00000000  17 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
+00000010  00 00 00 00 00 cb 4e bc  d1 a9 58 ef c8 39 a9 36  |......N...X..9.6|
+00000020  f4 35 05 96 8e a4 50 bc  f4 15 06 f9 fd 41 6d 1e  |.5....P......Am.|
+00000030  5e 7c 82 63 94 15 03 03  00 30 00 00 00 00 00 00  |^|.c.....0......|
+00000040  00 00 00 00 00 00 00 00  00 00 bd 77 87 a5 5a d4  |...........w..Z.|
+00000050  b8 59 e6 6b 0f dd ea f9  ed 18 b2 9f a9 61 b4 3a  |.Y.k.........a.:|
+00000060  47 15 15 3b 83 ef e1 6d  db a8                    |G..;...m..|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA b/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
new file mode 100644
index 0000000..df3eaa4
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
@@ -0,0 +1,126 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
+00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
+00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
+00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
+00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
+00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 51 02 00 00  4d 03 03 53 04 f1 02 1d  |....Q...M..S....|
+00000010  0e dc 86 e5 a9 07 71 46  15 34 af 47 15 3f 03 9c  |......qF.4.G.?..|
+00000020  fc d6 fd 44 7c f4 f1 c7  8d 6f f8 20 28 ea 3c dc  |...D|....o. (.<.|
+00000030  b2 4c b7 ba 20 88 c4 db  a5 73 ea 93 ab 3a 85 a6  |.L.. ....s...:..|
+00000040  8f 59 49 d9 a9 31 14 d5  a6 2b 4f d1 00 05 00 00  |.YI..1...+O.....|
+00000050  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
+00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000080  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000090  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+000000a0  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+000000b0  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000c0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000d0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000e0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000f0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+00000100  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+00000110  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000120  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000130  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000140  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000150  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000160  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000170  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000180  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000190  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+000001a0  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+000001b0  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001c0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001d0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001e0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001f0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+00000200  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+00000210  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000220  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000230  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000240  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000250  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000260  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000270  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000280  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000290  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+000002a0  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+000002b0  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002c0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002d0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002e0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002f0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+00000300  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 30 0d 00  |n8P)l........0..|
+00000320  00 28 03 01 02 40 00 20  06 01 06 02 06 03 05 01  |.(... at . ........|
+00000330  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
+00000340  02 01 02 02 02 03 01 01  00 00 0e 00 00 00        |..............|
+>>> Flow 3 (client to server)
+00000000  16 03 03 01 fb 0b 00 01  f7 00 01 f4 00 01 f1 30  |...............0|
+00000010  82 01 ed 30 82 01 58 a0  03 02 01 02 02 01 00 30  |...0..X........0|
+00000020  0b 06 09 2a 86 48 86 f7  0d 01 01 05 30 26 31 10  |...*.H......0&1.|
+00000030  30 0e 06 03 55 04 0a 13  07 41 63 6d 65 20 43 6f  |0...U....Acme Co|
+00000040  31 12 30 10 06 03 55 04  03 13 09 31 32 37 2e 30  |1.0...U....127.0|
+00000050  2e 30 2e 31 30 1e 17 0d  31 31 31 32 30 38 30 37  |.0.10...11120807|
+00000060  35 35 31 32 5a 17 0d 31  32 31 32 30 37 30 38 30  |5512Z..121207080|
+00000070  30 31 32 5a 30 26 31 10  30 0e 06 03 55 04 0a 13  |012Z0&1.0...U...|
+00000080  07 41 63 6d 65 20 43 6f  31 12 30 10 06 03 55 04  |.Acme Co1.0...U.|
+00000090  03 13 09 31 32 37 2e 30  2e 30 2e 31 30 81 9c 30  |...127.0.0.10..0|
+000000a0  0b 06 09 2a 86 48 86 f7  0d 01 01 01 03 81 8c 00  |...*.H..........|
+000000b0  30 81 88 02 81 80 4e d0  7b 31 e3 82 64 d9 59 c0  |0.....N.{1..d.Y.|
+000000c0  c2 87 a4 5e 1e 8b 73 33  c7 63 53 df 66 92 06 84  |...^..s3.cS.f...|
+000000d0  f6 64 d5 8f e4 36 a7 1d  2b e8 b3 20 36 45 23 b5  |.d...6..+.. 6E#.|
+000000e0  e3 95 ae ed e0 f5 20 9c  8d 95 df 7f 5a 12 ef 87  |...... .....Z...|
+000000f0  e4 5b 68 e4 e9 0e 74 ec  04 8a 7f de 93 27 c4 01  |.[h...t......'..|
+00000100  19 7a bd f2 dc 3d 14 ab  d0 54 ca 21 0c d0 4d 6e  |.z...=...T.!..Mn|
+00000110  87 2e 5c c5 d2 bb 4d 4b  4f ce b6 2c f7 7e 88 ec  |..\...MKO..,.~..|
+00000120  7c d7 02 91 74 a6 1e 0c  1a da e3 4a 5a 2e de 13  ||...t......JZ...|
+00000130  9c 4c 40 88 59 93 02 03  01 00 01 a3 32 30 30 30  |.L at .Y.......2000|
+00000140  0e 06 03 55 1d 0f 01 01  ff 04 04 03 02 00 a0 30  |...U...........0|
+00000150  0d 06 03 55 1d 0e 04 06  04 04 01 02 03 04 30 0f  |...U..........0.|
+00000160  06 03 55 1d 23 04 08 30  06 80 04 01 02 03 04 30  |..U.#..0.......0|
+00000170  0b 06 09 2a 86 48 86 f7  0d 01 01 05 03 81 81 00  |...*.H..........|
+00000180  36 1f b3 7a 0c 75 c9 6e  37 46 61 2b d5 bd c0 a7  |6..z.u.n7Fa+....|
+00000190  4b cc 46 9a 81 58 7c 85  79 29 c8 c8 c6 67 dd 32  |K.F..X|.y)...g.2|
+000001a0  56 45 2b 75 b6 e9 24 a9  50 9a be 1f 5a fa 1a 15  |VE+u..$.P...Z...|
+000001b0  d9 cc 55 95 72 16 83 b9  c2 b6 8f fd 88 8c 38 84  |..U.r.........8.|
+000001c0  1d ab 5d 92 31 13 4f fd  83 3b c6 9d f1 11 62 b6  |..].1.O..;....b.|
+000001d0  8b ec ab 67 be c8 64 b0  11 50 46 58 17 6b 99 1c  |...g..d..PFX.k..|
+000001e0  d3 1d fc 06 f1 0e e5 96  a8 0c f9 78 20 b7 44 18  |...........x .D.|
+000001f0  51 8d 10 7e 4f 94 67 df  a3 4e 70 73 8e 90 91 85  |Q..~O.g..Nps....|
+00000200  16 03 03 00 86 10 00 00  82 00 80 6d 51 f3 7f f9  |...........mQ...|
+00000210  3e fb 75 82 41 36 83 e8  6a ee 2a 2e 25 90 67 4c  |>.u.A6..j.*.%.gL|
+00000220  8e 62 2f 30 81 17 e0 85  09 0c 2b b7 23 d7 b0 e2  |.b/0......+.#...|
+00000230  1d f7 3b d7 f5 a1 27 b6  ee 24 b6 1b cc 5b ea 66  |..;...'..$...[.f|
+00000240  0d 6a f4 e5 85 f9 da 43  b4 0e 86 85 e1 f5 aa be  |.j.....C........|
+00000250  c8 ce 39 4c 9c 86 00 08  c2 4b e2 c6 ec 2f f7 ce  |..9L.....K.../..|
+00000260  e6 bd 77 82 6f 23 b6 e0  bd a2 92 b7 3a ac e8 56  |..w.o#......:..V|
+00000270  f1 af 54 5e 46 87 e9 3b  33 e7 b8 28 b7 d6 c8 90  |..T^F..;3..(....|
+00000280  35 d4 1c 43 d1 30 6f 55  4e 0a 70 16 03 03 00 88  |5..C.0oUN.p.....|
+00000290  0f 00 00 84 04 01 00 80  2a 1f ae 48 9f 86 16 dc  |........*..H....|
+000002a0  c2 55 1f 5f 95 81 ed 56  00 5d 35 46 e5 b6 57 d5  |.U._...V.]5F..W.|
+000002b0  a6 3e 32 38 8b e2 c6 1c  b9 b1 38 b2 da 66 45 ed  |.>28......8..fE.|
+000002c0  58 6a 7f 43 41 93 a5 09  da b9 04 ce 3f 13 8a 19  |Xj.CA.......?...|
+000002d0  13 e9 2c 1f c5 e7 35 b4  2d ea 7c 81 90 33 c0 66  |..,...5.-.|..3.f|
+000002e0  dc 41 8b 23 08 8f 69 d4  d6 a2 5f c1 bd 26 e6 2e  |.A.#..i..._..&..|
+000002f0  7f c8 7c a8 2d d4 08 95  ce 6e 58 54 04 a2 a6 63  |..|.-....nXT...c|
+00000300  54 72 67 f2 7f 61 0a 6b  58 46 d4 88 95 38 37 f2  |Trg..a.kXF...87.|
+00000310  93 95 48 56 14 a7 b9 7c  14 03 03 00 01 01 16 03  |..HV...|........|
+00000320  03 00 24 64 bb 41 3a cb  a2 2f 95 53 5c 2f f7 83  |..$d.A:../.S\/..|
+00000330  a2 35 18 f6 d0 8d 6f e2  54 ed 2f 07 10 f4 36 e2  |.5....o.T./...6.|
+00000340  3d e5 30 1d e3 63 01                              |=.0..c.|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 24 0a 22 b6 bc da  |..........$."...|
+00000010  34 38 53 8e 80 e2 25 7b  31 2f 70 8e 3a db e8 a3  |48S...%{1/p.:...|
+00000020  70 0e 88 22 b4 a8 be d4  a3 e3 cc 13 94 ef 47     |p.."..........G|
+>>> Flow 5 (client to server)
+00000000  17 03 03 00 1a b4 9c b1  57 ea 01 03 fe 01 e7 1e  |........W.......|
+00000010  c4 a7 0f 25 14 99 00 4f  88 51 c1 98 6e 99 01 15  |...%...O.Q..n...|
+00000020  03 03 00 16 2e c4 11 8b  1a fc 37 81 18 33 e4 9f  |..........7..3..|
+00000030  48 a3 29 e3 ad 9b 9b ec  9f 99                    |H.).......|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES b/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
new file mode 100644
index 0000000..7644590
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
@@ -0,0 +1,89 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
+00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
+00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
+00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
+00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
+00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 59 02 00 00  55 03 03 53 04 f1 02 a0  |....Y...U..S....|
+00000010  5f bd a4 8d 98 93 b8 da  08 86 9f b2 be 9a a4 91  |_...............|
+00000020  2b 3c 1f 18 f0 75 7c a9  a8 a0 f7 20 4a 89 9a d2  |+<...u|.... J...|
+00000030  34 3b d9 b1 c2 fd 61 bd  97 19 22 ce b9 d1 5b a7  |4;....a..."...[.|
+00000040  83 80 9c 19 d0 f5 a0 aa  4c ac 06 20 c0 09 00 00  |........L.. ....|
+00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
+00000060  03 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
+00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
+00000080  30 09 06 07 2a 86 48 ce  3d 04 01 30 45 31 0b 30  |0...*.H.=..0E1.0|
+00000090  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
+000000a0  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
+000000b0  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
+000000c0  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
+000000d0  74 64 30 1e 17 0d 31 32  31 31 32 32 31 35 30 36  |td0...1211221506|
+000000e0  33 32 5a 17 0d 32 32 31  31 32 30 31 35 30 36 33  |32Z..22112015063|
+000000f0  32 5a 30 45 31 0b 30 09  06 03 55 04 06 13 02 41  |2Z0E1.0...U....A|
+00000100  55 31 13 30 11 06 03 55  04 08 13 0a 53 6f 6d 65  |U1.0...U....Some|
+00000110  2d 53 74 61 74 65 31 21  30 1f 06 03 55 04 0a 13  |-State1!0...U...|
+00000120  18 49 6e 74 65 72 6e 65  74 20 57 69 64 67 69 74  |.Internet Widgit|
+00000130  73 20 50 74 79 20 4c 74  64 30 81 9b 30 10 06 07  |s Pty Ltd0..0...|
+00000140  2a 86 48 ce 3d 02 01 06  05 2b 81 04 00 23 03 81  |*.H.=....+...#..|
+00000150  86 00 04 00 c4 a1 ed be  98 f9 0b 48 73 36 7e c3  |...........Hs6~.|
+00000160  16 56 11 22 f2 3d 53 c3  3b 4d 21 3d cd 6b 75 e6  |.V.".=S.;M!=.ku.|
+00000170  f6 b0 dc 9a df 26 c1 bc  b2 87 f0 72 32 7c b3 64  |.....&.....r2|.d|
+00000180  2f 1c 90 bc ea 68 23 10  7e fe e3 25 c0 48 3a 69  |/....h#.~..%.H:i|
+00000190  e0 28 6d d3 37 00 ef 04  62 dd 0d a0 9c 70 62 83  |.(m.7...b....pb.|
+000001a0  d8 81 d3 64 31 aa 9e 97  31 bd 96 b0 68 c0 9b 23  |...d1...1...h..#|
+000001b0  de 76 64 3f 1a 5c 7f e9  12 0e 58 58 b6 5f 70 dd  |.vd?.\....XX._p.|
+000001c0  9b d8 ea d5 d7 f5 d5 cc  b9 b6 9f 30 66 5b 66 9a  |...........0f[f.|
+000001d0  20 e2 27 e5 bf fe 3b 30  09 06 07 2a 86 48 ce 3d  | .'...;0...*.H.=|
+000001e0  04 01 03 81 8c 00 30 81  88 02 42 01 88 a2 4f eb  |......0...B...O.|
+000001f0  e2 45 c5 48 7d 1b ac f5  ed 98 9d ae 47 70 c0 5e  |.E.H}.......Gp.^|
+00000200  1b b6 2f bd f1 b6 4d b7  61 40 d3 11 a2 ce ee 0b  |../...M.a at ......|
+00000210  7e 92 7e ff 76 9d c3 3b  7e a5 3f ce fa 10 e2 59  |~.~.v..;~.?....Y|
+00000220  ec 47 2d 7c ac da 4e 97  0e 15 a0 6f d0 02 42 01  |.G-|..N....o..B.|
+00000230  4d fc be 67 13 9c 2d 05  0e bd 3f a3 8c 25 c1 33  |M..g..-...?..%.3|
+00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
+00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
+00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
+00000270  2a 16 03 03 00 d7 0c 00  00 d3 03 00 17 41 04 3c  |*............A.<|
+00000280  8f 35 1e 47 5d 7b ad 13  0c e9 5c c0 97 c7 83 06  |.5.G]{....\.....|
+00000290  49 0f 6c cf e5 4d 3b ed  f7 1b c6 96 8d ba 54 35  |I.l..M;.......T5|
+000002a0  7f df 35 e3 6e 28 e9 71  f2 24 b5 ab 17 2b 4b 2b  |..5.n(.q.$...+K+|
+000002b0  0c 8f 9f 48 89 73 8f 09  69 84 af 7f ec 43 7a 04  |...H.s..i....Cz.|
+000002c0  03 00 8a 30 81 87 02 41  79 84 43 0c 78 fa 7e e2  |...0...Ay.C.x.~.|
+000002d0  c5 51 c1 60 88 c4 4a 59  7d 02 fa dc 19 68 33 ed  |.Q.`..JY}....h3.|
+000002e0  19 ef a1 df ef 6b 21 a6  98 aa ba a9 13 70 91 0f  |.....k!......p..|
+000002f0  cc 6c 5c 1e 99 53 1b 42  51 6c 06 a7 3c c4 04 22  |.l\..S.BQl..<.."|
+00000300  5d 0d c1 30 ab e3 ec b4  54 02 42 01 15 15 1a 6e  |]..0....T.B....n|
+00000310  6f f1 c6 b1 10 84 2c c8  04 de 2b 52 d5 b4 f7 c9  |o.....,...+R....|
+00000320  4f 6d 0e 0e 26 45 1d 7a  28 59 2b 8b f6 92 3a 23  |Om..&E.z(Y+...:#|
+00000330  7a 39 9c d5 4e cc 5d c5  45 92 9c d0 5f 33 12 e3  |z9..N.].E..._3..|
+00000340  2b 29 39 52 bb 16 aa e1  72 9e b5 fe 99 16 03 03  |+)9R....r.......|
+00000350  00 04 0e 00 00 00                                 |......|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
+00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
+00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
+00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
+00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
+00000050  01 16 03 03 00 40 00 00  00 00 00 00 00 00 00 00  |..... at ..........|
+00000060  00 00 00 00 00 00 20 a3  f8 5a e2 ea f3 09 19 3e  |...... ..Z.....>|
+00000070  4a 54 69 70 06 5b 17 35  0f ed e7 30 3b 6f eb a1  |JTip.[.5...0;o..|
+00000080  cb 9c 35 81 10 2e 34 f7  12 a5 e4 63 20 b2 65 31  |..5...4....c .e1|
+00000090  19 da 30 43 39 59                                 |..0C9Y|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 40 8d 4d 31 07 df  |.......... at .M1..|
+00000010  ab 41 f5 19 9c 1a 57 fc  33 ab 5f e6 bd 45 b9 fa  |.A....W.3._..E..|
+00000020  7f db c0 df 72 f2 3b ef  aa d4 5e 34 e6 3d 44 7c  |....r.;...^4.=D||
+00000030  12 05 c7 57 da 54 b1 e3  66 f0 0a ab cd 15 a5 bf  |...W.T..f.......|
+00000040  c5 c2 07 a9 d9 a7 2e 5e  29 da da                 |.......^)..|
+>>> Flow 5 (client to server)
+00000000  17 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
+00000010  00 00 00 00 00 dc 03 7b  29 2c 49 64 58 2d dc f7  |.......{),IdX-..|
+00000020  26 a1 3b ec 2d e8 30 c4  6c a3 ff e2 bc b5 a4 a6  |&.;.-.0.l.......|
+00000030  93 ce 14 bd da 15 03 03  00 30 00 00 00 00 00 00  |.........0......|
+00000040  00 00 00 00 00 00 00 00  00 00 a6 77 10 30 15 eb  |...........w.0..|
+00000050  ed cf 73 5b 74 5d 09 52  4a 5b e2 f0 e4 67 f8 7a  |..s[t].RJ[...g.z|
+00000060  5e 5e fc ba 7f 80 0a d2  f4 fb                    |^^........|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM b/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
new file mode 100644
index 0000000..fb5af17
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
@@ -0,0 +1,84 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
+00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
+00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
+00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
+00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
+00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 59 02 00 00  55 03 03 53 04 f1 02 48  |....Y...U..S...H|
+00000010  03 36 01 05 56 6f f0 54  d2 c3 d3 41 c2 e2 69 7b  |.6..Vo.T...A..i{|
+00000020  50 f8 03 ef 3f 5d 7c e6  9c cb fe 20 82 a0 81 fd  |P...?]|.... ....|
+00000030  72 4b b8 e6 29 76 3b 0f  1d 0a b7 82 9d 0b cf a0  |rK..)v;.........|
+00000040  65 b1 56 53 c9 d5 58 7b  f0 b6 2d cf c0 2b 00 00  |e.VS..X{..-..+..|
+00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
+00000060  03 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
+00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
+00000080  30 09 06 07 2a 86 48 ce  3d 04 01 30 45 31 0b 30  |0...*.H.=..0E1.0|
+00000090  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
+000000a0  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
+000000b0  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
+000000c0  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
+000000d0  74 64 30 1e 17 0d 31 32  31 31 32 32 31 35 30 36  |td0...1211221506|
+000000e0  33 32 5a 17 0d 32 32 31  31 32 30 31 35 30 36 33  |32Z..22112015063|
+000000f0  32 5a 30 45 31 0b 30 09  06 03 55 04 06 13 02 41  |2Z0E1.0...U....A|
+00000100  55 31 13 30 11 06 03 55  04 08 13 0a 53 6f 6d 65  |U1.0...U....Some|
+00000110  2d 53 74 61 74 65 31 21  30 1f 06 03 55 04 0a 13  |-State1!0...U...|
+00000120  18 49 6e 74 65 72 6e 65  74 20 57 69 64 67 69 74  |.Internet Widgit|
+00000130  73 20 50 74 79 20 4c 74  64 30 81 9b 30 10 06 07  |s Pty Ltd0..0...|
+00000140  2a 86 48 ce 3d 02 01 06  05 2b 81 04 00 23 03 81  |*.H.=....+...#..|
+00000150  86 00 04 00 c4 a1 ed be  98 f9 0b 48 73 36 7e c3  |...........Hs6~.|
+00000160  16 56 11 22 f2 3d 53 c3  3b 4d 21 3d cd 6b 75 e6  |.V.".=S.;M!=.ku.|
+00000170  f6 b0 dc 9a df 26 c1 bc  b2 87 f0 72 32 7c b3 64  |.....&.....r2|.d|
+00000180  2f 1c 90 bc ea 68 23 10  7e fe e3 25 c0 48 3a 69  |/....h#.~..%.H:i|
+00000190  e0 28 6d d3 37 00 ef 04  62 dd 0d a0 9c 70 62 83  |.(m.7...b....pb.|
+000001a0  d8 81 d3 64 31 aa 9e 97  31 bd 96 b0 68 c0 9b 23  |...d1...1...h..#|
+000001b0  de 76 64 3f 1a 5c 7f e9  12 0e 58 58 b6 5f 70 dd  |.vd?.\....XX._p.|
+000001c0  9b d8 ea d5 d7 f5 d5 cc  b9 b6 9f 30 66 5b 66 9a  |...........0f[f.|
+000001d0  20 e2 27 e5 bf fe 3b 30  09 06 07 2a 86 48 ce 3d  | .'...;0...*.H.=|
+000001e0  04 01 03 81 8c 00 30 81  88 02 42 01 88 a2 4f eb  |......0...B...O.|
+000001f0  e2 45 c5 48 7d 1b ac f5  ed 98 9d ae 47 70 c0 5e  |.E.H}.......Gp.^|
+00000200  1b b6 2f bd f1 b6 4d b7  61 40 d3 11 a2 ce ee 0b  |../...M.a at ......|
+00000210  7e 92 7e ff 76 9d c3 3b  7e a5 3f ce fa 10 e2 59  |~.~.v..;~.?....Y|
+00000220  ec 47 2d 7c ac da 4e 97  0e 15 a0 6f d0 02 42 01  |.G-|..N....o..B.|
+00000230  4d fc be 67 13 9c 2d 05  0e bd 3f a3 8c 25 c1 33  |M..g..-...?..%.3|
+00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
+00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
+00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
+00000270  2a 16 03 03 00 d7 0c 00  00 d3 03 00 17 41 04 86  |*............A..|
+00000280  36 b4 78 76 87 70 ed ae  0d 34 70 3d 16 e5 a4 db  |6.xv.p...4p=....|
+00000290  ae 28 58 4c 01 5a 56 73  a7 0d 34 59 a7 04 75 69  |.(XL.ZVs..4Y..ui|
+000002a0  f2 55 24 40 b0 33 c6 93  ff ae e0 14 f5 4b ce a8  |.U$@.3.......K..|
+000002b0  e2 e6 9a 67 1d 66 fb 8f  fd 56 59 e7 73 f2 2c 04  |...g.f...VY.s.,.|
+000002c0  03 00 8a 30 81 87 02 41  73 ab a8 3c 64 17 69 9f  |...0...As..<d.i.|
+000002d0  4d b2 9b 55 12 60 33 94  cf f3 83 40 2b 7b 1b af  |M..U.`3.... at +{..|
+000002e0  5c f4 cd 02 66 fb 83 04  35 fd ab 74 98 1a 7d f6  |\...f...5..t..}.|
+000002f0  9e 50 98 c3 98 e8 56 9c  f2 2a b0 30 9d 05 14 58  |.P....V..*.0...X|
+00000300  68 6a 88 04 49 07 78 bf  3a 02 42 01 be b2 05 9e  |hj..I.x.:.B.....|
+00000310  67 da 1e e9 5a 36 98 52  21 9f 43 75 43 ba bb 9a  |g...Z6.R!.CuC...|
+00000320  e6 e2 65 f4 e0 44 45 08  5a 1e 54 06 dd 5f 60 2e  |..e..DE.Z.T.._`.|
+00000330  7d e7 55 08 d3 7b 4e 0a  c7 da d4 27 34 d4 bd b0  |}.U..{N....'4...|
+00000340  12 2f 41 7a ed 71 32 ef  ee 12 74 66 00 16 03 03  |./Az.q2...tf....|
+00000350  00 04 0e 00 00 00                                 |......|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
+00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
+00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
+00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
+00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 87 7a  |.....(.........z|
+00000060  82 d7 46 25 1d a6 bb c2  a8 a8 4e a5 d1 f8 02 db  |..F%......N.....|
+00000070  33 33 ca 78 b6 d3 bd 77  8a 33 23 a7 95 fb        |33.x...w.3#...|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 28 ce a1 9d 01 c0  |..........(.....|
+00000010  31 e5 d5 57 16 e1 a6 b3  8b 25 58 0f fa 2a de 3e  |1..W.....%X..*.>|
+00000020  0c d9 06 11 a6 b0 d7 b0  33 ad 31 73 5b 26 b4 d2  |........3.1s[&..|
+00000030  12 56 c8                                          |.V.|
+>>> Flow 5 (client to server)
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 d5 04 4c  |...............L|
+00000010  7b 35 b4 d7 90 ae fe 00  d2 f2 4b 76 f1 36 5e 24  |{5........Kv.6^$|
+00000020  4a aa 94 15 03 03 00 1a  00 00 00 00 00 00 00 02  |J...............|
+00000030  d3 1c 41 37 ab f6 17 79  f0 01 a4 19 a5 75 7a 8e  |..A7...y.....uz.|
+00000040  a3 b2                                             |..|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES b/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
new file mode 100644
index 0000000..5336bbb
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
@@ -0,0 +1,99 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
+00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
+00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
+00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
+00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
+00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 59 02 00 00  55 03 03 53 04 f1 02 41  |....Y...U..S...A|
+00000010  95 cc 56 30 65 46 24 75  d5 9e 3c a7 5b 6c 99 fe  |..V0eF$u..<.[l..|
+00000020  86 35 23 42 3a 8f 4d 4c  b9 98 7d 20 a7 46 43 72  |.5#B:.ML..} .FCr|
+00000030  66 bb b6 ad ff ad cf 63  37 fe 6b b4 78 94 08 49  |f......c7.k.x..I|
+00000040  54 06 ed f4 85 73 38 4a  c6 fe b6 98 c0 13 00 00  |T....s8J........|
+00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
+00000060  03 02 be 0b 00 02 ba 00  02 b7 00 02 b4 30 82 02  |.............0..|
+00000070  b0 30 82 02 19 a0 03 02  01 02 02 09 00 85 b0 bb  |.0..............|
+00000080  a4 8a 7f b8 ca 30 0d 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
+00000090  01 05 05 00 30 45 31 0b  30 09 06 03 55 04 06 13  |....0E1.0...U...|
+000000a0  02 41 55 31 13 30 11 06  03 55 04 08 13 0a 53 6f  |.AU1.0...U....So|
+000000b0  6d 65 2d 53 74 61 74 65  31 21 30 1f 06 03 55 04  |me-State1!0...U.|
+000000c0  0a 13 18 49 6e 74 65 72  6e 65 74 20 57 69 64 67  |...Internet Widg|
+000000d0  69 74 73 20 50 74 79 20  4c 74 64 30 1e 17 0d 31  |its Pty Ltd0...1|
+000000e0  30 30 34 32 34 30 39 30  39 33 38 5a 17 0d 31 31  |00424090938Z..11|
+000000f0  30 34 32 34 30 39 30 39  33 38 5a 30 45 31 0b 30  |0424090938Z0E1.0|
+00000100  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
+00000110  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
+00000120  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
+00000130  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
+00000140  74 64 30 81 9f 30 0d 06  09 2a 86 48 86 f7 0d 01  |td0..0...*.H....|
+00000150  01 01 05 00 03 81 8d 00  30 81 89 02 81 81 00 bb  |........0.......|
+00000160  79 d6 f5 17 b5 e5 bf 46  10 d0 dc 69 be e6 2b 07  |y......F...i..+.|
+00000170  43 5a d0 03 2d 8a 7a 43  85 b7 14 52 e7 a5 65 4c  |CZ..-.zC...R..eL|
+00000180  2c 78 b8 23 8c b5 b4 82  e5 de 1f 95 3b 7e 62 a5  |,x.#........;~b.|
+00000190  2c a5 33 d6 fe 12 5c 7a  56 fc f5 06 bf fa 58 7b  |,.3...\zV.....X{|
+000001a0  26 3f b5 cd 04 d3 d0 c9  21 96 4a c7 f4 54 9f 5a  |&?......!.J..T.Z|
+000001b0  bf ef 42 71 00 fe 18 99  07 7f 7e 88 7d 7d f1 04  |..Bq......~.}}..|
+000001c0  39 c4 a2 2e db 51 c9 7c  e3 c0 4c 3b 32 66 01 cf  |9....Q.|..L;2f..|
+000001d0  af b1 1d b8 71 9a 1d db  db 89 6b ae da 2d 79 02  |....q.....k..-y.|
+000001e0  03 01 00 01 a3 81 a7 30  81 a4 30 1d 06 03 55 1d  |.......0..0...U.|
+000001f0  0e 04 16 04 14 b1 ad e2  85 5a cf cb 28 db 69 ce  |.........Z..(.i.|
+00000200  23 69 de d3 26 8e 18 88  39 30 75 06 03 55 1d 23  |#i..&...90u..U.#|
+00000210  04 6e 30 6c 80 14 b1 ad  e2 85 5a cf cb 28 db 69  |.n0l......Z..(.i|
+00000220  ce 23 69 de d3 26 8e 18  88 39 a1 49 a4 47 30 45  |.#i..&...9.I.G0E|
+00000230  31 0b 30 09 06 03 55 04  06 13 02 41 55 31 13 30  |1.0...U....AU1.0|
+00000240  11 06 03 55 04 08 13 0a  53 6f 6d 65 2d 53 74 61  |...U....Some-Sta|
+00000250  74 65 31 21 30 1f 06 03  55 04 0a 13 18 49 6e 74  |te1!0...U....Int|
+00000260  65 72 6e 65 74 20 57 69  64 67 69 74 73 20 50 74  |ernet Widgits Pt|
+00000270  79 20 4c 74 64 82 09 00  85 b0 bb a4 8a 7f b8 ca  |y Ltd...........|
+00000280  30 0c 06 03 55 1d 13 04  05 30 03 01 01 ff 30 0d  |0...U....0....0.|
+00000290  06 09 2a 86 48 86 f7 0d  01 01 05 05 00 03 81 81  |..*.H...........|
+000002a0  00 08 6c 45 24 c7 6b b1  59 ab 0c 52 cc f2 b0 14  |..lE$.k.Y..R....|
+000002b0  d7 87 9d 7a 64 75 b5 5a  95 66 e4 c5 2b 8e ae 12  |...zdu.Z.f..+...|
+000002c0  66 1f eb 4f 38 b3 6e 60  d3 92 fd f7 41 08 b5 25  |f..O8.n`....A..%|
+000002d0  13 b1 18 7a 24 fb 30 1d  ba ed 98 b9 17 ec e7 d7  |...z$.0.........|
+000002e0  31 59 db 95 d3 1d 78 ea  50 56 5c d5 82 5a 2d 5a  |1Y....x.PV\..Z-Z|
+000002f0  5f 33 c4 b6 d8 c9 75 90  96 8c 0f 52 98 b5 cd 98  |_3....u....R....|
+00000300  1f 89 20 5f f2 a0 1c a3  1b 96 94 dd a9 fd 57 e9  |.. _..........W.|
+00000310  70 e8 26 6d 71 99 9b 26  6e 38 50 29 6c 90 a7 bd  |p.&mq..&n8P)l...|
+00000320  d9 16 03 03 00 cd 0c 00  00 c9 03 00 17 41 04 48  |.............A.H|
+00000330  68 d8 8a 10 b4 bf eb 8d  d1 98 b0 a6 f4 47 5d 91  |h............G].|
+00000340  61 da 50 d9 85 7b 5d 90  02 2c 38 c9 af 81 d3 55  |a.P..{]..,8....U|
+00000350  07 62 b1 62 58 7f 39 94  d7 91 96 a8 1f 47 60 a5  |.b.bX.9......G`.|
+00000360  c0 04 f2 fb cb 15 75 a6  16 3f 94 53 7c ff dd 04  |......u..?.S|...|
+00000370  01 00 80 b9 82 fa 0b f8  8c 94 2c 6e 05 81 7d 80  |..........,n..}.|
+00000380  5d 9a 77 78 af c8 33 5d  89 7e 2e 3c e5 72 66 a8  |].wx..3].~.<.rf.|
+00000390  f1 5c 02 04 02 70 76 7b  45 ff 0d 29 a0 cb 0d db  |.\...pv{E..)....|
+000003a0  7a 4c c4 13 19 cd 47 b2  f1 c9 43 4f 95 d2 f1 c6  |zL....G...CO....|
+000003b0  bc ae 31 4a 9d de 80 b2  a4 b7 b6 dd 8c 03 3e 2a  |..1J..........>*|
+000003c0  46 5e d1 e7 5b c5 9e 06  58 f3 55 b2 77 09 f3 98  |F^..[...X.U.w...|
+000003d0  d5 7f 5a 74 64 7e 48 22  8f 7d a8 68 b6 1d 90 df  |..Ztd~H".}.h....|
+000003e0  2c 91 d7 c5 07 3d d1 6f  e9 c1 91 03 3c 23 5a 56  |,....=.o....<#ZV|
+000003f0  3b b2 c2 16 03 03 00 04  0e 00 00 00              |;...........|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
+00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
+00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
+00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
+00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
+00000050  01 16 03 03 00 40 00 00  00 00 00 00 00 00 00 00  |..... at ..........|
+00000060  00 00 00 00 00 00 59 e6  92 05 27 ec 09 2c b0 a5  |......Y...'..,..|
+00000070  2a fb 7e f1 03 53 16 63  68 a1 86 13 bb da 98 27  |*.~..S.ch......'|
+00000080  6d 42 08 35 6a ec 58 61  2a 4d 44 ec ae c5 b9 d2  |mB.5j.Xa*MD.....|
+00000090  76 57 1f 75 9f 8d                                 |vW.u..|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 40 6e 03 d0 e6 98  |.......... at n....|
+00000010  1f f5 39 7b 06 9f 95 f0  7a 88 35 7c 55 db c3 2f  |..9{....z.5|U../|
+00000020  00 ef 5b d3 62 87 a2 94  da 2f f6 4a 89 c9 a8 3d  |..[.b..../.J...=|
+00000030  3a 92 db 77 35 92 01 4b  f5 c5 6b 95 09 9f cd 79  |:..w5..K..k....y|
+00000040  3c af 37 5b 27 bf 93 3e  04 55 71                 |<.7['..>.Uq|
+>>> Flow 5 (client to server)
+00000000  17 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
+00000010  00 00 00 00 00 bc c9 d0  8e 80 14 de 32 18 49 e8  |............2.I.|
+00000020  20 dc 5e 6c e4 6d 14 00  df 51 71 fb 86 95 16 4c  | .^l.m...Qq....L|
+00000030  04 8e 71 e1 48 15 03 03  00 30 00 00 00 00 00 00  |..q.H....0......|
+00000040  00 00 00 00 00 00 00 00  00 00 b7 6d 30 72 61 53  |...........m0raS|
+00000050  d8 0a d4 1d ae e5 d4 22  46 c9 d5 4e 4a 86 f5 ac  |......."F..NJ...|
+00000060  72 98 c6 db 38 29 97 2c  84 0b                    |r...8).,..|
diff --git a/src/pkg/crypto/tls/testdata/Client-TLSv12-RSA-RC4 b/src/pkg/crypto/tls/testdata/Client-TLSv12-RSA-RC4
new file mode 100644
index 0000000..0377f05
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Client-TLSv12-RSA-RC4
@@ -0,0 +1,83 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1a c0 2f  |.............../|
+00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
+00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
+00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
+00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
+00000070  03 02 01 02 03 ff 01 00  01 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 51 02 00 00  4d 03 03 53 04 f1 02 9d  |....Q...M..S....|
+00000010  2e 4e d9 17 4a 35 fa 9d  94 f6 45 0a f6 6b 5d 1c  |.N..J5....E..k].|
+00000020  1e 15 19 8d 6d 94 cc 90  d9 39 94 20 8b 4b de 76  |....m....9. .K.v|
+00000030  d5 64 5d b7 19 df e7 eb  7e a0 22 c4 09 38 a0 12  |.d].....~."..8..|
+00000040  d5 59 10 c8 31 06 dc fc  e4 9d d1 80 00 05 00 00  |.Y..1...........|
+00000050  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
+00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000080  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000090  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+000000a0  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+000000b0  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000c0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000d0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000e0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000f0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+00000100  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+00000110  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000120  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000130  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000140  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000150  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000160  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000170  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000180  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000190  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+000001a0  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+000001b0  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001c0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001d0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001e0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001f0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+00000200  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+00000210  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000220  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000230  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000240  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000250  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000260  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000270  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000280  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000290  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+000002a0  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+000002b0  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002c0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002d0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002e0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002f0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+00000300  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 04 0e 00  |n8P)l...........|
+00000320  00 00                                             |..|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 86 10 00 00  82 00 80 6d 51 f3 7f f9  |...........mQ...|
+00000010  3e fb 75 82 41 36 83 e8  6a ee 2a 2e 25 90 67 4c  |>.u.A6..j.*.%.gL|
+00000020  8e 62 2f 30 81 17 e0 85  09 0c 2b b7 23 d7 b0 e2  |.b/0......+.#...|
+00000030  1d f7 3b d7 f5 a1 27 b6  ee 24 b6 1b cc 5b ea 66  |..;...'..$...[.f|
+00000040  0d 6a f4 e5 85 f9 da 43  b4 0e 86 85 e1 f5 aa be  |.j.....C........|
+00000050  c8 ce 39 4c 9c 86 00 08  c2 4b e2 c6 ec 2f f7 ce  |..9L.....K.../..|
+00000060  e6 bd 77 82 6f 23 b6 e0  bd a2 92 b7 3a ac e8 56  |..w.o#......:..V|
+00000070  f1 af 54 5e 46 87 e9 3b  33 e7 b8 28 b7 d6 c8 90  |..T^F..;3..(....|
+00000080  35 d4 1c 43 d1 30 6f 55  4e 0a 70 14 03 03 00 01  |5..C.0oUN.p.....|
+00000090  01 16 03 03 00 24 37 14  b2 97 7b b5 f0 9a 38 05  |.....$7...{...8.|
+000000a0  22 35 69 9c 95 2f 86 4b  37 98 22 db 4e 9a 46 9c  |"5i../.K7.".N.F.|
+000000b0  b9 81 74 72 58 18 53 0c  5c 3c                    |..trX.S.\<|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 24 3c b3 e7 77 5a  |..........$<..wZ|
+00000010  7c 36 5a 74 74 26 8d 5b  5a 09 96 60 e8 24 45 2f  ||6Ztt&.[Z..`.$E/|
+00000020  c2 39 14 5e db 58 12 49  ad a8 b6 ea ef 58 16     |.9.^.X.I.....X.|
+>>> Flow 5 (client to server)
+00000000  17 03 03 00 1a 6d 29 d7  ba 2f 85 02 b6 f0 82 64  |.....m)../.....d|
+00000010  6c 55 ae ab f6 fd 14 ff  b8 38 f0 f8 a6 ea cc 15  |lU.......8......|
+00000020  03 03 00 16 10 c5 d9 41  7b e2 89 67 dc 29 8e f8  |.......A{..g.)..|
+00000030  b5 ab 32 91 44 2c 27 84  49 f7                    |..2.D,'.I.|
diff --git a/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-3DES b/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-3DES
new file mode 100644
index 0000000..a6c7a41
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-3DES
@@ -0,0 +1,83 @@
+>>> Flow 1 (client to server)
+00000000  16 03 00 00 2f 01 00 00  2b 03 00 52 cc 57 59 d8  |..../...+..R.WY.|
+00000010  86 d6 07 ae e0 8d 63 b7  1e cb aa c6 67 32 c8 dd  |......c.....g2..|
+00000020  68 03 d8 3d 37 18 72 c3  c0 f1 9d 00 00 04 00 0a  |h..=7.r.........|
+00000030  00 ff 01 00                                       |....|
+>>> Flow 2 (server to client)
+00000000  16 03 00 00 31 02 00 00  2d 03 00 00 00 00 00 00  |....1...-.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 0a 00 00  |................|
+00000030  05 ff 01 00 01 00 16 03  00 02 be 0b 00 02 ba 00  |................|
+00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 00 00 04 0e 00  |n8P)l...........|
+00000300  00 00                                             |..|
+>>> Flow 3 (client to server)
+00000000  16 03 00 00 84 10 00 00  80 75 e0 c9 76 d6 e9 34  |.........u..v..4|
+00000010  1d e3 31 9e db 3b 03 41  93 e8 db 73 7c e9 3f 6a  |..1..;.A...s|.?j|
+00000020  d8 2a 7b 25 83 4f 45 de  3f 78 3f b6 53 a7 b4 6c  |.*{%.OE.?x?.S..l|
+00000030  e3 87 c4 c3 70 55 71 79  55 dc 74 98 84 21 19 13  |....pUqyU.t..!..|
+00000040  be d5 8e 0a ff 2f 9f 7a  6b d4 6c ef 78 d1 cb 65  |...../.zk.l.x..e|
+00000050  32 4c 0c c5 29 b9 60 94  c6 79 56 a2 aa 2d d9 ad  |2L..).`..yV..-..|
+00000060  51 2c 54 1b 28 23 33 54  cd 48 cb 80 13 45 3d 4a  |Q,T.(#3T.H...E=J|
+00000070  8e 2f f2 da bd 68 3e 1b  eb 73 f9 2d 35 6b b1 40  |./...h>..s.-5k.@|
+00000080  2e 6d 9d 1c e9 c1 02 80  37 14 03 00 00 01 01 16  |.m......7.......|
+00000090  03 00 00 40 f7 c3 dd a4  64 3d 81 24 de a2 81 7d  |... at ....d=.$...}|
+000000a0  e4 df 78 46 e7 ba 93 6c  36 43 05 96 fc 75 ef ec  |..xF...l6C...u..|
+000000b0  a5 46 6d 47 a5 be 74 ad  15 93 d9 87 4f 1d e2 b3  |.FmG..t.....O...|
+000000c0  03 ff 2e 89 6e 50 f4 d6  a6 e2 b3 54 cb 74 07 f7  |....nP.....T.t..|
+000000d0  ca 1b 8c 0a                                       |....|
+>>> Flow 4 (server to client)
+00000000  14 03 00 00 01 01 16 03  00 00 40 6d 3d d8 d5 cf  |.......... at m=...|
+00000010  05 7d 98 8c 28 28 e2 43  ab ad 4a fa ae bf ec c3  |.}..((.C..J.....|
+00000020  9c 0a 13 4d 28 a4 45 c4  b9 f2 bc c5 12 a2 68 91  |...M(.E.......h.|
+00000030  77 fa 72 f8 9e 4e b7 1f  b4 02 02 e3 5d 57 b0 8b  |w.r..N......]W..|
+00000040  d8 90 0c 9d e6 df 5b 90  92 a1 0d 17 03 00 00 18  |......[.........|
+00000050  91 48 8a e1 d6 bf 79 1c  d5 0a 70 d5 94 20 25 78  |.H....y...p.. %x|
+00000060  d8 84 c8 6e 54 f0 99 01  17 03 00 00 28 74 19 90  |...nT.......(t..|
+00000070  41 44 53 27 bb fb 1f fd  71 34 20 61 a0 eb a4 7c  |ADS'....q4 a...||
+00000080  fe 36 f8 4b d7 b0 27 d3  b9 36 e1 67 af 2d 0e 23  |.6.K..'..6.g.-.#|
+00000090  2b 76 a7 2f c3 15 03 00  00 18 db fc e9 fd 87 5f  |+v./..........._|
+000000a0  92 a8 3d 4b 35 f5 c6 48  2c b4 42 50 c3 81 28 f0  |..=K5..H,.BP..(.|
+000000b0  2b 41                                             |+A|
diff --git a/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-AES b/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-AES
new file mode 100644
index 0000000..4885b26
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-AES
@@ -0,0 +1,84 @@
+>>> Flow 1 (client to server)
+00000000  16 03 00 00 2f 01 00 00  2b 03 00 52 cc 57 59 30  |..../...+..R.WY0|
+00000010  e1 ee 8c 60 5b 40 dd 95  bd b4 84 87 2f 01 15 e7  |...`[@....../...|
+00000020  50 88 4c 82 6b 6d 93 8a  57 d0 27 00 00 04 00 2f  |P.L.km..W.'..../|
+00000030  00 ff 01 00                                       |....|
+>>> Flow 2 (server to client)
+00000000  16 03 00 00 31 02 00 00  2d 03 00 00 00 00 00 00  |....1...-.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 2f 00 00  |............./..|
+00000030  05 ff 01 00 01 00 16 03  00 02 be 0b 00 02 ba 00  |................|
+00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 00 00 04 0e 00  |n8P)l...........|
+00000300  00 00                                             |..|
+>>> Flow 3 (client to server)
+00000000  16 03 00 00 84 10 00 00  80 74 50 05 6f f5 83 c9  |.........tP.o...|
+00000010  f5 0c 5a 65 c7 4e c6 f3  87 96 d7 5d 3e 88 27 32  |..Ze.N.....]>.'2|
+00000020  89 12 ba ec db ef c0 85  70 84 ed b6 83 03 8f 44  |........p......D|
+00000030  f5 6f fa fa d0 1f 95 30  d1 ae a7 71 cf ee e9 b1  |.o.....0...q....|
+00000040  80 7b 34 a9 ea 1b 5e e5  71 40 3f e8 7d 30 d1 8b  |.{4...^.q@?.}0..|
+00000050  11 f1 68 1f c8 25 f0 77  c5 af b3 92 6e d9 81 cc  |..h..%.w....n...|
+00000060  f8 fd 82 95 cc 1f 4a b1  05 15 7a b3 a1 22 33 09  |......J...z.."3.|
+00000070  e7 a5 c2 89 7f 03 e0 91  b6 61 a3 a0 4e 17 0d 7a  |.........a..N..z|
+00000080  13 01 c4 b6 50 c7 d9 81  15 14 03 00 00 01 01 16  |....P...........|
+00000090  03 00 00 40 56 da 56 ab  e6 26 98 58 53 1f 36 b5  |... at V.V..&.XS.6.|
+000000a0  03 14 bd 42 29 ee 9c 7c  e4 48 26 82 68 ae fd fe  |...B)..|.H&.h...|
+000000b0  5e a4 43 22 75 95 7b c8  77 88 fd d6 d4 9b c9 b5  |^.C"u.{.w.......|
+000000c0  ee 3e a6 e8 c5 04 90 63  3f ac be 56 67 da 30 d4  |.>.....c?..Vg.0.|
+000000d0  64 fb a8 a0                                       |d...|
+>>> Flow 4 (server to client)
+00000000  14 03 00 00 01 01 16 03  00 00 40 96 af fb 79 96  |.......... at ...y.|
+00000010  92 97 2d d0 67 46 1e 08  b5 35 65 ef dc bc 8e 57  |..-.gF...5e....W|
+00000020  53 b7 36 58 74 d7 88 b1  55 fc eb fa 2e f3 17 b7  |S.6Xt...U.......|
+00000030  62 58 a0 9d 99 e1 85 d4  33 e0 b4 1f 1d 94 f2 88  |bX......3.......|
+00000040  d5 9a 34 5b 74 cd d2 ff  87 bd 52 17 03 00 00 20  |..4[t.....R.... |
+00000050  c6 61 c2 28 ac d2 0c 08  7f f1 c2 62 af 37 7e 78  |.a.(.......b.7~x|
+00000060  e8 e2 a1 54 f2 3a 80 97  f8 47 64 f2 cd 94 dd 0b  |...T.:...Gd.....|
+00000070  17 03 00 00 30 b8 40 8f  a3 18 ff 03 84 d4 1c 28  |....0. at ........(|
+00000080  82 ce d8 9a 81 3a dd 23  7c 65 d8 ca f7 f1 46 1b  |.....:.#|e....F.|
+00000090  70 f0 d7 d9 54 a7 71 e6  4d d4 25 61 5a e4 30 d3  |p...T.q.M.%aZ.0.|
+000000a0  4a 42 ae 26 a5 15 03 00  00 20 c4 e8 ed 40 57 00  |JB.&..... ... at W.|
+000000b0  dc a5 0e 82 90 47 92 08  dd 7e 50 6b 30 66 5e 90  |.....G...~Pk0f^.|
+000000c0  73 7c 81 93 8d 24 b1 06  e7 39                    |s|...$...9|
diff --git a/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-RC4 b/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-RC4
new file mode 100644
index 0000000..1314b65
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-SSLv3-RSA-RC4
@@ -0,0 +1,79 @@
+>>> Flow 1 (client to server)
+00000000  16 03 00 00 2f 01 00 00  2b 03 00 52 cc 57 59 79  |..../...+..R.WYy|
+00000010  b9 3b ef df 53 fb 09 f6  01 e5 18 0a fc 3d 65 bb  |.;..S........=e.|
+00000020  cf 9c 4c 77 b1 e8 6b 4f  5f c7 94 00 00 04 00 05  |..Lw..kO_.......|
+00000030  00 ff 01 00                                       |....|
+>>> Flow 2 (server to client)
+00000000  16 03 00 00 31 02 00 00  2d 03 00 00 00 00 00 00  |....1...-.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 05 00 00  |................|
+00000030  05 ff 01 00 01 00 16 03  00 02 be 0b 00 02 ba 00  |................|
+00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 00 00 04 0e 00  |n8P)l...........|
+00000300  00 00                                             |..|
+>>> Flow 3 (client to server)
+00000000  16 03 00 00 84 10 00 00  80 4d 66 7a f3 f8 ab 86  |.........Mfz....|
+00000010  43 4c 5f 7c 52 ca e7 3f  ba 62 b3 82 88 16 7d ca  |CL_|R..?.b....}.|
+00000020  3a 66 15 c0 36 55 2c ab  bf 30 6b cd 9c d8 b9 48  |:f..6U,..0k....H|
+00000030  03 c9 d0 98 ab 0b a6 5b  39 c8 fe 82 8e bb f0 16  |.......[9.......|
+00000040  6f 96 62 81 f2 dc 52 02  c9 de e4 47 73 21 6e 1e  |o.b...R....Gs!n.|
+00000050  3a 11 89 7a e2 6b 9e 04  64 72 15 ba 2d 10 a2 69  |:..z.k..dr..-..i|
+00000060  07 e6 ba 17 cf 54 d6 4e  5f 99 e8 59 8b 54 ce 8e  |.....T.N_..Y.T..|
+00000070  6b 58 ba 83 68 46 4a 5f  43 3e 9b e1 32 a2 19 42  |kX..hFJ_C>..2..B|
+00000080  46 0f e4 47 1a 3b 16 5f  e1 14 03 00 00 01 01 16  |F..G.;._........|
+00000090  03 00 00 3c 78 7e ee da  0d 38 0b 1a d6 d4 8e d5  |...<x~...8......|
+000000a0  6a c5 3a 0f 85 e7 37 a6  3c 8d 1e 4b da 02 94 bf  |j.:...7.<..K....|
+000000b0  ae 2c 50 3b 4e 1c 0c 3c  4f cc d5 1c da 33 13 43  |.,P;N..<O....3.C|
+000000c0  37 64 44 ac 26 43 28 0b  d0 c2 04 09 b5 0f 23 1d  |7dD.&C(.......#.|
+>>> Flow 4 (server to client)
+00000000  14 03 00 00 01 01 16 03  00 00 3c 23 29 64 62 23  |..........<#)db#|
+00000010  19 20 f8 2e 15 07 ee c8  f4 ab f0 3e 66 c3 ed 7b  |. .........>f..{|
+00000020  7c a7 c2 7e c3 25 3c 8f  f3 04 dc 37 e8 fc 0a 1d  ||..~.%<....7....|
+00000030  fa 7a 09 d4 21 11 e3 24  21 4b 37 d1 85 cc 40 bf  |.z..!..$!K7... at .|
+00000040  bd bd f8 59 6b cd 73 17  03 00 00 21 47 1d ac 54  |...Yk.s....!G..T|
+00000050  bd 58 a6 c0 04 e2 0c 6b  66 64 5a 85 09 0e 47 fc  |.X.....kfdZ...G.|
+00000060  0b 57 ee f1 24 b6 89 57  46 be 6b 0d f2 15 03 00  |.W..$..WF.k.....|
+00000070  00 16 b4 f7 34 99 19 43  b6 b3 5a 8b c3 d2 67 2f  |....4..C..Z...g/|
+00000080  3b 19 1c 31 d4 f9 bd 96                           |;..1....|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES b/src/pkg/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
new file mode 100644
index 0000000..9b8cb4d
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
@@ -0,0 +1,84 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 76 01 00 00  72 03 01 53 04 f0 f9 4b  |....v...r..S...K|
+00000010  30 a8 68 d0 79 13 14 69  ee 3b 5d 05 cb 71 63 43  |0.h.y..i.;]..qcC|
+00000020  4a 55 6b 05 25 53 19 ba  e0 2f b1 00 00 04 c0 0a  |JUk.%S.../......|
+00000030  00 ff 01 00 00 45 00 0b  00 04 03 00 01 02 00 0a  |.....E..........|
+00000040  00 34 00 32 00 0e 00 0d  00 19 00 0b 00 0c 00 18  |.4.2............|
+00000050  00 09 00 0a 00 16 00 17  00 08 00 06 00 07 00 14  |................|
+00000060  00 15 00 04 00 05 00 12  00 13 00 01 00 02 00 03  |................|
+00000070  00 0f 00 10 00 11 00 0f  00 01 01                 |...........|
+>>> Flow 2 (server to client)
+00000000  16 03 01 00 31 02 00 00  2d 03 01 00 00 00 00 00  |....1...-.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 c0 0a 00 00  |................|
+00000030  05 ff 01 00 01 00 16 03  01 02 0e 0b 00 02 0a 00  |................|
+00000040  02 07 00 02 04 30 82 02  00 30 82 01 62 02 09 00  |.....0...0..b...|
+00000050  b8 bf 2d 47 a0 d2 eb f4  30 09 06 07 2a 86 48 ce  |..-G....0...*.H.|
+00000060  3d 04 01 30 45 31 0b 30  09 06 03 55 04 06 13 02  |=..0E1.0...U....|
+00000070  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+00000080  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000090  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+000000a0  74 73 20 50 74 79 20 4c  74 64 30 1e 17 0d 31 32  |ts Pty Ltd0...12|
+000000b0  31 31 32 32 31 35 30 36  33 32 5a 17 0d 32 32 31  |1122150632Z..221|
+000000c0  31 32 30 31 35 30 36 33  32 5a 30 45 31 0b 30 09  |120150632Z0E1.0.|
+000000d0  06 03 55 04 06 13 02 41  55 31 13 30 11 06 03 55  |..U....AU1.0...U|
+000000e0  04 08 13 0a 53 6f 6d 65  2d 53 74 61 74 65 31 21  |....Some-State1!|
+000000f0  30 1f 06 03 55 04 0a 13  18 49 6e 74 65 72 6e 65  |0...U....Interne|
+00000100  74 20 57 69 64 67 69 74  73 20 50 74 79 20 4c 74  |t Widgits Pty Lt|
+00000110  64 30 81 9b 30 10 06 07  2a 86 48 ce 3d 02 01 06  |d0..0...*.H.=...|
+00000120  05 2b 81 04 00 23 03 81  86 00 04 00 c4 a1 ed be  |.+...#..........|
+00000130  98 f9 0b 48 73 36 7e c3  16 56 11 22 f2 3d 53 c3  |...Hs6~..V.".=S.|
+00000140  3b 4d 21 3d cd 6b 75 e6  f6 b0 dc 9a df 26 c1 bc  |;M!=.ku......&..|
+00000150  b2 87 f0 72 32 7c b3 64  2f 1c 90 bc ea 68 23 10  |...r2|.d/....h#.|
+00000160  7e fe e3 25 c0 48 3a 69  e0 28 6d d3 37 00 ef 04  |~..%.H:i.(m.7...|
+00000170  62 dd 0d a0 9c 70 62 83  d8 81 d3 64 31 aa 9e 97  |b....pb....d1...|
+00000180  31 bd 96 b0 68 c0 9b 23  de 76 64 3f 1a 5c 7f e9  |1...h..#.vd?.\..|
+00000190  12 0e 58 58 b6 5f 70 dd  9b d8 ea d5 d7 f5 d5 cc  |..XX._p.........|
+000001a0  b9 b6 9f 30 66 5b 66 9a  20 e2 27 e5 bf fe 3b 30  |...0f[f. .'...;0|
+000001b0  09 06 07 2a 86 48 ce 3d  04 01 03 81 8c 00 30 81  |...*.H.=......0.|
+000001c0  88 02 42 01 88 a2 4f eb  e2 45 c5 48 7d 1b ac f5  |..B...O..E.H}...|
+000001d0  ed 98 9d ae 47 70 c0 5e  1b b6 2f bd f1 b6 4d b7  |....Gp.^../...M.|
+000001e0  61 40 d3 11 a2 ce ee 0b  7e 92 7e ff 76 9d c3 3b  |a at ......~.~.v..;|
+000001f0  7e a5 3f ce fa 10 e2 59  ec 47 2d 7c ac da 4e 97  |~.?....Y.G-|..N.|
+00000200  0e 15 a0 6f d0 02 42 01  4d fc be 67 13 9c 2d 05  |...o..B.M..g..-.|
+00000210  0e bd 3f a3 8c 25 c1 33  13 83 0d 94 06 bb d4 37  |..?..%.3.......7|
+00000220  7a f6 ec 7a c9 86 2e dd  d7 11 69 7f 85 7c 56 de  |z..z......i..|V.|
+00000230  fb 31 78 2b e4 c7 78 0d  ae cb be 9e 4e 36 24 31  |.1x+..x.....N6$1|
+00000240  7b 6a 0f 39 95 12 07 8f  2a 16 03 01 00 d6 0c 00  |{j.9....*.......|
+00000250  00 d2 03 00 17 41 04 1e  18 37 ef 0d 19 51 88 35  |.....A...7...Q.5|
+00000260  75 71 b5 e5 54 5b 12 2e  8f 09 67 fd a7 24 20 3e  |uq..T[....g..$ >|
+00000270  b2 56 1c ce 97 28 5e f8  2b 2d 4f 9e f1 07 9f 6c  |.V...(^.+-O....l|
+00000280  4b 5b 83 56 e2 32 42 e9  58 b6 d7 49 a6 b5 68 1a  |K[.V.2B.X..I..h.|
+00000290  41 03 56 6b dc 5a 89 00  8b 30 81 88 02 42 00 c6  |A.Vk.Z...0...B..|
+000002a0  85 8e 06 b7 04 04 e9 cd  9e 3e cb 66 23 95 b4 42  |.........>.f#..B|
+000002b0  9c 64 81 39 05 3f b5 21  f8 28 af 60 6b 4d 3d ba  |.d.9.?.!.(.`kM=.|
+000002c0  a1 4b 5e 77 ef e7 59 28  fe 1d c1 27 a2 ff a8 de  |.K^w..Y(...'....|
+000002d0  33 48 b3 c1 85 6a 42 9b  f9 7e 7e 31 c2 e5 bd 66  |3H...jB..~~1...f|
+000002e0  02 42 00 ad 7d 06 35 ab  ec 8d ac d4 ba 1b 49 5e  |.B..}.5.......I^|
+000002f0  05 5f f0 97 93 82 b8 2b  8d 91 98 63 8e b4 14 62  |._.....+...c...b|
+00000300  db 1e c9 2b 30 f8 41 9b  a6 e6 bc de 0e 68 30 21  |...+0.A......h0!|
+00000310  d8 ef 2f 05 42 da f2 e0  2c 06 33 1d 0d 9a 1a 75  |../.B...,.3....u|
+00000320  59 a7 3a bc 16 03 01 00  04 0e 00 00 00           |Y.:..........|
+>>> Flow 3 (client to server)
+00000000  16 03 01 00 46 10 00 00  42 41 04 08 28 cf bd 3c  |....F...BA..(..<|
+00000010  3c cc 98 9e 73 3f 92 a7  cb 22 83 3b c7 61 46 0e  |<...s?...".;.aF.|
+00000020  4d 7c 30 b5 06 85 2f 01  be b5 40 e2 64 1e 45 c1  |M|0.../... at .d.E.|
+00000030  9d 73 95 d5 65 92 0b 9b  e7 6f c6 91 ab b6 fa be  |.s..e....o......|
+00000040  61 83 a7 f2 eb f5 65 31  fe 24 7b 14 03 01 00 01  |a.....e1.${.....|
+00000050  01 16 03 01 00 30 15 d1  c4 ca 0b 01 84 13 5a ba  |.....0........Z.|
+00000060  89 04 87 73 7c bb d8 89  7e 10 27 ba 6f 5d dc d3  |...s|...~.'.o]..|
+00000070  b5 ef 32 86 58 cc fb eb  5c 32 9e 95 ef 01 1c ac  |..2.X...\2......|
+00000080  dc 8e df 7f fe 0a                                 |......|
+>>> Flow 4 (server to client)
+00000000  14 03 01 00 01 01 16 03  01 00 30 e8 48 86 81 3c  |..........0.H..<|
+00000010  f5 25 5c 94 a9 06 c4 5c  71 62 b1 43 76 ec 2c 44  |.%\....\qb.Cv.,D|
+00000020  95 b5 8c 95 d2 ff 82 92  b6 fc 52 75 03 c6 a1 f0  |..........Ru....|
+00000030  99 6d b1 ed ec 68 6c d7  9f 18 50 17 03 01 00 20  |.m...hl...P.... |
+00000040  32 d9 26 8a 81 b8 9d a5  7b fd d5 4e 7a db 2e 29  |2.&.....{..Nz..)|
+00000050  58 9a 4f 6a 27 18 bc dc  c2 49 b8 65 cb 8e 16 5a  |X.Oj'....I.e...Z|
+00000060  17 03 01 00 30 c4 56 0a  ad 9a 82 cb 3e 32 f1 7c  |....0.V.....>2.||
+00000070  95 6e dd cd e9 4d f0 e5  2d c9 a3 f7 de bb d7 fd  |.n...M..-.......|
+00000080  84 bb df 34 8c 64 1f 03  58 64 19 4a 5b 7a a8 81  |...4.d..Xd.J[z..|
+00000090  52 bb 51 0a 43 15 03 01  00 20 89 18 7a 40 ec 49  |R.Q.C.... ..z at .I|
+000000a0  52 d5 d3 20 ac 07 eb e9  4a 78 23 cf e7 21 32 74  |R.. ....Jx#..!2t|
+000000b0  ec 40 8d a8 f4 33 1c ae  93 cf                    |. at ...3....|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-3DES b/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-3DES
new file mode 100644
index 0000000..c0e6241
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-3DES
@@ -0,0 +1,79 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 36 01 00 00  32 03 01 52 cc 57 59 13  |....6...2..R.WY.|
+00000010  8b e6 5b a3 1d cb 94 ef  48 e4 59 7e 20 6d 07 67  |..[.....H.Y~ m.g|
+00000020  1e 28 6d 31 a2 e7 96 b3  7d 32 cc 00 00 04 00 0a  |.(m1....}2......|
+00000030  00 ff 01 00 00 05 00 0f  00 01 01                 |...........|
+>>> Flow 2 (server to client)
+00000000  16 03 01 00 31 02 00 00  2d 03 01 00 00 00 00 00  |....1...-.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 0a 00 00  |................|
+00000030  05 ff 01 00 01 00 16 03  01 02 be 0b 00 02 ba 00  |................|
+00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 01 00 04 0e 00  |n8P)l...........|
+00000300  00 00                                             |..|
+>>> Flow 3 (client to server)
+00000000  16 03 01 00 86 10 00 00  82 00 80 2e af d2 61 f6  |..............a.|
+00000010  e2 b8 24 da 28 17 55 99  fd 11 bd 7a ab 98 dd f2  |..$.(.U....z....|
+00000020  f6 5f e0 11 6b 12 61 6f  86 48 b2 6e db f0 dd d5  |._..k.ao.H.n....|
+00000030  07 88 e5 95 f4 2d 6b 0c  d0 09 1a 5e 5f 50 1f dc  |.....-k....^_P..|
+00000040  f2 e7 02 7d 5e a0 70 29  80 ef 87 aa cc 95 3f 2e  |...}^.p)......?.|
+00000050  24 d1 40 b6 62 53 1d 25  31 87 1e 2f 77 d3 e1 1c  |$. at .bS.%1../w...|
+00000060  c4 99 89 bc 99 09 e9 ad  1f ce 09 e6 36 1c 3e 97  |............6.>.|
+00000070  be 62 69 a0 4e 14 20 9c  82 2a 3e fc 7e 9b c4 7a  |.bi.N. ..*>.~..z|
+00000080  5a f7 ad 1a 03 17 2a f8  7a 5f 44 14 03 01 00 01  |Z.....*.z_D.....|
+00000090  01 16 03 01 00 28 49 6b  da 73 07 ad 85 9a 0e fb  |.....(Ik.s......|
+000000a0  dd e0 69 ef c9 22 2d 86  91 51 26 63 d0 24 7d 16  |..i.."-..Q&c.$}.|
+000000b0  3c db 9b 00 c9 7e 64 e2  69 02 85 7d f7 47        |<....~d.i..}.G|
+>>> Flow 4 (server to client)
+00000000  14 03 01 00 01 01 16 03  01 00 28 dc 60 83 43 6c  |..........(.`.Cl|
+00000010  37 79 ab 6e 92 1f 66 d0  b1 12 ce c1 64 9d 2b 68  |7y.n..f.....d.+h|
+00000020  c7 1a e5 1f 8c 80 08 d2  86 3e a1 2c e3 7e f4 64  |.........>.,.~.d|
+00000030  e7 96 b2 17 03 01 00 18  8d b5 7c 03 78 cf dc 09  |..........|.x...|
+00000040  95 06 4b a6 82 f9 30 d2  6b 26 cb 0a 9a 9d 47 9f  |..K...0.k&....G.|
+00000050  17 03 01 00 28 30 a9 55  dd b9 4d 6a 76 00 39 96  |....(0.U..Mjv.9.|
+00000060  a3 94 6a df e5 af 1e a2  eb bb e4 ac 95 2c f7 93  |..j..........,..|
+00000070  ef d1 b5 13 d8 e2 06 1a  ad 5c 00 dd 0c 15 03 01  |.........\......|
+00000080  00 18 a5 62 e4 8b 51 1d  28 46 bc 8a c8 50 a3 32  |...b..Q.(F...P.2|
+00000090  6b 7b f1 b6 19 43 63 1f  7d 38                    |k{...Cc.}8|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-AES b/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-AES
new file mode 100644
index 0000000..1670997
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-AES
@@ -0,0 +1,82 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 36 01 00 00  32 03 01 52 cc 57 59 5d  |....6...2..R.WY]|
+00000010  0d 77 24 3e b3 32 3d ba  0f b0 aa 1d e3 13 06 f6  |.w$>.2=.........|
+00000020  0f be 3c 92 ba 93 bd a6  6d 69 53 00 00 04 00 2f  |..<.....miS..../|
+00000030  00 ff 01 00 00 05 00 0f  00 01 01                 |...........|
+>>> Flow 2 (server to client)
+00000000  16 03 01 00 31 02 00 00  2d 03 01 00 00 00 00 00  |....1...-.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 2f 00 00  |............./..|
+00000030  05 ff 01 00 01 00 16 03  01 02 be 0b 00 02 ba 00  |................|
+00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 01 00 04 0e 00  |n8P)l...........|
+00000300  00 00                                             |..|
+>>> Flow 3 (client to server)
+00000000  16 03 01 00 86 10 00 00  82 00 80 20 e6 80 f7 48  |........... ...H|
+00000010  7e 7d 08 08 54 e1 b4 e3  98 27 5f 90 9d 3b e3 c2  |~}..T....'_..;..|
+00000020  c8 8b dc 9e ff 75 fa fc  60 e1 9e 67 7c c4 08 27  |.....u..`..g|..'|
+00000030  cc 6f 15 6c bc 7c 96 de  83 8f 98 6d 4a c7 b7 20  |.o.l.|.....mJ.. |
+00000040  8c 19 47 5a ff 76 92 0a  df df 66 d2 b6 9d 2d 06  |..GZ.v....f...-.|
+00000050  fb ac 07 cf 38 08 f1 fd  0d fe 07 d7 69 3e 8a 79  |....8.......i>.y|
+00000060  dc 2d ab bb f7 18 3c 51  14 6e c6 70 95 a2 59 b1  |.-....<Q.n.p..Y.|
+00000070  39 04 9f ae f3 5f fb a7  2b d3 5a c0 96 d9 4d 2a  |9...._..+.Z...M*|
+00000080  2a 6c 6d 39 ee fc ce 76  1a 92 1b 14 03 01 00 01  |*lm9...v........|
+00000090  01 16 03 01 00 30 10 20  90 7b 0e e6 c2 05 81 c3  |.....0. .{......|
+000000a0  bc da 84 67 dd 5f 97 e2  74 c4 35 4e bf d2 1b 90  |...g._..t.5N....|
+000000b0  2f e0 af dd 6b f5 52 db  36 cd 3e e1 e6 bd 99 30  |/...k.R.6.>....0|
+000000c0  ed c6 bc c2 38 b6                                 |....8.|
+>>> Flow 4 (server to client)
+00000000  14 03 01 00 01 01 16 03  01 00 30 5d 0c a2 18 13  |..........0]....|
+00000010  40 a1 84 ce c5 d8 4e fc  a4 8a 14 b5 94 18 b1 86  |@.....N.........|
+00000020  da 6a 7d 26 08 d6 a0 f8  78 5b 42 7e f8 83 54 56  |.j}&....x[B~..TV|
+00000030  36 a4 91 37 67 5a d7 68  37 c4 4f 17 03 01 00 20  |6..7gZ.h7.O.... |
+00000040  fd aa 5e cf 4b 12 c5 be  a4 a2 65 5d 6e 65 46 5f  |..^.K.....e]neF_|
+00000050  d2 fe 46 e7 77 2d 9c 1e  0b 39 40 48 c2 2f be 21  |..F.w-...9 at H./.!|
+00000060  17 03 01 00 30 03 af 9e  6b d6 76 ed 9e 1d 8b 8b  |....0...k.v.....|
+00000070  2e 2a 5d da c4 73 95 ac  0e 6f 69 cb 63 df 50 27  |.*]..s...oi.c.P'|
+00000080  30 de 2e 55 86 85 ad 3e  33 22 49 72 f2 e2 9f 8f  |0..U...>3"Ir....|
+00000090  ba cf 4e 30 34 15 03 01  00 20 4c 4c 97 61 70 ea  |..N04.... LL.ap.|
+000000a0  ae fc a2 e9 c6 c2 b6 2e  4d 85 f6 ae 2b 56 46 82  |........M...+VF.|
+000000b0  9d d8 a5 82 17 fa 3e 62  67 7e                    |......>bg~|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-RC4 b/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-RC4
new file mode 100644
index 0000000..d653561
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv10-RSA-RC4
@@ -0,0 +1,76 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 36 01 00 00  32 03 01 52 cc 57 59 cf  |....6...2..R.WY.|
+00000010  00 a1 49 a4 37 69 74 d8  a7 93 ea 8d e7 50 b7 b3  |..I.7it......P..|
+00000020  8c ec e5 56 fb dc 5f 1a  2e ab 18 00 00 04 00 05  |...V.._.........|
+00000030  00 ff 01 00 00 05 00 0f  00 01 01                 |...........|
+>>> Flow 2 (server to client)
+00000000  16 03 01 00 31 02 00 00  2d 03 01 00 00 00 00 00  |....1...-.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 05 00 00  |................|
+00000030  05 ff 01 00 01 00 16 03  01 02 be 0b 00 02 ba 00  |................|
+00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 01 00 04 0e 00  |n8P)l...........|
+00000300  00 00                                             |..|
+>>> Flow 3 (client to server)
+00000000  16 03 01 00 86 10 00 00  82 00 80 b1 96 7b 6f f5  |.............{o.|
+00000010  a0 cb 0d 60 9b 64 d3 f5  17 76 47 7b bc a5 0e 96  |...`.d...vG{....|
+00000020  53 af 68 0c 96 22 f7 28  0c 24 37 9c 51 69 ed b2  |S.h..".(.$7.Qi..|
+00000030  47 14 ba 33 c5 79 6b 96  f2 ab 3c 02 5c 37 a4 97  |G..3.yk...<.\7..|
+00000040  23 fc 7f d3 95 2d 85 99  1a 10 1b 38 e5 f1 83 55  |#....-.....8...U|
+00000050  4a ab 60 f8 89 0a 6a c4  eb 45 f5 b0 f4 f8 09 31  |J.`...j..E.....1|
+00000060  6e f0 25 30 fd 5e 68 61  bc cb 0d 9e 05 73 0a f4  |n.%0.^ha.....s..|
+00000070  a5 2e d9 d5 4e 08 f6 3b  8d 2d 21 f5 79 b6 97 55  |....N..;.-!.y..U|
+00000080  b9 99 03 49 ea 96 36 49  21 56 bf 14 03 01 00 01  |...I..6I!V......|
+00000090  01 16 03 01 00 24 f0 4f  30 06 c3 25 01 93 34 ab  |.....$.O0..%..4.|
+000000a0  93 8f 59 26 83 6e 8a fd  5a a6 cf af ad b1 a2 83  |..Y&.n..Z.......|
+000000b0  28 ff c2 66 5f ac e5 a5  a5 03                    |(..f_.....|
+>>> Flow 4 (server to client)
+00000000  14 03 01 00 01 01 16 03  01 00 24 9d b4 ea d8 be  |..........$.....|
+00000010  b5 9f 00 fd b5 99 04 12  6b 7a 3f b8 52 d7 52 a9  |........kz?.R.R.|
+00000020  e9 bd 5b 63 ad b0 53 ac  46 80 be 48 6e dd ee 17  |..[c..S.F..Hn...|
+00000030  03 01 00 21 07 ac c4 fb  21 e4 b8 6b 64 3b b5 27  |...!....!..kd;.'|
+00000040  29 67 a1 10 2e d2 71 d5  59 5e fc 1d 84 31 15 6e  |)g....q.Y^...1.n|
+00000050  4d 4b dc a9 3a 15 03 01  00 16 25 22 a5 78 23 5a  |MK..:.....%".x#Z|
+00000060  69 6f 99 a1 b3 1c 8d bf  f3 bd 1b c8 1c 57 15 75  |io...........W.u|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv11-RSA-RC4 b/src/pkg/crypto/tls/testdata/Server-TLSv11-RSA-RC4
new file mode 100644
index 0000000..9237db0
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv11-RSA-RC4
@@ -0,0 +1,76 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 36 01 00 00  32 03 02 52 cc 57 59 bd  |....6...2..R.WY.|
+00000010  cd 9d 1e 17 38 43 a5 e3  e7 30 e4 2b 2a ef f7 5b  |....8C...0.+*..[|
+00000020  81 91 0c 0b 52 f8 2d 2c  61 d3 13 00 00 04 00 05  |....R.-,a.......|
+00000030  00 ff 01 00 00 05 00 0f  00 01 01                 |...........|
+>>> Flow 2 (server to client)
+00000000  16 03 02 00 31 02 00 00  2d 03 02 00 00 00 00 00  |....1...-.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 05 00 00  |................|
+00000030  05 ff 01 00 01 00 16 03  02 02 be 0b 00 02 ba 00  |................|
+00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 02 00 04 0e 00  |n8P)l...........|
+00000300  00 00                                             |..|
+>>> Flow 3 (client to server)
+00000000  16 03 02 00 86 10 00 00  82 00 80 71 2b 19 25 86  |...........q+.%.|
+00000010  a0 ff ba d5 1c a6 0c 8b  6b 0a b8 e9 42 93 2f 55  |........k...B./U|
+00000020  a8 ee 62 fa ed bc 6d e2  9d e3 76 a6 73 d7 99 58  |..b...m...v.s..X|
+00000030  cc 0b 14 42 96 7c b6 c7  8f 21 16 cf 71 9b 2b b9  |...B.|...!..q.+.|
+00000040  e0 34 57 76 22 d5 87 8a  ce 1f ea 26 6e 1e e6 ca  |.4Wv"......&n...|
+00000050  55 3b 20 cd cf 42 26 b1  51 3e 8c 1d a2 ae c4 63  |U; ..B&.Q>.....c|
+00000060  f5 ce 27 3c 1e c3 e0 e3  b1 16 c1 8a 62 bd 21 7f  |..'<........b.!.|
+00000070  38 b5 b7 3a 3c bb 03 37  e1 a5 ff f1 29 e2 21 0a  |8..:<..7....).!.|
+00000080  8c 20 02 e0 c0 82 97 9d  18 6d f8 14 03 02 00 01  |. .......m......|
+00000090  01 16 03 02 00 24 bc 19  16 6e fd 0b db 9e d5 1d  |.....$...n......|
+000000a0  65 b6 57 1c 58 b5 6a ac  f7 4f f0 cd a1 a9 0c c0  |e.W.X.j..O......|
+000000b0  df e6 eb d5 00 f7 fd 43  bb 27                    |.......C.'|
+>>> Flow 4 (server to client)
+00000000  14 03 02 00 01 01 16 03  02 00 24 cf 4f e4 27 b0  |..........$.O.'.|
+00000010  3d 17 34 b1 3c 37 6e c5  2b 3d 4a c3 46 50 44 b4  |=.4.<7n.+=J.FPD.|
+00000020  de 77 18 10 4f 60 b3 4e  dc 06 fd 25 ec 05 15 17  |.w..O`.N...%....|
+00000030  03 02 00 21 a5 c9 32 f2  21 fb 94 7e 0d 15 65 fd  |...!..2.!..~..e.|
+00000040  3e fe e4 c1 a5 e9 88 72  b2 f1 26 39 a6 48 59 97  |>......r..&9.HY.|
+00000050  65 e3 f0 cb 46 15 03 02  00 16 4b 02 ec cd ca 30  |e...F.....K....0|
+00000060  42 cf 3d a0 4a fa 8e 79  bb ed b0 59 40 9b 2c 1a  |B.=.J..y...Y at .,.|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA b/src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
new file mode 100644
index 0000000..0ab8b8d
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
@@ -0,0 +1,91 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 ca 01 00 00  c6 03 03 53 04 f1 3f 5f  |...........S..?_|
+00000010  f4 ef 1f b3 41 0b 54 e4  4d 56 0a 31 22 b8 5c 73  |....A.T.MV.1".\s|
+00000020  a3 cb b5 b2 9d 43 f1 83  bc d3 bd 00 00 32 c0 30  |.....C.......2.0|
+00000030  c0 2c c0 28 c0 24 c0 14  c0 0a c0 22 c0 21 00 a3  |.,.(.$.....".!..|
+00000040  00 9f 00 6b 00 6a 00 39  00 38 00 88 00 87 c0 32  |...k.j.9.8.....2|
+00000050  c0 2e c0 2a c0 26 c0 0f  c0 05 00 9d 00 3d 00 35  |...*.&.......=.5|
+00000060  01 00 00 6b 00 0b 00 04  03 00 01 02 00 0a 00 34  |...k...........4|
+00000070  00 32 00 0e 00 0d 00 19  00 0b 00 0c 00 18 00 09  |.2..............|
+00000080  00 0a 00 16 00 17 00 08  00 06 00 07 00 14 00 15  |................|
+00000090  00 04 00 05 00 12 00 13  00 01 00 02 00 03 00 0f  |................|
+000000a0  00 10 00 11 00 0d 00 22  00 20 06 01 06 02 06 03  |.......". ......|
+000000b0  05 01 05 02 05 03 04 01  04 02 04 03 03 01 03 02  |................|
+000000c0  03 03 02 01 02 02 02 03  01 01 00 0f 00 01 01     |...............|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 2a 02 00 00  26 03 03 00 00 00 00 00  |....*...&.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 c0 0a 00 16  |................|
+00000030  03 03 02 0e 0b 00 02 0a  00 02 07 00 02 04 30 82  |..............0.|
+00000040  02 00 30 82 01 62 02 09  00 b8 bf 2d 47 a0 d2 eb  |..0..b.....-G...|
+00000050  f4 30 09 06 07 2a 86 48  ce 3d 04 01 30 45 31 0b  |.0...*.H.=..0E1.|
+00000060  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+00000070  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+00000080  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+00000090  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000a0  4c 74 64 30 1e 17 0d 31  32 31 31 32 32 31 35 30  |Ltd0...121122150|
+000000b0  36 33 32 5a 17 0d 32 32  31 31 32 30 31 35 30 36  |632Z..2211201506|
+000000c0  33 32 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |32Z0E1.0...U....|
+000000d0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+000000e0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+000000f0  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000100  74 73 20 50 74 79 20 4c  74 64 30 81 9b 30 10 06  |ts Pty Ltd0..0..|
+00000110  07 2a 86 48 ce 3d 02 01  06 05 2b 81 04 00 23 03  |.*.H.=....+...#.|
+00000120  81 86 00 04 00 c4 a1 ed  be 98 f9 0b 48 73 36 7e  |............Hs6~|
+00000130  c3 16 56 11 22 f2 3d 53  c3 3b 4d 21 3d cd 6b 75  |..V.".=S.;M!=.ku|
+00000140  e6 f6 b0 dc 9a df 26 c1  bc b2 87 f0 72 32 7c b3  |......&.....r2|.|
+00000150  64 2f 1c 90 bc ea 68 23  10 7e fe e3 25 c0 48 3a  |d/....h#.~..%.H:|
+00000160  69 e0 28 6d d3 37 00 ef  04 62 dd 0d a0 9c 70 62  |i.(m.7...b....pb|
+00000170  83 d8 81 d3 64 31 aa 9e  97 31 bd 96 b0 68 c0 9b  |....d1...1...h..|
+00000180  23 de 76 64 3f 1a 5c 7f  e9 12 0e 58 58 b6 5f 70  |#.vd?.\....XX._p|
+00000190  dd 9b d8 ea d5 d7 f5 d5  cc b9 b6 9f 30 66 5b 66  |............0f[f|
+000001a0  9a 20 e2 27 e5 bf fe 3b  30 09 06 07 2a 86 48 ce  |. .'...;0...*.H.|
+000001b0  3d 04 01 03 81 8c 00 30  81 88 02 42 01 88 a2 4f  |=......0...B...O|
+000001c0  eb e2 45 c5 48 7d 1b ac  f5 ed 98 9d ae 47 70 c0  |..E.H}.......Gp.|
+000001d0  5e 1b b6 2f bd f1 b6 4d  b7 61 40 d3 11 a2 ce ee  |^../...M.a at .....|
+000001e0  0b 7e 92 7e ff 76 9d c3  3b 7e a5 3f ce fa 10 e2  |.~.~.v..;~.?....|
+000001f0  59 ec 47 2d 7c ac da 4e  97 0e 15 a0 6f d0 02 42  |Y.G-|..N....o..B|
+00000200  01 4d fc be 67 13 9c 2d  05 0e bd 3f a3 8c 25 c1  |.M..g..-...?..%.|
+00000210  33 13 83 0d 94 06 bb d4  37 7a f6 ec 7a c9 86 2e  |3.......7z..z...|
+00000220  dd d7 11 69 7f 85 7c 56  de fb 31 78 2b e4 c7 78  |...i..|V..1x+..x|
+00000230  0d ae cb be 9e 4e 36 24  31 7b 6a 0f 39 95 12 07  |.....N6$1{j.9...|
+00000240  8f 2a 16 03 03 00 d8 0c  00 00 d4 03 00 17 41 04  |.*............A.|
+00000250  1e 18 37 ef 0d 19 51 88  35 75 71 b5 e5 54 5b 12  |..7...Q.5uq..T[.|
+00000260  2e 8f 09 67 fd a7 24 20  3e b2 56 1c ce 97 28 5e  |...g..$ >.V...(^|
+00000270  f8 2b 2d 4f 9e f1 07 9f  6c 4b 5b 83 56 e2 32 42  |.+-O....lK[.V.2B|
+00000280  e9 58 b6 d7 49 a6 b5 68  1a 41 03 56 6b dc 5a 89  |.X..I..h.A.Vk.Z.|
+00000290  04 03 00 8b 30 81 88 02  42 00 c6 85 8e 06 b7 04  |....0...B.......|
+000002a0  04 e9 cd 9e 3e cb 66 23  95 b4 42 9c 64 81 39 05  |....>.f#..B.d.9.|
+000002b0  3f b5 21 f8 28 af 60 6b  4d 3d ba a1 4b 5e 77 ef  |?.!.(.`kM=..K^w.|
+000002c0  e7 59 28 fe 1d c1 27 a2  ff a8 de 33 48 b3 c1 85  |.Y(...'....3H...|
+000002d0  6a 42 9b f9 7e 7e 31 c2  e5 bd 66 02 42 00 ad 7d  |jB..~~1...f.B..}|
+000002e0  06 35 ab ec 8d ac d4 ba  1b 49 5e 05 5f f0 97 93  |.5.......I^._...|
+000002f0  82 b8 2b 8d 91 98 63 8e  b4 14 62 db 1e c9 2b 64  |..+...c...b...+d|
+00000300  e9 e6 bf 15 5b 67 c2 40  90 c6 1f b7 92 db 4b f6  |....[g. at ......K.|
+00000310  f4 db ae 82 f1 4f 02 75  52 40 38 10 ff 35 f0 16  |.....O.uR at 8..5..|
+00000320  03 03 00 04 0e 00 00 00                           |........|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 46 10 00 00  42 41 04 d8 94 c4 05 26  |....F...BA.....&|
+00000010  76 29 2d 0e ec 47 b6 50  d5 a3 da 2a ba 02 11 37  |v)-..G.P...*...7|
+00000020  3d ef e6 2a db d0 47 47  a7 9a 5f 43 2d 98 78 26  |=..*..GG.._C-.x&|
+00000030  81 e2 f1 ba fe f7 66 c6  61 cb c1 b7 60 62 34 a5  |......f.a...`b4.|
+00000040  78 67 50 3d 9a 0e 4a 8c  8f d7 10 14 03 03 00 01  |xgP=..J.........|
+00000050  01 16 03 03 00 40 5e 46  b0 5d 30 f6 da 8f 9e 67  |.....@^F.]0....g|
+00000060  f5 3e bd fe c9 b8 53 b2  10 d5 7c 0e 34 e3 93 6d  |.>....S...|.4..m|
+00000070  0e 8e 8a 2b df fb 9a 0f  a5 23 55 e7 0a 4b e2 d3  |...+.....#U..K..|
+00000080  db 15 e8 52 74 26 78 b3  b0 56 65 63 ac ae 1e c0  |...Rt&x..Vec....|
+00000090  0b f4 92 56 a9 04                                 |...V..|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 40 00 00 00 00 00  |.......... at .....|
+00000010  00 00 00 00 00 00 00 00  00 00 00 16 a9 63 0a 99  |.............c..|
+00000020  21 8a fc 5c b3 ee 05 71  4e 75 c0 d9 40 54 0d 3e  |!..\...qNu.. at T.>|
+00000030  4e 5d 44 b7 4b 5d a9 e7  5a 30 ed b6 d5 08 50 b1  |N]D.K]..Z0....P.|
+00000040  e8 8c 54 eb 1b 39 7a f9  3b ac 2e 17 03 03 00 40  |..T..9z.;......@|
+00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000060  96 03 20 2b 20 c4 c1 9a  76 7b f3 96 bd 33 ed e6  |.. + ...v{...3..|
+00000070  38 48 ea 53 d5 e0 62 b5  7e 1a 36 a8 dd 9f 2d 4b  |8H.S..b.~.6...-K|
+00000080  06 0d ae f6 bc 99 14 b3  93 14 27 63 e2 a0 c8 76  |..........'c...v|
+00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
+000000a0  00 00 00 00 00 48 af e1  e4 11 e1 b7 03 19 b0 e3  |.....H..........|
+000000b0  e6 a9 66 d8 ac af aa 03  f6 0d 51 df 9a 27 78 3a  |..f.......Q..'x:|
+000000c0  56 5a 03 1a 4c                                    |VZ..L|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA b/src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
new file mode 100644
index 0000000..88abb15
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
@@ -0,0 +1,101 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 ca 01 00 00  c6 03 03 53 04 f1 3f cc  |...........S..?.|
+00000010  41 74 00 07 cb ae 3b 30  79 48 51 60 41 a3 8c ab  |At....;0yHQ`A...|
+00000020  dc 76 f9 74 52 1e c5 fb  a9 69 c2 00 00 32 c0 30  |.v.tR....i...2.0|
+00000030  c0 2c c0 28 c0 24 c0 14  c0 0a c0 22 c0 21 00 a3  |.,.(.$.....".!..|
+00000040  00 9f 00 6b 00 6a 00 39  00 38 00 88 00 87 c0 32  |...k.j.9.8.....2|
+00000050  c0 2e c0 2a c0 26 c0 0f  c0 05 00 9d 00 3d 00 35  |...*.&.......=.5|
+00000060  01 00 00 6b 00 0b 00 04  03 00 01 02 00 0a 00 34  |...k...........4|
+00000070  00 32 00 0e 00 0d 00 19  00 0b 00 0c 00 18 00 09  |.2..............|
+00000080  00 0a 00 16 00 17 00 08  00 06 00 07 00 14 00 15  |................|
+00000090  00 04 00 05 00 12 00 13  00 01 00 02 00 03 00 0f  |................|
+000000a0  00 10 00 11 00 0d 00 22  00 20 06 01 06 02 06 03  |.......". ......|
+000000b0  05 01 05 02 05 03 04 01  04 02 04 03 03 01 03 02  |................|
+000000c0  03 03 02 01 02 02 02 03  01 01 00 0f 00 01 01     |...............|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 2a 02 00 00  26 03 03 00 00 00 00 00  |....*...&.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 c0 14 00 16  |................|
+00000030  03 03 02 be 0b 00 02 ba  00 02 b7 00 02 b4 30 82  |..............0.|
+00000040  02 b0 30 82 02 19 a0 03  02 01 02 02 09 00 85 b0  |..0.............|
+00000050  bb a4 8a 7f b8 ca 30 0d  06 09 2a 86 48 86 f7 0d  |......0...*.H...|
+00000060  01 01 05 05 00 30 45 31  0b 30 09 06 03 55 04 06  |.....0E1.0...U..|
+00000070  13 02 41 55 31 13 30 11  06 03 55 04 08 13 0a 53  |..AU1.0...U....S|
+00000080  6f 6d 65 2d 53 74 61 74  65 31 21 30 1f 06 03 55  |ome-State1!0...U|
+00000090  04 0a 13 18 49 6e 74 65  72 6e 65 74 20 57 69 64  |....Internet Wid|
+000000a0  67 69 74 73 20 50 74 79  20 4c 74 64 30 1e 17 0d  |gits Pty Ltd0...|
+000000b0  31 30 30 34 32 34 30 39  30 39 33 38 5a 17 0d 31  |100424090938Z..1|
+000000c0  31 30 34 32 34 30 39 30  39 33 38 5a 30 45 31 0b  |10424090938Z0E1.|
+000000d0  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+000000e0  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+000000f0  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+00000100  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+00000110  4c 74 64 30 81 9f 30 0d  06 09 2a 86 48 86 f7 0d  |Ltd0..0...*.H...|
+00000120  01 01 01 05 00 03 81 8d  00 30 81 89 02 81 81 00  |.........0......|
+00000130  bb 79 d6 f5 17 b5 e5 bf  46 10 d0 dc 69 be e6 2b  |.y......F...i..+|
+00000140  07 43 5a d0 03 2d 8a 7a  43 85 b7 14 52 e7 a5 65  |.CZ..-.zC...R..e|
+00000150  4c 2c 78 b8 23 8c b5 b4  82 e5 de 1f 95 3b 7e 62  |L,x.#........;~b|
+00000160  a5 2c a5 33 d6 fe 12 5c  7a 56 fc f5 06 bf fa 58  |.,.3...\zV.....X|
+00000170  7b 26 3f b5 cd 04 d3 d0  c9 21 96 4a c7 f4 54 9f  |{&?......!.J..T.|
+00000180  5a bf ef 42 71 00 fe 18  99 07 7f 7e 88 7d 7d f1  |Z..Bq......~.}}.|
+00000190  04 39 c4 a2 2e db 51 c9  7c e3 c0 4c 3b 32 66 01  |.9....Q.|..L;2f.|
+000001a0  cf af b1 1d b8 71 9a 1d  db db 89 6b ae da 2d 79  |.....q.....k..-y|
+000001b0  02 03 01 00 01 a3 81 a7  30 81 a4 30 1d 06 03 55  |........0..0...U|
+000001c0  1d 0e 04 16 04 14 b1 ad  e2 85 5a cf cb 28 db 69  |..........Z..(.i|
+000001d0  ce 23 69 de d3 26 8e 18  88 39 30 75 06 03 55 1d  |.#i..&...90u..U.|
+000001e0  23 04 6e 30 6c 80 14 b1  ad e2 85 5a cf cb 28 db  |#.n0l......Z..(.|
+000001f0  69 ce 23 69 de d3 26 8e  18 88 39 a1 49 a4 47 30  |i.#i..&...9.I.G0|
+00000200  45 31 0b 30 09 06 03 55  04 06 13 02 41 55 31 13  |E1.0...U....AU1.|
+00000210  30 11 06 03 55 04 08 13  0a 53 6f 6d 65 2d 53 74  |0...U....Some-St|
+00000220  61 74 65 31 21 30 1f 06  03 55 04 0a 13 18 49 6e  |ate1!0...U....In|
+00000230  74 65 72 6e 65 74 20 57  69 64 67 69 74 73 20 50  |ternet Widgits P|
+00000240  74 79 20 4c 74 64 82 09  00 85 b0 bb a4 8a 7f b8  |ty Ltd..........|
+00000250  ca 30 0c 06 03 55 1d 13  04 05 30 03 01 01 ff 30  |.0...U....0....0|
+00000260  0d 06 09 2a 86 48 86 f7  0d 01 01 05 05 00 03 81  |...*.H..........|
+00000270  81 00 08 6c 45 24 c7 6b  b1 59 ab 0c 52 cc f2 b0  |...lE$.k.Y..R...|
+00000280  14 d7 87 9d 7a 64 75 b5  5a 95 66 e4 c5 2b 8e ae  |....zdu.Z.f..+..|
+00000290  12 66 1f eb 4f 38 b3 6e  60 d3 92 fd f7 41 08 b5  |.f..O8.n`....A..|
+000002a0  25 13 b1 18 7a 24 fb 30  1d ba ed 98 b9 17 ec e7  |%...z$.0........|
+000002b0  d7 31 59 db 95 d3 1d 78  ea 50 56 5c d5 82 5a 2d  |.1Y....x.PV\..Z-|
+000002c0  5a 5f 33 c4 b6 d8 c9 75  90 96 8c 0f 52 98 b5 cd  |Z_3....u....R...|
+000002d0  98 1f 89 20 5f f2 a0 1c  a3 1b 96 94 dd a9 fd 57  |... _..........W|
+000002e0  e9 70 e8 26 6d 71 99 9b  26 6e 38 50 29 6c 90 a7  |.p.&mq..&n8P)l..|
+000002f0  bd d9 16 03 03 00 cd 0c  00 00 c9 03 00 17 41 04  |..............A.|
+00000300  1e 18 37 ef 0d 19 51 88  35 75 71 b5 e5 54 5b 12  |..7...Q.5uq..T[.|
+00000310  2e 8f 09 67 fd a7 24 20  3e b2 56 1c ce 97 28 5e  |...g..$ >.V...(^|
+00000320  f8 2b 2d 4f 9e f1 07 9f  6c 4b 5b 83 56 e2 32 42  |.+-O....lK[.V.2B|
+00000330  e9 58 b6 d7 49 a6 b5 68  1a 41 03 56 6b dc 5a 89  |.X..I..h.A.Vk.Z.|
+00000340  04 01 00 80 9d 84 09 35  73 fb f6 ea 94 7b 49 fb  |.......5s....{I.|
+00000350  c2 70 b1 11 64 5b 93 9f  d9 8c f5 56 98 f6 d3 66  |.p..d[.....V...f|
+00000360  a6 1d 18 56 88 87 71 3f  b0 38 9d 44 1f ad 2c 0d  |...V..q?.8.D..,.|
+00000370  3a a7 e8 d4 3e 33 3c 41  20 f3 3f 5c e5 fb e3 23  |:...>3<A .?\...#|
+00000380  12 48 ff d2 c4 30 7c 8a  51 3f 9f 19 6e 34 d7 60  |.H...0|.Q?..n4.`|
+00000390  7d 12 8a aa 90 0f 50 d9  0b 9a b2 d7 66 b1 c6 84  |}.....P.....f...|
+000003a0  af 5c e2 5e 16 3e 36 61  73 84 64 89 b3 c1 6d 50  |.\.^.>6as.d...mP|
+000003b0  33 55 c7 e1 c5 a5 4c 32  5c 95 dc 07 43 60 49 11  |3U....L2\...C`I.|
+000003c0  e9 98 cc ba 16 03 03 00  04 0e 00 00 00           |.............|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 46 10 00 00  42 41 04 28 02 84 d5 b4  |....F...BA.(....|
+00000010  58 07 47 d5 a0 d6 0b 1d  37 91 e6 34 a4 ad 0b ad  |X.G.....7..4....|
+00000020  22 01 82 77 a7 32 86 78  83 3a da 75 2f e5 68 7a  |"..w.2.x.:.u/.hz|
+00000030  de e4 05 e0 02 47 40 4e  38 d2 2c c3 7b da 53 73  |.....G at N8.,.{.Ss|
+00000040  19 cb 8b 73 34 72 4d 33  71 39 c8 14 03 03 00 01  |...s4rM3q9......|
+00000050  01 16 03 03 00 40 10 63  43 76 83 bd 36 e4 1e 4d  |..... at .cCv..6..M|
+00000060  7e 13 b0 ac aa c8 ec 90  31 df 84 46 49 68 39 5a  |~.......1..FIh9Z|
+00000070  05 8b 73 32 86 15 3a 18  57 d8 e2 2c 2d 05 89 93  |..s2..:.W..,-...|
+00000080  37 b8 dd 73 33 92 ff a7  b2 53 27 94 b7 25 56 64  |7..s3....S'..%Vd|
+00000090  a1 d3 2c f7 6b 71                                 |..,.kq|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 40 00 00 00 00 00  |.......... at .....|
+00000010  00 00 00 00 00 00 00 00  00 00 00 21 5c 31 b1 4b  |...........!\1.K|
+00000020  96 96 30 8f 79 35 3a 3a  2d 26 67 d0 70 48 be 30  |..0.y5::-&g.pH.0|
+00000030  f8 3e e8 c1 cb 1d d5 89  f6 9c 72 bb 1c f9 4d 90  |.>........r...M.|
+00000040  9c d7 c6 fa 40 76 a5 61  46 61 24 17 03 03 00 40  |.... at v.aFa$....@|
+00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000060  94 8a 14 04 06 b9 30 a0  67 fd b2 4c 84 f4 10 93  |......0.g..L....|
+00000070  7d d4 2b 23 f0 e9 62 93  c2 20 a2 f2 7c 07 21 4b  |}.+#..b.. ..|.!K|
+00000080  94 ba 7b 7d cb 77 da 85  93 bd 53 ee ca db 9b 3e  |..{}.w....S....>|
+00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
+000000a0  00 00 00 00 00 17 3f 53  8d b3 35 b4 84 ed bb 12  |......?S..5.....|
+000000b0  cf 73 25 25 7c c3 d3 bb  1f 5a 6b 73 9a 8a b1 a2  |.s%%|....Zks....|
+000000c0  ba 99 f8 0e 43                                    |....C|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven b/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
new file mode 100644
index 0000000..547f798
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
@@ -0,0 +1,122 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 5c 01 00 00  58 03 03 52 cc 57 59 65  |....\...X..R.WYe|
+00000010  ae b3 ec a4 7a 05 f7 ec  39 22 7d 8c 91 96 6b e0  |....z...9"}...k.|
+00000020  69 81 ff 88 28 17 60 ac  94 19 ff 00 00 04 00 05  |i...(.`.........|
+00000030  00 ff 01 00 00 2b 00 0d  00 22 00 20 06 01 06 02  |.....+...". ....|
+00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
+00000050  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
+00000060  01                                                |.|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 05 00 00  |................|
+00000030  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
+00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 0f 0d 00  |n8P)l...........|
+00000300  00 0b 02 01 40 00 04 04  01 04 03 00 00 16 03 03  |.... at ...........|
+00000310  00 04 0e 00 00 00                                 |......|
+>>> Flow 3 (client to server)
+00000000  16 03 03 02 0a 0b 00 02  06 00 02 03 00 02 00 30  |...............0|
+00000010  82 01 fc 30 82 01 5e 02  09 00 9a 30 84 6c 26 35  |...0..^....0.l&5|
+00000020  d9 17 30 09 06 07 2a 86  48 ce 3d 04 01 30 45 31  |..0...*.H.=..0E1|
+00000030  0b 30 09 06 03 55 04 06  13 02 41 55 31 13 30 11  |.0...U....AU1.0.|
+00000040  06 03 55 04 08 13 0a 53  6f 6d 65 2d 53 74 61 74  |..U....Some-Stat|
+00000050  65 31 21 30 1f 06 03 55  04 0a 13 18 49 6e 74 65  |e1!0...U....Inte|
+00000060  72 6e 65 74 20 57 69 64  67 69 74 73 20 50 74 79  |rnet Widgits Pty|
+00000070  20 4c 74 64 30 1e 17 0d  31 32 31 31 31 34 31 33  | Ltd0...12111413|
+00000080  32 35 35 33 5a 17 0d 32  32 31 31 31 32 31 33 32  |2553Z..221112132|
+00000090  35 35 33 5a 30 41 31 0b  30 09 06 03 55 04 06 13  |553Z0A1.0...U...|
+000000a0  02 41 55 31 0c 30 0a 06  03 55 04 08 13 03 4e 53  |.AU1.0...U....NS|
+000000b0  57 31 10 30 0e 06 03 55  04 07 13 07 50 79 72 6d  |W1.0...U....Pyrm|
+000000c0  6f 6e 74 31 12 30 10 06  03 55 04 03 13 09 4a 6f  |ont1.0...U....Jo|
+000000d0  65 6c 20 53 69 6e 67 30  81 9b 30 10 06 07 2a 86  |el Sing0..0...*.|
+000000e0  48 ce 3d 02 01 06 05 2b  81 04 00 23 03 81 86 00  |H.=....+...#....|
+000000f0  04 00 95 8c 91 75 14 c0  5e c4 57 b4 d4 c3 6f 8d  |.....u..^.W...o.|
+00000100  ae 68 1e dd 6f ce 86 e1  7e 6e b2 48 3e 81 e5 4e  |.h..o...~n.H>..N|
+00000110  e2 c6 88 4b 64 dc f5 30  bb d3 ff 65 cc 5b f4 dd  |...Kd..0...e.[..|
+00000120  b5 6a 3e 3e d0 1d de 47  c3 76 ad 19 f6 45 2c 8c  |.j>>...G.v...E,.|
+00000130  bc d8 1d 01 4c 1f 70 90  46 76 48 8b 8f 83 cc 4a  |....L.p.FvH....J|
+00000140  5c 8f 40 76 da e0 89 ec  1d 2b c4 4e 30 76 28 41  |\. at v.....+.N0v(A|
+00000150  b2 62 a8 fb 5b f1 f9 4e  7a 8d bd 09 b8 ae ea 8b  |.b..[..Nz.......|
+00000160  18 27 4f 2e 70 fe 13 96  ba c3 d3 40 16 cd 65 4e  |.'O.p...... at ..eN|
+00000170  ac 11 1e e6 f1 30 09 06  07 2a 86 48 ce 3d 04 01  |.....0...*.H.=..|
+00000180  03 81 8c 00 30 81 88 02  42 00 e0 14 c4 60 60 0b  |....0...B....``.|
+00000190  72 68 b0 32 5d 61 4a 02  74 5c c2 81 b9 16 a8 3f  |rh.2]aJ.t\.....?|
+000001a0  29 c8 36 c7 81 ff 6c b6  5b d9 70 f1 38 3b 50 48  |).6...l.[.p.8;PH|
+000001b0  28 94 cb 09 1a 52 f1 5d  ee 8d f2 b9 f0 f0 da d9  |(....R.]........|
+000001c0  15 3a f9 bd 03 7a 87 a2  23 35 ec 02 42 01 a3 d4  |.:...z..#5..B...|
+000001d0  8a 78 35 1c 4a 9a 23 d2  0a be 2b 10 31 9d 9c 5f  |.x5.J.#...+.1.._|
+000001e0  be e8 91 b3 da 1a f5 5d  a3 23 f5 26 8b 45 70 8d  |.......].#.&.Ep.|
+000001f0  65 62 9b 7e 01 99 3d 18  f6 10 9a 38 61 9b 2e 57  |eb.~..=....8a..W|
+00000200  e4 fa cc b1 8a ce e2 23  a0 87 f0 e1 67 51 eb 16  |.......#....gQ..|
+00000210  03 03 00 86 10 00 00 82  00 80 47 5a 2f b8 78 46  |..........GZ/.xF|
+00000220  9f 3c fc ab 8b 35 c9 77  da c3 96 78 31 7c 2b 4f  |.<...5.w...x1|+O|
+00000230  56 be 0f 33 bd 17 bc 1c  86 5a ae b3 0f 8b 18 2f  |V..3.....Z...../|
+00000240  48 0d e0 0a 20 d3 53 96  88 d2 8a 7d b6 58 13 44  |H... .S....}.X.D|
+00000250  a5 e8 19 6d 02 df a6 1b  79 c5 54 c2 ef 4d 41 4f  |...m....y.T..MAO|
+00000260  04 1c eb 37 55 b7 2b f4  7c 6d 37 9c f1 89 a0 2c  |...7U.+.|m7....,|
+00000270  0f ba 10 09 e4 a1 ee 0a  7e 9a fd 2c 32 63 1c 55  |........~..,2c.U|
+00000280  85 38 de d0 7b 5f 46 03  1f cc 4d 69 51 97 d8 d7  |.8..{_F...MiQ...|
+00000290  88 6f ba 43 04 b0 42 09  61 5e 16 03 03 00 92 0f  |.o.C..B.a^......|
+000002a0  00 00 8e 04 03 00 8a 30  81 87 02 41 14 3d 4c 71  |.......0...A.=Lq|
+000002b0  c2 32 4a 20 ee b7 69 17  55 e8 99 55 11 76 51 7a  |.2J ..i.U..U.vQz|
+000002c0  74 55 e7 e8 c3 3b b3 70  db 1c 8e f6 8a d4 99 40  |tU...;.p.......@|
+000002d0  6e da 04 fd 7a 47 41 d6  ae c0 63 ad fd 91 a8 58  |n...zGA...c....X|
+000002e0  24 b9 ac 2f 7a 4c bf 5b  24 12 cb 3a f3 02 42 00  |$../zL.[$..:..B.|
+000002f0  90 f9 48 97 0e d4 33 99  09 9f 1d a8 97 16 60 82  |..H...3.......`.|
+00000300  85 cc 5a 5d 79 f7 2f 03  2a c0 b8 12 61 ac 9f 88  |..Z]y./.*...a...|
+00000310  1d 0d 9e 0a ee 28 a8 5a  e2 42 b7 94 e2 e6 0e 13  |.....(.Z.B......|
+00000320  c8 64 dc 4e d3 6b 10 d6  83 41 9c dc d4 53 c3 08  |.d.N.k...A...S..|
+00000330  19 14 03 03 00 01 01 16  03 03 00 24 ef bd e3 23  |...........$...#|
+00000340  10 23 ae 6e b5 12 eb 9c  21 78 db 36 fd bf 7f ee  |.#.n....!x.6....|
+00000350  6f c8 00 2d b6 35 cc 2f  38 73 ae a4 34 cf 0d df  |o..-.5./8s..4...|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 24 a7 50 0f 50 b4  |..........$.P.P.|
+00000010  1c c3 4d f3 7a 64 df 65  ac 35 22 13 46 cc ec 36  |..M.zd.e.5".F..6|
+00000020  e6 d2 f3 67 94 6a 18 85  9f 4a 3c 44 a3 58 b0 17  |...g.j...J<D.X..|
+00000030  03 03 00 21 51 0a 41 8c  fd 50 e3 54 8b 6a 1f 83  |...!Q.A..P.T.j..|
+00000040  a5 37 98 e1 5b 1e ec 03  1d c7 0e 28 6d 79 3f 34  |.7..[......(my?4|
+00000050  de 1c 38 6d 7e 15 03 03  00 16 06 fc b1 7d ad 70  |..8m~........}.p|
+00000060  1a de d4 b7 b5 e7 a2 6d  1b 9a b0 31 0c cc 7b 70  |.......m...1..{p|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven b/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
new file mode 100644
index 0000000..04a5b11
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
@@ -0,0 +1,121 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 5c 01 00 00  58 03 03 52 cc 57 59 6b  |....\...X..R.WYk|
+00000010  11 07 04 39 77 20 c2 b4  3f cb 0a c9 53 fe 5b 3e  |...9w ..?...S.[>|
+00000020  5f 58 2c 7e 30 69 e1 8e  6c 9d c8 00 00 04 00 05  |_X,~0i..l.......|
+00000030  00 ff 01 00 00 2b 00 0d  00 22 00 20 06 01 06 02  |.....+...". ....|
+00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
+00000050  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
+00000060  01                                                |.|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 05 00 00  |................|
+00000030  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
+00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 0f 0d 00  |n8P)l...........|
+00000300  00 0b 02 01 40 00 04 04  01 04 03 00 00 16 03 03  |.... at ...........|
+00000310  00 04 0e 00 00 00                                 |......|
+>>> Flow 3 (client to server)
+00000000  16 03 03 01 fb 0b 00 01  f7 00 01 f4 00 01 f1 30  |...............0|
+00000010  82 01 ed 30 82 01 58 a0  03 02 01 02 02 01 00 30  |...0..X........0|
+00000020  0b 06 09 2a 86 48 86 f7  0d 01 01 05 30 26 31 10  |...*.H......0&1.|
+00000030  30 0e 06 03 55 04 0a 13  07 41 63 6d 65 20 43 6f  |0...U....Acme Co|
+00000040  31 12 30 10 06 03 55 04  03 13 09 31 32 37 2e 30  |1.0...U....127.0|
+00000050  2e 30 2e 31 30 1e 17 0d  31 31 31 32 30 38 30 37  |.0.10...11120807|
+00000060  35 35 31 32 5a 17 0d 31  32 31 32 30 37 30 38 30  |5512Z..121207080|
+00000070  30 31 32 5a 30 26 31 10  30 0e 06 03 55 04 0a 13  |012Z0&1.0...U...|
+00000080  07 41 63 6d 65 20 43 6f  31 12 30 10 06 03 55 04  |.Acme Co1.0...U.|
+00000090  03 13 09 31 32 37 2e 30  2e 30 2e 31 30 81 9c 30  |...127.0.0.10..0|
+000000a0  0b 06 09 2a 86 48 86 f7  0d 01 01 01 03 81 8c 00  |...*.H..........|
+000000b0  30 81 88 02 81 80 4e d0  7b 31 e3 82 64 d9 59 c0  |0.....N.{1..d.Y.|
+000000c0  c2 87 a4 5e 1e 8b 73 33  c7 63 53 df 66 92 06 84  |...^..s3.cS.f...|
+000000d0  f6 64 d5 8f e4 36 a7 1d  2b e8 b3 20 36 45 23 b5  |.d...6..+.. 6E#.|
+000000e0  e3 95 ae ed e0 f5 20 9c  8d 95 df 7f 5a 12 ef 87  |...... .....Z...|
+000000f0  e4 5b 68 e4 e9 0e 74 ec  04 8a 7f de 93 27 c4 01  |.[h...t......'..|
+00000100  19 7a bd f2 dc 3d 14 ab  d0 54 ca 21 0c d0 4d 6e  |.z...=...T.!..Mn|
+00000110  87 2e 5c c5 d2 bb 4d 4b  4f ce b6 2c f7 7e 88 ec  |..\...MKO..,.~..|
+00000120  7c d7 02 91 74 a6 1e 0c  1a da e3 4a 5a 2e de 13  ||...t......JZ...|
+00000130  9c 4c 40 88 59 93 02 03  01 00 01 a3 32 30 30 30  |.L at .Y.......2000|
+00000140  0e 06 03 55 1d 0f 01 01  ff 04 04 03 02 00 a0 30  |...U...........0|
+00000150  0d 06 03 55 1d 0e 04 06  04 04 01 02 03 04 30 0f  |...U..........0.|
+00000160  06 03 55 1d 23 04 08 30  06 80 04 01 02 03 04 30  |..U.#..0.......0|
+00000170  0b 06 09 2a 86 48 86 f7  0d 01 01 05 03 81 81 00  |...*.H..........|
+00000180  36 1f b3 7a 0c 75 c9 6e  37 46 61 2b d5 bd c0 a7  |6..z.u.n7Fa+....|
+00000190  4b cc 46 9a 81 58 7c 85  79 29 c8 c8 c6 67 dd 32  |K.F..X|.y)...g.2|
+000001a0  56 45 2b 75 b6 e9 24 a9  50 9a be 1f 5a fa 1a 15  |VE+u..$.P...Z...|
+000001b0  d9 cc 55 95 72 16 83 b9  c2 b6 8f fd 88 8c 38 84  |..U.r.........8.|
+000001c0  1d ab 5d 92 31 13 4f fd  83 3b c6 9d f1 11 62 b6  |..].1.O..;....b.|
+000001d0  8b ec ab 67 be c8 64 b0  11 50 46 58 17 6b 99 1c  |...g..d..PFX.k..|
+000001e0  d3 1d fc 06 f1 0e e5 96  a8 0c f9 78 20 b7 44 18  |...........x .D.|
+000001f0  51 8d 10 7e 4f 94 67 df  a3 4e 70 73 8e 90 91 85  |Q..~O.g..Nps....|
+00000200  16 03 03 00 86 10 00 00  82 00 80 44 89 7d aa 26  |...........D.}.&|
+00000210  30 ce 6b db 25 70 b0 1e  16 fa 5b 3a dd 4a 4b bd  |0.k.%p....[:.JK.|
+00000220  ec ee 50 9d 21 ba 52 b5  51 4f a8 65 d8 2e 41 e2  |..P.!.R.QO.e..A.|
+00000230  e1 dc f3 1a df 58 4f 87  7a d3 e1 e1 1c 13 b2 0b  |.....XO.z.......|
+00000240  b7 43 b7 92 f2 df 19 bb  79 71 e0 71 44 ab 19 2f  |.C......yq.qD../|
+00000250  37 11 ac 62 50 b6 f1 53  fe aa b4 bc 29 8e 0b 4c  |7..bP..S....)..L|
+00000260  0b 12 8d d5 84 a9 fa a9  ea 16 aa c3 0d da 32 c8  |..............2.|
+00000270  e0 4c 9f 99 f8 69 cd a8  c3 b1 76 42 67 f3 ff 15  |.L...i....vBg...|
+00000280  52 95 43 66 da 49 43 25  9d e5 eb 16 03 03 00 88  |R.Cf.IC%........|
+00000290  0f 00 00 84 04 01 00 80  01 d5 0e 1c 75 97 89 52  |............u..R|
+000002a0  1a f0 cc ef 93 6e 71 b2  b1 38 8c 50 11 f7 a3 02  |.....nq..8.P....|
+000002b0  71 c4 d5 6f 8d 01 83 06  2e ea 5a 10 8a 0d d0 fc  |q..o......Z.....|
+000002c0  b6 a2 63 af 4f 99 b5 eb  ab fd 01 c2 fb 26 fc fd  |..c.O........&..|
+000002d0  ad 2c b3 63 b3 87 a6 f5  14 ea 7d e7 fe a8 e7 7e  |.,.c......}....~|
+000002e0  20 ab b9 f6 c3 58 bd c0  f3 96 eb 83 dc 42 6c 0d  | ....X.......Bl.|
+000002f0  5e e8 09 55 c7 b8 24 05  dd e1 7c af 9f 2c 22 6c  |^..U..$...|..,"l|
+00000300  fa b8 94 13 3b f1 09 e1  38 59 fc a1 8c cb aa ca  |....;...8Y......|
+00000310  f8 e0 2a 9c 36 f9 c3 2b  14 03 03 00 01 01 16 03  |..*.6..+........|
+00000320  03 00 24 d0 12 7c cc d2  3e 37 1f f4 7d b4 c0 fc  |..$..|..>7..}...|
+00000330  19 f6 c8 ea 62 12 e0 0d  af 62 d4 69 f7 96 5a c0  |....b....b.i..Z.|
+00000340  97 d3 bb b0 a3 f7 3f                              |......?|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 24 cd 20 85 1e 74  |..........$. ..t|
+00000010  18 b2 71 48 d5 10 61 c6  b0 18 26 83 c2 7f f1 b1  |..qH..a...&.....|
+00000020  2f b5 35 d0 47 a8 99 9a  9a a5 62 64 fb f9 29 17  |/.5.G.....bd..).|
+00000030  03 03 00 21 22 7b ed 61  e3 9b 6d 98 b9 23 98 e3  |...!"{.a..m..#..|
+00000040  55 11 b8 0f 7e 2b e1 c1  d4 f1 83 79 c3 f8 03 f0  |U...~+.....y....|
+00000050  02 5c 61 24 d7 15 03 03  00 16 14 2b a3 5a 56 f0  |.\a$.......+.ZV.|
+00000060  92 da d0 e6 32 91 d8 30  7a b4 d0 a2 93 f5 01 ea  |....2..0z.......|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven b/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
new file mode 100644
index 0000000..562fe1a
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
@@ -0,0 +1,81 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 5c 01 00 00  58 03 03 52 cc 57 59 1b  |....\...X..R.WY.|
+00000010  08 fe f7 8a bf 07 84 2b  60 a6 13 2d 15 13 f8 b6  |.......+`..-....|
+00000020  d4 b6 3b f2 7a 98 ff 32  a0 68 7c 00 00 04 00 05  |..;.z..2.h|.....|
+00000030  00 ff 01 00 00 2b 00 0d  00 22 00 20 06 01 06 02  |.....+...". ....|
+00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
+00000050  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
+00000060  01                                                |.|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 05 00 00  |................|
+00000030  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
+00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 0f 0d 00  |n8P)l...........|
+00000300  00 0b 02 01 40 00 04 04  01 04 03 00 00 16 03 03  |.... at ...........|
+00000310  00 04 0e 00 00 00                                 |......|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 07 0b 00 00  03 00 00 00 16 03 03 00  |................|
+00000010  86 10 00 00 82 00 80 6b  51 48 d3 18 7d 30 e0 0c  |.......kQH..}0..|
+00000020  20 8d f3 e4 39 47 30 0e  a5 85 79 f9 8b 11 50 9e  | ...9G0...y...P.|
+00000030  81 71 5c 26 c6 bb cb aa  d5 00 d1 89 79 b1 77 2d  |.q\&........y.w-|
+00000040  eb 9b 86 7c 52 c6 f7 b7  10 b0 b6 94 22 51 b8 12  |...|R......."Q..|
+00000050  3c 09 35 8e 1b cc f4 3b  b7 b8 78 ab 89 59 41 49  |<.5....;..x..YAI|
+00000060  21 31 eb f0 f8 94 63 3d  e6 96 8f b6 63 95 05 dd  |!1....c=....c...|
+00000070  46 b3 00 8a d6 83 75 99  1b 5a 48 0a 23 b5 10 c1  |F.....u..ZH.#...|
+00000080  95 b5 bc 15 72 b5 f5 a0  62 e2 1d c0 ff d2 87 a5  |....r...b.......|
+00000090  97 5c 33 49 a7 26 35 14  03 03 00 01 01 16 03 03  |.\3I.&5.........|
+000000a0  00 24 61 38 1f 9d fb d9  65 2e 02 07 fb be f9 85  |.$a8....e.......|
+000000b0  8d 15 34 c0 d1 0e 4e 10  3c 25 60 2f ac 04 21 66  |..4...N.<%`/..!f|
+000000c0  04 9d 9a 60 31 72                                 |...`1r|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 24 fe 0e 3e 84 af  |..........$..>..|
+00000010  e5 6b 10 ed 41 9c 2b e0  ba e0 2b 53 61 36 1b 40  |.k..A.+...+Sa6.@|
+00000020  35 de 3a c7 c3 5c df 74  67 f7 05 74 84 f5 e1 17  |5.:..\.tg..t....|
+00000030  03 03 00 21 d3 8d 81 85  b7 1f 30 bd 89 33 f9 81  |...!......0..3..|
+00000040  89 f7 af d1 be b0 c1 46  e3 df 32 f6 dc 2f 4d 82  |.......F..2../M.|
+00000050  0a 84 9f 5b 03 15 03 03  00 16 13 af 37 91 82 67  |...[........7..g|
+00000060  b0 7c 5e 0e ec 8e cc 31  a0 ea a5 72 a4 2b 0b 73  |.|^....1...r.+.s|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES b/src/pkg/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
new file mode 100644
index 0000000..aacbb86
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
@@ -0,0 +1,89 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 9c 01 00 00  98 03 03 53 04 f0 f9 09  |...........S....|
+00000010  13 56 01 37 84 b1 32 59  4c 73 b1 8e bb 02 1a 32  |.V.7..2YLs.....2|
+00000020  db ab 8c e6 ed ad 7f 52  9a 59 39 00 00 04 c0 0a  |.......R.Y9.....|
+00000030  00 ff 01 00 00 6b 00 0b  00 04 03 00 01 02 00 0a  |.....k..........|
+00000040  00 34 00 32 00 0e 00 0d  00 19 00 0b 00 0c 00 18  |.4.2............|
+00000050  00 09 00 0a 00 16 00 17  00 08 00 06 00 07 00 14  |................|
+00000060  00 15 00 04 00 05 00 12  00 13 00 01 00 02 00 03  |................|
+00000070  00 0f 00 10 00 11 00 0d  00 22 00 20 06 01 06 02  |.........". ....|
+00000080  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
+00000090  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
+000000a0  01                                                |.|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 c0 0a 00 00  |................|
+00000030  05 ff 01 00 01 00 16 03  03 02 0e 0b 00 02 0a 00  |................|
+00000040  02 07 00 02 04 30 82 02  00 30 82 01 62 02 09 00  |.....0...0..b...|
+00000050  b8 bf 2d 47 a0 d2 eb f4  30 09 06 07 2a 86 48 ce  |..-G....0...*.H.|
+00000060  3d 04 01 30 45 31 0b 30  09 06 03 55 04 06 13 02  |=..0E1.0...U....|
+00000070  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+00000080  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000090  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+000000a0  74 73 20 50 74 79 20 4c  74 64 30 1e 17 0d 31 32  |ts Pty Ltd0...12|
+000000b0  31 31 32 32 31 35 30 36  33 32 5a 17 0d 32 32 31  |1122150632Z..221|
+000000c0  31 32 30 31 35 30 36 33  32 5a 30 45 31 0b 30 09  |120150632Z0E1.0.|
+000000d0  06 03 55 04 06 13 02 41  55 31 13 30 11 06 03 55  |..U....AU1.0...U|
+000000e0  04 08 13 0a 53 6f 6d 65  2d 53 74 61 74 65 31 21  |....Some-State1!|
+000000f0  30 1f 06 03 55 04 0a 13  18 49 6e 74 65 72 6e 65  |0...U....Interne|
+00000100  74 20 57 69 64 67 69 74  73 20 50 74 79 20 4c 74  |t Widgits Pty Lt|
+00000110  64 30 81 9b 30 10 06 07  2a 86 48 ce 3d 02 01 06  |d0..0...*.H.=...|
+00000120  05 2b 81 04 00 23 03 81  86 00 04 00 c4 a1 ed be  |.+...#..........|
+00000130  98 f9 0b 48 73 36 7e c3  16 56 11 22 f2 3d 53 c3  |...Hs6~..V.".=S.|
+00000140  3b 4d 21 3d cd 6b 75 e6  f6 b0 dc 9a df 26 c1 bc  |;M!=.ku......&..|
+00000150  b2 87 f0 72 32 7c b3 64  2f 1c 90 bc ea 68 23 10  |...r2|.d/....h#.|
+00000160  7e fe e3 25 c0 48 3a 69  e0 28 6d d3 37 00 ef 04  |~..%.H:i.(m.7...|
+00000170  62 dd 0d a0 9c 70 62 83  d8 81 d3 64 31 aa 9e 97  |b....pb....d1...|
+00000180  31 bd 96 b0 68 c0 9b 23  de 76 64 3f 1a 5c 7f e9  |1...h..#.vd?.\..|
+00000190  12 0e 58 58 b6 5f 70 dd  9b d8 ea d5 d7 f5 d5 cc  |..XX._p.........|
+000001a0  b9 b6 9f 30 66 5b 66 9a  20 e2 27 e5 bf fe 3b 30  |...0f[f. .'...;0|
+000001b0  09 06 07 2a 86 48 ce 3d  04 01 03 81 8c 00 30 81  |...*.H.=......0.|
+000001c0  88 02 42 01 88 a2 4f eb  e2 45 c5 48 7d 1b ac f5  |..B...O..E.H}...|
+000001d0  ed 98 9d ae 47 70 c0 5e  1b b6 2f bd f1 b6 4d b7  |....Gp.^../...M.|
+000001e0  61 40 d3 11 a2 ce ee 0b  7e 92 7e ff 76 9d c3 3b  |a at ......~.~.v..;|
+000001f0  7e a5 3f ce fa 10 e2 59  ec 47 2d 7c ac da 4e 97  |~.?....Y.G-|..N.|
+00000200  0e 15 a0 6f d0 02 42 01  4d fc be 67 13 9c 2d 05  |...o..B.M..g..-.|
+00000210  0e bd 3f a3 8c 25 c1 33  13 83 0d 94 06 bb d4 37  |..?..%.3.......7|
+00000220  7a f6 ec 7a c9 86 2e dd  d7 11 69 7f 85 7c 56 de  |z..z......i..|V.|
+00000230  fb 31 78 2b e4 c7 78 0d  ae cb be 9e 4e 36 24 31  |.1x+..x.....N6$1|
+00000240  7b 6a 0f 39 95 12 07 8f  2a 16 03 03 00 d8 0c 00  |{j.9....*.......|
+00000250  00 d4 03 00 17 41 04 1e  18 37 ef 0d 19 51 88 35  |.....A...7...Q.5|
+00000260  75 71 b5 e5 54 5b 12 2e  8f 09 67 fd a7 24 20 3e  |uq..T[....g..$ >|
+00000270  b2 56 1c ce 97 28 5e f8  2b 2d 4f 9e f1 07 9f 6c  |.V...(^.+-O....l|
+00000280  4b 5b 83 56 e2 32 42 e9  58 b6 d7 49 a6 b5 68 1a  |K[.V.2B.X..I..h.|
+00000290  41 03 56 6b dc 5a 89 04  03 00 8b 30 81 88 02 42  |A.Vk.Z.....0...B|
+000002a0  00 c6 85 8e 06 b7 04 04  e9 cd 9e 3e cb 66 23 95  |...........>.f#.|
+000002b0  b4 42 9c 64 81 39 05 3f  b5 21 f8 28 af 60 6b 4d  |.B.d.9.?.!.(.`kM|
+000002c0  3d ba a1 4b 5e 77 ef e7  59 28 fe 1d c1 27 a2 ff  |=..K^w..Y(...'..|
+000002d0  a8 de 33 48 b3 c1 85 6a  42 9b f9 7e 7e 31 c2 e5  |..3H...jB..~~1..|
+000002e0  bd 66 02 42 00 ad 7d 06  35 ab ec 8d ac d4 ba 1b  |.f.B..}.5.......|
+000002f0  49 5e 05 5f f0 97 93 82  b8 2b 8d 91 98 63 8e b4  |I^._.....+...c..|
+00000300  14 62 db 1e c9 2c 13 ae  b7 d3 17 38 23 2f f6 7f  |.b...,.....8#/..|
+00000310  0c 4d d3 33 d2 79 d1 77  ee cb b1 c2 fc 34 b8 69  |.M.3.y.w.....4.i|
+00000320  f9 10 8b 61 89 85 16 03  03 00 04 0e 00 00 00     |...a...........|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 46 10 00 00  42 41 04 dd 22 68 a1 4e  |....F...BA.."h.N|
+00000010  04 1b 47 f9 c5 7d 04 1d  d8 fe 84 fa be 31 2e a7  |..G..}.......1..|
+00000020  f8 e5 b8 14 92 44 99 11  0e 34 97 fc e5 b1 91 cf  |.....D...4......|
+00000030  a4 d1 3f b4 71 94 c6 06  16 f0 98 c0 3e 05 f9 2f  |..?.q.......>../|
+00000040  0a 97 78 3d ef dc fa a2  d7 ee 7d 14 03 03 00 01  |..x=......}.....|
+00000050  01 16 03 03 00 40 90 bf  7f e9 c9 6e d1 80 f5 12  |..... at .....n....|
+00000060  6d c5 b7 c5 15 4b 18 a5  d3 18 1e f8 8c 4d 7e 6d  |m....K.......M~m|
+00000070  03 60 29 7c 45 7c b2 ca  8c 07 71 70 aa 23 fa 6e  |.`)|E|....qp.#.n|
+00000080  d9 0b 0a 32 4c 9e e5 00  f9 19 9b b6 8d dc d3 67  |...2L..........g|
+00000090  3d 0f bb b8 4b 9e                                 |=...K.|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 40 00 00 00 00 00  |.......... at .....|
+00000010  00 00 00 00 00 00 00 00  00 00 00 a1 6e e5 d1 ca  |............n...|
+00000020  03 f4 77 dc ec ee 5d f0  22 5e 7f 55 1a 8d ad 45  |..w...]."^.U...E|
+00000030  09 f1 3b b2 61 36 dc 3d  2a 1e 1f e5 a7 84 76 a9  |..;.a6.=*.....v.|
+00000040  41 5b 86 03 ac 22 18 20  9b a9 29 17 03 03 00 40  |A[...". ..)....@|
+00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000060  f5 cb 28 1e b5 bc 82 7f  82 38 54 14 e8 b9 6d 3b  |..(......8T...m;|
+00000070  bc 99 d6 0e f9 00 96 99  a8 92 2e 86 9d 62 4e 90  |.............bN.|
+00000080  27 52 58 45 20 93 90 a1  f3 a8 89 2b e7 21 24 16  |'RXE ......+.!$.|
+00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
+000000a0  00 00 00 00 00 a8 2a ab  8f b0 ce 49 8b fd a5 c9  |......*....I....|
+000000b0  11 b2 04 83 18 f3 1d 6c  82 34 1d df dd 2f 45 3b  |.......l.4.../E;|
+000000c0  27 8a 0f 16 69                                    |'...i|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-IssueTicket b/src/pkg/crypto/tls/testdata/Server-TLSv12-IssueTicket
new file mode 100644
index 0000000..e3e62f2
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-IssueTicket
@@ -0,0 +1,87 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 60 01 00 00  5c 03 03 52 cc 57 59 7e  |....`...\..R.WY~|
+00000010  43 5c 3b fd 50 ab 61 3f  64 a4 f9 bd ba 8c 28 e1  |C\;.P.a?d.....(.|
+00000020  f9 a1 45 7e 48 9e 62 af  25 de 0e 00 00 04 00 05  |..E~H.b.%.......|
+00000030  00 ff 01 00 00 2f 00 23  00 00 00 0d 00 22 00 20  |...../.#.....". |
+00000040  06 01 06 02 06 03 05 01  05 02 05 03 04 01 04 02  |................|
+00000050  04 03 03 01 03 02 03 03  02 01 02 02 02 03 01 01  |................|
+00000060  00 0f 00 01 01                                    |.....|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 35 02 00 00  31 03 03 00 00 00 00 00  |....5...1.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 05 00 00  |................|
+00000030  09 00 23 00 00 ff 01 00  01 00 16 03 03 02 be 0b  |..#.............|
+00000040  00 02 ba 00 02 b7 00 02  b4 30 82 02 b0 30 82 02  |.........0...0..|
+00000050  19 a0 03 02 01 02 02 09  00 85 b0 bb a4 8a 7f b8  |................|
+00000060  ca 30 0d 06 09 2a 86 48  86 f7 0d 01 01 05 05 00  |.0...*.H........|
+00000070  30 45 31 0b 30 09 06 03  55 04 06 13 02 41 55 31  |0E1.0...U....AU1|
+00000080  13 30 11 06 03 55 04 08  13 0a 53 6f 6d 65 2d 53  |.0...U....Some-S|
+00000090  74 61 74 65 31 21 30 1f  06 03 55 04 0a 13 18 49  |tate1!0...U....I|
+000000a0  6e 74 65 72 6e 65 74 20  57 69 64 67 69 74 73 20  |nternet Widgits |
+000000b0  50 74 79 20 4c 74 64 30  1e 17 0d 31 30 30 34 32  |Pty Ltd0...10042|
+000000c0  34 30 39 30 39 33 38 5a  17 0d 31 31 30 34 32 34  |4090938Z..110424|
+000000d0  30 39 30 39 33 38 5a 30  45 31 0b 30 09 06 03 55  |090938Z0E1.0...U|
+000000e0  04 06 13 02 41 55 31 13  30 11 06 03 55 04 08 13  |....AU1.0...U...|
+000000f0  0a 53 6f 6d 65 2d 53 74  61 74 65 31 21 30 1f 06  |.Some-State1!0..|
+00000100  03 55 04 0a 13 18 49 6e  74 65 72 6e 65 74 20 57  |.U....Internet W|
+00000110  69 64 67 69 74 73 20 50  74 79 20 4c 74 64 30 81  |idgits Pty Ltd0.|
+00000120  9f 30 0d 06 09 2a 86 48  86 f7 0d 01 01 01 05 00  |.0...*.H........|
+00000130  03 81 8d 00 30 81 89 02  81 81 00 bb 79 d6 f5 17  |....0.......y...|
+00000140  b5 e5 bf 46 10 d0 dc 69  be e6 2b 07 43 5a d0 03  |...F...i..+.CZ..|
+00000150  2d 8a 7a 43 85 b7 14 52  e7 a5 65 4c 2c 78 b8 23  |-.zC...R..eL,x.#|
+00000160  8c b5 b4 82 e5 de 1f 95  3b 7e 62 a5 2c a5 33 d6  |........;~b.,.3.|
+00000170  fe 12 5c 7a 56 fc f5 06  bf fa 58 7b 26 3f b5 cd  |..\zV.....X{&?..|
+00000180  04 d3 d0 c9 21 96 4a c7  f4 54 9f 5a bf ef 42 71  |....!.J..T.Z..Bq|
+00000190  00 fe 18 99 07 7f 7e 88  7d 7d f1 04 39 c4 a2 2e  |......~.}}..9...|
+000001a0  db 51 c9 7c e3 c0 4c 3b  32 66 01 cf af b1 1d b8  |.Q.|..L;2f......|
+000001b0  71 9a 1d db db 89 6b ae  da 2d 79 02 03 01 00 01  |q.....k..-y.....|
+000001c0  a3 81 a7 30 81 a4 30 1d  06 03 55 1d 0e 04 16 04  |...0..0...U.....|
+000001d0  14 b1 ad e2 85 5a cf cb  28 db 69 ce 23 69 de d3  |.....Z..(.i.#i..|
+000001e0  26 8e 18 88 39 30 75 06  03 55 1d 23 04 6e 30 6c  |&...90u..U.#.n0l|
+000001f0  80 14 b1 ad e2 85 5a cf  cb 28 db 69 ce 23 69 de  |......Z..(.i.#i.|
+00000200  d3 26 8e 18 88 39 a1 49  a4 47 30 45 31 0b 30 09  |.&...9.I.G0E1.0.|
+00000210  06 03 55 04 06 13 02 41  55 31 13 30 11 06 03 55  |..U....AU1.0...U|
+00000220  04 08 13 0a 53 6f 6d 65  2d 53 74 61 74 65 31 21  |....Some-State1!|
+00000230  30 1f 06 03 55 04 0a 13  18 49 6e 74 65 72 6e 65  |0...U....Interne|
+00000240  74 20 57 69 64 67 69 74  73 20 50 74 79 20 4c 74  |t Widgits Pty Lt|
+00000250  64 82 09 00 85 b0 bb a4  8a 7f b8 ca 30 0c 06 03  |d...........0...|
+00000260  55 1d 13 04 05 30 03 01  01 ff 30 0d 06 09 2a 86  |U....0....0...*.|
+00000270  48 86 f7 0d 01 01 05 05  00 03 81 81 00 08 6c 45  |H.............lE|
+00000280  24 c7 6b b1 59 ab 0c 52  cc f2 b0 14 d7 87 9d 7a  |$.k.Y..R.......z|
+00000290  64 75 b5 5a 95 66 e4 c5  2b 8e ae 12 66 1f eb 4f  |du.Z.f..+...f..O|
+000002a0  38 b3 6e 60 d3 92 fd f7  41 08 b5 25 13 b1 18 7a  |8.n`....A..%...z|
+000002b0  24 fb 30 1d ba ed 98 b9  17 ec e7 d7 31 59 db 95  |$.0.........1Y..|
+000002c0  d3 1d 78 ea 50 56 5c d5  82 5a 2d 5a 5f 33 c4 b6  |..x.PV\..Z-Z_3..|
+000002d0  d8 c9 75 90 96 8c 0f 52  98 b5 cd 98 1f 89 20 5f  |..u....R...... _|
+000002e0  f2 a0 1c a3 1b 96 94 dd  a9 fd 57 e9 70 e8 26 6d  |..........W.p.&m|
+000002f0  71 99 9b 26 6e 38 50 29  6c 90 a7 bd d9 16 03 03  |q..&n8P)l.......|
+00000300  00 04 0e 00 00 00                                 |......|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 86 10 00 00  82 00 80 6e 2e 79 82 3a  |...........n.y.:|
+00000010  c4 68 72 f5 a2 42 3d 71  f9 ec 22 8c 0b fa f0 82  |.hr..B=q..".....|
+00000020  82 c0 cb fc 52 0a 51 03  04 8c eb 4a 4e 4f b6 49  |....R.Q....JNO.I|
+00000030  ef 94 65 21 3c f7 9d 46  85 6e 35 d5 17 6b ff a3  |..e!<..F.n5..k..|
+00000040  5e 4d c1 36 1a 2f 68 f5  06 d4 2d 73 4f 1c 3b 7b  |^M.6./h...-sO.;{|
+00000050  c1 fa 4e 7e 7c f9 6c 13  a6 f4 3a 43 e9 aa be 22  |..N~|.l...:C..."|
+00000060  85 6f 2f 7c 5b b0 08 e2  86 b2 ae cb a9 12 d8 32  |.o/|[..........2|
+00000070  80 1d e4 2e 5d c3 66 d1  19 e5 89 33 2a 88 24 40  |....].f....3*.$@|
+00000080  2a 6d 6b b5 f1 92 4b 66  06 b8 49 14 03 03 00 01  |*mk...Kf..I.....|
+00000090  01 16 03 03 00 24 16 49  e2 a0 67 31 cf 0d 72 cb  |.....$.I..g1..r.|
+000000a0  ac 16 2c 80 37 71 69 f7  5f c4 d3 00 19 b7 4b fb  |..,.7qi._.....K.|
+000000b0  e5 e9 74 8e 30 b3 1c c5  ae e6                    |..t.0.....|
+>>> Flow 4 (server to client)
+00000000  16 03 03 00 72 04 00 00  6e 00 00 00 00 00 68 00  |....r...n.....h.|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 65  |...............e|
+00000020  ea 4b d1 ef ba 06 38 1e  e1 88 82 3a cd 03 ac 3b  |.K....8....:...;|
+00000030  39 0a e0 19 fd af 6c 57  30 df 31 6e f7 92 38 4b  |9.....lW0.1n..8K|
+00000040  5d 77 90 39 ff 32 51 f5  ed 12 d7 b0 7c 4d 6c c5  |]w.9.2Q.....|Ml.|
+00000050  76 e4 72 48 3e 59 23 fe  0d 15 df f4 ba ea b9 67  |v.rH>Y#........g|
+00000060  16 23 8f 7d 15 b6 11 f1  ab d7 d4 cd a3 21 82 92  |.#.}.........!..|
+00000070  2a 12 cf 95 f3 60 b2 14  03 03 00 01 01 16 03 03  |*....`..........|
+00000080  00 24 89 ad 87 04 4f 08  dc 2a 71 37 fb f1 95 d1  |.$....O..*q7....|
+00000090  2e 3c c2 6e 0f 38 5d e4  0e c3 f7 27 d0 46 a3 c1  |.<.n.8]....'.F..|
+000000a0  a8 3b 06 ed 96 ec 17 03  03 00 21 30 d4 9f 0b 49  |.;........!0...I|
+000000b0  9f a2 a8 a1 2c 0a 79 93  56 2d 8a ee 85 ed 62 42  |....,.y.V-....bB|
+000000c0  8c 18 fe 7a 09 3a 24 c4  5e ed 7d 2a 15 03 03 00  |...z.:$.^.}*....|
+000000d0  16 a0 24 0a 8b 90 4c fc  99 ba 67 bb 04 1e 59 69  |..$...L...g...Yi|
+000000e0  c2 98 49 b5 00 0b e0                              |..I....|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-3DES b/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-3DES
new file mode 100644
index 0000000..5995b33
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-3DES
@@ -0,0 +1,83 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 5c 01 00 00  58 03 03 52 cc 57 59 68  |....\...X..R.WYh|
+00000010  11 72 a6 ec 6b 0a 47 1d  10 06 ec 75 af 07 38 a0  |.r..k.G....u..8.|
+00000020  30 9e 91 12 e1 9b 19 46  0d d4 45 00 00 04 00 0a  |0......F..E.....|
+00000030  00 ff 01 00 00 2b 00 0d  00 22 00 20 06 01 06 02  |.....+...". ....|
+00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
+00000050  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
+00000060  01                                                |.|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 0a 00 00  |................|
+00000030  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
+00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 04 0e 00  |n8P)l...........|
+00000300  00 00                                             |..|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 86 10 00 00  82 00 80 7a c0 73 ec cb  |...........z.s..|
+00000010  cf c2 a8 86 c0 7e 03 63  57 a1 ce 42 37 6d 78 54  |.....~.cW..B7mxT|
+00000020  29 f5 3e cc 57 c7 0d d9  69 e1 52 5c 3b 6b c4 c7  |).>.W...i.R\;k..|
+00000030  20 6d 59 ee c0 07 81 74  74 9f 62 41 64 f0 4d c8  | mY....tt.bAd.M.|
+00000040  9b aa 1a b9 da 56 07 f5  6c 1c 59 8c d3 f9 08 d9  |.....V..l.Y.....|
+00000050  08 f4 16 93 5d 9a e5 6f  fb 9f ba 3d 3c d6 81 ad  |....]..o...=<...|
+00000060  02 12 a7 28 b6 81 6a 77  c3 e9 d7 c7 54 d6 77 83  |...(..jw....T.w.|
+00000070  77 de 71 fb b3 f3 2d c4  a5 b1 e5 de aa 0e 21 bd  |w.q...-.......!.|
+00000080  91 a2 dc 7f f7 6f 90 82  54 b1 e7 14 03 03 00 01  |.....o..T.......|
+00000090  01 16 03 03 00 30 8f ee  bf fb c8 5c 54 f5 29 23  |.....0.....\T.)#|
+000000a0  d4 55 f6 98 a1 6e d5 43  e7 81 b2 36 f2 98 d8 1b  |.U...n.C...6....|
+000000b0  0d 76 cb 14 ba 32 d7 36  30 e6 ab 42 80 95 f6 8a  |.v...2.60..B....|
+000000c0  60 64 a0 6b 90 81                                 |`d.k..|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 30 00 00 00 00 00  |..........0.....|
+00000010  00 00 00 2c 21 52 34 63  ac e3 a3 66 45 00 41 0c  |...,!R4c...fE.A.|
+00000020  93 5d 6a 74 5a 25 dc 69  1d 76 73 0c f4 42 6a 18  |.]jtZ%.i.vs..Bj.|
+00000030  5b 62 23 e7 fe 41 cf d4  9b 86 35 17 03 03 00 30  |[b#..A....5....0|
+00000040  00 00 00 00 00 00 00 00  7d 5d ce 43 85 5c 6b 89  |........}].C.\k.|
+00000050  c9 a5 0e 22 69 8e b9 4a  77 4c c0 4e cc 79 d9 7e  |..."i..JwL.N.y.~|
+00000060  a3 c8 d3 db 5c 53 f8 92  4d c4 5a 88 72 58 05 11  |....\S..M.Z.rX..|
+00000070  15 03 03 00 20 00 00 00  00 00 00 00 00 1d 63 8b  |.... .........c.|
+00000080  a7 74 fb 76 1d 47 31 93  1f ec 8c e2 18 8e 21 dd  |.t.v.G1.......!.|
+00000090  87 97 9f 1c ca                                    |.....|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES b/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES
new file mode 100644
index 0000000..a152a96
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES
@@ -0,0 +1,87 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 5c 01 00 00  58 03 03 52 cc 57 59 d0  |....\...X..R.WY.|
+00000010  38 05 36 7e e3 1e 93 2a  5a bf dc c2 f8 0a 03 6f  |8.6~...*Z......o|
+00000020  1a fc 21 74 e5 8b 2a c3  9e 2c 26 00 00 04 00 2f  |..!t..*..,&..../|
+00000030  00 ff 01 00 00 2b 00 0d  00 22 00 20 06 01 06 02  |.....+...". ....|
+00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
+00000050  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
+00000060  01                                                |.|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 2f 00 00  |............./..|
+00000030  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
+00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 04 0e 00  |n8P)l...........|
+00000300  00 00                                             |..|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 86 10 00 00  82 00 80 4b b4 28 bc 78  |...........K.(.x|
+00000010  41 34 f3 49 e8 74 07 74  42 ae 2e 55 9e 9a ce e5  |A4.I.t.tB..U....|
+00000020  4a 1b e7 55 c7 64 c4 9c  b3 dd 20 d6 f8 8e 67 b3  |J..U.d.... ...g.|
+00000030  7a 5c 3b 34 e4 1a f6 bd  65 fc 21 cd 9a de 64 77  |z\;4....e.!...dw|
+00000040  09 a5 92 e5 a4 f5 18 7b  23 5b 8b c1 95 23 97 6f  |.......{#[...#.o|
+00000050  76 55 04 34 22 7d 43 71  db cd eb f8 36 36 44 4b  |vU.4"}Cq....66DK|
+00000060  ae e3 cc ec 64 88 7b e1  ea d6 ab 49 35 94 a5 04  |....d.{....I5...|
+00000070  1e 83 c5 cf 21 bb ca 33  5f d4 bf 1d d3 4d 07 59  |....!..3_....M.Y|
+00000080  b4 39 b2 4b 7b 05 43 70  0d ba 7a 14 03 03 00 01  |.9.K{.Cp..z.....|
+00000090  01 16 03 03 00 40 74 4b  7d b2 53 49 ea 86 90 c3  |..... at tK}.SI....|
+000000a0  64 6b 64 31 1a 2a 3f 1a  37 1e 56 b8 dd 12 6d 56  |dkd1.*?.7.V...mV|
+000000b0  2a 61 92 5b 39 e7 e1 be  71 70 4b 9b b3 f0 71 e7  |*a.[9...qpK...q.|
+000000c0  47 2e 2e 17 c3 0a 66 9f  69 74 30 2d f0 a0 7f 84  |G.....f.it0-....|
+000000d0  25 db c1 81 ee cf                                 |%.....|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 40 00 00 00 00 00  |.......... at .....|
+00000010  00 00 00 00 00 00 00 00  00 00 00 f3 4d 5a fc 21  |............MZ.!|
+00000020  30 b5 a1 86 9d e2 ea 38  ac 54 57 fa 5a 54 97 b8  |0......8.TW.ZT..|
+00000030  bb 4d 64 09 ef ce a1 75  0c 50 8d ff 5c c2 e9 47  |.Md....u.P..\..G|
+00000040  95 93 53 c0 bd dc c5 9c  e0 59 17 17 03 03 00 40  |..S......Y.....@|
+00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000060  69 c5 48 6e 45 cf 98 1b  2c 23 40 d1 ab a3 c2 e2  |i.HnE...,#@.....|
+00000070  10 7b b1 c8 21 3c f0 eb  96 bd 4f 78 b2 4a 7b 18  |.{..!<....Ox.J{.|
+00000080  4c b1 a6 67 bf 06 40 01  d0 8d 91 be 17 d8 0c 71  |L..g.. at ........q|
+00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
+000000a0  00 00 00 00 00 20 84 80  3d 70 fe ae ee d7 2f e9  |..... ..=p..../.|
+000000b0  bf 65 30 bf 0b dd 98 ea  bb ba 12 14 98 53 7f d5  |.e0..........S..|
+000000c0  56 ce 06 3c d0                                    |V..<.|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM b/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
new file mode 100644
index 0000000..0ddfe02
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
@@ -0,0 +1,93 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 9c 01 00 00  98 03 03 53 04 f1 30 73  |...........S..0s|
+00000010  a1 ea 8c d2 90 1c c6 d6  0d 3c af 58 21 65 90 25  |.........<.X!e.%|
+00000020  5e fa f4 27 22 65 c9 68  90 b9 04 00 00 04 c0 2f  |^..'"e.h......./|
+00000030  00 ff 01 00 00 6b 00 0b  00 04 03 00 01 02 00 0a  |.....k..........|
+00000040  00 34 00 32 00 0e 00 0d  00 19 00 0b 00 0c 00 18  |.4.2............|
+00000050  00 09 00 0a 00 16 00 17  00 08 00 06 00 07 00 14  |................|
+00000060  00 15 00 04 00 05 00 12  00 13 00 01 00 02 00 03  |................|
+00000070  00 0f 00 10 00 11 00 0d  00 22 00 20 06 01 06 02  |.........". ....|
+00000080  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
+00000090  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
+000000a0  01                                                |.|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 c0 2f 00 00  |............./..|
+00000030  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
+00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 cd 0c 00  |n8P)l...........|
+00000300  00 c9 03 00 17 41 04 1e  18 37 ef 0d 19 51 88 35  |.....A...7...Q.5|
+00000310  75 71 b5 e5 54 5b 12 2e  8f 09 67 fd a7 24 20 3e  |uq..T[....g..$ >|
+00000320  b2 56 1c ce 97 28 5e f8  2b 2d 4f 9e f1 07 9f 6c  |.V...(^.+-O....l|
+00000330  4b 5b 83 56 e2 32 42 e9  58 b6 d7 49 a6 b5 68 1a  |K[.V.2B.X..I..h.|
+00000340  41 03 56 6b dc 5a 89 04  01 00 80 a2 54 61 84 29  |A.Vk.Z......Ta.)|
+00000350  3e 97 4b 97 9a 9f 5c c0  49 6d 86 d2 79 8e 95 a1  |>.K...\.Im..y...|
+00000360  0a 5a 36 73 34 bb 05 73  35 47 e1 2b 5d f3 ef 36  |.Z6s4..s5G.+]..6|
+00000370  a8 32 e2 7e ef aa 3f 1f  b3 64 60 d4 06 2e 98 e3  |.2.~..?..d`.....|
+00000380  11 e2 60 3c d6 20 17 63  b2 6f a0 cd 21 01 2b 4e  |..`<. .c.o..!.+N|
+00000390  b2 a8 55 04 39 37 5c 6c  71 66 4d a3 eb 1b 83 67  |..U.97\lqfM....g|
+000003a0  6b 15 a0 56 9a f1 a2 79  92 29 ce 58 3c 10 4d 65  |k..V...y.).X<.Me|
+000003b0  1f 22 e3 ea d8 74 aa 01  7e ca f3 89 23 41 4d bd  |."...t..~...#AM.|
+000003c0  df 77 4e 59 54 97 74 ad  07 ea c0 16 03 03 00 04  |.wNYT.t.........|
+000003d0  0e 00 00 00                                       |....|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 46 10 00 00  42 41 04 45 65 ce f7 b9  |....F...BA.Ee...|
+00000010  52 e3 fb 13 db 91 f2 65  43 84 57 f5 1a 19 a0 e6  |R......eC.W.....|
+00000020  89 2d bb 2c 83 6b 62 f6  6f 1f 26 ae 59 67 bd dc  |.-.,.kb.o.&.Yg..|
+00000030  c4 9e 0b dc 7d 6e f8 6b  95 8c 61 47 3d cd d1 df  |....}n.k..aG=...|
+00000040  82 45 30 81 c3 a3 49 5d  85 59 70 14 03 03 00 01  |.E0...I].Yp.....|
+00000050  01 16 03 03 00 28 3f aa  85 33 f9 c6 95 a0 56 ff  |.....(?..3....V.|
+00000060  1c f1 5a ba 6e 41 50 0c  ab 92 e1 e2 8e 89 1c f1  |..Z.nAP.........|
+00000070  fa 54 1b f1 f5 00 01 12  6d c4 96 78 b6 87        |.T......m..x..|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 28 00 00 00 00 00  |..........(.....|
+00000010  00 00 00 94 5c be 46 05  d6 d0 b0 3a 56 dc 2c 10  |....\.F....:V.,.|
+00000020  0f 6f 5d 33 33 7f a5 4e  74 84 bf 63 87 c4 f4 49  |.o]33..Nt..c...I|
+00000030  bc 6b ab 17 03 03 00 25  00 00 00 00 00 00 00 01  |.k.....%........|
+00000040  7e 4f f9 ae ae fe 6b a0  4a f8 0f 0b b4 b6 65 b6  |~O....k.J.....e.|
+00000050  be 24 5f 94 6d d1 db 54  11 07 b9 ce 01 15 03 03  |.$_.m..T........|
+00000060  00 1a 00 00 00 00 00 00  00 02 a8 1c d6 62 ac fd  |.............b..|
+00000070  77 ba 23 92 5d 34 f1 17  c7 e1 1c 99              |w.#.]4......|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-RC4 b/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-RC4
new file mode 100644
index 0000000..b703a8f
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-RSA-RC4
@@ -0,0 +1,79 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 5c 01 00 00  58 03 03 52 cc 57 59 c9  |....\...X..R.WY.|
+00000010  c3 13 fc 18 8a ee c2 0e  88 ff fb 4a 16 f2 eb eb  |...........J....|
+00000020  d4 f8 b3 5b cd bb 25 0e  0b cb 48 00 00 04 00 05  |...[..%...H.....|
+00000030  00 ff 01 00 00 2b 00 0d  00 22 00 20 06 01 06 02  |.....+...". ....|
+00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
+00000050  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
+00000060  01                                                |.|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 05 00 00  |................|
+00000030  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
+00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
+00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
+00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
+00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
+00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
+000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
+000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
+000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
+000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
+000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
+00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
+00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
+00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
+00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
+00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
+00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
+00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
+00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
+000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
+000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
+000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
+000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
+000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
+000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
+00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
+00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
+00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
+00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
+00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
+00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
+00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
+00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
+00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
+000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
+000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
+000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
+000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
+000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
+000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 04 0e 00  |n8P)l...........|
+00000300  00 00                                             |..|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 86 10 00 00  82 00 80 35 b3 60 ba 14  |...........5.`..|
+00000010  5f 19 24 a0 24 de 4e 85  a9 64 78 3a 51 24 64 70  |_.$.$.N..dx:Q$dp|
+00000020  88 55 6d c3 11 b8 d3 9f  bc 7a 33 f8 3c 48 93 2f  |.Um......z3.<H./|
+00000030  66 69 11 33 39 37 7a 36  a3 1c ef b0 81 71 7d 25  |fi.397z6.....q}%|
+00000040  35 da 2c 42 e2 ab d3 b7  07 8b 4a 0d 6d 77 bd ae  |5.,B......J.mw..|
+00000050  02 51 7c a5 0d a6 03 4c  3c d0 ce 89 2c 83 6c de  |.Q|....L<...,.l.|
+00000060  40 15 cc 72 c7 95 c8 6d  ee 05 86 da 3e c6 7c d4  |@..r...m....>.|.|
+00000070  44 82 f4 24 03 22 40 00  64 27 53 15 41 8c 01 e9  |D..$."@.d'S.A...|
+00000080  39 32 fa 8e 2d f9 b4 89  34 15 d6 14 03 03 00 01  |92..-...4.......|
+00000090  01 16 03 03 00 24 f5 61  8b 24 bf b4 82 3a cf 49  |.....$.a.$...:.I|
+000000a0  99 a0 b1 1b a7 a7 a3 92  7c 84 85 e0 64 a3 3d bd  |........|...d.=.|
+000000b0  38 98 7d 97 a8 b9 2a 35  a9 09                    |8.}...*5..|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 24 c9 0b 84 e6 39  |..........$....9|
+00000010  f2 e0 f3 ac 9f 0f 17 92  5f 6d de 94 18 c4 60 d9  |........_m....`.|
+00000020  66 c3 0d 1a ae c2 8f 46  8f 7f f0 58 0e 4a 9b 17  |f......F...X.J..|
+00000030  03 03 00 21 8b 73 a1 6a  7e d9 7e 4f 1d cc b2 7d  |...!.s.j~.~O...}|
+00000040  3c 83 3f 52 f8 08 77 01  4c 65 11 6d 50 25 9a cc  |<.?R..w.Le.mP%..|
+00000050  e3 54 27 72 59 15 03 03  00 16 3d c8 ab 14 51 fa  |.T'rY.....=...Q.|
+00000060  97 f1 ef 5f b4 4f 44 58  d4 93 3b ae e5 61 1f a3  |..._.ODX..;..a..|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-Resume b/src/pkg/crypto/tls/testdata/Server-TLSv12-Resume
new file mode 100644
index 0000000..c495d4a
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-Resume
@@ -0,0 +1,36 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 e8 01 00 00  e4 03 03 52 cc 57 59 c3  |...........R.WY.|
+00000010  8b df 97 05 d8 5f 16 22  b4 b1 e7 cb 7d 2f 9b 58  |....._."....}/.X|
+00000020  a3 f4 d7 2c a4 c1 9d 49  ed 4b ba 20 90 da 90 3e  |...,...I.K. ...>|
+00000030  36 19 7a db 56 43 26 f7  dc 42 57 33 22 ed 9d a4  |6.z.VC&..BW3"...|
+00000040  9d 53 da f8 9d 4e 60 66  71 a0 2e 2e 00 04 00 05  |.S...N`fq.......|
+00000050  00 ff 01 00 00 97 00 23  00 68 00 00 00 00 00 00  |.......#.h......|
+00000060  00 00 00 00 00 00 00 00  00 00 65 ea 4b d1 ef ba  |..........e.K...|
+00000070  06 38 1e e1 88 82 3a cd  03 ac 3b 39 0a e0 19 fd  |.8....:...;9....|
+00000080  af 6c 57 30 df 31 6e f7  92 38 4b 5d 77 90 39 ff  |.lW0.1n..8K]w.9.|
+00000090  32 51 f5 ed 12 d7 b0 7c  4d 6c c5 76 e4 72 48 3e  |2Q.....|Ml.v.rH>|
+000000a0  59 23 fe 0d 15 df f4 ba  ea b9 67 16 23 8f 7d 15  |Y#........g.#.}.|
+000000b0  b6 11 f1 ab d7 d4 cd a3  21 82 92 2a 12 cf 95 f3  |........!..*....|
+000000c0  60 b2 00 0d 00 22 00 20  06 01 06 02 06 03 05 01  |`....". ........|
+000000d0  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
+000000e0  02 01 02 02 02 03 01 01  00 0f 00 01 01           |.............|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 51 02 00 00  4d 03 03 00 00 00 00 00  |....Q...M.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 20 90 da 90 3e  |........... ...>|
+00000030  36 19 7a db 56 43 26 f7  dc 42 57 33 22 ed 9d a4  |6.z.VC&..BW3"...|
+00000040  9d 53 da f8 9d 4e 60 66  71 a0 2e 2e 00 05 00 00  |.S...N`fq.......|
+00000050  05 ff 01 00 01 00 14 03  03 00 01 01 16 03 03 00  |................|
+00000060  24 11 12 ff 28 10 14 4c  e5 0e ad a7 fa f3 92 fb  |$...(..L........|
+00000070  13 7d ae f2 b2 4a 6b a1  9e 67 cf a8 f7 8c 6f a0  |.}...Jk..g....o.|
+00000080  6c 30 0e 18 55                                    |l0..U|
+>>> Flow 3 (client to server)
+00000000  14 03 03 00 01 01 16 03  03 00 24 0d 46 41 8b 24  |..........$.FA.$|
+00000010  36 01 a9 fd 8b ec fc e6  b1 83 96 df 0d 3e 53 54  |6............>ST|
+00000020  58 b8 43 f2 a6 25 5e 1a  ae 19 9e d2 28 44 92     |X.C..%^.....(D.|
+>>> Flow 4 (server to client)
+00000000  17 03 03 00 21 c4 fb f6  53 bb 3e 04 cc 0b a0 03  |....!...S.>.....|
+00000010  fa 49 96 da b5 8d b2 f2  e5 d8 f3 5c 27 57 4f 9c  |.I.........\'WO.|
+00000020  30 00 34 fc 52 92 15 03  03 00 16 a3 02 7a 50 d2  |0.4.R........zP.|
+00000030  c6 b3 fc 69 8f e4 94 ae  ab 22 ad 05 1d 15 69 b9  |...i....."....i.|
+00000040  a5                                                |.|
diff --git a/src/pkg/crypto/tls/testdata/Server-TLSv12-SNI b/src/pkg/crypto/tls/testdata/Server-TLSv12-SNI
new file mode 100644
index 0000000..61b17a1
--- /dev/null
+++ b/src/pkg/crypto/tls/testdata/Server-TLSv12-SNI
@@ -0,0 +1,76 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 70 01 00 00  6c 03 03 52 cc 57 59 2d  |....p...l..R.WY-|
+00000010  77 aa 75 35 fa ff 2a a2  bf 91 5e e3 7f 38 7d 7a  |w.u5..*...^..8}z|
+00000020  e3 93 d3 e8 8b 09 bb 06  c8 6d 91 00 00 04 00 2f  |.........m...../|
+00000030  00 ff 01 00 00 3f 00 00  00 10 00 0e 00 00 0b 73  |.....?.........s|
+00000040  6e 69 74 65 73 74 2e 63  6f 6d 00 0d 00 22 00 20  |nitest.com...". |
+00000050  06 01 06 02 06 03 05 01  05 02 05 03 04 01 04 02  |................|
+00000060  04 03 03 01 03 02 03 03  02 01 02 02 02 03 01 01  |................|
+00000070  00 0f 00 01 01                                    |.....|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 2f 00 00  |............./..|
+00000030  05 ff 01 00 01 00 16 03  03 02 00 0b 00 01 fc 00  |................|
+00000040  01 f9 00 01 f6 30 82 01  f2 30 82 01 5d a0 03 02  |.....0...0..]...|
+00000050  01 02 02 01 00 30 0b 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
+00000060  01 05 30 28 31 10 30 0e  06 03 55 04 0a 13 07 41  |..0(1.0...U....A|
+00000070  63 6d 65 20 43 6f 31 14  30 12 06 03 55 04 03 13  |cme Co1.0...U...|
+00000080  0b 73 6e 69 74 65 73 74  2e 63 6f 6d 30 1e 17 0d  |.snitest.com0...|
+00000090  31 32 30 34 31 31 31 37  34 30 33 35 5a 17 0d 31  |120411174035Z..1|
+000000a0  33 30 34 31 31 31 37 34  35 33 35 5a 30 28 31 10  |30411174535Z0(1.|
+000000b0  30 0e 06 03 55 04 0a 13  07 41 63 6d 65 20 43 6f  |0...U....Acme Co|
+000000c0  31 14 30 12 06 03 55 04  03 13 0b 73 6e 69 74 65  |1.0...U....snite|
+000000d0  73 74 2e 63 6f 6d 30 81  9d 30 0b 06 09 2a 86 48  |st.com0..0...*.H|
+000000e0  86 f7 0d 01 01 01 03 81  8d 00 30 81 89 02 81 81  |..........0.....|
+000000f0  00 bb 79 d6 f5 17 b5 e5  bf 46 10 d0 dc 69 be e6  |..y......F...i..|
+00000100  2b 07 43 5a d0 03 2d 8a  7a 43 85 b7 14 52 e7 a5  |+.CZ..-.zC...R..|
+00000110  65 4c 2c 78 b8 23 8c b5  b4 82 e5 de 1f 95 3b 7e  |eL,x.#........;~|
+00000120  62 a5 2c a5 33 d6 fe 12  5c 7a 56 fc f5 06 bf fa  |b.,.3...\zV.....|
+00000130  58 7b 26 3f b5 cd 04 d3  d0 c9 21 96 4a c7 f4 54  |X{&?......!.J..T|
+00000140  9f 5a bf ef 42 71 00 fe  18 99 07 7f 7e 88 7d 7d  |.Z..Bq......~.}}|
+00000150  f1 04 39 c4 a2 2e db 51  c9 7c e3 c0 4c 3b 32 66  |..9....Q.|..L;2f|
+00000160  01 cf af b1 1d b8 71 9a  1d db db 89 6b ae da 2d  |......q.....k..-|
+00000170  79 02 03 01 00 01 a3 32  30 30 30 0e 06 03 55 1d  |y......2000...U.|
+00000180  0f 01 01 ff 04 04 03 02  00 a0 30 0d 06 03 55 1d  |..........0...U.|
+00000190  0e 04 06 04 04 01 02 03  04 30 0f 06 03 55 1d 23  |.........0...U.#|
+000001a0  04 08 30 06 80 04 01 02  03 04 30 0b 06 09 2a 86  |..0.......0...*.|
+000001b0  48 86 f7 0d 01 01 05 03  81 81 00 89 c6 45 5f 1c  |H............E_.|
+000001c0  1f 5e f8 eb 1a b1 74 ee  24 39 05 9f 5c 42 59 bb  |.^....t.$9..\BY.|
+000001d0  1a 8d 86 cd b1 d0 56 f5  6a 71 7d a4 0e 95 ab 90  |......V.jq}.....|
+000001e0  f5 9e 8d ea f6 27 c1 57  99 50 94 db 08 02 26 6e  |.....'.W.P....&n|
+000001f0  b3 4f c6 84 2d ea 8a 4b  68 d9 c1 38 91 03 ab 84  |.O..-..Kh..8....|
+00000200  fb 9e 1f 85 d9 b5 d2 3f  f2 31 2c 86 70 fb b5 40  |.......?.1,.p..@|
+00000210  14 82 45 a4 eb af e2 64  d9 0c 8a 4c f4 f8 5b 0f  |..E....d...L..[.|
+00000220  ac 12 ac 2f c4 a3 15 4b  ad 52 46 28 68 af 96 c6  |.../...K.RF(h...|
+00000230  2c 65 25 d6 52 b6 e3 18  45 bd cc 16 03 03 00 04  |,e%.R...E.......|
+00000240  0e 00 00 00                                       |....|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 86 10 00 00  82 00 80 0d f2 bf 75 a9  |..............u.|
+00000010  aa db f3 25 55 d4 20 59  63 54 d1 70 82 f9 61 c5  |...%U. YcT.p..a.|
+00000020  b7 ae 3f 75 71 75 9d c5  01 a1 ed b1 07 66 9f 3f  |..?uqu.......f.?|
+00000030  cf c6 e6 ad 44 03 fd 18  6f 53 24 ce 76 01 bd fe  |....D...oS$.v...|
+00000040  e2 51 f7 df 8a 23 3a 21  c4 00 15 ff d0 e0 ff c8  |.Q...#:!........|
+00000050  8b 89 33 c6 8e e0 ce 97  ef b4 c6 f9 b0 ea 38 89  |..3...........8.|
+00000060  79 98 34 9e f7 bc c6 fd  d2 5d 56 84 5c d2 9a ce  |y.4......]V.\...|
+00000070  ae de 09 bc 24 25 fc 09  0c bc 0e 91 0d 6b 36 ae  |....$%.......k6.|
+00000080  ce 6b cd 14 ec b6 3c fa  d6 df fc 14 03 03 00 01  |.k....<.........|
+00000090  01 16 03 03 00 40 ad 21  13 2b 33 7a 4a 0d fb 0f  |..... at .!.+3zJ...|
+000000a0  eb d2 b6 85 29 1f 59 79  ba 86 53 5c 68 b4 c7 e3  |....).Yy..S\h...|
+000000b0  8a 6c 5c 18 04 4d e4 76  19 30 ba 92 b4 79 8c 64  |.l\..M.v.0...y.d|
+000000c0  00 a0 2e 13 96 45 9f e7  a9 e4 23 9e 9f 89 23 26  |.....E....#...#&|
+000000d0  36 20 82 fc 75 fe                                 |6 ..u.|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 40 00 00 00 00 00  |.......... at .....|
+00000010  00 00 00 00 00 00 00 00  00 00 00 b7 87 61 10 03  |.............a..|
+00000020  b8 a4 42 d4 8b 49 bc 40  80 70 92 c8 25 b0 c6 7f  |..B..I. at .p..%...|
+00000030  b3 87 76 50 5a 59 b3 3c  d8 3e 23 24 aa 1a f3 36  |..vPZY.<.>#$...6|
+00000040  c9 2c 87 c1 22 d2 94 f8  2c fd ef 17 03 03 00 40  |.,.."...,......@|
+00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000060  e5 7f bd 3e ff 9f d4 1b  91 02 f8 69 6f 70 9d 51  |...>.......iop.Q|
+00000070  a5 ec ef 5b 10 3f 4e 3f  44 e5 9a 39 68 7c 3a b9  |...[.?N?D..9h|:.|
+00000080  69 38 31 ec 9c 45 bf 19  d1 5c 5e 2e 06 00 ca 19  |i81..E...\^.....|
+00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
+000000a0  00 00 00 00 00 63 5e 79  2c f2 05 dc 2b d7 5b ac  |.....c^y,...+.[.|
+000000b0  9d fc 75 94 03 16 ca 1f  b2 75 58 2d f1 2f f1 1e  |..u......uX-./..|
+000000c0  d2 f6 84 8f 2e                                    |.....|
diff --git a/src/pkg/crypto/tls/tls.go b/src/pkg/crypto/tls/tls.go
index 6c67506..d50e120 100644
--- a/src/pkg/crypto/tls/tls.go
+++ b/src/pkg/crypto/tls/tls.go
@@ -15,6 +15,7 @@ import (
 	"io/ioutil"
 	"net"
 	"strings"
+	"time"
 )
 
 // Server returns a new TLS server side connection
@@ -27,9 +28,8 @@ func Server(conn net.Conn, config *Config) *Conn {
 
 // Client returns a new TLS client side connection
 // using conn as the underlying transport.
-// Client interprets a nil configuration as equivalent to
-// the zero configuration; see the documentation of Config
-// for the defaults.
+// The config cannot be nil: users must set either ServerName or
+// InsecureSkipVerify in the config.
 func Client(conn net.Conn, config *Config) *Conn {
 	return &Conn{conn: conn, config: config, isClient: true}
 }
@@ -77,24 +77,51 @@ func Listen(network, laddr string, config *Config) (net.Listener, error) {
 	return NewListener(l, config), nil
 }
 
-// Dial connects to the given network address using net.Dial
-// and then initiates a TLS handshake, returning the resulting
-// TLS connection.
-// Dial interprets a nil configuration as equivalent to
-// the zero configuration; see the documentation of Config
-// for the defaults.
-func Dial(network, addr string, config *Config) (*Conn, error) {
-	raddr := addr
-	c, err := net.Dial(network, raddr)
+type timeoutError struct{}
+
+func (timeoutError) Error() string   { return "tls: DialWithDialer timed out" }
+func (timeoutError) Timeout() bool   { return true }
+func (timeoutError) Temporary() bool { return true }
+
+// DialWithDialer connects to the given network address using dialer.Dial and
+// then initiates a TLS handshake, returning the resulting TLS connection. Any
+// timeout or deadline given in the dialer apply to connection and TLS
+// handshake as a whole.
+//
+// DialWithDialer interprets a nil configuration as equivalent to the zero
+// configuration; see the documentation of Config for the defaults.
+func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) {
+	// We want the Timeout and Deadline values from dialer to cover the
+	// whole process: TCP connection and TLS handshake. This means that we
+	// also need to start our own timers now.
+	timeout := dialer.Timeout
+
+	if !dialer.Deadline.IsZero() {
+		deadlineTimeout := dialer.Deadline.Sub(time.Now())
+		if timeout == 0 || deadlineTimeout < timeout {
+			timeout = deadlineTimeout
+		}
+	}
+
+	var errChannel chan error
+
+	if timeout != 0 {
+		errChannel = make(chan error, 2)
+		time.AfterFunc(timeout, func() {
+			errChannel <- timeoutError{}
+		})
+	}
+
+	rawConn, err := dialer.Dial(network, addr)
 	if err != nil {
 		return nil, err
 	}
 
-	colonPos := strings.LastIndex(raddr, ":")
+	colonPos := strings.LastIndex(addr, ":")
 	if colonPos == -1 {
-		colonPos = len(raddr)
+		colonPos = len(addr)
 	}
-	hostname := raddr[:colonPos]
+	hostname := addr[:colonPos]
 
 	if config == nil {
 		config = defaultConfig()
@@ -107,14 +134,37 @@ func Dial(network, addr string, config *Config) (*Conn, error) {
 		c.ServerName = hostname
 		config = &c
 	}
-	conn := Client(c, config)
-	if err = conn.Handshake(); err != nil {
-		c.Close()
+
+	conn := Client(rawConn, config)
+
+	if timeout == 0 {
+		err = conn.Handshake()
+	} else {
+		go func() {
+			errChannel <- conn.Handshake()
+		}()
+
+		err = <-errChannel
+	}
+
+	if err != nil {
+		rawConn.Close()
 		return nil, err
 	}
+
 	return conn, nil
 }
 
+// Dial connects to the given network address using net.Dial
+// and then initiates a TLS handshake, returning the resulting
+// TLS connection.
+// Dial interprets a nil configuration as equivalent to
+// the zero configuration; see the documentation of Config
+// for the defaults.
+func Dial(network, addr string, config *Config) (*Conn, error) {
+	return DialWithDialer(new(net.Dialer), network, addr, config)
+}
+
 // LoadX509KeyPair reads and parses a public/private key pair from a pair of
 // files. The files must contain PEM encoded data.
 func LoadX509KeyPair(certFile, keyFile string) (cert Certificate, err error) {
diff --git a/src/pkg/crypto/tls/tls_test.go b/src/pkg/crypto/tls/tls_test.go
index 3822901..f8c94ff 100644
--- a/src/pkg/crypto/tls/tls_test.go
+++ b/src/pkg/crypto/tls/tls_test.go
@@ -5,7 +5,12 @@
 package tls
 
 import (
+	"fmt"
+	"io"
+	"net"
+	"strings"
 	"testing"
+	"time"
 )
 
 var rsaCertPEM = `-----BEGIN CERTIFICATE-----
@@ -105,3 +110,128 @@ func TestX509MixedKeyPair(t *testing.T) {
 		t.Error("Load of ECDSA certificate succeeded with RSA private key")
 	}
 }
+
+func newLocalListener(t *testing.T) net.Listener {
+	ln, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		ln, err = net.Listen("tcp6", "[::1]:0")
+	}
+	if err != nil {
+		t.Fatal(err)
+	}
+	return ln
+}
+
+func TestDialTimeout(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping in short mode")
+	}
+	listener := newLocalListener(t)
+
+	addr := listener.Addr().String()
+	defer listener.Close()
+
+	complete := make(chan bool)
+	defer close(complete)
+
+	go func() {
+		conn, err := listener.Accept()
+		if err != nil {
+			t.Error(err)
+			return
+		}
+		<-complete
+		conn.Close()
+	}()
+
+	dialer := &net.Dialer{
+		Timeout: 10 * time.Millisecond,
+	}
+
+	var err error
+	if _, err = DialWithDialer(dialer, "tcp", addr, nil); err == nil {
+		t.Fatal("DialWithTimeout completed successfully")
+	}
+
+	if !strings.Contains(err.Error(), "timed out") {
+		t.Errorf("resulting error not a timeout: %s", err)
+	}
+}
+
+// tests that Conn.Read returns (non-zero, io.EOF) instead of
+// (non-zero, nil) when a Close (alertCloseNotify) is sitting right
+// behind the application data in the buffer.
+func TestConnReadNonzeroAndEOF(t *testing.T) {
+	// This test is racy: it assumes that after a write to a
+	// localhost TCP connection, the peer TCP connection can
+	// immediately read it.  Because it's racy, we skip this test
+	// in short mode, and then retry it several times with an
+	// increasing sleep in between our final write (via srv.Close
+	// below) and the following read.
+	if testing.Short() {
+		t.Skip("skipping in short mode")
+	}
+	var err error
+	for delay := time.Millisecond; delay <= 64*time.Millisecond; delay *= 2 {
+		if err = testConnReadNonzeroAndEOF(t, delay); err == nil {
+			return
+		}
+	}
+	t.Error(err)
+}
+
+func testConnReadNonzeroAndEOF(t *testing.T, delay time.Duration) error {
+	ln := newLocalListener(t)
+	defer ln.Close()
+
+	srvCh := make(chan *Conn, 1)
+	var serr error
+	go func() {
+		sconn, err := ln.Accept()
+		if err != nil {
+			serr = err
+			srvCh <- nil
+			return
+		}
+		serverConfig := *testConfig
+		srv := Server(sconn, &serverConfig)
+		if err := srv.Handshake(); err != nil {
+			serr = fmt.Errorf("handshake: %v", err)
+			srvCh <- nil
+			return
+		}
+		srvCh <- srv
+	}()
+
+	clientConfig := *testConfig
+	conn, err := Dial("tcp", ln.Addr().String(), &clientConfig)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer conn.Close()
+
+	srv := <-srvCh
+	if srv == nil {
+		return serr
+	}
+
+	buf := make([]byte, 6)
+
+	srv.Write([]byte("foobar"))
+	n, err := conn.Read(buf)
+	if n != 6 || err != nil || string(buf) != "foobar" {
+		return fmt.Errorf("Read = %d, %v, data %q; want 6, nil, foobar", n, err, buf)
+	}
+
+	srv.Write([]byte("abcdef"))
+	srv.Close()
+	time.Sleep(delay)
+	n, err = conn.Read(buf)
+	if n != 6 || string(buf) != "abcdef" {
+		return fmt.Errorf("Read = %d, buf= %q; want 6, abcdef", n, buf)
+	}
+	if err != io.EOF {
+		return fmt.Errorf("Second Read error = %v; want io.EOF", err)
+	}
+	return nil
+}
diff --git a/src/pkg/crypto/x509/example_test.go b/src/pkg/crypto/x509/example_test.go
new file mode 100644
index 0000000..29e7c21
--- /dev/null
+++ b/src/pkg/crypto/x509/example_test.go
@@ -0,0 +1,91 @@
+// 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 x509_test
+
+import (
+	"crypto/x509"
+	"encoding/pem"
+)
+
+func ExampleCertificate_Verify() {
+	// Verifying with a custom list of root certificates.
+
+	const rootPEM = `
+-----BEGIN CERTIFICATE-----
+MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG
+EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy
+bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP
+VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv
+h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE
+ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ
+EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC
+DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7
+qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD
+VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g
+K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI
+KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n
+ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB
+BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY
+/iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/
+zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza
+HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto
+WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6
+yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx
+-----END CERTIFICATE-----`
+
+	const certPEM = `
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgIIE31FZVaPXTUwDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
+BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
+cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMTI5MTMyNzQzWhcNMTQwNTI5MDAwMDAw
+WjBpMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
+TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEYMBYGA1UEAwwPbWFp
+bC5nb29nbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfRrObuSW5T7q
+5CnSEqefEmtH4CCv6+5EckuriNr1CjfVvqzwfAhopXkLrq45EQm8vkmf7W96XJhC
+7ZM0dYi1/qOCAU8wggFLMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAa
+BgNVHREEEzARgg9tYWlsLmdvb2dsZS5jb20wCwYDVR0PBAQDAgeAMGgGCCsGAQUF
+BwEBBFwwWjArBggrBgEFBQcwAoYfaHR0cDovL3BraS5nb29nbGUuY29tL0dJQUcy
+LmNydDArBggrBgEFBQcwAYYfaHR0cDovL2NsaWVudHMxLmdvb2dsZS5jb20vb2Nz
+cDAdBgNVHQ4EFgQUiJxtimAuTfwb+aUtBn5UYKreKvMwDAYDVR0TAQH/BAIwADAf
+BgNVHSMEGDAWgBRK3QYWG7z2aLV29YG2u2IaulqBLzAXBgNVHSAEEDAOMAwGCisG
+AQQB1nkCBQEwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL3BraS5nb29nbGUuY29t
+L0dJQUcyLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAH6RYHxHdcGpMpFE3oxDoFnP+
+gtuBCHan2yE2GRbJ2Cw8Lw0MmuKqHlf9RSeYfd3BXeKkj1qO6TVKwCh+0HdZk283
+TZZyzmEOyclm3UGFYe82P/iDFt+CeQ3NpmBg+GoaVCuWAARJN/KfglbLyyYygcQq
+0SgeDh8dRKUiaW3HQSoYvTvdTuqzwK4CXsr3b5/dAOY8uMuG/IAR3FgwTbZ1dtoW
+RvOTa8hYiU6A475WuZKyEHcwnGYe57u2I2KbMgcKjPniocj4QzgYsVAVKW3IwaOh
+yE+vPxsiUkvQHdO2fojCkY8jg70jxM+gu59tPDNbw3Uh/2Ij310FgTHsnGQMyA==
+-----END CERTIFICATE-----`
+
+	// First, create the set of root certificates. For this example we only
+	// have one. It's also possible to omit this in order to use the
+	// default root set of the current operating system.
+	roots := x509.NewCertPool()
+	ok := roots.AppendCertsFromPEM([]byte(rootPEM))
+	if !ok {
+		panic("failed to parse root certificate")
+	}
+
+	block, _ := pem.Decode([]byte(certPEM))
+	if block == nil {
+		panic("failed to parse certificate PEM")
+	}
+	cert, err := x509.ParseCertificate(block.Bytes)
+	if err != nil {
+		panic("failed to parse certificate: " + err.Error())
+	}
+
+	opts := x509.VerifyOptions{
+		DNSName: "mail.google.com",
+		Roots:   roots,
+	}
+
+	if _, err := cert.Verify(opts); err != nil {
+		panic("failed to verify certificate: " + err.Error())
+	}
+}
diff --git a/src/pkg/crypto/x509/pkix/pkix.go b/src/pkg/crypto/x509/pkix/pkix.go
index 5034946..58c1e54 100644
--- a/src/pkg/crypto/x509/pkix/pkix.go
+++ b/src/pkg/crypto/x509/pkix/pkix.go
@@ -30,6 +30,13 @@ type AttributeTypeAndValue struct {
 	Value interface{}
 }
 
+// AttributeTypeAndValueSET represents a set of ASN.1 sequences of
+// AttributeTypeAndValue sequences from RFC 2986 (PKCS #10).
+type AttributeTypeAndValueSET struct {
+	Type  asn1.ObjectIdentifier
+	Value [][]AttributeTypeAndValue `asn1:"set"`
+}
+
 // Extension represents the ASN.1 structure of the same name. See RFC
 // 5280, section 4.2.
 type Extension struct {
diff --git a/src/pkg/crypto/x509/root_cgo_darwin.go b/src/pkg/crypto/x509/root_cgo_darwin.go
new file mode 100644
index 0000000..bdcc2c1
--- /dev/null
+++ b/src/pkg/crypto/x509/root_cgo_darwin.go
@@ -0,0 +1,79 @@
+// 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.
+
+// +build cgo
+
+package x509
+
+/*
+#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
+#cgo LDFLAGS: -framework CoreFoundation -framework Security
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/Security.h>
+
+// FetchPEMRoots fetches the system's list of trusted X.509 root certificates.
+//
+// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
+// certificates of the system. On failure, the function returns -1.
+//
+// Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after
+// we've consumed its content.
+int FetchPEMRoots(CFDataRef *pemRoots) {
+	if (pemRoots == NULL) {
+		return -1;
+	}
+
+	CFArrayRef certs = NULL;
+	OSStatus err = SecTrustCopyAnchorCertificates(&certs);
+	if (err != noErr) {
+		return -1;
+	}
+
+	CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
+	int i, ncerts = CFArrayGetCount(certs);
+	for (i = 0; i < ncerts; i++) {
+		CFDataRef data = NULL;
+		SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
+		if (cert == NULL) {
+			continue;
+		}
+
+		// Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
+		// Once we support weak imports via cgo we should prefer that, and fall back to this
+		// for older systems.
+		err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
+		if (err != noErr) {
+			continue;
+		}
+
+		if (data != NULL) {
+			CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
+			CFRelease(data);
+		}
+	}
+
+	CFRelease(certs);
+
+	*pemRoots = combinedData;
+	return 0;
+}
+*/
+import "C"
+import "unsafe"
+
+func initSystemRoots() {
+	roots := NewCertPool()
+
+	var data C.CFDataRef = nil
+	err := C.FetchPEMRoots(&data)
+	if err == -1 {
+		return
+	}
+
+	defer C.CFRelease(C.CFTypeRef(data))
+	buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data)))
+	roots.AppendCertsFromPEM(buf)
+	systemRoots = roots
+}
diff --git a/src/pkg/crypto/x509/root_darwin.go b/src/pkg/crypto/x509/root_darwin.go
index ad3bfb4..2a61d36 100644
--- a/src/pkg/crypto/x509/root_darwin.go
+++ b/src/pkg/crypto/x509/root_darwin.go
@@ -1,81 +1,23 @@
-// Copyright 2011 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.
 
 package x509
 
-/*
-#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
-#cgo LDFLAGS: -framework CoreFoundation -framework Security
-
-#include <CoreFoundation/CoreFoundation.h>
-#include <Security/Security.h>
-
-// FetchPEMRoots fetches the system's list of trusted X.509 root certificates.
-//
-// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
-// certificates of the system. On failure, the function returns -1.
-//
-// Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after
-// we've consumed its content.
-int FetchPEMRoots(CFDataRef *pemRoots) {
-	if (pemRoots == NULL) {
-		return -1;
-	}
-
-	CFArrayRef certs = NULL;
-	OSStatus err = SecTrustCopyAnchorCertificates(&certs);
-	if (err != noErr) {
-		return -1;
-	}
-
-	CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
-	int i, ncerts = CFArrayGetCount(certs);
-	for (i = 0; i < ncerts; i++) {
-		CFDataRef data = NULL;
-		SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
-		if (cert == NULL) {
-			continue;
-		}
-
-		// Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
-		// Once we support weak imports via cgo we should prefer that, and fall back to this
-		// for older systems.
-		err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
-		if (err != noErr) {
-			continue;
-		}
-
-		if (data != NULL) {
-			CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
-			CFRelease(data);
-		}
-	}
-
-	CFRelease(certs);
-
-	*pemRoots = combinedData;
-	return 0;
-}
-*/
-import "C"
-import "unsafe"
+import "os/exec"
 
 func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
 	return nil, nil
 }
 
-func initSystemRoots() {
-	roots := NewCertPool()
-
-	var data C.CFDataRef = nil
-	err := C.FetchPEMRoots(&data)
-	if err == -1 {
-		return
+func execSecurityRoots() (*CertPool, error) {
+	cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain")
+	data, err := cmd.Output()
+	if err != nil {
+		return nil, err
 	}
 
-	defer C.CFRelease(C.CFTypeRef(data))
-	buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data)))
-	roots.AppendCertsFromPEM(buf)
-	systemRoots = roots
+	roots := NewCertPool()
+	roots.AppendCertsFromPEM(data)
+	return roots, nil
 }
diff --git a/src/pkg/crypto/x509/root_darwin_test.go b/src/pkg/crypto/x509/root_darwin_test.go
new file mode 100644
index 0000000..87ea4e3
--- /dev/null
+++ b/src/pkg/crypto/x509/root_darwin_test.go
@@ -0,0 +1,50 @@
+package x509
+
+import "testing"
+
+func TestSystemRoots(t *testing.T) {
+	sysRoots := systemRootsPool()         // actual system roots
+	execRoots, err := execSecurityRoots() // non-cgo roots
+
+	if err != nil {
+		t.Fatalf("failed to read system roots: %v", err)
+	}
+
+	for _, tt := range []*CertPool{sysRoots, execRoots} {
+		if tt == nil {
+			t.Fatal("no system roots")
+		}
+		// On Mavericks, there are 212 bundled certs; require only
+		// 150 here, since this is just a sanity check, and the
+		// exact number will vary over time.
+		if want, have := 150, len(tt.certs); have < want {
+			t.Fatalf("want at least %d system roots, have %d", want, have)
+		}
+	}
+
+	// Check that the two cert pools are roughly the same;
+	// |A∩B| > max(|A|, |B|) / 2 should be a reasonably robust check.
+
+	isect := make(map[string]bool, len(sysRoots.certs))
+	for _, c := range sysRoots.certs {
+		isect[string(c.Raw)] = true
+	}
+
+	have := 0
+	for _, c := range execRoots.certs {
+		if isect[string(c.Raw)] {
+			have++
+		}
+	}
+
+	var want int
+	if nsys, nexec := len(sysRoots.certs), len(execRoots.certs); nsys > nexec {
+		want = nsys / 2
+	} else {
+		want = nexec / 2
+	}
+
+	if have < want {
+		t.Errorf("insufficent overlap between cgo and non-cgo roots; want at least %d, have %d", want, have)
+	}
+}
diff --git a/src/pkg/crypto/x509/root_nocgo_darwin.go b/src/pkg/crypto/x509/root_nocgo_darwin.go
new file mode 100644
index 0000000..d00e257
--- /dev/null
+++ b/src/pkg/crypto/x509/root_nocgo_darwin.go
@@ -0,0 +1,11 @@
+// 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 !cgo
+
+package x509
+
+func initSystemRoots() {
+	systemRoots, _ = execSecurityRoots()
+}
diff --git a/src/pkg/crypto/x509/root_stub.go b/src/pkg/crypto/x509/root_stub.go
deleted file mode 100644
index 4c742cc..0000000
--- a/src/pkg/crypto/x509/root_stub.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// 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.
-
-// +build darwin,!cgo
-
-package x509
-
-func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
-	return nil, nil
-}
-
-func initSystemRoots() {
-}
diff --git a/src/pkg/crypto/x509/root_unix.go b/src/pkg/crypto/x509/root_unix.go
index 324f855..11ad3c4 100644
--- a/src/pkg/crypto/x509/root_unix.go
+++ b/src/pkg/crypto/x509/root_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 dragonfly freebsd linux openbsd netbsd
+// +build dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package x509
 
diff --git a/src/pkg/crypto/x509/verify.go b/src/pkg/crypto/x509/verify.go
index 8327463..5fd8e37 100644
--- a/src/pkg/crypto/x509/verify.go
+++ b/src/pkg/crypto/x509/verify.go
@@ -425,6 +425,7 @@ func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
 	// by each certificate. If we cross out all the usages, then the chain
 	// is unacceptable.
 
+NextCert:
 	for i := len(chain) - 1; i >= 0; i-- {
 		cert := chain[i]
 		if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
@@ -435,7 +436,7 @@ func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
 		for _, usage := range cert.ExtKeyUsage {
 			if usage == ExtKeyUsageAny {
 				// The certificate is explicitly good for any usage.
-				continue
+				continue NextCert
 			}
 		}
 
diff --git a/src/pkg/crypto/x509/verify_test.go b/src/pkg/crypto/x509/verify_test.go
index ba6c13d..96b9d9b 100644
--- a/src/pkg/crypto/x509/verify_test.go
+++ b/src/pkg/crypto/x509/verify_test.go
@@ -31,8 +31,8 @@ type verifyTest struct {
 var verifyTests = []verifyTest{
 	{
 		leaf:                 googleLeaf,
-		intermediates:        []string{thawteIntermediate},
-		currentTime:          1302726541,
+		intermediates:        []string{giag2Intermediate},
+		currentTime:          1395785200,
 		dnsName:              "www.google.com",
 		testSystemRootsError: true,
 
@@ -42,39 +42,39 @@ var verifyTests = []verifyTest{
 	},
 	{
 		leaf:          googleLeaf,
-		intermediates: []string{thawteIntermediate},
-		roots:         []string{verisignRoot},
-		currentTime:   1302726541,
+		intermediates: []string{giag2Intermediate},
+		roots:         []string{geoTrustRoot},
+		currentTime:   1395785200,
 		dnsName:       "www.google.com",
 
 		expectedChains: [][]string{
-			{"Google", "Thawte", "VeriSign"},
+			{"Google", "Google Internet Authority", "GeoTrust"},
 		},
 	},
 	{
 		leaf:          googleLeaf,
-		intermediates: []string{thawteIntermediate},
-		roots:         []string{verisignRoot},
-		currentTime:   1302726541,
+		intermediates: []string{giag2Intermediate},
+		roots:         []string{geoTrustRoot},
+		currentTime:   1395785200,
 		dnsName:       "WwW.GooGLE.coM",
 
 		expectedChains: [][]string{
-			{"Google", "Thawte", "VeriSign"},
+			{"Google", "Google Internet Authority", "GeoTrust"},
 		},
 	},
 	{
 		leaf:          googleLeaf,
-		intermediates: []string{thawteIntermediate},
-		roots:         []string{verisignRoot},
-		currentTime:   1302726541,
+		intermediates: []string{giag2Intermediate},
+		roots:         []string{geoTrustRoot},
+		currentTime:   1395785200,
 		dnsName:       "www.example.com",
 
 		errorCallback: expectHostnameError,
 	},
 	{
 		leaf:          googleLeaf,
-		intermediates: []string{thawteIntermediate},
-		roots:         []string{verisignRoot},
+		intermediates: []string{giag2Intermediate},
+		roots:         []string{geoTrustRoot},
 		currentTime:   1,
 		dnsName:       "www.example.com",
 
@@ -82,8 +82,8 @@ var verifyTests = []verifyTest{
 	},
 	{
 		leaf:        googleLeaf,
-		roots:       []string{verisignRoot},
-		currentTime: 1302726541,
+		roots:       []string{geoTrustRoot},
+		currentTime: 1395785200,
 		dnsName:     "www.google.com",
 
 		// Skip when using systemVerify, since Windows
@@ -93,14 +93,22 @@ var verifyTests = []verifyTest{
 	},
 	{
 		leaf:          googleLeaf,
-		intermediates: []string{verisignRoot, thawteIntermediate},
-		roots:         []string{verisignRoot},
-		currentTime:   1302726541,
+		intermediates: []string{geoTrustRoot, giag2Intermediate},
+		roots:         []string{geoTrustRoot},
+		currentTime:   1395785200,
 		dnsName:       "www.google.com",
 
 		expectedChains: [][]string{
-			{"Google", "Thawte", "VeriSign"},
+			{"Google", "Google Internet Authority", "GeoTrust"},
+			// TODO(agl): this is ok, but it would be nice if the
+			//            chain building didn't visit the same SPKI
+			//            twice.
+			{"Google", "Google Internet Authority", "GeoTrust", "GeoTrust"},
 		},
+		// CAPI doesn't build the chain with the duplicated GeoTrust
+		// entry so the results don't match. Thus we skip this test
+		// until that's fixed.
+		systemSkip: true,
 	},
 	{
 		leaf:          dnssecExpLeaf,
@@ -128,9 +136,9 @@ var verifyTests = []verifyTest{
 	},
 	{
 		leaf:          googleLeafWithInvalidHash,
-		intermediates: []string{thawteIntermediate},
-		roots:         []string{verisignRoot},
-		currentTime:   1302726541,
+		intermediates: []string{giag2Intermediate},
+		roots:         []string{geoTrustRoot},
+		currentTime:   1395785200,
 		dnsName:       "www.google.com",
 
 		// The specific error message may not occur when using system
@@ -201,6 +209,24 @@ var verifyTests = []verifyTest{
 			},
 		},
 	},
+	{
+		// Check that SHA-384 intermediates (which are popping up)
+		// work.
+		leaf:          moipLeafCert,
+		intermediates: []string{comodoIntermediateSHA384, comodoRSAAuthority},
+		roots:         []string{addTrustRoot},
+		currentTime:   1397502195,
+		dnsName:       "api.moip.com.br",
+
+		expectedChains: [][]string{
+			{
+				"api.moip.com.br",
+				"COMODO RSA Extended Validation Secure Server CA",
+				"COMODO RSA Certification Authority",
+				"AddTrust External CA Root",
+			},
+		},
+	},
 }
 
 func expectHostnameError(t *testing.T, i int, err error) (ok bool) {
@@ -385,84 +411,111 @@ func nameToKey(name *pkix.Name) string {
 	return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName
 }
 
-const verisignRoot = `-----BEGIN CERTIFICATE-----
-MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG
-A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
-cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
-MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
-BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
-YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
-ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
-BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
-I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
-CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do
-lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc
-AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
+const geoTrustRoot = `-----BEGIN CERTIFICATE-----
+MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
+R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
+9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
+fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
+iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
+1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
+MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
+ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
+uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
+Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
+tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
+PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
+hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
+5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
 -----END CERTIFICATE-----
 `
 
-const thawteIntermediate = `-----BEGIN CERTIFICATE-----
-MIIDIzCCAoygAwIBAgIEMAAAAjANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJV
-UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDMgUHVi
-bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNTEzMDAw
-MDAwWhcNMTQwNTEyMjM1OTU5WjBMMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh
-d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBD
-QTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1NNn0I0Vf67NMf59HZGhPwtx
-PKzMyGT7Y/wySweUvW+Aui/hBJPAM/wJMyPpC3QrccQDxtLN4i/1CWPN/0ilAL/g
-5/OIty0y3pg25gqtAHvEZEo7hHUD8nCSfQ5i9SGraTaEMXWQ+L/HbIgbBpV8yeWo
-3nWhLHpo39XKHIdYYBkCAwEAAaOB/jCB+zASBgNVHRMBAf8ECDAGAQH/AgEAMAsG
-A1UdDwQEAwIBBjARBglghkgBhvhCAQEEBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAX
-BgNVBAMTEFByaXZhdGVMYWJlbDMtMTUwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDov
-L2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwMgYIKwYBBQUHAQEEJjAkMCIGCCsG
-AQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMDQGA1UdJQQtMCsGCCsGAQUF
-BwMBBggrBgEFBQcDAgYJYIZIAYb4QgQBBgpghkgBhvhFAQgBMA0GCSqGSIb3DQEB
-BQUAA4GBAFWsY+reod3SkF+fC852vhNRj5PZBSvIG3dLrWlQoe7e3P3bB+noOZTc
-q3J5Lwa/q4FwxKjt6lM07e8eU9kGx1Yr0Vz00YqOtCuxN5BICEIlxT6Ky3/rbwTR
-bcV0oveifHtgPHfNDs5IAn8BL7abN+AqKjbc1YXWrOU/VG+WHgWv
+const giag2Intermediate = `-----BEGIN CERTIFICATE-----
+MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG
+EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy
+bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP
+VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv
+h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE
+ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ
+EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC
+DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7
+qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD
+VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g
+K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI
+KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n
+ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB
+BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY
+/iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/
+zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza
+HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto
+WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6
+yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx
 -----END CERTIFICATE-----
 `
 
 const googleLeaf = `-----BEGIN CERTIFICATE-----
-MIIDITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BAQUFADBM
-MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg
-THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0wOTEyMTgwMDAwMDBaFw0x
-MTEyMTgyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh
-MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw
-FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
-gYEA6PmGD5D6htffvXImttdEAoN4c9kCKO+IRTn7EOh8rqk41XXGOOsKFQebg+jN
-gtXj9xVoRaELGYW84u+E593y17iYwqG7tcFR39SDAqc9BkJb4SLD3muFXxzW2k6L
-05vuuWciKh0R73mkszeK9P4Y/bz5RiNQl/Os/CRGK1w7t0UCAwEAAaOB5zCB5DAM
-BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl
-LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF
-BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw
-Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0
-ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF
-AAOBgQCfQ89bxFApsb/isJr/aiEdLRLDLE5a+RLizrmCUi3nHX4adpaQedEkUjh5
-u2ONgJd8IyAPkU0Wueru9G2Jysa9zCRo1kNbzipYvzwY4OA8Ys+WAi0oR1A04Se6
-z5nRUP8pJcA2NhUzUnC+MY+f6H/nEQyNv4SgQhqAibAxWEEHXw==
------END CERTIFICATE-----`
+MIIEdjCCA16gAwIBAgIIcR5k4dkoe04wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
+BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
+cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMzEyMDkzODMwWhcNMTQwNjEwMDAwMDAw
+WjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
+TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UEAwwOd3d3
+Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4zYCe
+m0oUBhwE0EwBr65eBOcgcQO2PaSIAB2dEP/c1EMX2tOy0ov8rk83ePhJ+MWdT1z6
+jge9X4zQQI8ZyA9qIiwrKBZOi8DNUvrqNZC7fJAVRrb9aX/99uYOJCypIbpmWG1q
+fhbHjJewhwf8xYPj71eU4rLG80a+DapWmphtfq3h52lDQIBzLVf1yYbyrTaELaz4
+NXF7HXb5YkId/gxIsSzM0aFUVu2o8sJcLYAsJqwfFKBKOMxUcn545nlspf0mTcWZ
+0APlbwsKznNs4/xCDwIxxWjjqgHrYAFl6y07i1gzbAOqdNEyR24p+3JWI8WZBlBI
+dk2KGj0W1fIfsvyxAgMBAAGjggFBMIIBPTAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
+KwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYBBQUHAQEE
+XDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0
+MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0G
+A1UdDgQWBBTXD5Bx6iqT+dmEhbFL4OUoHyZn8zAMBgNVHRMBAf8EAjAAMB8GA1Ud
+IwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMBcGA1UdIAQQMA4wDAYKKwYBBAHW
+eQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lB
+RzIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCR3RJtHzgDh33b/MI1ugiki+nl8Ikj
+5larbJRE/rcA5oite+QJyAr6SU1gJJ/rRrK3ItVEHr9L621BCM7GSdoNMjB9MMcf
+tJAW0kYGJ+wqKm53wG/JaOADTnnq2Mt/j6F2uvjgN/ouns1nRHufIvd370N0LeH+
+orKqTuAPzXK7imQk6+OycYABbqCtC/9qmwRd8wwn7sF97DtYfK8WuNHtFalCAwyi
+8LxJJYJCLWoMhZ+V8GZm+FOex5qkQAjnZrtNlbQJ8ro4r+rpKXtmMFFhfa+7L+PA
+Kom08eUK8skxAzfDDijZPh10VtJ66uBoiDPdT+uCBehcBIcmSTrKjFGX
+-----END CERTIFICATE-----
+`
 
 // googleLeafWithInvalidHash is the same as googleLeaf, but the signature
 // algorithm in the certificate contains a nonsense OID.
 const googleLeafWithInvalidHash = `-----BEGIN CERTIFICATE-----
-MIIDITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BATIFADBM
-MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg
-THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0wOTEyMTgwMDAwMDBaFw0x
-MTEyMTgyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh
-MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw
-FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
-gYEA6PmGD5D6htffvXImttdEAoN4c9kCKO+IRTn7EOh8rqk41XXGOOsKFQebg+jN
-gtXj9xVoRaELGYW84u+E593y17iYwqG7tcFR39SDAqc9BkJb4SLD3muFXxzW2k6L
-05vuuWciKh0R73mkszeK9P4Y/bz5RiNQl/Os/CRGK1w7t0UCAwEAAaOB5zCB5DAM
-BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl
-LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF
-BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw
-Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0
-ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAVAF
-AAOBgQCfQ89bxFApsb/isJr/aiEdLRLDLE5a+RLizrmCUi3nHX4adpaQedEkUjh5
-u2ONgJd8IyAPkU0Wueru9G2Jysa9zCRo1kNbzipYvzwY4OA8Ys+WAi0oR1A04Se6
-z5nRUP8pJcA2NhUzUnC+MY+f6H/nEQyNv4SgQhqAibAxWEEHXw==
------END CERTIFICATE-----`
+MIIEdjCCA16gAwIBAgIIcR5k4dkoe04wDQYJKoZIhvcNAWAFBQAwSTELMAkGA1UE
+BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
+cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMzEyMDkzODMwWhcNMTQwNjEwMDAwMDAw
+WjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
+TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UEAwwOd3d3
+Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4zYCe
+m0oUBhwE0EwBr65eBOcgcQO2PaSIAB2dEP/c1EMX2tOy0ov8rk83ePhJ+MWdT1z6
+jge9X4zQQI8ZyA9qIiwrKBZOi8DNUvrqNZC7fJAVRrb9aX/99uYOJCypIbpmWG1q
+fhbHjJewhwf8xYPj71eU4rLG80a+DapWmphtfq3h52lDQIBzLVf1yYbyrTaELaz4
+NXF7HXb5YkId/gxIsSzM0aFUVu2o8sJcLYAsJqwfFKBKOMxUcn545nlspf0mTcWZ
+0APlbwsKznNs4/xCDwIxxWjjqgHrYAFl6y07i1gzbAOqdNEyR24p+3JWI8WZBlBI
+dk2KGj0W1fIfsvyxAgMBAAGjggFBMIIBPTAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
+KwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYBBQUHAQEE
+XDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0
+MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0G
+A1UdDgQWBBTXD5Bx6iqT+dmEhbFL4OUoHyZn8zAMBgNVHRMBAf8EAjAAMB8GA1Ud
+IwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMBcGA1UdIAQQMA4wDAYKKwYBBAHW
+eQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lB
+RzIuY3JsMA0GCSqGSIb3DQFgBQUAA4IBAQCR3RJtHzgDh33b/MI1ugiki+nl8Ikj
+5larbJRE/rcA5oite+QJyAr6SU1gJJ/rRrK3ItVEHr9L621BCM7GSdoNMjB9MMcf
+tJAW0kYGJ+wqKm53wG/JaOADTnnq2Mt/j6F2uvjgN/ouns1nRHufIvd370N0LeH+
+orKqTuAPzXK7imQk6+OycYABbqCtC/9qmwRd8wwn7sF97DtYfK8WuNHtFalCAwyi
+8LxJJYJCLWoMhZ+V8GZm+FOex5qkQAjnZrtNlbQJ8ro4r+rpKXtmMFFhfa+7L+PA
+Kom08eUK8skxAzfDDijZPh10VtJ66uBoiDPdT+uCBehcBIcmSTrKjFGX
+-----END CERTIFICATE-----
+`
 
 const dnssecExpLeaf = `-----BEGIN CERTIFICATE-----
 MIIGzTCCBbWgAwIBAgIDAdD6MA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
@@ -936,3 +989,135 @@ AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
 DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
 HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
 -----END CERTIFICATE-----`
+
+var moipLeafCert = `-----BEGIN CERTIFICATE-----
+MIIGQDCCBSigAwIBAgIRAPe/cwh7CUWizo8mYSDavLIwDQYJKoZIhvcNAQELBQAw
+gZIxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
+BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMTgwNgYD
+VQQDEy9DT01PRE8gUlNBIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZl
+ciBDQTAeFw0xMzA4MTUwMDAwMDBaFw0xNDA4MTUyMzU5NTlaMIIBQjEXMBUGA1UE
+BRMOMDg3MTg0MzEwMDAxMDgxEzARBgsrBgEEAYI3PAIBAxMCQlIxGjAYBgsrBgEE
+AYI3PAIBAhMJU2FvIFBhdWxvMR0wGwYDVQQPExRQcml2YXRlIE9yZ2FuaXphdGlv
+bjELMAkGA1UEBhMCQlIxETAPBgNVBBETCDAxNDUyMDAwMRIwEAYDVQQIEwlTYW8g
+UGF1bG8xEjAQBgNVBAcTCVNhbyBQYXVsbzEtMCsGA1UECRMkQXZlbmlkYSBCcmln
+YWRlaXJvIEZhcmlhIExpbWEgLCAyOTI3MR0wGwYDVQQKExRNb2lwIFBhZ2FtZW50
+b3MgUy5BLjENMAsGA1UECxMETU9JUDEYMBYGA1UECxMPU1NMIEJsaW5kYWRvIEVW
+MRgwFgYDVQQDEw9hcGkubW9pcC5jb20uYnIwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDN0b9x6TrXXA9hPCF8/NjqGJ++2D4LO4ZiMFTjs0VwpXy2Y1Oe
+s74/HuiLGnAHxTmAtV7IpZMibiOcTxcnDYp9oEWkf+gR+hZvwFZwyOBC7wyb3SR3
+UvV0N1ZbEVRYpN9kuX/3vjDghjDmzzBwu8a/T+y5JTym5uiJlngVAWyh/RjtIvYi
++NVkQMbyVlPGkoCe6c30pH8DKYuUCZU6DHjUsPTX3jAskqbhDSAnclX9iX0p2bmw
+KVBc+5Vh/2geyzDuquF0w+mNIYdU5h7uXvlmJnf3d2Cext5dxdL8/jezD3U0dAqI
+pYSKERbyxSkJWxdvRlhdpM9YXMJcpc88xNp1AgMBAAGjggHcMIIB2DAfBgNVHSME
+GDAWgBQ52v/KKBSKqHQTCLnkDqnS+n6daTAdBgNVHQ4EFgQU/lXuOa7DMExzZjRj
+LQWcMWGZY7swDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYw
+FAYIKwYBBQUHAwEGCCsGAQUFBwMCMEYGA1UdIAQ/MD0wOwYMKwYBBAGyMQECAQUB
+MCswKQYIKwYBBQUHAgEWHWh0dHBzOi8vc2VjdXJlLmNvbW9kby5jb20vQ1BTMFYG
+A1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET1JT
+QUV4dGVuZGVkVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNybDCBhwYIKwYBBQUH
+AQEEezB5MFEGCCsGAQUFBzAChkVodHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9DT01P
+RE9SU0FFeHRlbmRlZFZhbGlkYXRpb25TZWN1cmVTZXJ2ZXJDQS5jcnQwJAYIKwYB
+BQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTAvBgNVHREEKDAmgg9hcGku
+bW9pcC5jb20uYnKCE3d3dy5hcGkubW9pcC5jb20uYnIwDQYJKoZIhvcNAQELBQAD
+ggEBAFoTmPlaDcf+nudhjXHwud8g7/LRyA8ucb+3/vfmgbn7FUc1eprF5sJS1mA+
+pbiTyXw4IxcJq2KUj0Nw3IPOe9k84mzh+XMmdCKH+QK3NWkE9Udz+VpBOBc0dlqC
+1RH5umStYDmuZg/8/r652eeQ5kUDcJyADfpKWBgDPYaGtwzKVT4h3Aok9SLXRHx6
+z/gOaMjEDMarMCMw4VUIG1pvNraZrG5oTaALPaIXXpd8VqbQYPudYJ6fR5eY3FeW
+H/ofbYFdRcuD26MfBFWE9VGGral9Fgo8sEHffho+UWhgApuQV4/l5fMzxB5YBXyQ
+jhuy8PqqZS9OuLilTeLu4a8z2JI=
+-----END CERTIFICATE-----`
+
+var comodoIntermediateSHA384 = `-----BEGIN CERTIFICATE-----
+MIIGDjCCA/agAwIBAgIQBqdDgNTr/tQ1taP34Wq92DANBgkqhkiG9w0BAQwFADCB
+hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
+BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTIwMjEy
+MDAwMDAwWhcNMjcwMjExMjM1OTU5WjCBkjELMAkGA1UEBhMCR0IxGzAZBgNVBAgT
+EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
+Q09NT0RPIENBIExpbWl0ZWQxODA2BgNVBAMTL0NPTU9ETyBSU0EgRXh0ZW5kZWQg
+VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAlVbeVLTf1QJJe9FbXKKyHo+cK2JMK40SKPMalaPGEP0p3uGf
+CzhAk9HvbpUQ/OGQF3cs7nU+e2PsYZJuTzurgElr3wDqAwB/L3XVKC/sVmePgIOj
+vdwDmZOLlJFWW6G4ajo/Br0OksxgnP214J9mMF/b5pTwlWqvyIqvgNnmiDkBfBzA
+xSr3e5Wg8narbZtyOTDr0VdVAZ1YEZ18bYSPSeidCfw8/QpKdhQhXBZzQCMZdMO6
+WAqmli7eNuWf0MLw4eDBYuPCGEUZUaoXHugjddTI0JYT/8ck0YwLJ66eetw6YWNg
+iJctXQUL5Tvrrs46R3N2qPos3cCHF+msMJn4HwIDAQABo4IBaTCCAWUwHwYDVR0j
+BBgwFoAUu69+Aj36pvE8hI6t7jiY7NkyMtQwHQYDVR0OBBYEFDna/8ooFIqodBMI
+ueQOqdL6fp1pMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMD4G
+A1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5j
+b21vZG8uY29tL0NQUzBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9k
+b2NhLmNvbS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggr
+BgEFBQcBAQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29t
+L0NPTU9ET1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz
+cC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAERCnUFRK0iIXZebeV4R
+AUpSGXtBLMeJPNBy3IX6WK/VJeQT+FhlZ58N/1eLqYVeyqZLsKeyLeCMIs37/3mk
+jCuN/gI9JN6pXV/kD0fQ22YlPodHDK4ixVAihNftSlka9pOlk7DgG4HyVsTIEFPk
+1Hax0VtpS3ey4E/EhOfUoFDuPPpE/NBXueEoU/1Tzdy5H3pAvTA/2GzS8+cHnx8i
+teoiccsq8FZ8/qyo0QYPFBRSTP5kKwxpKrgNUG4+BAe/eiCL+O5lCeHHSQgyPQ0o
+fkkdt0rvAucNgBfIXOBhYsvss2B5JdoaZXOcOBCgJjqwyBZ9kzEi7nQLiMBciUEA
+KKlHMd99SUWa9eanRRrSjhMQ34Ovmw2tfn6dNVA0BM7pINae253UqNpktNEvWS5e
+ojZh1CSggjMziqHRbO9haKPl0latxf1eYusVqHQSTC8xjOnB3xBLAer2VBvNfzu9
+XJ/B288ByvK6YBIhMe2pZLiySVgXbVrXzYxtvp5/4gJYp9vDLVj2dAZqmvZh+fYA
+tmnYOosxWd2R5nwnI4fdAw+PKowegwFOAWEMUnNt/AiiuSpm5HZNMaBWm9lTjaK2
+jwLI5jqmBNFI+8NKAnb9L9K8E7bobTQk+p0pisehKxTxlgBzuRPpwLk6R1YCcYAn
+pLwltum95OmYdBbxN4SBB7SC
+-----END CERTIFICATE-----`
+
+const comodoRSAAuthority = `-----BEGIN CERTIFICATE-----
+MIIFdDCCBFygAwIBAgIQJ2buVutJ846r13Ci/ITeIjANBgkqhkiG9w0BAQwFADBv
+MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk
+ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF
+eHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFow
+gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
+BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD
+VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkq
+hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAkehUktIKVrGsDSTdxc9EZ3SZKzejfSNw
+AHG8U9/E+ioSj0t/EFa9n3Byt2F/yUsPF6c947AEYe7/EZfH9IY+Cvo+XPmT5jR6
+2RRr55yzhaCCenavcZDX7P0N+pxs+t+wgvQUfvm+xKYvT3+Zf7X8Z0NyvQwA1onr
+ayzT7Y+YHBSrfuXjbvzYqOSSJNpDa2K4Vf3qwbxstovzDo2a5JtsaZn4eEgwRdWt
+4Q08RWD8MpZRJ7xnw8outmvqRsfHIKCxH2XeSAi6pE6p8oNGN4Tr6MyBSENnTnIq
+m1y9TBsoilwie7SrmNnu4FGDwwlGTm0+mfqVF9p8M1dBPI1R7Qu2XK8sYxrfV8g/
+vOldxJuvRZnio1oktLqpVj3Pb6r/SVi+8Kj/9Lit6Tf7urj0Czr56ENCHonYhMsT
+8dm74YlguIwoVqwUHZwK53Hrzw7dPamWoUi9PPevtQ0iTMARgexWO/bTouJbt7IE
+IlKVgJNp6I5MZfGRAy1wdALqi2cVKWlSArvX31BqVUa/oKMoYX9w0MOiqiwhqkfO
+KJwGRXa/ghgntNWutMtQ5mv0TIZxMOmm3xaG4Nj/QN370EKIf6MzOi5cHkERgWPO
+GHFrK+ymircxXDpqR+DDeVnWIBqv8mqYqnK8V0rSS527EPywTEHl7R09XiidnMy/
+s1Hap0flhFMCAwEAAaOB9DCB8TAfBgNVHSMEGDAWgBStvZh6NLQm9/rEJlTvA73g
+JMtUGjAdBgNVHQ4EFgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQD
+AgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMEQGA1UdHwQ9
+MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9BZGRUcnVzdEV4dGVy
+bmFsQ0FSb290LmNybDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6
+Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggEBAGS/g/FfmoXQ
+zbihKVcN6Fr30ek+8nYEbvFScLsePP9NDXRqzIGCJdPDoCpdTPW6i6FtxFQJdcfj
+Jw5dhHk3QBN39bSsHNA7qxcS1u80GH4r6XnTq1dFDK8o+tDb5VCViLvfhVdpfZLY
+Uspzgb8c8+a4bmYRBbMelC1/kZWSWfFMzqORcUx8Rww7Cxn2obFshj5cqsQugsv5
+B5a6SE2Q8pTIqXOi6wZ7I53eovNNVZ96YUWYGGjHXkBrI/V5eu+MtWuLt29G9Hvx
+PUsE2JOAWVrgQSQdso8VYFhH2+9uRv0V9dlfmrPb2LjkQLPNlzmuhbsdjrzch5vR
+pu/xO28QOG8=
+-----END CERTIFICATE-----`
+
+const addTrustRoot = `-----BEGIN CERTIFICATE-----
+MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
+IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
+MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
+FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
+bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
+H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
+uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
+mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
+a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
+E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
+WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
+VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
+Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
+cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
+IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
+AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
+YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
+6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
+Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
+c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
+mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
+-----END CERTIFICATE-----`
diff --git a/src/pkg/crypto/x509/x509.go b/src/pkg/crypto/x509/x509.go
index 57f68ba..c347fb3 100644
--- a/src/pkg/crypto/x509/x509.go
+++ b/src/pkg/crypto/x509/x509.go
@@ -13,6 +13,8 @@ import (
 	"crypto/elliptic"
 	"crypto/rsa"
 	"crypto/sha1"
+	_ "crypto/sha256"
+	_ "crypto/sha512"
 	"crypto/x509/pkix"
 	"encoding/asn1"
 	"encoding/pem"
@@ -241,32 +243,31 @@ var (
 	oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
 )
 
+var signatureAlgorithmDetails = []struct {
+	algo       SignatureAlgorithm
+	oid        asn1.ObjectIdentifier
+	pubKeyAlgo PublicKeyAlgorithm
+	hash       crypto.Hash
+}{
+	{MD2WithRSA, oidSignatureMD2WithRSA, RSA, crypto.Hash(0) /* no value for MD2 */},
+	{MD5WithRSA, oidSignatureMD5WithRSA, RSA, crypto.MD5},
+	{SHA1WithRSA, oidSignatureSHA1WithRSA, RSA, crypto.SHA1},
+	{SHA256WithRSA, oidSignatureSHA256WithRSA, RSA, crypto.SHA256},
+	{SHA384WithRSA, oidSignatureSHA384WithRSA, RSA, crypto.SHA384},
+	{SHA512WithRSA, oidSignatureSHA512WithRSA, RSA, crypto.SHA512},
+	{DSAWithSHA1, oidSignatureDSAWithSHA1, DSA, crypto.SHA1},
+	{DSAWithSHA256, oidSignatureDSAWithSHA256, DSA, crypto.SHA256},
+	{ECDSAWithSHA1, oidSignatureECDSAWithSHA1, ECDSA, crypto.SHA1},
+	{ECDSAWithSHA256, oidSignatureECDSAWithSHA256, ECDSA, crypto.SHA256},
+	{ECDSAWithSHA384, oidSignatureECDSAWithSHA384, ECDSA, crypto.SHA384},
+	{ECDSAWithSHA512, oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512},
+}
+
 func getSignatureAlgorithmFromOID(oid asn1.ObjectIdentifier) SignatureAlgorithm {
-	switch {
-	case oid.Equal(oidSignatureMD2WithRSA):
-		return MD2WithRSA
-	case oid.Equal(oidSignatureMD5WithRSA):
-		return MD5WithRSA
-	case oid.Equal(oidSignatureSHA1WithRSA):
-		return SHA1WithRSA
-	case oid.Equal(oidSignatureSHA256WithRSA):
-		return SHA256WithRSA
-	case oid.Equal(oidSignatureSHA384WithRSA):
-		return SHA384WithRSA
-	case oid.Equal(oidSignatureSHA512WithRSA):
-		return SHA512WithRSA
-	case oid.Equal(oidSignatureDSAWithSHA1):
-		return DSAWithSHA1
-	case oid.Equal(oidSignatureDSAWithSHA256):
-		return DSAWithSHA256
-	case oid.Equal(oidSignatureECDSAWithSHA1):
-		return ECDSAWithSHA1
-	case oid.Equal(oidSignatureECDSAWithSHA256):
-		return ECDSAWithSHA256
-	case oid.Equal(oidSignatureECDSAWithSHA384):
-		return ECDSAWithSHA384
-	case oid.Equal(oidSignatureECDSAWithSHA512):
-		return ECDSAWithSHA512
+	for _, details := range signatureAlgorithmDetails {
+		if oid.Equal(details.oid) {
+			return details.algo
+		}
 	}
 	return UnknownSignatureAlgorithm
 }
@@ -790,6 +791,58 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{
 	}
 }
 
+func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddresses []net.IP, err error) {
+	// RFC 5280, 4.2.1.6
+
+	// SubjectAltName ::= GeneralNames
+	//
+	// GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+	//
+	// GeneralName ::= CHOICE {
+	//      otherName                       [0]     OtherName,
+	//      rfc822Name                      [1]     IA5String,
+	//      dNSName                         [2]     IA5String,
+	//      x400Address                     [3]     ORAddress,
+	//      directoryName                   [4]     Name,
+	//      ediPartyName                    [5]     EDIPartyName,
+	//      uniformResourceIdentifier       [6]     IA5String,
+	//      iPAddress                       [7]     OCTET STRING,
+	//      registeredID                    [8]     OBJECT IDENTIFIER }
+	var seq asn1.RawValue
+	if _, err = asn1.Unmarshal(value, &seq); err != nil {
+		return
+	}
+	if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
+		err = asn1.StructuralError{Msg: "bad SAN sequence"}
+		return
+	}
+
+	rest := seq.Bytes
+	for len(rest) > 0 {
+		var v asn1.RawValue
+		rest, err = asn1.Unmarshal(rest, &v)
+		if err != nil {
+			return
+		}
+		switch v.Tag {
+		case 1:
+			emailAddresses = append(emailAddresses, string(v.Bytes))
+		case 2:
+			dnsNames = append(dnsNames, string(v.Bytes))
+		case 7:
+			switch len(v.Bytes) {
+			case net.IPv4len, net.IPv6len:
+				ipAddresses = append(ipAddresses, v.Bytes)
+			default:
+				err = errors.New("x509: certificate contained IP address of length " + strconv.Itoa(len(v.Bytes)))
+				return
+			}
+		}
+	}
+
+	return
+}
+
 func parseCertificate(in *certificate) (*Certificate, error) {
 	out := new(Certificate)
 	out.Raw = in.Raw
@@ -863,58 +916,12 @@ func parseCertificate(in *certificate) (*Certificate, error) {
 					continue
 				}
 			case 17:
-				// RFC 5280, 4.2.1.6
-
-				// SubjectAltName ::= GeneralNames
-				//
-				// GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
-				//
-				// GeneralName ::= CHOICE {
-				//      otherName                       [0]     OtherName,
-				//      rfc822Name                      [1]     IA5String,
-				//      dNSName                         [2]     IA5String,
-				//      x400Address                     [3]     ORAddress,
-				//      directoryName                   [4]     Name,
-				//      ediPartyName                    [5]     EDIPartyName,
-				//      uniformResourceIdentifier       [6]     IA5String,
-				//      iPAddress                       [7]     OCTET STRING,
-				//      registeredID                    [8]     OBJECT IDENTIFIER }
-				var seq asn1.RawValue
-				_, err := asn1.Unmarshal(e.Value, &seq)
+				out.DNSNames, out.EmailAddresses, out.IPAddresses, err = parseSANExtension(e.Value)
 				if err != nil {
 					return nil, err
 				}
-				if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
-					return nil, asn1.StructuralError{Msg: "bad SAN sequence"}
-				}
 
-				parsedName := false
-
-				rest := seq.Bytes
-				for len(rest) > 0 {
-					var v asn1.RawValue
-					rest, err = asn1.Unmarshal(rest, &v)
-					if err != nil {
-						return nil, err
-					}
-					switch v.Tag {
-					case 1:
-						out.EmailAddresses = append(out.EmailAddresses, string(v.Bytes))
-						parsedName = true
-					case 2:
-						out.DNSNames = append(out.DNSNames, string(v.Bytes))
-						parsedName = true
-					case 7:
-						switch len(v.Bytes) {
-						case net.IPv4len, net.IPv6len:
-							out.IPAddresses = append(out.IPAddresses, v.Bytes)
-						default:
-							return nil, errors.New("x509: certificate contained IP address of length " + strconv.Itoa(len(v.Bytes)))
-						}
-					}
-				}
-
-				if parsedName {
+				if len(out.DNSNames) > 0 || len(out.EmailAddresses) > 0 || len(out.IPAddresses) > 0 {
 					continue
 				}
 				// If we didn't parse any of the names then we
@@ -1151,6 +1158,27 @@ func oidInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extension) boo
 	return false
 }
 
+// marshalSANs marshals a list of addresses into a the contents of an X.509
+// SubjectAlternativeName extension.
+func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP) (derBytes []byte, err error) {
+	var rawValues []asn1.RawValue
+	for _, name := range dnsNames {
+		rawValues = append(rawValues, asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)})
+	}
+	for _, email := range emailAddresses {
+		rawValues = append(rawValues, asn1.RawValue{Tag: 1, Class: 2, Bytes: []byte(email)})
+	}
+	for _, rawIP := range ipAddresses {
+		// If possible, we always want to encode IPv4 addresses in 4 bytes.
+		ip := rawIP.To4()
+		if ip == nil {
+			ip = rawIP
+		}
+		rawValues = append(rawValues, asn1.RawValue{Tag: 7, Class: 2, Bytes: ip})
+	}
+	return asn1.Marshal(rawValues)
+}
+
 func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
 	ret = make([]pkix.Extension, 10 /* maximum number of elements. */)
 	n := 0
@@ -1252,22 +1280,7 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
 	if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0) &&
 		!oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) {
 		ret[n].Id = oidExtensionSubjectAltName
-		var rawValues []asn1.RawValue
-		for _, name := range template.DNSNames {
-			rawValues = append(rawValues, asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)})
-		}
-		for _, email := range template.EmailAddresses {
-			rawValues = append(rawValues, asn1.RawValue{Tag: 1, Class: 2, Bytes: []byte(email)})
-		}
-		for _, rawIP := range template.IPAddresses {
-			// If possible, we always want to encode IPv4 addresses in 4 bytes.
-			ip := rawIP.To4()
-			if ip == nil {
-				ip = rawIP
-			}
-			rawValues = append(rawValues, asn1.RawValue{Tag: 7, Class: 2, Bytes: ip})
-		}
-		ret[n].Value, err = asn1.Marshal(rawValues)
+		ret[n].Value, err = marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses)
 		if err != nil {
 			return
 		}
@@ -1342,11 +1355,76 @@ func subjectBytes(cert *Certificate) ([]byte, error) {
 	return asn1.Marshal(cert.Subject.ToRDNSequence())
 }
 
+// signingParamsForPrivateKey returns the parameters to use for signing with
+// priv. If requestedSigAlgo is not zero then it overrides the default
+// signature algorithm.
+func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
+	var pubType PublicKeyAlgorithm
+
+	switch priv := priv.(type) {
+	case *rsa.PrivateKey:
+		pubType = RSA
+		sigAlgo.Algorithm = oidSignatureSHA256WithRSA
+		hashFunc = crypto.SHA256
+
+	case *ecdsa.PrivateKey:
+		pubType = ECDSA
+
+		switch priv.Curve {
+		case elliptic.P224(), elliptic.P256():
+			hashFunc = crypto.SHA256
+			sigAlgo.Algorithm = oidSignatureECDSAWithSHA256
+		case elliptic.P384():
+			hashFunc = crypto.SHA384
+			sigAlgo.Algorithm = oidSignatureECDSAWithSHA384
+		case elliptic.P521():
+			hashFunc = crypto.SHA512
+			sigAlgo.Algorithm = oidSignatureECDSAWithSHA512
+		default:
+			err = errors.New("x509: unknown elliptic curve")
+		}
+
+	default:
+		err = errors.New("x509: only RSA and ECDSA private keys supported")
+	}
+
+	if err != nil {
+		return
+	}
+
+	if requestedSigAlgo == 0 {
+		return
+	}
+
+	found := false
+	for _, details := range signatureAlgorithmDetails {
+		if details.algo == requestedSigAlgo {
+			if details.pubKeyAlgo != pubType {
+				err = errors.New("x509: requested SignatureAlgorithm does not match private key type")
+				return
+			}
+			sigAlgo.Algorithm, hashFunc = details.oid, details.hash
+			if hashFunc == 0 {
+				err = errors.New("x509: cannot sign with hash function requested")
+				return
+			}
+			found = true
+			break
+		}
+	}
+
+	if !found {
+		err = errors.New("x509: unknown SignatureAlgorithm")
+	}
+
+	return
+}
+
 // CreateCertificate creates a new certificate based on a template. The
 // following members of template are used: SerialNumber, Subject, NotBefore,
 // NotAfter, KeyUsage, ExtKeyUsage, UnknownExtKeyUsage, BasicConstraintsValid,
 // IsCA, MaxPathLen, SubjectKeyId, DNSNames, PermittedDNSDomainsCritical,
-// PermittedDNSDomains.
+// PermittedDNSDomains, SignatureAlgorithm.
 //
 // The certificate is signed by parent. If parent is equal to template then the
 // certificate is self-signed. The parameter pub is the public key of the
@@ -1355,38 +1433,16 @@ func subjectBytes(cert *Certificate) ([]byte, error) {
 // The returned slice is the certificate in DER encoding.
 //
 // The only supported key types are RSA and ECDSA (*rsa.PublicKey or
-// *ecdsa.PublicKey for pub, *rsa.PrivateKey or *ecdsa.PublicKey for priv).
+// *ecdsa.PublicKey for pub, *rsa.PrivateKey or *ecdsa.PrivateKey for priv).
 func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interface{}, priv interface{}) (cert []byte, err error) {
-	var publicKeyBytes []byte
-	var publicKeyAlgorithm pkix.AlgorithmIdentifier
-
-	if publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(pub); err != nil {
+	hashFunc, signatureAlgorithm, err := signingParamsForPrivateKey(priv, template.SignatureAlgorithm)
+	if err != nil {
 		return nil, err
 	}
 
-	var signatureAlgorithm pkix.AlgorithmIdentifier
-	var hashFunc crypto.Hash
-
-	switch priv := priv.(type) {
-	case *rsa.PrivateKey:
-		signatureAlgorithm.Algorithm = oidSignatureSHA1WithRSA
-		hashFunc = crypto.SHA1
-	case *ecdsa.PrivateKey:
-		switch priv.Curve {
-		case elliptic.P224(), elliptic.P256():
-			hashFunc = crypto.SHA256
-			signatureAlgorithm.Algorithm = oidSignatureECDSAWithSHA256
-		case elliptic.P384():
-			hashFunc = crypto.SHA384
-			signatureAlgorithm.Algorithm = oidSignatureECDSAWithSHA384
-		case elliptic.P521():
-			hashFunc = crypto.SHA512
-			signatureAlgorithm.Algorithm = oidSignatureECDSAWithSHA512
-		default:
-			return nil, errors.New("x509: unknown elliptic curve")
-		}
-	default:
-		return nil, errors.New("x509: only RSA and ECDSA private keys supported")
+	publicKeyBytes, publicKeyAlgorithm, err := marshalPublicKey(pub)
+	if err != nil {
+		return nil, err
 	}
 
 	if err != nil {
@@ -1535,3 +1591,313 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts [
 		SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
 	})
 }
+
+// CertificateRequest represents a PKCS #10, certificate signature request.
+type CertificateRequest struct {
+	Raw                      []byte // Complete ASN.1 DER content (CSR, signature algorithm and signature).
+	RawTBSCertificateRequest []byte // Certificate request info part of raw ASN.1 DER content.
+	RawSubjectPublicKeyInfo  []byte // DER encoded SubjectPublicKeyInfo.
+	RawSubject               []byte // DER encoded Subject.
+
+	Version            int
+	Signature          []byte
+	SignatureAlgorithm SignatureAlgorithm
+
+	PublicKeyAlgorithm PublicKeyAlgorithm
+	PublicKey          interface{}
+
+	Subject pkix.Name
+
+	// Attributes is a collection of attributes providing
+	// additional information about the subject of the certificate.
+	// See RFC 2986 section 4.1.
+	Attributes []pkix.AttributeTypeAndValueSET
+
+	// Extensions contains raw X.509 extensions. When parsing CSRs, this
+	// can be used to extract extensions that are not parsed by this
+	// package.
+	Extensions []pkix.Extension
+
+	// ExtraExtensions contains extensions to be copied, raw, into any
+	// marshaled CSR. Values override any extensions that would otherwise
+	// be produced based on the other fields but are overridden by any
+	// extensions specified in Attributes.
+	//
+	// The ExtraExtensions field is not populated when parsing CSRs, see
+	// Extensions.
+	ExtraExtensions []pkix.Extension
+
+	// Subject Alternate Name values.
+	DNSNames       []string
+	EmailAddresses []string
+	IPAddresses    []net.IP
+}
+
+// These structures reflect the ASN.1 structure of X.509 certificate
+// signature requests (see RFC 2986):
+
+type tbsCertificateRequest struct {
+	Raw        asn1.RawContent
+	Version    int
+	Subject    asn1.RawValue
+	PublicKey  publicKeyInfo
+	Attributes []pkix.AttributeTypeAndValueSET `asn1:"tag:0"`
+}
+
+type certificateRequest struct {
+	Raw                asn1.RawContent
+	TBSCSR             tbsCertificateRequest
+	SignatureAlgorithm pkix.AlgorithmIdentifier
+	SignatureValue     asn1.BitString
+}
+
+// oidExtensionRequest is a PKCS#9 OBJECT IDENTIFIER that indicates requested
+// extensions in a CSR.
+var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
+
+// CreateCertificateRequest creates a new certificate based on a template. The
+// following members of template are used: Subject, Attributes,
+// SignatureAlgorithm, Extension, DNSNames, EmailAddresses, and IPAddresses.
+// The private key is the private key of the signer.
+//
+// The returned slice is the certificate request in DER encoding.
+//
+// The only supported key types are RSA (*rsa.PrivateKey) and ECDSA
+// (*ecdsa.PrivateKey).
+func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv interface{}) (csr []byte, err error) {
+	hashFunc, sigAlgo, err := signingParamsForPrivateKey(priv, template.SignatureAlgorithm)
+	if err != nil {
+		return nil, err
+	}
+
+	var publicKeyBytes []byte
+	var publicKeyAlgorithm pkix.AlgorithmIdentifier
+
+	switch priv := priv.(type) {
+	case *rsa.PrivateKey:
+		publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(&priv.PublicKey)
+	case *ecdsa.PrivateKey:
+		publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(&priv.PublicKey)
+	default:
+		panic("internal error")
+	}
+
+	if err != nil {
+		return nil, err
+	}
+
+	var extensions []pkix.Extension
+
+	if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0) &&
+		!oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) {
+		sanBytes, err := marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses)
+		if err != nil {
+			return nil, err
+		}
+
+		extensions = append(extensions, pkix.Extension{
+			Id:    oidExtensionSubjectAltName,
+			Value: sanBytes,
+		})
+	}
+
+	extensions = append(extensions, template.ExtraExtensions...)
+
+	var attributes []pkix.AttributeTypeAndValueSET
+	attributes = append(attributes, template.Attributes...)
+
+	if len(extensions) > 0 {
+		// specifiedExtensions contains all the extensions that we
+		// found specified via template.Attributes.
+		specifiedExtensions := make(map[string]bool)
+
+		for _, atvSet := range template.Attributes {
+			if !atvSet.Type.Equal(oidExtensionRequest) {
+				continue
+			}
+
+			for _, atvs := range atvSet.Value {
+				for _, atv := range atvs {
+					specifiedExtensions[atv.Type.String()] = true
+				}
+			}
+		}
+
+		atvs := make([]pkix.AttributeTypeAndValue, 0, len(extensions))
+		for _, e := range extensions {
+			if specifiedExtensions[e.Id.String()] {
+				// Attributes already contained a value for
+				// this extension and it takes priority.
+				continue
+			}
+
+			atvs = append(atvs, pkix.AttributeTypeAndValue{
+				// There is no place for the critical flag in a CSR.
+				Type:  e.Id,
+				Value: e.Value,
+			})
+		}
+
+		// Append the extensions to an existing attribute if possible.
+		appended := false
+		for _, atvSet := range attributes {
+			if !atvSet.Type.Equal(oidExtensionRequest) || len(atvSet.Value) == 0 {
+				continue
+			}
+
+			atvSet.Value[0] = append(atvSet.Value[0], atvs...)
+			appended = true
+			break
+		}
+
+		// Otherwise, add a new attribute for the extensions.
+		if !appended {
+			attributes = append(attributes, pkix.AttributeTypeAndValueSET{
+				Type: oidExtensionRequest,
+				Value: [][]pkix.AttributeTypeAndValue{
+					atvs,
+				},
+			})
+		}
+	}
+
+	asn1Subject := template.RawSubject
+	if len(asn1Subject) == 0 {
+		asn1Subject, err = asn1.Marshal(template.Subject.ToRDNSequence())
+		if err != nil {
+			return
+		}
+	}
+
+	tbsCSR := tbsCertificateRequest{
+		Version: 0, // PKCS #10, RFC 2986
+		Subject: asn1.RawValue{FullBytes: asn1Subject},
+		PublicKey: publicKeyInfo{
+			Algorithm: publicKeyAlgorithm,
+			PublicKey: asn1.BitString{
+				Bytes:     publicKeyBytes,
+				BitLength: len(publicKeyBytes) * 8,
+			},
+		},
+		Attributes: attributes,
+	}
+
+	tbsCSRContents, err := asn1.Marshal(tbsCSR)
+	if err != nil {
+		return
+	}
+	tbsCSR.Raw = tbsCSRContents
+
+	h := hashFunc.New()
+	h.Write(tbsCSRContents)
+	digest := h.Sum(nil)
+
+	var signature []byte
+	switch priv := priv.(type) {
+	case *rsa.PrivateKey:
+		signature, err = rsa.SignPKCS1v15(rand, priv, hashFunc, digest)
+	case *ecdsa.PrivateKey:
+		var r, s *big.Int
+		if r, s, err = ecdsa.Sign(rand, priv, digest); err == nil {
+			signature, err = asn1.Marshal(ecdsaSignature{r, s})
+		}
+	default:
+		panic("internal error")
+	}
+
+	if err != nil {
+		return
+	}
+
+	return asn1.Marshal(certificateRequest{
+		TBSCSR:             tbsCSR,
+		SignatureAlgorithm: sigAlgo,
+		SignatureValue: asn1.BitString{
+			Bytes:     signature,
+			BitLength: len(signature) * 8,
+		},
+	})
+}
+
+// ParseCertificateRequest parses a single certificate request from the
+// given ASN.1 DER data.
+func ParseCertificateRequest(asn1Data []byte) (*CertificateRequest, error) {
+	var csr certificateRequest
+
+	rest, err := asn1.Unmarshal(asn1Data, &csr)
+	if err != nil {
+		return nil, err
+	} else if len(rest) != 0 {
+		return nil, asn1.SyntaxError{Msg: "trailing data"}
+	}
+
+	return parseCertificateRequest(&csr)
+}
+
+func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error) {
+	out := &CertificateRequest{
+		Raw: in.Raw,
+		RawTBSCertificateRequest: in.TBSCSR.Raw,
+		RawSubjectPublicKeyInfo:  in.TBSCSR.PublicKey.Raw,
+		RawSubject:               in.TBSCSR.Subject.FullBytes,
+
+		Signature:          in.SignatureValue.RightAlign(),
+		SignatureAlgorithm: getSignatureAlgorithmFromOID(in.SignatureAlgorithm.Algorithm),
+
+		PublicKeyAlgorithm: getPublicKeyAlgorithmFromOID(in.TBSCSR.PublicKey.Algorithm.Algorithm),
+
+		Version:    in.TBSCSR.Version,
+		Attributes: in.TBSCSR.Attributes,
+	}
+
+	var err error
+	out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCSR.PublicKey)
+	if err != nil {
+		return nil, err
+	}
+
+	var subject pkix.RDNSequence
+	if _, err := asn1.Unmarshal(in.TBSCSR.Subject.FullBytes, &subject); err != nil {
+		return nil, err
+	}
+
+	out.Subject.FillFromRDNSequence(&subject)
+
+	var extensions []pkix.AttributeTypeAndValue
+
+	for _, atvSet := range in.TBSCSR.Attributes {
+		if !atvSet.Type.Equal(oidExtensionRequest) {
+			continue
+		}
+
+		for _, atvs := range atvSet.Value {
+			extensions = append(extensions, atvs...)
+		}
+	}
+
+	out.Extensions = make([]pkix.Extension, 0, len(extensions))
+
+	for _, e := range extensions {
+		value, ok := e.Value.([]byte)
+		if !ok {
+			return nil, errors.New("x509: extension attribute contained non-OCTET STRING data")
+		}
+
+		out.Extensions = append(out.Extensions, pkix.Extension{
+			Id:    e.Type,
+			Value: value,
+		})
+
+		if len(e.Type) == 4 && e.Type[0] == 2 && e.Type[1] == 5 && e.Type[2] == 29 {
+			switch e.Type[3] {
+			case 17:
+				out.DNSNames, out.EmailAddresses, out.IPAddresses, err = parseSANExtension(value)
+				if err != nil {
+					return nil, err
+				}
+			}
+		}
+	}
+
+	return out, nil
+}
diff --git a/src/pkg/crypto/x509/x509_test.go b/src/pkg/crypto/x509/x509_test.go
index f1097e9..2fd54c7 100644
--- a/src/pkg/crypto/x509/x509_test.go
+++ b/src/pkg/crypto/x509/x509_test.go
@@ -20,7 +20,9 @@ import (
 	"encoding/pem"
 	"math/big"
 	"net"
+	"os/exec"
 	"reflect"
+	"runtime"
 	"testing"
 	"time"
 )
@@ -305,11 +307,12 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
 		name      string
 		pub, priv interface{}
 		checkSig  bool
+		sigAlgo   SignatureAlgorithm
 	}{
-		{"RSA/RSA", &rsaPriv.PublicKey, rsaPriv, true},
-		{"RSA/ECDSA", &rsaPriv.PublicKey, ecdsaPriv, false},
-		{"ECDSA/RSA", &ecdsaPriv.PublicKey, rsaPriv, false},
-		{"ECDSA/ECDSA", &ecdsaPriv.PublicKey, ecdsaPriv, true},
+		{"RSA/RSA", &rsaPriv.PublicKey, rsaPriv, true, SHA1WithRSA},
+		{"RSA/ECDSA", &rsaPriv.PublicKey, ecdsaPriv, false, ECDSAWithSHA384},
+		{"ECDSA/RSA", &ecdsaPriv.PublicKey, rsaPriv, false, SHA256WithRSA},
+		{"ECDSA/ECDSA", &ecdsaPriv.PublicKey, ecdsaPriv, true, ECDSAWithSHA1},
 	}
 
 	testExtKeyUsage := []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageServerAuth}
@@ -327,6 +330,8 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
 			NotBefore: time.Unix(1000, 0),
 			NotAfter:  time.Unix(100000, 0),
 
+			SignatureAlgorithm: test.sigAlgo,
+
 			SubjectKeyId: []byte{1, 2, 3, 4},
 			KeyUsage:     KeyUsageCertSign,
 
@@ -390,6 +395,10 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
 			t.Errorf("%s: issuer wasn't correctly copied from the template. Got %s, want %s", test.name, cert.Issuer.CommonName, commonName)
 		}
 
+		if cert.SignatureAlgorithm != test.sigAlgo {
+			t.Errorf("%s: SignatureAlgorithm wasn't copied from template. Got %v, want %v", test.name, cert.SignatureAlgorithm, test.sigAlgo)
+		}
+
 		if !reflect.DeepEqual(cert.ExtKeyUsage, testExtKeyUsage) {
 			t.Errorf("%s: extkeyusage wasn't correctly copied from the template. Got %v, want %v", test.name, cert.ExtKeyUsage, testExtKeyUsage)
 		}
@@ -671,11 +680,11 @@ func TestCRLCreation(t *testing.T) {
 
 func fromBase64(in string) []byte {
 	out := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
-	_, err := base64.StdEncoding.Decode(out, []byte(in))
+	n, err := base64.StdEncoding.Decode(out, []byte(in))
 	if err != nil {
 		panic("failed to base64 decode")
 	}
-	return out
+	return out[:n]
 }
 
 func TestParseDERCRL(t *testing.T) {
@@ -718,6 +727,226 @@ func TestParsePEMCRL(t *testing.T) {
 	// Can't check the signature here without a package cycle.
 }
 
+func TestImports(t *testing.T) {
+	if runtime.GOOS == "nacl" {
+		t.Skip("skipping on nacl")
+	}
+
+	if err := exec.Command("go", "run", "x509_test_import.go").Run(); err != nil {
+		t.Errorf("failed to run x509_test_import.go: %s", err)
+	}
+}
+
 const derCRLBase64 = "MIINqzCCDJMCAQEwDQYJKoZIhvcNAQEFBQAwVjEZMBcGA1UEAxMQUEtJIEZJTk1FQ0NBTklDQTEVMBMGA1UEChMMRklOTUVDQ0FOSUNBMRUwEwYDVQQLEwxGSU5NRUNDQU5JQ0ExCzAJBgNVBAYTAklUFw0xMTA1MDQxNjU3NDJaFw0xMTA1MDQyMDU3NDJaMIIMBzAhAg4Ze1od49Lt1qIXBydAzhcNMDkwNzE2MDg0MzIyWjAAMCECDl0HSL9bcZ1Ci/UHJ0DPFw0wOTA3MTYwODQzMTNaMAAwIQIOESB9tVAmX3cY7QcnQNAXDTA5MDcxNjA4NDUyMlowADAhAg4S1tGAQ3mHt8uVBydA1RcNMDkwODA0MTUyNTIyWjAAMCECDlQ249Y7vtC25ScHJ0DWFw0wOTA4MDQxNTI1MzdaMAAwIQIOISMop3NkA4PfYwcnQNkXDTA5MDgwNDExMD [...]
 
 const pemCRLBase64 = "LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tDQpNSUlCOWpDQ0FWOENBUUV3RFFZSktvWklodmNOQVFFRkJRQXdiREVhTUJnR0ExVUVDaE1SVWxOQklGTmxZM1Z5DQphWFI1SUVsdVl5NHhIakFjQmdOVkJBTVRGVkpUUVNCUWRXSnNhV01nVW05dmRDQkRRU0IyTVRFdU1Dd0dDU3FHDQpTSWIzRFFFSkFSWWZjbk5oYTJWdmJuSnZiM1J6YVdkdVFISnpZWE5sWTNWeWFYUjVMbU52YlJjTk1URXdNakl6DQpNVGt5T0RNd1doY05NVEV3T0RJeU1Ua3lPRE13V2pDQmpEQktBaEVBckRxb2g5RkhKSFhUN09QZ3V1bjQrQmNODQpNRGt4TVRBeU1UUXlOekE1V2pBbU1Bb0dBMVVkRlFRRENnRUpNQmdHQTFVZEdBUVJHQTh5TURBNU1URXdNak [...]
+
+func TestCreateCertificateRequest(t *testing.T) {
+	random := rand.Reader
+
+	block, _ := pem.Decode([]byte(pemPrivateKey))
+	rsaPriv, err := ParsePKCS1PrivateKey(block.Bytes)
+	if err != nil {
+		t.Fatalf("Failed to parse private key: %s", err)
+	}
+
+	ecdsa256Priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	if err != nil {
+		t.Fatalf("Failed to generate ECDSA key: %s", err)
+	}
+
+	ecdsa384Priv, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
+	if err != nil {
+		t.Fatalf("Failed to generate ECDSA key: %s", err)
+	}
+
+	ecdsa521Priv, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
+	if err != nil {
+		t.Fatalf("Failed to generate ECDSA key: %s", err)
+	}
+
+	tests := []struct {
+		name    string
+		priv    interface{}
+		sigAlgo SignatureAlgorithm
+	}{
+		{"RSA", rsaPriv, SHA1WithRSA},
+		{"ECDSA-256", ecdsa256Priv, ECDSAWithSHA1},
+		{"ECDSA-384", ecdsa384Priv, ECDSAWithSHA1},
+		{"ECDSA-521", ecdsa521Priv, ECDSAWithSHA1},
+	}
+
+	for _, test := range tests {
+		template := CertificateRequest{
+			Subject: pkix.Name{
+				CommonName:   "test.example.com",
+				Organization: []string{"Σ Acme Co"},
+			},
+			SignatureAlgorithm: test.sigAlgo,
+			DNSNames:           []string{"test.example.com"},
+			EmailAddresses:     []string{"gopher at golang.org"},
+			IPAddresses:        []net.IP{net.IPv4(127, 0, 0, 1).To4(), net.ParseIP("2001:4860:0:2001::68")},
+		}
+
+		derBytes, err := CreateCertificateRequest(random, &template, test.priv)
+		if err != nil {
+			t.Errorf("%s: failed to create certificate request: %s", test.name, err)
+			continue
+		}
+
+		out, err := ParseCertificateRequest(derBytes)
+		if err != nil {
+			t.Errorf("%s: failed to create certificate request: %s", test.name, err)
+			continue
+		}
+
+		if out.Subject.CommonName != template.Subject.CommonName {
+			t.Errorf("%s: output subject common name and template subject common name don't match", test.name)
+		} else if len(out.Subject.Organization) != len(template.Subject.Organization) {
+			t.Errorf("%s: output subject organisation and template subject organisation don't match", test.name)
+		} else if len(out.DNSNames) != len(template.DNSNames) {
+			t.Errorf("%s: output DNS names and template DNS names don't match", test.name)
+		} else if len(out.EmailAddresses) != len(template.EmailAddresses) {
+			t.Errorf("%s: output email addresses and template email addresses don't match", test.name)
+		} else if len(out.IPAddresses) != len(template.IPAddresses) {
+			t.Errorf("%s: output IP addresses and template IP addresses names don't match", test.name)
+		}
+	}
+}
+
+func marshalAndParseCSR(t *testing.T, template *CertificateRequest) *CertificateRequest {
+	block, _ := pem.Decode([]byte(pemPrivateKey))
+	rsaPriv, err := ParsePKCS1PrivateKey(block.Bytes)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	derBytes, err := CreateCertificateRequest(rand.Reader, template, rsaPriv)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	csr, err := ParseCertificateRequest(derBytes)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	return csr
+}
+
+func TestCertificateRequestOverrides(t *testing.T) {
+	sanContents, err := marshalSANs([]string{"foo.example.com"}, nil, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	template := CertificateRequest{
+		Subject: pkix.Name{
+			CommonName:   "test.example.com",
+			Organization: []string{"Σ Acme Co"},
+		},
+		DNSNames: []string{"test.example.com"},
+
+		// An explicit extension should override the DNSNames from the
+		// template.
+		ExtraExtensions: []pkix.Extension{
+			pkix.Extension{
+				Id:    oidExtensionSubjectAltName,
+				Value: sanContents,
+			},
+		},
+	}
+
+	csr := marshalAndParseCSR(t, &template)
+
+	if len(csr.DNSNames) != 1 || csr.DNSNames[0] != "foo.example.com" {
+		t.Errorf("Extension did not override template. Got %v\n", csr.DNSNames)
+	}
+
+	// If there is already an attribute with X.509 extensions then the
+	// extra extensions should be added to it rather than creating a CSR
+	// with two extension attributes.
+
+	template.Attributes = []pkix.AttributeTypeAndValueSET{
+		pkix.AttributeTypeAndValueSET{
+			Type: oidExtensionRequest,
+			Value: [][]pkix.AttributeTypeAndValue{
+				[]pkix.AttributeTypeAndValue{
+					pkix.AttributeTypeAndValue{
+						Type:  oidExtensionAuthorityInfoAccess,
+						Value: []byte("foo"),
+					},
+				},
+			},
+		},
+	}
+
+	csr = marshalAndParseCSR(t, &template)
+	if l := len(csr.Attributes); l != 1 {
+		t.Errorf("incorrect number of attributes: %d\n", l)
+	}
+
+	if !csr.Attributes[0].Type.Equal(oidExtensionRequest) ||
+		len(csr.Attributes[0].Value) != 1 ||
+		len(csr.Attributes[0].Value[0]) != 2 {
+		t.Errorf("bad attributes: %#v\n", csr.Attributes)
+	}
+
+	sanContents2, err := marshalSANs([]string{"foo2.example.com"}, nil, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Extensions in Attributes should override those in ExtraExtensions.
+	template.Attributes[0].Value[0] = append(template.Attributes[0].Value[0], pkix.AttributeTypeAndValue{
+		Type:  oidExtensionSubjectAltName,
+		Value: sanContents2,
+	})
+
+	csr = marshalAndParseCSR(t, &template)
+
+	if len(csr.DNSNames) != 1 || csr.DNSNames[0] != "foo2.example.com" {
+		t.Errorf("Attributes did not override ExtraExtensions. Got %v\n", csr.DNSNames)
+	}
+}
+
+func TestParseCertificateRequest(t *testing.T) {
+	csrBytes := fromBase64(csrBase64)
+	csr, err := ParseCertificateRequest(csrBytes)
+	if err != nil {
+		t.Fatalf("failed to parse CSR: %s", err)
+	}
+
+	if len(csr.EmailAddresses) != 1 || csr.EmailAddresses[0] != "gopher at golang.org" {
+		t.Errorf("incorrect email addresses found: %v", csr.EmailAddresses)
+	}
+
+	if len(csr.DNSNames) != 1 || csr.DNSNames[0] != "test.example.com" {
+		t.Errorf("incorrect DNS names found: %v", csr.DNSNames)
+	}
+
+	if len(csr.Subject.Country) != 1 || csr.Subject.Country[0] != "AU" {
+		t.Errorf("incorrect Subject name: %v", csr.Subject)
+	}
+
+	found := false
+	for _, e := range csr.Extensions {
+		if e.Id.Equal(oidExtensionBasicConstraints) {
+			found = true
+			break
+		}
+	}
+	if !found {
+		t.Errorf("basic constraints extension not found in CSR")
+	}
+}
+
+// This CSR was generated with OpenSSL:
+//  openssl req -out CSR.csr -new -newkey rsa:2048 -nodes -keyout privateKey.key -config openssl.cnf
+//
+// The openssl.cnf needs to include this section:
+//   [ v3_req ]
+//   basicConstraints = CA:FALSE
+//   keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+//   subjectAltName = email:gopher at golang.org,DNS:test.example.com
+const csrBase64 = "MIIC4zCCAcsCAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOY+MVedRg2JEnyeLcSzcsMv2VcsTfkB5+Etd6hihAh6MrGezNyASMMKuQN6YhCX1icQDiQtGsDLTtheNnSXK06tAhHjAP/hGlszRJp+5+rP2M58fDBAkUBEhskbCUWwpY14jFtVuGNJ8vF8h8IeczdolvQhX9lVai9G0EUXJMliMKdjA899H0mRs9PzHyidyrXFNiZlQXfD8Kg7gETn2Ny965iyI6ujAIYSCvam6TnxRHYH2MBKyVGvsYGbPYUQJCsgdgyajEg6ekihvQY3SzO1HSAlZAd7d1QYO4VeWJ2mY6Wu3Jpmh+AmG19S9CcHq [...]
diff --git a/src/pkg/crypto/x509/x509_test_import.go b/src/pkg/crypto/x509/x509_test_import.go
new file mode 100644
index 0000000..3fda7da
--- /dev/null
+++ b/src/pkg/crypto/x509/x509_test_import.go
@@ -0,0 +1,53 @@
+// 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
+
+// This file is run by the x509 tests to ensure that a program with minimal
+// imports can sign certificates without errors resulting from missing hash
+// functions.
+package main
+
+import (
+	"crypto/rand"
+	"crypto/x509"
+	"crypto/x509/pkix"
+	"encoding/pem"
+	"math/big"
+	"time"
+)
+
+func main() {
+	block, _ := pem.Decode([]byte(pemPrivateKey))
+	rsaPriv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
+	if err != nil {
+		panic("Failed to parse private key: " + err.Error())
+	}
+
+	template := x509.Certificate{
+		SerialNumber: big.NewInt(1),
+		Subject: pkix.Name{
+			CommonName:   "test",
+			Organization: []string{"Σ Acme Co"},
+		},
+		NotBefore: time.Unix(1000, 0),
+		NotAfter:  time.Unix(100000, 0),
+		KeyUsage:  x509.KeyUsageCertSign,
+	}
+
+	if _, err = x509.CreateCertificate(rand.Reader, &template, &template, &rsaPriv.PublicKey, rsaPriv); err != nil {
+		panic("failed to create certificate with basic imports: " + err.Error())
+	}
+}
+
+var pemPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
+MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
+fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
+/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
+RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
+EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
+IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
+tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
+-----END RSA PRIVATE KEY-----
+`
diff --git a/src/pkg/database/sql/convert.go b/src/pkg/database/sql/convert.go
index c04adde..c0b38a2 100644
--- a/src/pkg/database/sql/convert.go
+++ b/src/pkg/database/sql/convert.go
@@ -160,27 +160,19 @@ func convertAssign(dest, src interface{}) error {
 			reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
 			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
 			reflect.Float32, reflect.Float64:
-			*d = fmt.Sprintf("%v", src)
+			*d = asString(src)
 			return nil
 		}
 	case *[]byte:
 		sv = reflect.ValueOf(src)
-		switch sv.Kind() {
-		case reflect.Bool,
-			reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
-			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
-			reflect.Float32, reflect.Float64:
-			*d = []byte(fmt.Sprintf("%v", src))
+		if b, ok := asBytes(nil, sv); ok {
+			*d = b
 			return nil
 		}
 	case *RawBytes:
 		sv = reflect.ValueOf(src)
-		switch sv.Kind() {
-		case reflect.Bool,
-			reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
-			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
-			reflect.Float32, reflect.Float64:
-			*d = RawBytes(fmt.Sprintf("%v", src))
+		if b, ok := asBytes([]byte(*d)[:0], sv); ok {
+			*d = RawBytes(b)
 			return nil
 		}
 	case *bool:
@@ -271,5 +263,37 @@ func asString(src interface{}) string {
 	case []byte:
 		return string(v)
 	}
+	rv := reflect.ValueOf(src)
+	switch rv.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return strconv.FormatInt(rv.Int(), 10)
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		return strconv.FormatUint(rv.Uint(), 10)
+	case reflect.Float64:
+		return strconv.FormatFloat(rv.Float(), 'g', -1, 64)
+	case reflect.Float32:
+		return strconv.FormatFloat(rv.Float(), 'g', -1, 32)
+	case reflect.Bool:
+		return strconv.FormatBool(rv.Bool())
+	}
 	return fmt.Sprintf("%v", src)
 }
+
+func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
+	switch rv.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return strconv.AppendInt(buf, rv.Int(), 10), true
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		return strconv.AppendUint(buf, rv.Uint(), 10), true
+	case reflect.Float32:
+		return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true
+	case reflect.Float64:
+		return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true
+	case reflect.Bool:
+		return strconv.AppendBool(buf, rv.Bool()), true
+	case reflect.String:
+		s := rv.String()
+		return append(buf, s...), true
+	}
+	return
+}
diff --git a/src/pkg/database/sql/convert_test.go b/src/pkg/database/sql/convert_test.go
index a39c2c5..6e24830 100644
--- a/src/pkg/database/sql/convert_test.go
+++ b/src/pkg/database/sql/convert_test.go
@@ -8,6 +8,7 @@ import (
 	"database/sql/driver"
 	"fmt"
 	"reflect"
+	"runtime"
 	"testing"
 	"time"
 )
@@ -279,3 +280,58 @@ func TestValueConverters(t *testing.T) {
 		}
 	}
 }
+
+// Tests that assigning to RawBytes doesn't allocate (and also works).
+func TestRawBytesAllocs(t *testing.T) {
+	buf := make(RawBytes, 10)
+	test := func(name string, in interface{}, want string) {
+		if err := convertAssign(&buf, in); err != nil {
+			t.Fatalf("%s: convertAssign = %v", name, err)
+		}
+		match := len(buf) == len(want)
+		if match {
+			for i, b := range buf {
+				if want[i] != b {
+					match = false
+					break
+				}
+			}
+		}
+		if !match {
+			t.Fatalf("%s: got %q (len %d); want %q (len %d)", name, buf, len(buf), want, len(want))
+		}
+	}
+	n := testing.AllocsPerRun(100, func() {
+		test("uint64", uint64(12345678), "12345678")
+		test("uint32", uint32(1234), "1234")
+		test("uint16", uint16(12), "12")
+		test("uint8", uint8(1), "1")
+		test("uint", uint(123), "123")
+		test("int", int(123), "123")
+		test("int8", int8(1), "1")
+		test("int16", int16(12), "12")
+		test("int32", int32(1234), "1234")
+		test("int64", int64(12345678), "12345678")
+		test("float32", float32(1.5), "1.5")
+		test("float64", float64(64), "64")
+		test("bool", false, "false")
+	})
+
+	// The numbers below are only valid for 64-bit interface word sizes,
+	// and gc. With 32-bit words there are more convT2E allocs, and
+	// with gccgo, only pointers currently go in interface data.
+	// So only care on amd64 gc for now.
+	measureAllocs := runtime.GOARCH == "amd64" && runtime.Compiler == "gc"
+
+	if n > 0.5 && measureAllocs {
+		t.Fatalf("allocs = %v; want 0", n)
+	}
+
+	// This one involves a convT2E allocation, string -> interface{}
+	n = testing.AllocsPerRun(100, func() {
+		test("string", "foo", "foo")
+	})
+	if n > 1.5 && measureAllocs {
+		t.Fatalf("allocs = %v; want max 1", n)
+	}
+}
diff --git a/src/pkg/database/sql/driver/driver.go b/src/pkg/database/sql/driver/driver.go
index 0828e63..eca25f2 100644
--- a/src/pkg/database/sql/driver/driver.go
+++ b/src/pkg/database/sql/driver/driver.go
@@ -134,7 +134,7 @@ type Stmt interface {
 	// as an INSERT or UPDATE.
 	Exec(args []Value) (Result, error)
 
-	// Exec executes a query that may return rows, such as a
+	// Query executes a query that may return rows, such as a
 	// SELECT.
 	Query(args []Value) (Rows, error)
 }
diff --git a/src/pkg/database/sql/example_test.go b/src/pkg/database/sql/example_test.go
index d47eed5..dcb74e0 100644
--- a/src/pkg/database/sql/example_test.go
+++ b/src/pkg/database/sql/example_test.go
@@ -18,6 +18,7 @@ func ExampleDB_Query() {
 	if err != nil {
 		log.Fatal(err)
 	}
+	defer rows.Close()
 	for rows.Next() {
 		var name string
 		if err := rows.Scan(&name); err != nil {
diff --git a/src/pkg/database/sql/fakedb_test.go b/src/pkg/database/sql/fakedb_test.go
index a8adfdd..c7db0dd 100644
--- a/src/pkg/database/sql/fakedb_test.go
+++ b/src/pkg/database/sql/fakedb_test.go
@@ -23,7 +23,7 @@ var _ = log.Printf
 // interface, just for testing.
 //
 // It speaks a query language that's semantically similar to but
-// syntantically different and simpler than SQL.  The syntax is as
+// syntactically different and simpler than SQL.  The syntax is as
 // follows:
 //
 //   WIPE
@@ -433,11 +433,19 @@ func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (driver.Stmt, e
 	return stmt, nil
 }
 
+// hook to simulate broken connections
+var hookPrepareBadConn func() bool
+
 func (c *fakeConn) Prepare(query string) (driver.Stmt, error) {
 	c.numPrepare++
 	if c.db == nil {
 		panic("nil c.db; conn = " + fmt.Sprintf("%#v", c))
 	}
+
+	if hookPrepareBadConn != nil && hookPrepareBadConn() {
+		return nil, driver.ErrBadConn
+	}
+
 	parts := strings.Split(query, "|")
 	if len(parts) < 1 {
 		return nil, errf("empty query")
@@ -489,10 +497,18 @@ func (s *fakeStmt) Close() error {
 
 var errClosed = errors.New("fakedb: statement has been closed")
 
+// hook to simulate broken connections
+var hookExecBadConn func() bool
+
 func (s *fakeStmt) Exec(args []driver.Value) (driver.Result, error) {
 	if s.closed {
 		return nil, errClosed
 	}
+
+	if hookExecBadConn != nil && hookExecBadConn() {
+		return nil, driver.ErrBadConn
+	}
+
 	err := checkSubsetTypes(args)
 	if err != nil {
 		return nil, err
@@ -565,10 +581,18 @@ func (s *fakeStmt) execInsert(args []driver.Value, doInsert bool) (driver.Result
 	return driver.RowsAffected(1), nil
 }
 
+// hook to simulate broken connections
+var hookQueryBadConn func() bool
+
 func (s *fakeStmt) Query(args []driver.Value) (driver.Rows, error) {
 	if s.closed {
 		return nil, errClosed
 	}
+
+	if hookQueryBadConn != nil && hookQueryBadConn() {
+		return nil, driver.ErrBadConn
+	}
+
 	err := checkSubsetTypes(args)
 	if err != nil {
 		return nil, err
@@ -686,7 +710,13 @@ func (rc *rowsCursor) Columns() []string {
 	return rc.cols
 }
 
+var rowsCursorNextHook func(dest []driver.Value) error
+
 func (rc *rowsCursor) Next(dest []driver.Value) error {
+	if rowsCursorNextHook != nil {
+		return rowsCursorNextHook(dest)
+	}
+
 	if rc.closed {
 		return errors.New("fakedb: cursor is closed")
 	}
diff --git a/src/pkg/database/sql/sql.go b/src/pkg/database/sql/sql.go
index 84a0965..765b80c 100644
--- a/src/pkg/database/sql/sql.go
+++ b/src/pkg/database/sql/sql.go
@@ -181,7 +181,8 @@ type Scanner interface {
 // defers this error until a Scan.
 var ErrNoRows = errors.New("sql: no rows in result set")
 
-// DB is a database handle. It's safe for concurrent use by multiple
+// DB is a database handle representing a pool of zero or more
+// underlying connections. It's safe for concurrent use by multiple
 // goroutines.
 //
 // The sql package creates and frees connections automatically; it
@@ -256,7 +257,7 @@ func (dc *driverConn) prepareLocked(query string) (driver.Stmt, error) {
 		// stmt closes if the conn is about to close anyway? For now
 		// do the safe thing, in case stmts need to be closed.
 		//
-		// TODO(bradfitz): after Go 1.1, closing driver.Stmts
+		// TODO(bradfitz): after Go 1.2, closing driver.Stmts
 		// should be moved to driverStmt, using unique
 		// *driverStmts everywhere (including from
 		// *Stmt.connStmt, instead of returning a
@@ -405,7 +406,7 @@ func (db *DB) removeDepLocked(x finalCloser, dep interface{}) func() error {
 // This value should be larger than the maximum typical value
 // used for db.maxOpen. If maxOpen is significantly larger than
 // connectionRequestQueueSize then it is possible for ALL calls into the *DB
-// to block until the connectionOpener can satify the backlog of requests.
+// to block until the connectionOpener can satisfy the backlog of requests.
 var connectionRequestQueueSize = 1000000
 
 // Open opens a database specified by its database driver name and a
@@ -420,6 +421,11 @@ var connectionRequestQueueSize = 1000000
 // Open may just validate its arguments without creating a connection
 // to the database. To verify that the data source name is valid, call
 // Ping.
+//
+// The returned DB is safe for concurrent use by multiple goroutines
+// and maintains its own pool of idle connections. Thus, the Open
+// function should be called just once. It is rarely necessary to
+// close a DB.
 func Open(driverName, dataSourceName string) (*DB, error) {
 	driveri, ok := drivers[driverName]
 	if !ok {
@@ -452,6 +458,9 @@ func (db *DB) Ping() error {
 }
 
 // Close closes the database, releasing any open resources.
+//
+// It is rare to Close a DB, as the DB handle is meant to be
+// long-lived and shared between many goroutines.
 func (db *DB) Close() error {
 	db.mu.Lock()
 	if db.closed { // Make DB.Close idempotent
@@ -569,7 +578,7 @@ func (db *DB) maybeOpenNewConnections() {
 	}
 }
 
-// Runs in a seperate goroutine, opens new connections when requested.
+// Runs in a separate goroutine, opens new connections when requested.
 func (db *DB) connectionOpener() {
 	for _ = range db.openerCh {
 		db.openNewConnection()
@@ -652,13 +661,16 @@ func (db *DB) conn() (*driverConn, error) {
 		return conn, nil
 	}
 
+	db.numOpen++ // optimistically
 	db.mu.Unlock()
 	ci, err := db.driver.Open(db.dsn)
 	if err != nil {
+		db.mu.Lock()
+		db.numOpen-- // correct for earlier optimism
+		db.mu.Unlock()
 		return nil, err
 	}
 	db.mu.Lock()
-	db.numOpen++
 	dc := &driverConn{
 		db: db,
 		ci: ci,
@@ -774,11 +786,11 @@ func (db *DB) putConn(dc *driverConn, err error) {
 // Satisfy a connRequest or put the driverConn in the idle pool and return true
 // or return false.
 // putConnDBLocked will satisfy a connRequest if there is one, or it will
-// return the *driverConn to the freeConn list if err != nil and the idle
-// connection limit would not be reached.
+// return the *driverConn to the freeConn list if err == nil and the idle
+// connection limit will not be exceeded.
 // If err != nil, the value of dc is ignored.
 // If err == nil, then dc must not equal nil.
-// If a connRequest was fullfilled or the *driverConn was placed in the
+// If a connRequest was fulfilled or the *driverConn was placed in the
 // freeConn list, then true is returned, otherwise false is returned.
 func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
 	if db.connRequests.Len() > 0 {
@@ -791,20 +803,24 @@ func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
 			req <- dc
 		}
 		return true
-	} else if err == nil && !db.closed && db.maxIdleConnsLocked() > 0 && db.maxIdleConnsLocked() > db.freeConn.Len() {
+	} else if err == nil && !db.closed && db.maxIdleConnsLocked() > db.freeConn.Len() {
 		dc.listElem = db.freeConn.PushFront(dc)
 		return true
 	}
 	return false
 }
 
+// maxBadConnRetries is the number of maximum retries if the driver returns
+// driver.ErrBadConn to signal a broken connection.
+const maxBadConnRetries = 10
+
 // Prepare creates a prepared statement for later queries or executions.
 // Multiple queries or executions may be run concurrently from the
 // returned statement.
 func (db *DB) Prepare(query string) (*Stmt, error) {
 	var stmt *Stmt
 	var err error
-	for i := 0; i < 10; i++ {
+	for i := 0; i < maxBadConnRetries; i++ {
 		stmt, err = db.prepare(query)
 		if err != driver.ErrBadConn {
 			break
@@ -846,7 +862,7 @@ func (db *DB) prepare(query string) (*Stmt, error) {
 func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
 	var res Result
 	var err error
-	for i := 0; i < 10; i++ {
+	for i := 0; i < maxBadConnRetries; i++ {
 		res, err = db.exec(query, args)
 		if err != driver.ErrBadConn {
 			break
@@ -895,7 +911,7 @@ func (db *DB) exec(query string, args []interface{}) (res Result, err error) {
 func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
 	var rows *Rows
 	var err error
-	for i := 0; i < 10; i++ {
+	for i := 0; i < maxBadConnRetries; i++ {
 		rows, err = db.query(query, args)
 		if err != driver.ErrBadConn {
 			break
@@ -983,7 +999,7 @@ func (db *DB) QueryRow(query string, args ...interface{}) *Row {
 func (db *DB) Begin() (*Tx, error) {
 	var tx *Tx
 	var err error
-	for i := 0; i < 10; i++ {
+	for i := 0; i < maxBadConnRetries; i++ {
 		tx, err = db.begin()
 		if err != driver.ErrBadConn {
 			break
@@ -1245,13 +1261,24 @@ type Stmt struct {
 func (s *Stmt) Exec(args ...interface{}) (Result, error) {
 	s.closemu.RLock()
 	defer s.closemu.RUnlock()
-	dc, releaseConn, si, err := s.connStmt()
-	if err != nil {
-		return nil, err
-	}
-	defer releaseConn(nil)
 
-	return resultFromStatement(driverStmt{dc, si}, args...)
+	var res Result
+	for i := 0; i < maxBadConnRetries; i++ {
+		dc, releaseConn, si, err := s.connStmt()
+		if err != nil {
+			if err == driver.ErrBadConn {
+				continue
+			}
+			return nil, err
+		}
+
+		res, err = resultFromStatement(driverStmt{dc, si}, args...)
+		releaseConn(err)
+		if err != driver.ErrBadConn {
+			return res, err
+		}
+	}
+	return nil, driver.ErrBadConn
 }
 
 func resultFromStatement(ds driverStmt, args ...interface{}) (Result, error) {
@@ -1329,26 +1356,21 @@ func (s *Stmt) connStmt() (ci *driverConn, releaseConn func(error), si driver.St
 	// Make a new conn if all are busy.
 	// TODO(bradfitz): or wait for one? make configurable later?
 	if !match {
-		for i := 0; ; i++ {
-			dc, err := s.db.conn()
-			if err != nil {
-				return nil, nil, nil, err
-			}
-			dc.Lock()
-			si, err := dc.prepareLocked(s.query)
-			dc.Unlock()
-			if err == driver.ErrBadConn && i < 10 {
-				continue
-			}
-			if err != nil {
-				return nil, nil, nil, err
-			}
-			s.mu.Lock()
-			cs = connStmt{dc, si}
-			s.css = append(s.css, cs)
-			s.mu.Unlock()
-			break
+		dc, err := s.db.conn()
+		if err != nil {
+			return nil, nil, nil, err
+		}
+		dc.Lock()
+		si, err := dc.prepareLocked(s.query)
+		dc.Unlock()
+		if err != nil {
+			s.db.putConn(dc, err)
+			return nil, nil, nil, err
 		}
+		s.mu.Lock()
+		cs = connStmt{dc, si}
+		s.css = append(s.css, cs)
+		s.mu.Unlock()
 	}
 
 	conn := cs.dc
@@ -1361,31 +1383,39 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
 	s.closemu.RLock()
 	defer s.closemu.RUnlock()
 
-	dc, releaseConn, si, err := s.connStmt()
-	if err != nil {
-		return nil, err
-	}
+	var rowsi driver.Rows
+	for i := 0; i < maxBadConnRetries; i++ {
+		dc, releaseConn, si, err := s.connStmt()
+		if err != nil {
+			if err == driver.ErrBadConn {
+				continue
+			}
+			return nil, err
+		}
 
-	ds := driverStmt{dc, si}
-	rowsi, err := rowsiFromStatement(ds, args...)
-	if err != nil {
-		releaseConn(err)
-		return nil, err
-	}
+		rowsi, err = rowsiFromStatement(driverStmt{dc, si}, args...)
+		if err == nil {
+			// Note: ownership of ci passes to the *Rows, to be freed
+			// with releaseConn.
+			rows := &Rows{
+				dc:    dc,
+				rowsi: rowsi,
+				// releaseConn set below
+			}
+			s.db.addDep(s, rows)
+			rows.releaseConn = func(err error) {
+				releaseConn(err)
+				s.db.removeDep(s, rows)
+			}
+			return rows, nil
+		}
 
-	// Note: ownership of ci passes to the *Rows, to be freed
-	// with releaseConn.
-	rows := &Rows{
-		dc:    dc,
-		rowsi: rowsi,
-		// releaseConn set below
-	}
-	s.db.addDep(s, rows)
-	rows.releaseConn = func(err error) {
 		releaseConn(err)
-		s.db.removeDep(s, rows)
+		if err != driver.ErrBadConn {
+			return nil, err
+		}
 	}
-	return rows, nil
+	return nil, driver.ErrBadConn
 }
 
 func rowsiFromStatement(ds driverStmt, args ...interface{}) (driver.Rows, error) {
@@ -1476,6 +1506,7 @@ func (s *Stmt) finalClose() error {
 //
 //     rows, err := db.Query("SELECT ...")
 //     ...
+//     defer rows.Close()
 //     for rows.Next() {
 //         var id int
 //         var name string
@@ -1495,10 +1526,12 @@ type Rows struct {
 	closeStmt driver.Stmt // if non-nil, statement to Close on close
 }
 
-// Next prepares the next result row for reading with the Scan method.
-// It returns true on success, false if there is no next result row.
-// Every call to Scan, even the first one, must be preceded by a call
-// to Next.
+// Next prepares the next result row for reading with the Scan method.  It
+// returns true on success, or false if there is no next result row or an error
+// happened while preparing it.  Err should be consulted to distinguish between
+// the two cases.
+//
+// Every call to Scan, even the first one, must be preceded by a call to Next.
 func (rs *Rows) Next() bool {
 	if rs.closed {
 		return false
@@ -1625,12 +1658,19 @@ func (r *Row) Scan(dest ...interface{}) error {
 	}
 
 	if !r.rows.Next() {
+		if err := r.rows.Err(); err != nil {
+			return err
+		}
 		return ErrNoRows
 	}
 	err := r.rows.Scan(dest...)
 	if err != nil {
 		return err
 	}
+	// Make sure the query can be processed to completion with no errors.
+	if err := r.rows.Close(); err != nil {
+		return err
+	}
 
 	return nil
 }
diff --git a/src/pkg/database/sql/sql_test.go b/src/pkg/database/sql/sql_test.go
index 787a5c9..7971f14 100644
--- a/src/pkg/database/sql/sql_test.go
+++ b/src/pkg/database/sql/sql_test.go
@@ -348,7 +348,6 @@ func TestStatementQueryRow(t *testing.T) {
 			t.Errorf("%d: age=%d, want %d", n, age, tt.want)
 		}
 	}
-
 }
 
 // golang.org/issue/3734
@@ -462,7 +461,7 @@ func TestTxStmt(t *testing.T) {
 }
 
 // Issue: http://golang.org/issue/2784
-// This test didn't fail before because we got luckly with the fakedb driver.
+// This test didn't fail before because we got lucky with the fakedb driver.
 // It was failing, and now not, in github.com/bradfitz/go-sql-test
 func TestTxQuery(t *testing.T) {
 	db := newTestDB(t, "")
@@ -660,6 +659,35 @@ func TestQueryRowClosingStmt(t *testing.T) {
 	}
 }
 
+// Test issue 6651
+func TestIssue6651(t *testing.T) {
+	db := newTestDB(t, "people")
+	defer closeDB(t, db)
+
+	var v string
+
+	want := "error in rows.Next"
+	rowsCursorNextHook = func(dest []driver.Value) error {
+		return fmt.Errorf(want)
+	}
+	defer func() { rowsCursorNextHook = nil }()
+	err := db.QueryRow("SELECT|people|name|").Scan(&v)
+	if err == nil || err.Error() != want {
+		t.Errorf("error = %q; want %q", err, want)
+	}
+	rowsCursorNextHook = nil
+
+	want = "error in rows.Close"
+	rowsCloseHook = func(rows *Rows, err *error) {
+		*err = fmt.Errorf(want)
+	}
+	defer func() { rowsCloseHook = nil }()
+	err = db.QueryRow("SELECT|people|name|").Scan(&v)
+	if err == nil || err.Error() != want {
+		t.Errorf("error = %q; want %q", err, want)
+	}
+}
+
 type nullTestRow struct {
 	nullParam    interface{}
 	notNullParam interface{}
@@ -1249,6 +1277,111 @@ func TestStmtCloseOrder(t *testing.T) {
 	}
 }
 
+// golang.org/issue/5781
+func TestErrBadConnReconnect(t *testing.T) {
+	db := newTestDB(t, "foo")
+	defer closeDB(t, db)
+	exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
+
+	simulateBadConn := func(name string, hook *func() bool, op func() error) {
+		broken, retried := false, false
+		numOpen := db.numOpen
+
+		// simulate a broken connection on the first try
+		*hook = func() bool {
+			if !broken {
+				broken = true
+				return true
+			}
+			retried = true
+			return false
+		}
+
+		if err := op(); err != nil {
+			t.Errorf(name+": %v", err)
+			return
+		}
+
+		if !broken || !retried {
+			t.Error(name + ": Failed to simulate broken connection")
+		}
+		*hook = nil
+
+		if numOpen != db.numOpen {
+			t.Errorf(name+": leaked %d connection(s)!", db.numOpen-numOpen)
+			numOpen = db.numOpen
+		}
+	}
+
+	// db.Exec
+	dbExec := func() error {
+		_, err := db.Exec("INSERT|t1|name=?,age=?,dead=?", "Gordon", 3, true)
+		return err
+	}
+	simulateBadConn("db.Exec prepare", &hookPrepareBadConn, dbExec)
+	simulateBadConn("db.Exec exec", &hookExecBadConn, dbExec)
+
+	// db.Query
+	dbQuery := func() error {
+		rows, err := db.Query("SELECT|t1|age,name|")
+		if err == nil {
+			err = rows.Close()
+		}
+		return err
+	}
+	simulateBadConn("db.Query prepare", &hookPrepareBadConn, dbQuery)
+	simulateBadConn("db.Query query", &hookQueryBadConn, dbQuery)
+
+	// db.Prepare
+	simulateBadConn("db.Prepare", &hookPrepareBadConn, func() error {
+		stmt, err := db.Prepare("INSERT|t1|name=?,age=?,dead=?")
+		if err != nil {
+			return err
+		}
+		stmt.Close()
+		return nil
+	})
+
+	// stmt.Exec
+	stmt1, err := db.Prepare("INSERT|t1|name=?,age=?,dead=?")
+	if err != nil {
+		t.Fatalf("prepare: %v", err)
+	}
+	defer stmt1.Close()
+	// make sure we must prepare the stmt first
+	for _, cs := range stmt1.css {
+		cs.dc.inUse = true
+	}
+
+	stmtExec := func() error {
+		_, err := stmt1.Exec("Gopher", 3, false)
+		return err
+	}
+	simulateBadConn("stmt.Exec prepare", &hookPrepareBadConn, stmtExec)
+	simulateBadConn("stmt.Exec exec", &hookExecBadConn, stmtExec)
+
+	// stmt.Query
+	stmt2, err := db.Prepare("SELECT|t1|age,name|")
+	if err != nil {
+		t.Fatalf("prepare: %v", err)
+	}
+	defer stmt2.Close()
+	// make sure we must prepare the stmt first
+	for _, cs := range stmt2.css {
+		cs.dc.inUse = true
+	}
+
+	stmtQuery := func() error {
+		rows, err := stmt2.Query()
+		if err == nil {
+			err = rows.Close()
+		}
+		return err
+	}
+	simulateBadConn("stmt.Query prepare", &hookPrepareBadConn, stmtQuery)
+	simulateBadConn("stmt.Query exec", &hookQueryBadConn, stmtQuery)
+}
+
 type concurrentTest interface {
 	init(t testing.TB, db *DB)
 	finish(t testing.TB)
diff --git a/src/pkg/debug/dwarf/const.go b/src/pkg/debug/dwarf/const.go
index 9d32a0a..93c6888 100644
--- a/src/pkg/debug/dwarf/const.go
+++ b/src/pkg/debug/dwarf/const.go
@@ -207,10 +207,15 @@ const (
 	formRef8        format = 0x14
 	formRefUdata    format = 0x15
 	formIndirect    format = 0x16
+	// The following are new in DWARF 4.
 	formSecOffset   format = 0x17
 	formExprloc     format = 0x18
 	formFlagPresent format = 0x19
 	formRefSig8     format = 0x20
+	// Extensions for multi-file compression (.dwz)
+	// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1
+	formGnuRefAlt  format = 0x1f20
+	formGnuStrpAlt format = 0x1f21
 )
 
 // A Tag is the classification (the type) of an Entry.
@@ -264,15 +269,22 @@ const (
 	TagVariantPart            Tag = 0x33
 	TagVariable               Tag = 0x34
 	TagVolatileType           Tag = 0x35
-	TagDwarfProcedure         Tag = 0x36
-	TagRestrictType           Tag = 0x37
-	TagInterfaceType          Tag = 0x38
-	TagNamespace              Tag = 0x39
-	TagImportedModule         Tag = 0x3A
-	TagUnspecifiedType        Tag = 0x3B
-	TagPartialUnit            Tag = 0x3C
-	TagImportedUnit           Tag = 0x3D
-	TagMutableType            Tag = 0x3E
+	// The following are new in DWARF 3.
+	TagDwarfProcedure  Tag = 0x36
+	TagRestrictType    Tag = 0x37
+	TagInterfaceType   Tag = 0x38
+	TagNamespace       Tag = 0x39
+	TagImportedModule  Tag = 0x3A
+	TagUnspecifiedType Tag = 0x3B
+	TagPartialUnit     Tag = 0x3C
+	TagImportedUnit    Tag = 0x3D
+	TagMutableType     Tag = 0x3E // Later removed from DWARF.
+	TagCondition       Tag = 0x3F
+	TagSharedType      Tag = 0x40
+	// The following are new in DWARF 4.
+	TagTypeUnit            Tag = 0x41
+	TagRvalueReferenceType Tag = 0x42
+	TagTemplateAlias       Tag = 0x43
 )
 
 var tagNames = [...]string{
@@ -332,6 +344,11 @@ var tagNames = [...]string{
 	TagPartialUnit:            "PartialUnit",
 	TagImportedUnit:           "ImportedUnit",
 	TagMutableType:            "MutableType",
+	TagCondition:              "Condition",
+	TagSharedType:             "SharedType",
+	TagTypeUnit:               "TypeUnit",
+	TagRvalueReferenceType:    "RvalueReferenceType",
+	TagTemplateAlias:          "TemplateAlias",
 }
 
 func (t Tag) String() string {
diff --git a/src/pkg/debug/dwarf/entry.go b/src/pkg/debug/dwarf/entry.go
index c0c2889..665c684 100644
--- a/src/pkg/debug/dwarf/entry.go
+++ b/src/pkg/debug/dwarf/entry.go
@@ -241,10 +241,10 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
 		// lineptr, loclistptr, macptr, rangelistptr
 		// New in DWARF 4, but clang can generate them with -gdwarf-2.
 		// Section reference, replacing use of formData4 and formData8.
-		case formSecOffset:
+		case formSecOffset, formGnuRefAlt, formGnuStrpAlt:
 			is64, known := b.format.dwarf64()
 			if !known {
-				b.error("unknown size for DW_FORM_sec_offset")
+				b.error("unknown size for form 0x" + strconv.FormatInt(int64(fmt), 16))
 			} else if is64 {
 				val = int64(b.uint64())
 			} else {
@@ -387,3 +387,15 @@ func (r *Reader) SkipChildren() {
 		}
 	}
 }
+
+// clone returns a copy of the reader.  This is used by the typeReader
+// interface.
+func (r *Reader) clone() typeReader {
+	return r.d.Reader()
+}
+
+// offset returns the current buffer offset.  This is used by the
+// typeReader interface.
+func (r *Reader) offset() Offset {
+	return r.b.off
+}
diff --git a/src/pkg/debug/dwarf/open.go b/src/pkg/debug/dwarf/open.go
index 37a518b..c1b3f37 100644
--- a/src/pkg/debug/dwarf/open.go
+++ b/src/pkg/debug/dwarf/open.go
@@ -24,9 +24,9 @@ type Data struct {
 
 	// parsed data
 	abbrevCache map[uint32]abbrevTable
-	addrsize    int
 	order       binary.ByteOrder
 	typeCache   map[Offset]Type
+	typeSigs    map[uint64]*typeUnit
 	unit        []unit
 }
 
@@ -50,6 +50,7 @@ func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Dat
 		str:         str,
 		abbrevCache: make(map[uint32]abbrevTable),
 		typeCache:   make(map[Offset]Type),
+		typeSigs:    make(map[uint64]*typeUnit),
 	}
 
 	// Sniff .debug_info to figure out byte order.
@@ -76,3 +77,11 @@ func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Dat
 	d.unit = u
 	return d, nil
 }
+
+// AddTypes will add one .debug_types section to the DWARF data.  A
+// typical object with DWARF version 4 debug info will have multiple
+// .debug_types sections.  The name is used for error reporting only,
+// and serves to distinguish one .debug_types section from another.
+func (d *Data) AddTypes(name string, types []byte) error {
+	return d.parseTypes(name, types)
+}
diff --git a/src/pkg/debug/dwarf/testdata/typedef.elf4 b/src/pkg/debug/dwarf/testdata/typedef.elf4
new file mode 100644
index 0000000..3d5a5a1
Binary files /dev/null and b/src/pkg/debug/dwarf/testdata/typedef.elf4 differ
diff --git a/src/pkg/debug/dwarf/type.go b/src/pkg/debug/dwarf/type.go
index 1fbae6c..68866d0 100644
--- a/src/pkg/debug/dwarf/type.go
+++ b/src/pkg/debug/dwarf/type.go
@@ -251,23 +251,37 @@ func (t *TypedefType) String() string { return t.Name }
 
 func (t *TypedefType) Size() int64 { return t.Type.Size() }
 
+// typeReader is used to read from either the info section or the
+// types section.
+type typeReader interface {
+	Seek(Offset)
+	Next() (*Entry, error)
+	clone() typeReader
+	offset() Offset
+}
+
+// Type reads the type at off in the DWARF ``info'' section.
 func (d *Data) Type(off Offset) (Type, error) {
-	if t, ok := d.typeCache[off]; ok {
+	return d.readType("info", d.Reader(), off, d.typeCache)
+}
+
+// readType reads a type from r at off of name using and updating a
+// type cache.
+func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type) (Type, error) {
+	if t, ok := typeCache[off]; ok {
 		return t, nil
 	}
-
-	r := d.Reader()
 	r.Seek(off)
 	e, err := r.Next()
 	if err != nil {
 		return nil, err
 	}
 	if e == nil || e.Offset != off {
-		return nil, DecodeError{"info", off, "no type at offset"}
+		return nil, DecodeError{name, off, "no type at offset"}
 	}
 
 	// Parse type from Entry.
-	// Must always set d.typeCache[off] before calling
+	// Must always set typeCache[off] before calling
 	// d.Type recursively, to handle circular types correctly.
 	var typ Type
 
@@ -290,7 +304,7 @@ func (d *Data) Type(off Offset) (Type, error) {
 				return nil
 			}
 			if kid == nil {
-				err = DecodeError{"info", r.b.off, "unexpected end of DWARF entries"}
+				err = DecodeError{name, r.offset(), "unexpected end of DWARF entries"}
 				return nil
 			}
 			if kid.Tag == 0 {
@@ -313,15 +327,21 @@ func (d *Data) Type(off Offset) (Type, error) {
 	// Get Type referred to by Entry's AttrType field.
 	// Set err if error happens.  Not having a type is an error.
 	typeOf := func(e *Entry) Type {
-		toff, ok := e.Val(AttrType).(Offset)
-		if !ok {
+		tval := e.Val(AttrType)
+		var t Type
+		switch toff := tval.(type) {
+		case Offset:
+			if t, err = d.readType(name, r.clone(), toff, typeCache); err != nil {
+				return nil
+			}
+		case uint64:
+			if t, err = d.sigToType(toff); err != nil {
+				return nil
+			}
+		default:
 			// It appears that no Type means "void".
 			return new(VoidType)
 		}
-		var t Type
-		if t, err = d.Type(toff); err != nil {
-			return nil
-		}
 		return t
 	}
 
@@ -337,7 +357,7 @@ func (d *Data) Type(off Offset) (Type, error) {
 		//	dimensions are in left to right order.
 		t := new(ArrayType)
 		typ = t
-		d.typeCache[off] = t
+		typeCache[off] = t
 		if t.Type = typeOf(e); err != nil {
 			goto Error
 		}
@@ -363,7 +383,7 @@ func (d *Data) Type(off Offset) (Type, error) {
 				}
 				ndim++
 			case TagEnumerationType:
-				err = DecodeError{"info", kid.Offset, "cannot handle enumeration type as array bound"}
+				err = DecodeError{name, kid.Offset, "cannot handle enumeration type as array bound"}
 				goto Error
 			}
 		}
@@ -383,12 +403,12 @@ func (d *Data) Type(off Offset) (Type, error) {
 		name, _ := e.Val(AttrName).(string)
 		enc, ok := e.Val(AttrEncoding).(int64)
 		if !ok {
-			err = DecodeError{"info", e.Offset, "missing encoding attribute for " + name}
+			err = DecodeError{name, e.Offset, "missing encoding attribute for " + name}
 			goto Error
 		}
 		switch enc {
 		default:
-			err = DecodeError{"info", e.Offset, "unrecognized encoding attribute value"}
+			err = DecodeError{name, e.Offset, "unrecognized encoding attribute value"}
 			goto Error
 
 		case encAddress:
@@ -408,7 +428,7 @@ func (d *Data) Type(off Offset) (Type, error) {
 		case encUnsignedChar:
 			typ = new(UcharType)
 		}
-		d.typeCache[off] = typ
+		typeCache[off] = typ
 		t := typ.(interface {
 			Basic() *BasicType
 		}).Basic()
@@ -433,7 +453,7 @@ func (d *Data) Type(off Offset) (Type, error) {
 		// There is much more to handle C++, all ignored for now.
 		t := new(StructType)
 		typ = t
-		d.typeCache[off] = t
+		typeCache[off] = t
 		switch e.Tag {
 		case TagClassType:
 			t.Kind = "class"
@@ -453,12 +473,13 @@ func (d *Data) Type(off Offset) (Type, error) {
 				if f.Type = typeOf(kid); err != nil {
 					goto Error
 				}
-				if loc, ok := kid.Val(AttrDataMemberLoc).([]byte); ok {
+				switch loc := kid.Val(AttrDataMemberLoc).(type) {
+				case []byte:
 					// TODO: Should have original compilation
 					// unit here, not unknownFormat.
 					b := makeBuf(d, unknownFormat{}, "location", 0, loc)
 					if b.uint8() != opPlusUconst {
-						err = DecodeError{"info", kid.Offset, "unexpected opcode"}
+						err = DecodeError{name, kid.Offset, "unexpected opcode"}
 						goto Error
 					}
 					f.ByteOffset = int64(b.uint())
@@ -466,6 +487,8 @@ func (d *Data) Type(off Offset) (Type, error) {
 						err = b.err
 						goto Error
 					}
+				case int64:
+					f.ByteOffset = loc
 				}
 
 				haveBitOffset := false
@@ -502,7 +525,7 @@ func (d *Data) Type(off Offset) (Type, error) {
 		//	AttrType: subtype
 		t := new(QualType)
 		typ = t
-		d.typeCache[off] = t
+		typeCache[off] = t
 		if t.Type = typeOf(e); err != nil {
 			goto Error
 		}
@@ -526,7 +549,7 @@ func (d *Data) Type(off Offset) (Type, error) {
 		//		AttrConstValue: value of constant
 		t := new(EnumType)
 		typ = t
-		d.typeCache[off] = t
+		typeCache[off] = t
 		t.EnumName, _ = e.Val(AttrName).(string)
 		t.Val = make([]*EnumValue, 0, 8)
 		for kid := next(); kid != nil; kid = next() {
@@ -552,7 +575,7 @@ func (d *Data) Type(off Offset) (Type, error) {
 		//	AttrAddrClass: address class [ignored]
 		t := new(PtrType)
 		typ = t
-		d.typeCache[off] = t
+		typeCache[off] = t
 		if e.Val(AttrType) == nil {
 			t.Type = &VoidType{}
 			break
@@ -571,7 +594,7 @@ func (d *Data) Type(off Offset) (Type, error) {
 		//	TagUnspecifiedParameter: final ...
 		t := new(FuncType)
 		typ = t
-		d.typeCache[off] = t
+		typeCache[off] = t
 		if t.ReturnType = typeOf(e); err != nil {
 			goto Error
 		}
@@ -598,7 +621,7 @@ func (d *Data) Type(off Offset) (Type, error) {
 		//	AttrType: type definition [required]
 		t := new(TypedefType)
 		typ = t
-		d.typeCache[off] = t
+		typeCache[off] = t
 		t.Name, _ = e.Val(AttrName).(string)
 		t.Type = typeOf(e)
 	}
@@ -620,7 +643,7 @@ Error:
 	// If the parse fails, take the type out of the cache
 	// so that the next call with this offset doesn't hit
 	// the cache and return success.
-	delete(d.typeCache, off)
+	delete(typeCache, off)
 	return nil, err
 }
 
diff --git a/src/pkg/debug/dwarf/type_test.go b/src/pkg/debug/dwarf/type_test.go
index b5b255f..2cb85e7 100644
--- a/src/pkg/debug/dwarf/type_test.go
+++ b/src/pkg/debug/dwarf/type_test.go
@@ -73,6 +73,8 @@ func TestTypedefsMachO(t *testing.T) {
 	testTypedefs(t, machoData(t, "testdata/typedef.macho"), "macho")
 }
 
+func TestTypedefsELFDwarf4(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf4"), "elf") }
+
 func testTypedefs(t *testing.T, d *Data, kind string) {
 	r := d.Reader()
 	seen := make(map[string]bool)
diff --git a/src/pkg/debug/dwarf/typeunit.go b/src/pkg/debug/dwarf/typeunit.go
new file mode 100644
index 0000000..3fd1c99
--- /dev/null
+++ b/src/pkg/debug/dwarf/typeunit.go
@@ -0,0 +1,166 @@
+// 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.
+
+package dwarf
+
+import (
+	"fmt"
+	"strconv"
+)
+
+// Parse the type units stored in a DWARF4 .debug_types section.  Each
+// type unit defines a single primary type and an 8-byte signature.
+// Other sections may then use formRefSig8 to refer to the type.
+
+// The typeUnit format is a single type with a signature.  It holds
+// the same data as a compilation unit.
+type typeUnit struct {
+	unit
+	toff  Offset // Offset to signature type within data.
+	name  string // Name of .debug_type section.
+	cache Type   // Cache the type, nil to start.
+}
+
+// Parse a .debug_types section.
+func (d *Data) parseTypes(name string, types []byte) error {
+	b := makeBuf(d, unknownFormat{}, name, 0, types)
+	for len(b.data) > 0 {
+		base := b.off
+		dwarf64 := false
+		n := b.uint32()
+		if n == 0xffffffff {
+			n64 := b.uint64()
+			if n64 != uint64(uint32(n64)) {
+				b.error("type unit length overflow")
+				return b.err
+			}
+			n = uint32(n64)
+			dwarf64 = true
+		}
+		hdroff := b.off
+		vers := b.uint16()
+		if vers != 4 {
+			b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
+			return b.err
+		}
+		var ao uint32
+		if !dwarf64 {
+			ao = b.uint32()
+		} else {
+			ao64 := b.uint64()
+			if ao64 != uint64(uint32(ao64)) {
+				b.error("type unit abbrev offset overflow")
+				return b.err
+			}
+			ao = uint32(ao64)
+		}
+		atable, err := d.parseAbbrev(ao)
+		if err != nil {
+			return err
+		}
+		asize := b.uint8()
+		sig := b.uint64()
+
+		var toff uint32
+		if !dwarf64 {
+			toff = b.uint32()
+		} else {
+			to64 := b.uint64()
+			if to64 != uint64(uint32(to64)) {
+				b.error("type unit type offset overflow")
+				return b.err
+			}
+			toff = uint32(to64)
+		}
+
+		boff := b.off
+		d.typeSigs[sig] = &typeUnit{
+			unit: unit{
+				base:   base,
+				off:    boff,
+				data:   b.bytes(int(Offset(n) - (b.off - hdroff))),
+				atable: atable,
+				asize:  int(asize),
+				vers:   int(vers),
+				is64:   dwarf64,
+			},
+			toff: Offset(toff),
+			name: name,
+		}
+		if b.err != nil {
+			return b.err
+		}
+	}
+	return nil
+}
+
+// Return the type for a type signature.
+func (d *Data) sigToType(sig uint64) (Type, error) {
+	tu := d.typeSigs[sig]
+	if tu == nil {
+		return nil, fmt.Errorf("no type unit with signature %v", sig)
+	}
+	if tu.cache != nil {
+		return tu.cache, nil
+	}
+
+	b := makeBuf(d, tu, tu.name, tu.off, tu.data)
+	r := &typeUnitReader{d: d, tu: tu, b: b}
+	t, err := d.readType(tu.name, r, Offset(tu.toff), make(map[Offset]Type))
+	if err != nil {
+		return nil, err
+	}
+
+	tu.cache = t
+	return t, nil
+}
+
+// typeUnitReader is a typeReader for a tagTypeUnit.
+type typeUnitReader struct {
+	d   *Data
+	tu  *typeUnit
+	b   buf
+	err error
+}
+
+// Seek to a new position in the type unit.
+func (tur *typeUnitReader) Seek(off Offset) {
+	tur.err = nil
+	doff := off - tur.tu.off
+	if doff < 0 || doff >= Offset(len(tur.tu.data)) {
+		tur.err = fmt.Errorf("%s: offset %d out of range; max %d", tur.tu.name, doff, len(tur.tu.data))
+		return
+	}
+	tur.b = makeBuf(tur.d, tur.tu, tur.tu.name, off, tur.tu.data[doff:])
+}
+
+// Next reads the next Entry from the type unit.
+func (tur *typeUnitReader) Next() (*Entry, error) {
+	if tur.err != nil {
+		return nil, tur.err
+	}
+	if len(tur.tu.data) == 0 {
+		return nil, nil
+	}
+	e := tur.b.entry(tur.tu.atable, tur.tu.base)
+	if tur.b.err != nil {
+		tur.err = tur.b.err
+		return nil, tur.err
+	}
+	return e, nil
+}
+
+// clone returns a new reader for the type unit.
+func (tur *typeUnitReader) clone() typeReader {
+	return &typeUnitReader{
+		d:  tur.d,
+		tu: tur.tu,
+		b:  makeBuf(tur.d, tur.tu, tur.tu.name, tur.tu.off, tur.tu.data),
+	}
+}
+
+// offset returns the current offset.
+func (tur *typeUnitReader) offset() Offset {
+	return tur.b.off
+}
diff --git a/src/pkg/debug/dwarf/unit.go b/src/pkg/debug/dwarf/unit.go
index 270cd2e..0fbc8e0 100644
--- a/src/pkg/debug/dwarf/unit.go
+++ b/src/pkg/debug/dwarf/unit.go
@@ -66,7 +66,7 @@ func (d *Data) parseUnits() ([]unit, error) {
 			n = uint32(b.uint64())
 		}
 		vers := b.uint16()
-		if vers != 2 && vers != 3 {
+		if vers != 2 && vers != 3 && vers != 4 {
 			b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
 			break
 		}
diff --git a/src/pkg/debug/elf/elf.go b/src/pkg/debug/elf/elf.go
index 03e42b0..d622dae 100644
--- a/src/pkg/debug/elf/elf.go
+++ b/src/pkg/debug/elf/elf.go
@@ -517,7 +517,7 @@ const (
 	DT_INIT_ARRAY   DynTag = 25 /* Address of the array of pointers to initialization functions */
 	DT_FINI_ARRAY   DynTag = 26 /* Address of the array of pointers to termination functions */
 	DT_INIT_ARRAYSZ DynTag = 27 /* Size in bytes of the array of initialization functions. */
-	DT_FINI_ARRAYSZ DynTag = 28 /* Size in bytes of the array of terminationfunctions. */
+	DT_FINI_ARRAYSZ DynTag = 28 /* Size in bytes of the array of termination functions. */
 	DT_RUNPATH      DynTag = 29 /* String table offset of a null-terminated library search path string. */
 	DT_FLAGS        DynTag = 30 /* Object specific flag values. */
 	DT_ENCODING     DynTag = 32 /* Values greater than or equal to DT_ENCODING
diff --git a/src/pkg/debug/elf/elf_test.go b/src/pkg/debug/elf/elf_test.go
index 67b961b..e3c51bb 100644
--- a/src/pkg/debug/elf/elf_test.go
+++ b/src/pkg/debug/elf/elf_test.go
@@ -43,7 +43,7 @@ func TestNames(t *testing.T) {
 	for i, tt := range nameTests {
 		s := fmt.Sprint(tt.val)
 		if s != tt.str {
-			t.Errorf("#%d: want %q have %q", i, s, tt.str)
+			t.Errorf("#%d: Sprint(%d) = %q, want %q", i, tt.val, s, tt.str)
 		}
 	}
 }
diff --git a/src/pkg/debug/elf/file.go b/src/pkg/debug/elf/file.go
index a55c37e..423932f 100644
--- a/src/pkg/debug/elf/file.go
+++ b/src/pkg/debug/elf/file.go
@@ -76,6 +76,9 @@ type Section struct {
 func (s *Section) Data() ([]byte, error) {
 	dat := make([]byte, s.sr.Size())
 	n, err := s.sr.ReadAt(dat, 0)
+	if n == len(dat) {
+		err = nil
+	}
 	return dat[0:n], err
 }
 
@@ -412,7 +415,7 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
 	if err != nil {
 		return nil, nil, errors.New("cannot load symbol section")
 	}
-	symtab := bytes.NewBuffer(data)
+	symtab := bytes.NewReader(data)
 	if symtab.Len()%Sym32Size != 0 {
 		return nil, nil, errors.New("length of symbol section is not a multiple of SymSize")
 	}
@@ -455,7 +458,7 @@ func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
 	if err != nil {
 		return nil, nil, errors.New("cannot load symbol section")
 	}
-	symtab := bytes.NewBuffer(data)
+	symtab := bytes.NewReader(data)
 	if symtab.Len()%Sym64Size != 0 {
 		return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")
 	}
@@ -519,13 +522,17 @@ func (f *File) applyRelocations(dst []byte, rels []byte) error {
 	if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 {
 		return f.applyRelocationsAMD64(dst, rels)
 	}
+	if f.Class == ELFCLASS32 && f.Machine == EM_386 {
+		return f.applyRelocations386(dst, rels)
+	}
 
 	return errors.New("not implemented")
 }
 
 func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
-	if len(rels)%Sym64Size != 0 {
-		return errors.New("length of relocation section is not a multiple of Sym64Size")
+	// 24 is the size of Rela64.
+	if len(rels)%24 != 0 {
+		return errors.New("length of relocation section is not a multiple of 24")
 	}
 
 	symbols, _, err := f.getSymbols(SHT_SYMTAB)
@@ -533,7 +540,7 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
 		return err
 	}
 
-	b := bytes.NewBuffer(rels)
+	b := bytes.NewReader(rels)
 	var rela Rela64
 
 	for b.Len() > 0 {
@@ -567,6 +574,43 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
 	return nil
 }
 
+func (f *File) applyRelocations386(dst []byte, rels []byte) error {
+	// 8 is the size of Rel32.
+	if len(rels)%8 != 0 {
+		return errors.New("length of relocation section is not a multiple of 8")
+	}
+
+	symbols, _, err := f.getSymbols(SHT_SYMTAB)
+	if err != nil {
+		return err
+	}
+
+	b := bytes.NewReader(rels)
+	var rel Rel32
+
+	for b.Len() > 0 {
+		binary.Read(b, f.ByteOrder, &rel)
+		symNo := rel.Info >> 8
+		t := R_386(rel.Info & 0xff)
+
+		if symNo == 0 || symNo > uint32(len(symbols)) {
+			continue
+		}
+		sym := &symbols[symNo-1]
+
+		if t == R_386_32 {
+			if rel.Off+4 >= uint32(len(dst)) {
+				continue
+			}
+			val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
+			val += uint32(sym.Value)
+			f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
+		}
+	}
+
+	return nil
+}
+
 func (f *File) DWARF() (*dwarf.Data, error) {
 	// There are many other DWARF sections, but these
 	// are the required ones, and the debug/dwarf package
@@ -600,8 +644,58 @@ func (f *File) DWARF() (*dwarf.Data, error) {
 		}
 	}
 
+	// When using clang we need to process relocations even for 386.
+	rel := f.Section(".rel.debug_info")
+	if rel != nil && rel.Type == SHT_REL && f.Machine == EM_386 {
+		data, err := rel.Data()
+		if err != nil {
+			return nil, err
+		}
+		err = f.applyRelocations(dat[1], data)
+		if err != nil {
+			return nil, err
+		}
+	}
+
 	abbrev, info, str := dat[0], dat[1], dat[2]
-	return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
+	d, err := dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
+	if err != nil {
+		return nil, err
+	}
+
+	// Look for DWARF4 .debug_types sections.
+	for i, s := range f.Sections {
+		if s.Name == ".debug_types" {
+			b, err := s.Data()
+			if err != nil && uint64(len(b)) < s.Size {
+				return nil, err
+			}
+
+			for _, r := range f.Sections {
+				if r.Type != SHT_RELA && r.Type != SHT_REL {
+					continue
+				}
+				if int(r.Info) != i {
+					continue
+				}
+				rd, err := r.Data()
+				if err != nil {
+					return nil, err
+				}
+				err = f.applyRelocations(b, rd)
+				if err != nil {
+					return nil, err
+				}
+			}
+
+			err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	return d, nil
 }
 
 // Symbols returns the symbol table for f.
diff --git a/src/pkg/debug/elf/file_test.go b/src/pkg/debug/elf/file_test.go
index 38b5f9e..7f88a54 100644
--- a/src/pkg/debug/elf/file_test.go
+++ b/src/pkg/debug/elf/file_test.go
@@ -261,6 +261,12 @@ var relocationTests = []relocationTest{
 		},
 	},
 	{
+		"testdata/go-relocation-test-clang-x86.obj",
+		[]relocationTestEntry{
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)"}, {Attr: dwarf.AttrLanguage, Val: int64(12)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c"}, {Attr: dwarf.AttrStmtList, Val: int64(0)}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}}}},
+		},
+	},
+	{
 		"testdata/gcc-amd64-openbsd-debug-with-rela.obj",
 		[]relocationTestEntry{
 			{203, &dwarf.Entry{Offset: 0xc62, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_interval"}, {Attr: dwarf.AttrDeclFile, Val: int64(7)}, {Attr: dwarf.AttrDeclLine, Val: int64(236)}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}}}}},
diff --git a/src/pkg/debug/elf/testdata/go-relocation-test-clang-x86.obj b/src/pkg/debug/elf/testdata/go-relocation-test-clang-x86.obj
new file mode 100644
index 0000000..e909cf4
Binary files /dev/null and b/src/pkg/debug/elf/testdata/go-relocation-test-clang-x86.obj differ
diff --git a/src/pkg/debug/elf/testdata/hello.c b/src/pkg/debug/elf/testdata/hello.c
new file mode 100644
index 0000000..34d9ee7
--- /dev/null
+++ b/src/pkg/debug/elf/testdata/hello.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void
+main(int argc, char *argv[])
+{
+	printf("hello, world\n");
+}
diff --git a/src/pkg/debug/gosym/pclntab.go b/src/pkg/debug/gosym/pclntab.go
index 3e6a804..6620aef 100644
--- a/src/pkg/debug/gosym/pclntab.go
+++ b/src/pkg/debug/gosym/pclntab.go
@@ -196,6 +196,33 @@ func (t *LineTable) go12Init() {
 	t.go12 = 1 // so far so good
 }
 
+// go12Funcs returns a slice of Funcs derived from the Go 1.2 pcln table.
+func (t *LineTable) go12Funcs() []Func {
+	// Assume it is malformed and return nil on error.
+	defer func() {
+		recover()
+	}()
+
+	n := len(t.functab) / int(t.ptrsize) / 2
+	funcs := make([]Func, n)
+	for i := range funcs {
+		f := &funcs[i]
+		f.Entry = uint64(t.uintptr(t.functab[2*i*int(t.ptrsize):]))
+		f.End = uint64(t.uintptr(t.functab[(2*i+2)*int(t.ptrsize):]))
+		info := t.Data[t.uintptr(t.functab[(2*i+1)*int(t.ptrsize):]):]
+		f.LineTable = t
+		f.FrameSize = int(t.binary.Uint32(info[t.ptrsize+2*4:]))
+		f.Sym = &Sym{
+			Value:  f.Entry,
+			Type:   'T',
+			Name:   t.string(t.binary.Uint32(info[t.ptrsize:])),
+			GoType: 0,
+			Func:   f,
+		}
+	}
+	return funcs
+}
+
 // findFunc returns the func corresponding to the given program counter.
 func (t *LineTable) findFunc(pc uint64) []byte {
 	if pc < t.uintptr(t.functab) || pc >= t.uintptr(t.functab[len(t.functab)-int(t.ptrsize):]) {
diff --git a/src/pkg/debug/gosym/symtab.go b/src/pkg/debug/gosym/symtab.go
index 9ab05ba..3864e3c 100644
--- a/src/pkg/debug/gosym/symtab.go
+++ b/src/pkg/debug/gosym/symtab.go
@@ -129,6 +129,9 @@ var (
 )
 
 func walksymtab(data []byte, fn func(sym) error) error {
+	if len(data) == 0 { // missing symtab is okay
+		return nil
+	}
 	var order binary.ByteOrder = binary.BigEndian
 	newTable := false
 	switch {
@@ -455,6 +458,10 @@ func NewTable(symtab []byte, pcln *LineTable) (*Table, error) {
 			i = end - 1 // loop will i++
 		}
 	}
+
+	if t.go12line != nil && nf == 0 {
+		t.Funcs = t.go12line.go12Funcs()
+	}
 	if obj != nil {
 		obj.Funcs = t.Funcs[lastf:]
 	}
diff --git a/src/pkg/debug/macho/fat.go b/src/pkg/debug/macho/fat.go
new file mode 100644
index 0000000..93b8315
--- /dev/null
+++ b/src/pkg/debug/macho/fat.go
@@ -0,0 +1,146 @@
+// 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 macho
+
+import (
+	"encoding/binary"
+	"fmt"
+	"io"
+	"os"
+)
+
+// A FatFile is a Mach-O universal binary that contains at least one architecture.
+type FatFile struct {
+	Magic  uint32
+	Arches []FatArch
+	closer io.Closer
+}
+
+// A FatArchHeader represents a fat header for a specific image architecture.
+type FatArchHeader struct {
+	Cpu    Cpu
+	SubCpu uint32
+	Offset uint32
+	Size   uint32
+	Align  uint32
+}
+
+const fatArchHeaderSize = 5 * 4
+
+// A FatArch is a Mach-O File inside a FatFile.
+type FatArch struct {
+	FatArchHeader
+	*File
+}
+
+// ErrNotFat is returned from NewFatFile or OpenFat when the file is not a
+// universal binary but may be a thin binary, based on its magic number.
+var ErrNotFat = &FormatError{0, "not a fat Mach-O file", nil}
+
+// NewFatFile creates a new FatFile for accessing all the Mach-O images in a
+// universal binary. The Mach-O binary is expected to start at position 0 in
+// the ReaderAt.
+func NewFatFile(r io.ReaderAt) (*FatFile, error) {
+	var ff FatFile
+	sr := io.NewSectionReader(r, 0, 1<<63-1)
+
+	// Read the fat_header struct, which is always in big endian.
+	// Start with the magic number.
+	err := binary.Read(sr, binary.BigEndian, &ff.Magic)
+	if err != nil {
+		return nil, &FormatError{0, "error reading magic number", nil}
+	} else if ff.Magic != MagicFat {
+		// See if this is a Mach-O file via its magic number. The magic
+		// must be converted to little endian first though.
+		var buf [4]byte
+		binary.BigEndian.PutUint32(buf[:], ff.Magic)
+		leMagic := binary.LittleEndian.Uint32(buf[:])
+		if leMagic == Magic32 || leMagic == Magic64 {
+			return nil, ErrNotFat
+		} else {
+			return nil, &FormatError{0, "invalid magic number", nil}
+		}
+	}
+	offset := int64(4)
+
+	// Read the number of FatArchHeaders that come after the fat_header.
+	var narch uint32
+	err = binary.Read(sr, binary.BigEndian, &narch)
+	if err != nil {
+		return nil, &FormatError{offset, "invalid fat_header", nil}
+	}
+	offset += 4
+
+	if narch < 1 {
+		return nil, &FormatError{offset, "file contains no images", nil}
+	}
+
+	// Combine the Cpu and SubCpu (both uint32) into a uint64 to make sure
+	// there are not duplicate architectures.
+	seenArches := make(map[uint64]bool, narch)
+	// Make sure that all images are for the same MH_ type.
+	var machoType Type
+
+	// Following the fat_header comes narch fat_arch structs that index
+	// Mach-O images further in the file.
+	ff.Arches = make([]FatArch, narch)
+	for i := uint32(0); i < narch; i++ {
+		fa := &ff.Arches[i]
+		err = binary.Read(sr, binary.BigEndian, &fa.FatArchHeader)
+		if err != nil {
+			return nil, &FormatError{offset, "invalid fat_arch header", nil}
+		}
+		offset += fatArchHeaderSize
+
+		fr := io.NewSectionReader(r, int64(fa.Offset), int64(fa.Size))
+		fa.File, err = NewFile(fr)
+		if err != nil {
+			return nil, err
+		}
+
+		// Make sure the architecture for this image is not duplicate.
+		seenArch := (uint64(fa.Cpu) << 32) | uint64(fa.SubCpu)
+		if o, k := seenArches[seenArch]; o || k {
+			return nil, &FormatError{offset, fmt.Sprintf("duplicate architecture cpu=%v, subcpu=%#x", fa.Cpu, fa.SubCpu), nil}
+		}
+		seenArches[seenArch] = true
+
+		// Make sure the Mach-O type matches that of the first image.
+		if i == 0 {
+			machoType = fa.Type
+		} else {
+			if fa.Type != machoType {
+				return nil, &FormatError{offset, fmt.Sprintf("Mach-O type for architecture #%d (type=%#x) does not match first (type=%#x)", i, fa.Type, machoType), nil}
+			}
+		}
+	}
+
+	return &ff, nil
+}
+
+// OpenFat opens the named file using os.Open and prepares it for use as a Mach-O
+// universal binary.
+func OpenFat(name string) (ff *FatFile, err error) {
+	f, err := os.Open(name)
+	if err != nil {
+		return nil, err
+	}
+	ff, err = NewFatFile(f)
+	if err != nil {
+		f.Close()
+		return nil, err
+	}
+	ff.closer = f
+	return
+}
+
+func (ff *FatFile) Close() error {
+	var err error
+	if ff.closer != nil {
+		err = ff.closer.Close()
+		ff.closer = nil
+	}
+	return err
+}
diff --git a/src/pkg/debug/macho/file.go b/src/pkg/debug/macho/file.go
index f5f0ded..eefb744 100644
--- a/src/pkg/debug/macho/file.go
+++ b/src/pkg/debug/macho/file.go
@@ -11,7 +11,6 @@ import (
 	"bytes"
 	"debug/dwarf"
 	"encoding/binary"
-	"errors"
 	"fmt"
 	"io"
 	"os"
@@ -74,6 +73,9 @@ type Segment struct {
 func (s *Segment) Data() ([]byte, error) {
 	dat := make([]byte, s.sr.Size())
 	n, err := s.sr.ReadAt(dat, 0)
+	if n == len(dat) {
+		err = nil
+	}
 	return dat[0:n], err
 }
 
@@ -109,6 +111,9 @@ type Section struct {
 func (s *Section) Data() ([]byte, error) {
 	dat := make([]byte, s.sr.Size())
 	n, err := s.sr.ReadAt(dat, 0)
+	if n == len(dat) {
+		err = nil
+	}
 	return dat[0:n], err
 }
 
@@ -246,7 +251,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
 
 		case LoadCmdDylib:
 			var hdr DylibCmd
-			b := bytes.NewBuffer(cmddat)
+			b := bytes.NewReader(cmddat)
 			if err := binary.Read(b, bo, &hdr); err != nil {
 				return nil, err
 			}
@@ -263,7 +268,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
 
 		case LoadCmdSymtab:
 			var hdr SymtabCmd
-			b := bytes.NewBuffer(cmddat)
+			b := bytes.NewReader(cmddat)
 			if err := binary.Read(b, bo, &hdr); err != nil {
 				return nil, err
 			}
@@ -290,7 +295,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
 
 		case LoadCmdDysymtab:
 			var hdr DysymtabCmd
-			b := bytes.NewBuffer(cmddat)
+			b := bytes.NewReader(cmddat)
 			if err := binary.Read(b, bo, &hdr); err != nil {
 				return nil, err
 			}
@@ -299,7 +304,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
 				return nil, err
 			}
 			x := make([]uint32, hdr.Nindirectsyms)
-			if err := binary.Read(bytes.NewBuffer(dat), bo, x); err != nil {
+			if err := binary.Read(bytes.NewReader(dat), bo, x); err != nil {
 				return nil, err
 			}
 			st := new(Dysymtab)
@@ -311,7 +316,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
 
 		case LoadCmdSegment:
 			var seg32 Segment32
-			b := bytes.NewBuffer(cmddat)
+			b := bytes.NewReader(cmddat)
 			if err := binary.Read(b, bo, &seg32); err != nil {
 				return nil, err
 			}
@@ -349,7 +354,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
 
 		case LoadCmdSegment64:
 			var seg64 Segment64
-			b := bytes.NewBuffer(cmddat)
+			b := bytes.NewReader(cmddat)
 			if err := binary.Read(b, bo, &seg64); err != nil {
 				return nil, err
 			}
@@ -396,7 +401,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
 func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, error) {
 	bo := f.ByteOrder
 	symtab := make([]Symbol, hdr.Nsyms)
-	b := bytes.NewBuffer(symdat)
+	b := bytes.NewReader(symdat)
 	for i := range symtab {
 		var n Nlist64
 		if f.Magic == Magic64 {
@@ -475,7 +480,7 @@ func (f *File) DWARF() (*dwarf.Data, error) {
 		name = "__debug_" + name
 		s := f.Section(name)
 		if s == nil {
-			return nil, errors.New("missing Mach-O section " + name)
+			continue
 		}
 		b, err := s.Data()
 		if err != nil && uint64(len(b)) < s.Size {
diff --git a/src/pkg/debug/macho/file_test.go b/src/pkg/debug/macho/file_test.go
index 640225b..4797780 100644
--- a/src/pkg/debug/macho/file_test.go
+++ b/src/pkg/debug/macho/file_test.go
@@ -165,3 +165,46 @@ func TestOpenFailure(t *testing.T) {
 		t.Errorf("open %s: succeeded unexpectedly", filename)
 	}
 }
+
+func TestOpenFat(t *testing.T) {
+	ff, err := OpenFat("testdata/fat-gcc-386-amd64-darwin-exec")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if ff.Magic != MagicFat {
+		t.Errorf("OpenFat: got magic number %#x, want %#x", ff.Magic, MagicFat)
+	}
+	if len(ff.Arches) != 2 {
+		t.Errorf("OpenFat: got %d architectures, want 2", len(ff.Arches))
+	}
+
+	for i := range ff.Arches {
+		arch := &ff.Arches[i]
+		ftArch := &fileTests[i]
+
+		if arch.Cpu != ftArch.hdr.Cpu || arch.SubCpu != ftArch.hdr.SubCpu {
+			t.Errorf("OpenFat: architecture #%d got cpu=%#x subtype=%#x, expected cpu=%#x, subtype=%#x", i, arch.Cpu, arch.SubCpu, ftArch.hdr.Cpu, ftArch.hdr.SubCpu)
+		}
+
+		if !reflect.DeepEqual(arch.FileHeader, ftArch.hdr) {
+			t.Errorf("OpenFat header:\n\tgot %#v\n\twant %#v\n", arch.FileHeader, ftArch.hdr)
+		}
+	}
+}
+
+func TestOpenFatFailure(t *testing.T) {
+	filename := "file.go" // not a Mach-O file
+	if _, err := OpenFat(filename); err == nil {
+		t.Errorf("OpenFat %s: succeeded unexpectedly", filename)
+	}
+
+	filename = "testdata/gcc-386-darwin-exec" // not a fat Mach-O
+	ff, err := OpenFat(filename)
+	if err != ErrNotFat {
+		t.Errorf("OpenFat %s: got %v, want ErrNotFat", filename, err)
+	}
+	if ff != nil {
+		t.Errorf("OpenFat %s: got %v, want nil", filename, ff)
+	}
+}
diff --git a/src/pkg/debug/macho/macho.go b/src/pkg/debug/macho/macho.go
index bc14226..d9678c8 100644
--- a/src/pkg/debug/macho/macho.go
+++ b/src/pkg/debug/macho/macho.go
@@ -26,29 +26,40 @@ const (
 )
 
 const (
-	Magic32 uint32 = 0xfeedface
-	Magic64 uint32 = 0xfeedfacf
+	Magic32  uint32 = 0xfeedface
+	Magic64  uint32 = 0xfeedfacf
+	MagicFat uint32 = 0xcafebabe
 )
 
-// A Type is a Mach-O file type, either an object or an executable.
+// A Type is the Mach-O file type, e.g. an object file, executable, or dynamic library.
 type Type uint32
 
 const (
-	TypeObj  Type = 1
-	TypeExec Type = 2
+	TypeObj    Type = 1
+	TypeExec   Type = 2
+	TypeDylib  Type = 6
+	TypeBundle Type = 8
 )
 
 // A Cpu is a Mach-O cpu type.
 type Cpu uint32
 
+const cpuArch64 = 0x01000000
+
 const (
 	Cpu386   Cpu = 7
-	CpuAmd64 Cpu = Cpu386 + 1<<24
+	CpuAmd64 Cpu = Cpu386 | cpuArch64
+	CpuArm   Cpu = 12
+	CpuPpc   Cpu = 18
+	CpuPpc64 Cpu = CpuPpc | cpuArch64
 )
 
 var cpuStrings = []intName{
 	{uint32(Cpu386), "Cpu386"},
 	{uint32(CpuAmd64), "CpuAmd64"},
+	{uint32(CpuArm), "CpuArm"},
+	{uint32(CpuPpc), "CpuPpc"},
+	{uint32(CpuPpc64), "CpuPpc64"},
 }
 
 func (i Cpu) String() string   { return stringName(uint32(i), cpuStrings, false) }
diff --git a/src/pkg/debug/macho/testdata/fat-gcc-386-amd64-darwin-exec b/src/pkg/debug/macho/testdata/fat-gcc-386-amd64-darwin-exec
new file mode 100644
index 0000000..7efd193
Binary files /dev/null and b/src/pkg/debug/macho/testdata/fat-gcc-386-amd64-darwin-exec differ
diff --git a/src/pkg/debug/pe/file.go b/src/pkg/debug/pe/file.go
index f521566..ce6f140 100644
--- a/src/pkg/debug/pe/file.go
+++ b/src/pkg/debug/pe/file.go
@@ -13,13 +13,15 @@ import (
 	"io"
 	"os"
 	"strconv"
+	"unsafe"
 )
 
 // A File represents an open PE file.
 type File struct {
 	FileHeader
-	Sections []*Section
-	Symbols  []*Symbol
+	OptionalHeader interface{} // of type *OptionalHeader32 or *OptionalHeader64
+	Sections       []*Section
+	Symbols        []*Symbol
 
 	closer io.Closer
 }
@@ -72,6 +74,9 @@ type ImportDirectory struct {
 func (s *Section) Data() ([]byte, error) {
 	dat := make([]byte, s.sr.Size())
 	n, err := s.sr.ReadAt(dat, 0)
+	if n == len(dat) {
+		err = nil
+	}
 	return dat[0:n], err
 }
 
@@ -193,10 +198,33 @@ func NewFile(r io.ReaderAt) (*File, error) {
 		}
 	}
 
-	// Process sections.
+	// Read optional header.
 	sr.Seek(base, os.SEEK_SET)
-	binary.Read(sr, binary.LittleEndian, &f.FileHeader)
-	sr.Seek(int64(f.FileHeader.SizeOfOptionalHeader), os.SEEK_CUR) //Skip OptionalHeader
+	if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
+		return nil, err
+	}
+	var oh32 OptionalHeader32
+	var oh64 OptionalHeader64
+	switch uintptr(f.FileHeader.SizeOfOptionalHeader) {
+	case unsafe.Sizeof(oh32):
+		if err := binary.Read(sr, binary.LittleEndian, &oh32); err != nil {
+			return nil, err
+		}
+		if oh32.Magic != 0x10b { // PE32
+			return nil, fmt.Errorf("pe32 optional header has unexpected Magic of 0x%x", oh32.Magic)
+		}
+		f.OptionalHeader = &oh32
+	case unsafe.Sizeof(oh64):
+		if err := binary.Read(sr, binary.LittleEndian, &oh64); err != nil {
+			return nil, err
+		}
+		if oh64.Magic != 0x20b { // PE32+
+			return nil, fmt.Errorf("pe32+ optional header has unexpected Magic of 0x%x", oh64.Magic)
+		}
+		f.OptionalHeader = &oh64
+	}
+
+	// Process sections.
 	f.Sections = make([]*Section, f.FileHeader.NumberOfSections)
 	for i := 0; i < int(f.FileHeader.NumberOfSections); i++ {
 		sh := new(SectionHeader32)
@@ -213,15 +241,15 @@ func NewFile(r io.ReaderAt) (*File, error) {
 		s := new(Section)
 		s.SectionHeader = SectionHeader{
 			Name:                 name,
-			VirtualSize:          uint32(sh.VirtualSize),
-			VirtualAddress:       uint32(sh.VirtualAddress),
-			Size:                 uint32(sh.SizeOfRawData),
-			Offset:               uint32(sh.PointerToRawData),
-			PointerToRelocations: uint32(sh.PointerToRelocations),
-			PointerToLineNumbers: uint32(sh.PointerToLineNumbers),
-			NumberOfRelocations:  uint16(sh.NumberOfRelocations),
-			NumberOfLineNumbers:  uint16(sh.NumberOfLineNumbers),
-			Characteristics:      uint32(sh.Characteristics),
+			VirtualSize:          sh.VirtualSize,
+			VirtualAddress:       sh.VirtualAddress,
+			Size:                 sh.SizeOfRawData,
+			Offset:               sh.PointerToRawData,
+			PointerToRelocations: sh.PointerToRelocations,
+			PointerToLineNumbers: sh.PointerToLineNumbers,
+			NumberOfRelocations:  sh.NumberOfRelocations,
+			NumberOfLineNumbers:  sh.NumberOfLineNumbers,
+			Characteristics:      sh.Characteristics,
 		}
 		s.sr = io.NewSectionReader(r, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size))
 		s.ReaderAt = s.sr
diff --git a/src/pkg/debug/pe/file_test.go b/src/pkg/debug/pe/file_test.go
index c0f9fcb..ddbb271 100644
--- a/src/pkg/debug/pe/file_test.go
+++ b/src/pkg/debug/pe/file_test.go
@@ -12,6 +12,7 @@ import (
 type fileTest struct {
 	file     string
 	hdr      FileHeader
+	opthdr   interface{}
 	sections []*SectionHeader
 	symbols  []*Symbol
 }
@@ -20,6 +21,7 @@ var fileTests = []fileTest{
 	{
 		"testdata/gcc-386-mingw-obj",
 		FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104},
+		nil,
 		[]*SectionHeader{
 			{".text", 0, 0, 36, 500, 1440, 0, 3, 0, 0x60300020},
 			{".data", 0, 0, 0, 0, 0, 0, 0, 0, 3224371264},
@@ -56,27 +58,130 @@ var fileTests = []fileTest{
 	{
 		"testdata/gcc-386-mingw-exec",
 		FileHeader{0x014c, 0x000f, 0x4c6a1b60, 0x3c00, 0x282, 0xe0, 0x107},
+		&OptionalHeader32{
+			0x10b, 0x2, 0x38, 0xe00, 0x1a00, 0x200, 0x1160, 0x1000, 0x2000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x1, 0x0, 0x4, 0x0, 0x0, 0x10000, 0x400, 0x14abb, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10,
+			[16]DataDirectory{
+				{0x0, 0x0},
+				{0x5000, 0x3c8},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x7000, 0x18},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x0, 0x0},
+			},
+		},
+		[]*SectionHeader{
+			{".text", 0xcd8, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060},
+			{".data", 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+			{".rdata", 0x120, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040},
+			{".bss", 0xdc, 0x4000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0400080},
+			{".idata", 0x3c8, 0x5000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+			{".CRT", 0x18, 0x6000, 0x200, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+			{".tls", 0x20, 0x7000, 0x200, 0x1c00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+			{".debug_aranges", 0x20, 0x8000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0x42100000},
+			{".debug_pubnames", 0x51, 0x9000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0x42100000},
+			{".debug_pubtypes", 0x91, 0xa000, 0x200, 0x2200, 0x0, 0x0, 0x0, 0x0, 0x42100000},
+			{".debug_info", 0xe22, 0xb000, 0x1000, 0x2400, 0x0, 0x0, 0x0, 0x0, 0x42100000},
+			{".debug_abbrev", 0x157, 0xc000, 0x200, 0x3400, 0x0, 0x0, 0x0, 0x0, 0x42100000},
+			{".debug_line", 0x144, 0xd000, 0x200, 0x3600, 0x0, 0x0, 0x0, 0x0, 0x42100000},
+			{".debug_frame", 0x34, 0xe000, 0x200, 0x3800, 0x0, 0x0, 0x0, 0x0, 0x42300000},
+			{".debug_loc", 0x38, 0xf000, 0x200, 0x3a00, 0x0, 0x0, 0x0, 0x0, 0x42100000},
+		},
+		[]*Symbol{},
+	},
+	{
+		"testdata/gcc-amd64-mingw-obj",
+		FileHeader{0x8664, 0x6, 0x0, 0x198, 0x12, 0x0, 0x4},
+		nil,
+		[]*SectionHeader{
+			{".text", 0x0, 0x0, 0x30, 0x104, 0x15c, 0x0, 0x3, 0x0, 0x60500020},
+			{".data", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500040},
+			{".bss", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500080},
+			{".rdata", 0x0, 0x0, 0x10, 0x134, 0x0, 0x0, 0x0, 0x0, 0x40500040},
+			{".xdata", 0x0, 0x0, 0xc, 0x144, 0x0, 0x0, 0x0, 0x0, 0x40300040},
+			{".pdata", 0x0, 0x0, 0xc, 0x150, 0x17a, 0x0, 0x3, 0x0, 0x40300040},
+		},
+		[]*Symbol{
+			{".file", 0x0, -2, 0x0, 0x67},
+			{"main", 0x0, 1, 0x20, 0x2},
+			{".text", 0x0, 1, 0x0, 0x3},
+			{".data", 0x0, 2, 0x0, 0x3},
+			{".bss", 0x0, 3, 0x0, 0x3},
+			{".rdata", 0x0, 4, 0x0, 0x3},
+			{".xdata", 0x0, 5, 0x0, 0x3},
+			{".pdata", 0x0, 6, 0x0, 0x3},
+			{"__main", 0x0, 0, 0x20, 0x2},
+			{"puts", 0x0, 0, 0x20, 0x2},
+		},
+	},
+	{
+		"testdata/gcc-amd64-mingw-exec",
+		FileHeader{0x8664, 0x9, 0x53472993, 0x0, 0x0, 0xf0, 0x22f},
+		&OptionalHeader64{
+			0x20b, 0x2, 0x16, 0x6a00, 0x2400, 0x1600, 0x14e0, 0x1000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x0, 0x0, 0x5, 0x2, 0x0, 0x11000, 0x400, 0x1841e, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10,
+			[16]DataDirectory{
+				{0x0, 0x0},
+				{0xe000, 0x990},
+				{0x0, 0x0},
+				{0xa000, 0x498},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x10000, 0x28},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0xe254, 0x218},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x0, 0x0},
+			},
+		},
 		[]*SectionHeader{
-			{Name: ".text", VirtualSize: 0xcd8, VirtualAddress: 0x1000, Size: 0xe00, Offset: 0x400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x60500060},
-			{Name: ".data", VirtualSize: 0x10, VirtualAddress: 0x2000, Size: 0x200, Offset: 0x1200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
-			{Name: ".rdata", VirtualSize: 0x120, VirtualAddress: 0x3000, Size: 0x200, Offset: 0x1400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x40300040},
-			{Name: ".bss", VirtualSize: 0xdc, VirtualAddress: 0x4000, Size: 0x0, Offset: 0x0, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0400080},
-			{Name: ".idata", VirtualSize: 0x3c8, VirtualAddress: 0x5000, Size: 0x400, Offset: 0x1600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
-			{Name: ".CRT", VirtualSize: 0x18, VirtualAddress: 0x6000, Size: 0x200, Offset: 0x1a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
-			{Name: ".tls", VirtualSize: 0x20, VirtualAddress: 0x7000, Size: 0x200, Offset: 0x1c00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
-			{Name: ".debug_aranges", VirtualSize: 0x20, VirtualAddress: 0x8000, Size: 0x200, Offset: 0x1e00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
-			{Name: ".debug_pubnames", VirtualSize: 0x51, VirtualAddress: 0x9000, Size: 0x200, Offset: 0x2000, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
-			{Name: ".debug_pubtypes", VirtualSize: 0x91, VirtualAddress: 0xa000, Size: 0x200, Offset: 0x2200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
-			{Name: ".debug_info", VirtualSize: 0xe22, VirtualAddress: 0xb000, Size: 0x1000, Offset: 0x2400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
-			{Name: ".debug_abbrev", VirtualSize: 0x157, VirtualAddress: 0xc000, Size: 0x200, Offset: 0x3400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
-			{Name: ".debug_line", VirtualSize: 0x144, VirtualAddress: 0xd000, Size: 0x200, Offset: 0x3600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
-			{Name: ".debug_frame", VirtualSize: 0x34, VirtualAddress: 0xe000, Size: 0x200, Offset: 0x3800, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42300000},
-			{Name: ".debug_loc", VirtualSize: 0x38, VirtualAddress: 0xf000, Size: 0x200, Offset: 0x3a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+			{".text", 0x6860, 0x1000, 0x6a00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500020},
+			{".data", 0xe0, 0x8000, 0x200, 0x6e00, 0x0, 0x0, 0x0, 0x0, 0xc0500040},
+			{".rdata", 0x6b0, 0x9000, 0x800, 0x7000, 0x0, 0x0, 0x0, 0x0, 0x40600040},
+			{".pdata", 0x498, 0xa000, 0x600, 0x7800, 0x0, 0x0, 0x0, 0x0, 0x40300040},
+			{".xdata", 0x488, 0xb000, 0x600, 0x7e00, 0x0, 0x0, 0x0, 0x0, 0x40300040},
+			{".bss", 0x1410, 0xc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0600080},
+			{".idata", 0x990, 0xe000, 0xa00, 0x8400, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+			{".CRT", 0x68, 0xf000, 0x200, 0x8e00, 0x0, 0x0, 0x0, 0x0, 0xc0400040},
+			{".tls", 0x48, 0x10000, 0x200, 0x9000, 0x0, 0x0, 0x0, 0x0, 0xc0600040},
 		},
 		[]*Symbol{},
 	},
 }
 
+func isOptHdrEq(a, b interface{}) bool {
+	switch va := a.(type) {
+	case *OptionalHeader32:
+		vb, ok := b.(*OptionalHeader32)
+		if !ok {
+			return false
+		}
+		return *vb == *va
+	case *OptionalHeader64:
+		vb, ok := b.(*OptionalHeader64)
+		if !ok {
+			return false
+		}
+		return *vb == *va
+	case nil:
+		return b == nil
+	}
+	return false
+}
+
 func TestOpen(t *testing.T) {
 	for i := range fileTests {
 		tt := &fileTests[i]
@@ -90,6 +195,10 @@ func TestOpen(t *testing.T) {
 			t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
 			continue
 		}
+		if !isOptHdrEq(tt.opthdr, f.OptionalHeader) {
+			t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.OptionalHeader, tt.opthdr)
+			continue
+		}
 
 		for i, sh := range f.Sections {
 			if i >= len(tt.sections) {
diff --git a/src/pkg/debug/pe/pe.go b/src/pkg/debug/pe/pe.go
index 0606217..8e90b1b 100644
--- a/src/pkg/debug/pe/pe.go
+++ b/src/pkg/debug/pe/pe.go
@@ -14,6 +14,78 @@ type FileHeader struct {
 	Characteristics      uint16
 }
 
+type DataDirectory struct {
+	VirtualAddress uint32
+	Size           uint32
+}
+
+type OptionalHeader32 struct {
+	Magic                       uint16
+	MajorLinkerVersion          uint8
+	MinorLinkerVersion          uint8
+	SizeOfCode                  uint32
+	SizeOfInitializedData       uint32
+	SizeOfUninitializedData     uint32
+	AddressOfEntryPoint         uint32
+	BaseOfCode                  uint32
+	BaseOfData                  uint32
+	ImageBase                   uint32
+	SectionAlignment            uint32
+	FileAlignment               uint32
+	MajorOperatingSystemVersion uint16
+	MinorOperatingSystemVersion uint16
+	MajorImageVersion           uint16
+	MinorImageVersion           uint16
+	MajorSubsystemVersion       uint16
+	MinorSubsystemVersion       uint16
+	Win32VersionValue           uint32
+	SizeOfImage                 uint32
+	SizeOfHeaders               uint32
+	CheckSum                    uint32
+	Subsystem                   uint16
+	DllCharacteristics          uint16
+	SizeOfStackReserve          uint32
+	SizeOfStackCommit           uint32
+	SizeOfHeapReserve           uint32
+	SizeOfHeapCommit            uint32
+	LoaderFlags                 uint32
+	NumberOfRvaAndSizes         uint32
+	DataDirectory               [16]DataDirectory
+}
+
+type OptionalHeader64 struct {
+	Magic                       uint16
+	MajorLinkerVersion          uint8
+	MinorLinkerVersion          uint8
+	SizeOfCode                  uint32
+	SizeOfInitializedData       uint32
+	SizeOfUninitializedData     uint32
+	AddressOfEntryPoint         uint32
+	BaseOfCode                  uint32
+	ImageBase                   uint64
+	SectionAlignment            uint32
+	FileAlignment               uint32
+	MajorOperatingSystemVersion uint16
+	MinorOperatingSystemVersion uint16
+	MajorImageVersion           uint16
+	MinorImageVersion           uint16
+	MajorSubsystemVersion       uint16
+	MinorSubsystemVersion       uint16
+	Win32VersionValue           uint32
+	SizeOfImage                 uint32
+	SizeOfHeaders               uint32
+	CheckSum                    uint32
+	Subsystem                   uint16
+	DllCharacteristics          uint16
+	SizeOfStackReserve          uint64
+	SizeOfStackCommit           uint64
+	SizeOfHeapReserve           uint64
+	SizeOfHeapCommit            uint64
+	LoaderFlags                 uint32
+	NumberOfRvaAndSizes         uint32
+	DataDirectory               [16]DataDirectory
+}
+
 type SectionHeader32 struct {
 	Name                 [8]uint8
 	VirtualSize          uint32
diff --git a/src/pkg/debug/pe/testdata/gcc-amd64-mingw-exec b/src/pkg/debug/pe/testdata/gcc-amd64-mingw-exec
new file mode 100644
index 0000000..78d4e5f
Binary files /dev/null and b/src/pkg/debug/pe/testdata/gcc-amd64-mingw-exec differ
diff --git a/src/pkg/debug/pe/testdata/gcc-amd64-mingw-obj b/src/pkg/debug/pe/testdata/gcc-amd64-mingw-obj
new file mode 100644
index 0000000..48ae792
Binary files /dev/null and b/src/pkg/debug/pe/testdata/gcc-amd64-mingw-obj differ
diff --git a/src/pkg/debug/plan9obj/file.go b/src/pkg/debug/plan9obj/file.go
new file mode 100644
index 0000000..60a5857
--- /dev/null
+++ b/src/pkg/debug/plan9obj/file.go
@@ -0,0 +1,325 @@
+// 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 plan9obj implements access to Plan 9 a.out object files.
+package plan9obj
+
+import (
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"io"
+	"os"
+)
+
+// A FileHeader represents a Plan 9 a.out file header.
+type FileHeader struct {
+	Magic   uint32
+	Bss     uint32
+	Entry   uint64
+	PtrSize int
+}
+
+// A File represents an open Plan 9 a.out file.
+type File struct {
+	FileHeader
+	Sections []*Section
+	closer   io.Closer
+}
+
+// A SectionHeader represents a single Plan 9 a.out section header.
+// This structure doesn't exist on-disk, but eases navigation
+// through the object file.
+type SectionHeader struct {
+	Name   string
+	Size   uint32
+	Offset uint32
+}
+
+// A Section represents a single section in a Plan 9 a.out file.
+type Section struct {
+	SectionHeader
+
+	// Embed ReaderAt for ReadAt method.
+	// Do not embed SectionReader directly
+	// to avoid having Read and Seek.
+	// If a client wants Read and Seek it must use
+	// Open() to avoid fighting over the seek offset
+	// with other clients.
+	io.ReaderAt
+	sr *io.SectionReader
+}
+
+// Data reads and returns the contents of the Plan 9 a.out section.
+func (s *Section) Data() ([]byte, error) {
+	dat := make([]byte, s.sr.Size())
+	n, err := s.sr.ReadAt(dat, 0)
+	if n == len(dat) {
+		err = nil
+	}
+	return dat[0:n], err
+}
+
+// Open returns a new ReadSeeker reading the Plan 9 a.out section.
+func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
+
+// A Symbol represents an entry in a Plan 9 a.out symbol table section.
+type Sym struct {
+	Value uint64
+	Type  rune
+	Name  string
+}
+
+/*
+ * Plan 9 a.out reader
+ */
+
+// formatError is returned by some operations if the data does
+// not have the correct format for an object file.
+type formatError struct {
+	off int
+	msg string
+	val interface{}
+}
+
+func (e *formatError) Error() string {
+	msg := e.msg
+	if e.val != nil {
+		msg += fmt.Sprintf(" '%v'", e.val)
+	}
+	msg += fmt.Sprintf(" in record at byte %#x", e.off)
+	return msg
+}
+
+// Open opens the named file using os.Open and prepares it for use as a Plan 9 a.out binary.
+func Open(name string) (*File, error) {
+	f, err := os.Open(name)
+	if err != nil {
+		return nil, err
+	}
+	ff, err := NewFile(f)
+	if err != nil {
+		f.Close()
+		return nil, err
+	}
+	ff.closer = f
+	return ff, nil
+}
+
+// Close closes the File.
+// If the File was created using NewFile directly instead of Open,
+// Close has no effect.
+func (f *File) Close() error {
+	var err error
+	if f.closer != nil {
+		err = f.closer.Close()
+		f.closer = nil
+	}
+	return err
+}
+
+func parseMagic(magic []byte) (uint32, error) {
+	m := binary.BigEndian.Uint32(magic)
+	switch m {
+	case Magic386, MagicAMD64, MagicARM:
+		return m, nil
+	}
+	return 0, &formatError{0, "bad magic number", magic}
+}
+
+// NewFile creates a new File for accessing a Plan 9 binary in an underlying reader.
+// The Plan 9 binary is expected to start at position 0 in the ReaderAt.
+func NewFile(r io.ReaderAt) (*File, error) {
+	sr := io.NewSectionReader(r, 0, 1<<63-1)
+	// Read and decode Plan 9 magic
+	var magic [4]byte
+	if _, err := r.ReadAt(magic[:], 0); err != nil {
+		return nil, err
+	}
+	_, err := parseMagic(magic[:])
+	if err != nil {
+		return nil, err
+	}
+
+	ph := new(prog)
+	if err := binary.Read(sr, binary.BigEndian, ph); err != nil {
+		return nil, err
+	}
+
+	f := &File{FileHeader: FileHeader{
+		Magic:   ph.Magic,
+		Bss:     ph.Bss,
+		Entry:   uint64(ph.Entry),
+		PtrSize: 4,
+	}}
+
+	hdrSize := 4 * 8
+
+	if ph.Magic&Magic64 != 0 {
+		if err := binary.Read(sr, binary.BigEndian, &f.Entry); err != nil {
+			return nil, err
+		}
+		f.PtrSize = 8
+		hdrSize += 8
+	}
+
+	var sects = []struct {
+		name string
+		size uint32
+	}{
+		{"text", ph.Text},
+		{"data", ph.Data},
+		{"syms", ph.Syms},
+		{"spsz", ph.Spsz},
+		{"pcsz", ph.Pcsz},
+	}
+
+	f.Sections = make([]*Section, 5)
+
+	off := uint32(hdrSize)
+
+	for i, sect := range sects {
+		s := new(Section)
+		s.SectionHeader = SectionHeader{
+			Name:   sect.name,
+			Size:   sect.size,
+			Offset: off,
+		}
+		off += sect.size
+		s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Size))
+		s.ReaderAt = s.sr
+		f.Sections[i] = s
+	}
+
+	return f, nil
+}
+
+func walksymtab(data []byte, ptrsz int, fn func(sym) error) error {
+	var order binary.ByteOrder = binary.BigEndian
+	var s sym
+	p := data
+	for len(p) >= 4 {
+		// Symbol type, value.
+		if len(p) < ptrsz {
+			return &formatError{len(data), "unexpected EOF", nil}
+		}
+		// fixed-width value
+		if ptrsz == 8 {
+			s.value = order.Uint64(p[0:8])
+			p = p[8:]
+		} else {
+			s.value = uint64(order.Uint32(p[0:4]))
+			p = p[4:]
+		}
+
+		var typ byte
+		typ = p[0] & 0x7F
+		s.typ = typ
+		p = p[1:]
+
+		// Name.
+		var i int
+		var nnul int
+		for i = 0; i < len(p); i++ {
+			if p[i] == 0 {
+				nnul = 1
+				break
+			}
+		}
+		switch typ {
+		case 'z', 'Z':
+			p = p[i+nnul:]
+			for i = 0; i+2 <= len(p); i += 2 {
+				if p[i] == 0 && p[i+1] == 0 {
+					nnul = 2
+					break
+				}
+			}
+		}
+		if len(p) < i+nnul {
+			return &formatError{len(data), "unexpected EOF", nil}
+		}
+		s.name = p[0:i]
+		i += nnul
+		p = p[i:]
+
+		fn(s)
+	}
+	return nil
+}
+
+// NewTable decodes the Go symbol table in data,
+// returning an in-memory representation.
+func newTable(symtab []byte, ptrsz int) ([]Sym, error) {
+	var n int
+	err := walksymtab(symtab, ptrsz, func(s sym) error {
+		n++
+		return nil
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	fname := make(map[uint16]string)
+	syms := make([]Sym, 0, n)
+	err = walksymtab(symtab, ptrsz, func(s sym) error {
+		n := len(syms)
+		syms = syms[0 : n+1]
+		ts := &syms[n]
+		ts.Type = rune(s.typ)
+		ts.Value = s.value
+		switch s.typ {
+		default:
+			ts.Name = string(s.name[:])
+		case 'z', 'Z':
+			for i := 0; i < len(s.name); i += 2 {
+				eltIdx := binary.BigEndian.Uint16(s.name[i : i+2])
+				elt, ok := fname[eltIdx]
+				if !ok {
+					return &formatError{-1, "bad filename code", eltIdx}
+				}
+				if n := len(ts.Name); n > 0 && ts.Name[n-1] != '/' {
+					ts.Name += "/"
+				}
+				ts.Name += elt
+			}
+		}
+		switch s.typ {
+		case 'f':
+			fname[uint16(s.value)] = ts.Name
+		}
+		return nil
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	return syms, nil
+}
+
+// Symbols returns the symbol table for f.
+func (f *File) Symbols() ([]Sym, error) {
+	symtabSection := f.Section("syms")
+	if symtabSection == nil {
+		return nil, errors.New("no symbol section")
+	}
+
+	symtab, err := symtabSection.Data()
+	if err != nil {
+		return nil, errors.New("cannot load symbol section")
+	}
+
+	return newTable(symtab, f.PtrSize)
+}
+
+// Section returns a section with the given name, or nil if no such
+// section exists.
+func (f *File) Section(name string) *Section {
+	for _, s := range f.Sections {
+		if s.Name == name {
+			return s
+		}
+	}
+	return nil
+}
diff --git a/src/pkg/debug/plan9obj/file_test.go b/src/pkg/debug/plan9obj/file_test.go
new file mode 100644
index 0000000..96186d8
--- /dev/null
+++ b/src/pkg/debug/plan9obj/file_test.go
@@ -0,0 +1,81 @@
+// 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 plan9obj
+
+import (
+	"reflect"
+	"testing"
+)
+
+type fileTest struct {
+	file     string
+	hdr      FileHeader
+	sections []*SectionHeader
+}
+
+var fileTests = []fileTest{
+	{
+		"testdata/386-plan9-exec",
+		FileHeader{Magic386, 0x324, 0x14, 4},
+		[]*SectionHeader{
+			{"text", 0x4c5f, 0x20},
+			{"data", 0x94c, 0x4c7f},
+			{"syms", 0x2c2b, 0x55cb},
+			{"spsz", 0x0, 0x81f6},
+			{"pcsz", 0xf7a, 0x81f6},
+		},
+	},
+	{
+		"testdata/amd64-plan9-exec",
+		FileHeader{MagicAMD64, 0x618, 0x13, 8},
+		[]*SectionHeader{
+			{"text", 0x4213, 0x28},
+			{"data", 0xa80, 0x423b},
+			{"syms", 0x2c8c, 0x4cbb},
+			{"spsz", 0x0, 0x7947},
+			{"pcsz", 0xca0, 0x7947},
+		},
+	},
+}
+
+func TestOpen(t *testing.T) {
+	for i := range fileTests {
+		tt := &fileTests[i]
+
+		f, err := Open(tt.file)
+		if err != nil {
+			t.Error(err)
+			continue
+		}
+		if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
+			t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
+			continue
+		}
+
+		for i, sh := range f.Sections {
+			if i >= len(tt.sections) {
+				break
+			}
+			have := &sh.SectionHeader
+			want := tt.sections[i]
+			if !reflect.DeepEqual(have, want) {
+				t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
+			}
+		}
+		tn := len(tt.sections)
+		fn := len(f.Sections)
+		if tn != fn {
+			t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
+		}
+	}
+}
+
+func TestOpenFailure(t *testing.T) {
+	filename := "file.go"    // not a Plan 9 a.out file
+	_, err := Open(filename) // don't crash
+	if err == nil {
+		t.Errorf("open %s: succeeded unexpectedly", filename)
+	}
+}
diff --git a/src/pkg/debug/plan9obj/plan9obj.go b/src/pkg/debug/plan9obj/plan9obj.go
new file mode 100644
index 0000000..af98585
--- /dev/null
+++ b/src/pkg/debug/plan9obj/plan9obj.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.
+
+/*
+ * Plan 9 a.out constants and data structures
+ */
+
+package plan9obj
+
+// Plan 9 Program header.
+type prog struct {
+	Magic uint32 /* magic number */
+	Text  uint32 /* size of text segment */
+	Data  uint32 /* size of initialized data */
+	Bss   uint32 /* size of uninitialized data */
+	Syms  uint32 /* size of symbol table */
+	Entry uint32 /* entry point */
+	Spsz  uint32 /* size of pc/sp offset table */
+	Pcsz  uint32 /* size of pc/line number table */
+}
+
+// Plan 9 symbol table entries.
+type sym struct {
+	value uint64
+	typ   byte
+	name  []byte
+}
+
+const (
+	Magic64 = 0x8000 // 64-bit expanded header
+
+	Magic386   = (4*11+0)*11 + 7
+	MagicAMD64 = (4*26+0)*26 + 7 + Magic64
+	MagicARM   = (4*20+0)*20 + 7
+)
diff --git a/src/pkg/debug/plan9obj/testdata/386-plan9-exec b/src/pkg/debug/plan9obj/testdata/386-plan9-exec
new file mode 100755
index 0000000..748e83f
Binary files /dev/null and b/src/pkg/debug/plan9obj/testdata/386-plan9-exec differ
diff --git a/src/pkg/debug/plan9obj/testdata/amd64-plan9-exec b/src/pkg/debug/plan9obj/testdata/amd64-plan9-exec
new file mode 100755
index 0000000..3e257dd
Binary files /dev/null and b/src/pkg/debug/plan9obj/testdata/amd64-plan9-exec differ
diff --git a/src/pkg/debug/plan9obj/testdata/hello.c b/src/pkg/debug/plan9obj/testdata/hello.c
new file mode 100644
index 0000000..c0d633e
--- /dev/null
+++ b/src/pkg/debug/plan9obj/testdata/hello.c
@@ -0,0 +1,8 @@
+#include <u.h>
+#include <libc.h>
+
+void
+main(void)
+{
+	print("hello, world\n");
+}
diff --git a/src/pkg/encoding/ascii85/ascii85.go b/src/pkg/encoding/ascii85/ascii85.go
index e2afc58..60da304 100644
--- a/src/pkg/encoding/ascii85/ascii85.go
+++ b/src/pkg/encoding/ascii85/ascii85.go
@@ -281,6 +281,18 @@ func (d *decoder) Read(p []byte) (n int, err error) {
 				d.nbuf = copy(d.buf[0:], d.buf[nsrc:d.nbuf])
 				continue // copy out and return
 			}
+			if ndst == 0 && d.err == nil {
+				// Special case: input buffer is mostly filled with non-data bytes.
+				// Filter out such bytes to make room for more input.
+				off := 0
+				for i := 0; i < d.nbuf; i++ {
+					if d.buf[i] > ' ' {
+						d.buf[off] = d.buf[i]
+						off++
+					}
+				}
+				d.nbuf = off
+			}
 		}
 
 		// Out of input, out of decoded output.  Check errors.
diff --git a/src/pkg/encoding/ascii85/ascii85_test.go b/src/pkg/encoding/ascii85/ascii85_test.go
index 42cf7e8..aad199b 100644
--- a/src/pkg/encoding/ascii85/ascii85_test.go
+++ b/src/pkg/encoding/ascii85/ascii85_test.go
@@ -8,6 +8,7 @@ import (
 	"bytes"
 	"io"
 	"io/ioutil"
+	"strings"
 	"testing"
 )
 
@@ -16,6 +17,11 @@ type testpair struct {
 }
 
 var pairs = []testpair{
+	// Encode returns 0 when len(src) is 0
+	{
+		"",
+		"",
+	},
 	// Wikipedia example
 	{
 		"Man is distinguished, not only by his reason, but by this singular passion from " +
@@ -110,7 +116,7 @@ func TestDecode(t *testing.T) {
 
 func TestDecoder(t *testing.T) {
 	for _, p := range pairs {
-		decoder := NewDecoder(bytes.NewBufferString(p.encoded))
+		decoder := NewDecoder(strings.NewReader(p.encoded))
 		dbuf, err := ioutil.ReadAll(decoder)
 		if err != nil {
 			t.Fatal("Read failed", err)
@@ -125,7 +131,7 @@ func TestDecoder(t *testing.T) {
 
 func TestDecoderBuffering(t *testing.T) {
 	for bs := 1; bs <= 12; bs++ {
-		decoder := NewDecoder(bytes.NewBufferString(bigtest.encoded))
+		decoder := NewDecoder(strings.NewReader(bigtest.encoded))
 		buf := make([]byte, len(bigtest.decoded)+12)
 		var total int
 		for total = 0; total < len(bigtest.decoded); {
@@ -191,3 +197,14 @@ func TestBig(t *testing.T) {
 		t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
 	}
 }
+
+func TestDecoderInternalWhitespace(t *testing.T) {
+	s := strings.Repeat(" ", 2048) + "z"
+	decoded, err := ioutil.ReadAll(NewDecoder(strings.NewReader(s)))
+	if err != nil {
+		t.Errorf("Decode gave error %v", err)
+	}
+	if want := []byte("\000\000\000\000"); !bytes.Equal(want, decoded) {
+		t.Errorf("Decode failed: got %v, want %v", decoded, want)
+	}
+}
diff --git a/src/pkg/encoding/asn1/asn1.go b/src/pkg/encoding/asn1/asn1.go
index 992356c..ec7f91c 100644
--- a/src/pkg/encoding/asn1/asn1.go
+++ b/src/pkg/encoding/asn1/asn1.go
@@ -23,6 +23,7 @@ import (
 	"fmt"
 	"math/big"
 	"reflect"
+	"strconv"
 	"time"
 )
 
@@ -197,6 +198,19 @@ func (oi ObjectIdentifier) Equal(other ObjectIdentifier) bool {
 	return true
 }
 
+func (oi ObjectIdentifier) String() string {
+	var s string
+
+	for i, v := range oi {
+		if i > 0 {
+			s += "."
+		}
+		s += strconv.Itoa(v)
+	}
+
+	return s
+}
+
 // parseObjectIdentifier parses an OBJECT IDENTIFIER from the given bytes and
 // returns it. An object identifier is a sequence of variable length integers
 // that are assigned in a hierarchy.
@@ -451,11 +465,17 @@ func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type
 		if err != nil {
 			return
 		}
-		// We pretend that GENERAL STRINGs are PRINTABLE STRINGs so
-		// that a sequence of them can be parsed into a []string.
-		if t.tag == tagGeneralString {
+		switch t.tag {
+		case tagIA5String, tagGeneralString, tagT61String, tagUTF8String:
+			// We pretend that various other string types are
+			// PRINTABLE STRINGs so that a sequence of them can be
+			// parsed into a []string.
 			t.tag = tagPrintableString
+		case tagGeneralizedTime, tagUTCTime:
+			// Likewise, both time types are treated the same.
+			t.tag = tagUTCTime
 		}
+
 		if t.class != classUniversal || t.isCompound != compoundType || t.tag != expectedTag {
 			err = StructuralError{"sequence tag mismatch"}
 			return
@@ -632,6 +652,10 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
 		universalTag = tagGeneralizedTime
 	}
 
+	if params.set {
+		universalTag = tagSet
+	}
+
 	expectedClass := classUniversal
 	expectedTag := universalTag
 
@@ -852,13 +876,20 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
 //
 // The following tags on struct fields have special meaning to Unmarshal:
 //
-//	optional		marks the field as ASN.1 OPTIONAL
-//	[explicit] tag:x	specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC
-//	default:x		sets the default value for optional integer fields
+//	application	specifies that a APPLICATION tag is used
+//	default:x	sets the default value for optional integer fields
+//	explicit	specifies that an additional, explicit tag wraps the implicit one
+//	optional	marks the field as ASN.1 OPTIONAL
+//	set		causes a SET, rather than a SEQUENCE type to be expected
+//	tag:x		specifies the ASN.1 tag number; implies ASN.1 CONTEXT SPECIFIC
 //
 // If the type of the first field of a structure is RawContent then the raw
 // ASN1 contents of the struct will be stored in it.
 //
+// If the type name of a slice element ends with "SET" then it's treated as if
+// the "set" tag was set on it. This can be used with nested slices where a
+// struct tag cannot be given.
+//
 // Other ASN.1 types are not supported; if it encounters them,
 // Unmarshal returns a parse error.
 func Unmarshal(b []byte, val interface{}) (rest []byte, err error) {
diff --git a/src/pkg/encoding/asn1/asn1_test.go b/src/pkg/encoding/asn1/asn1_test.go
index f68804e..b553f78 100644
--- a/src/pkg/encoding/asn1/asn1_test.go
+++ b/src/pkg/encoding/asn1/asn1_test.go
@@ -6,6 +6,7 @@ package asn1
 
 import (
 	"bytes"
+	"fmt"
 	"math/big"
 	"reflect"
 	"testing"
@@ -171,6 +172,12 @@ func TestBitStringAt(t *testing.T) {
 	if bs.At(9) != 1 {
 		t.Error("#4: Failed")
 	}
+	if bs.At(-1) != 0 {
+		t.Error("#5: Failed")
+	}
+	if bs.At(17) != 0 {
+		t.Error("#6: Failed")
+	}
 }
 
 type bitStringRightAlignTest struct {
@@ -225,6 +232,10 @@ func TestObjectIdentifier(t *testing.T) {
 			}
 		}
 	}
+
+	if s := ObjectIdentifier([]int{1, 2, 3, 4}).String(); s != "1.2.3.4" {
+		t.Errorf("bad ObjectIdentifier.String(). Got %s, want 1.2.3.4", s)
+	}
 }
 
 type timeTest struct {
@@ -238,6 +249,7 @@ var utcTestData = []timeTest{
 	{"910506164540+0730", true, time.Date(1991, 05, 06, 16, 45, 40, 0, time.FixedZone("", 7*60*60+30*60))},
 	{"910506234540Z", true, time.Date(1991, 05, 06, 23, 45, 40, 0, time.UTC)},
 	{"9105062345Z", true, time.Date(1991, 05, 06, 23, 45, 0, 0, time.UTC)},
+	{"5105062345Z", true, time.Date(1951, 05, 06, 23, 45, 0, 0, time.UTC)},
 	{"a10506234540Z", false, time.Time{}},
 	{"91a506234540Z", false, time.Time{}},
 	{"9105a6234540Z", false, time.Time{}},
@@ -389,6 +401,10 @@ type TestBigInt struct {
 	X *big.Int
 }
 
+type TestSet struct {
+	Ints []int `asn1:"set"`
+}
+
 var unmarshalTestData = []struct {
 	in  []byte
 	out interface{}
@@ -408,6 +424,7 @@ var unmarshalTestData = []struct {
 	{[]byte{0x01, 0x01, 0xff}, newBool(true)},
 	{[]byte{0x30, 0x0b, 0x13, 0x03, 0x66, 0x6f, 0x6f, 0x02, 0x01, 0x22, 0x02, 0x01, 0x33}, &TestElementsAfterString{"foo", 0x22, 0x33}},
 	{[]byte{0x30, 0x05, 0x02, 0x03, 0x12, 0x34, 0x56}, &TestBigInt{big.NewInt(0x123456)}},
+	{[]byte{0x30, 0x0b, 0x31, 0x09, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x03}, &TestSet{Ints: []int{1, 2, 3}}},
 }
 
 func TestUnmarshal(t *testing.T) {
@@ -509,6 +526,38 @@ func TestRawStructs(t *testing.T) {
 	}
 }
 
+type oiEqualTest struct {
+	first  ObjectIdentifier
+	second ObjectIdentifier
+	same   bool
+}
+
+var oiEqualTests = []oiEqualTest{
+	{
+		ObjectIdentifier{1, 2, 3},
+		ObjectIdentifier{1, 2, 3},
+		true,
+	},
+	{
+		ObjectIdentifier{1},
+		ObjectIdentifier{1, 2, 3},
+		false,
+	},
+	{
+		ObjectIdentifier{1, 2, 3},
+		ObjectIdentifier{10, 11, 12},
+		false,
+	},
+}
+
+func TestObjectIdentifierEqual(t *testing.T) {
+	for _, o := range oiEqualTests {
+		if s := o.first.Equal(o.second); s != o.same {
+			t.Errorf("ObjectIdentifier.Equal: got: %t want: %t", s, o.same)
+		}
+	}
+}
+
 var derEncodedSelfSignedCert = Certificate{
 	TBSCertificate: TBSCertificate{
 		Version:            0,
@@ -737,3 +786,29 @@ var derEncodedPaypalNULCertBytes = []byte{
 	0xc8, 0x64, 0x8c, 0xb5, 0x50, 0x23, 0x82, 0x6f, 0xdb, 0xb8, 0x22, 0x1c, 0x43,
 	0x96, 0x07, 0xa8, 0xbb,
 }
+
+var stringSliceTestData = [][]string{
+	{"foo", "bar"},
+	{"foo", "\\bar"},
+	{"foo", "\"bar\""},
+	{"foo", "åäö"},
+}
+
+func TestStringSlice(t *testing.T) {
+	for _, test := range stringSliceTestData {
+		bs, err := Marshal(test)
+		if err != nil {
+			t.Error(err)
+		}
+
+		var res []string
+		_, err = Unmarshal(bs, &res)
+		if err != nil {
+			t.Error(err)
+		}
+
+		if fmt.Sprintf("%v", res) != fmt.Sprintf("%v", test) {
+			t.Errorf("incorrect marshal/unmarshal; %v != %v", res, test)
+		}
+	}
+}
diff --git a/src/pkg/encoding/asn1/marshal.go b/src/pkg/encoding/asn1/marshal.go
index ed17e41..e26fe59 100644
--- a/src/pkg/encoding/asn1/marshal.go
+++ b/src/pkg/encoding/asn1/marshal.go
@@ -295,8 +295,23 @@ func marshalTwoDigits(out *forkableWriter, v int) (err error) {
 	return out.WriteByte(byte('0' + v%10))
 }
 
+func marshalFourDigits(out *forkableWriter, v int) (err error) {
+	var bytes [4]byte
+	for i := range bytes {
+		bytes[3-i] = '0' + byte(v%10)
+		v /= 10
+	}
+	_, err = out.Write(bytes[:])
+	return
+}
+
+func outsideUTCRange(t time.Time) bool {
+	year := t.Year()
+	return year < 1950 || year >= 2050
+}
+
 func marshalUTCTime(out *forkableWriter, t time.Time) (err error) {
-	year, month, day := t.Date()
+	year := t.Year()
 
 	switch {
 	case 1950 <= year && year < 2000:
@@ -310,6 +325,24 @@ func marshalUTCTime(out *forkableWriter, t time.Time) (err error) {
 		return
 	}
 
+	return marshalTimeCommon(out, t)
+}
+
+func marshalGeneralizedTime(out *forkableWriter, t time.Time) (err error) {
+	year := t.Year()
+	if year < 0 || year > 9999 {
+		return StructuralError{"cannot represent time as GeneralizedTime"}
+	}
+	if err = marshalFourDigits(out, year); err != nil {
+		return
+	}
+
+	return marshalTimeCommon(out, t)
+}
+
+func marshalTimeCommon(out *forkableWriter, t time.Time) (err error) {
+	_, month, day := t.Date()
+
 	err = marshalTwoDigits(out, int(month))
 	if err != nil {
 		return
@@ -378,7 +411,12 @@ func stripTagAndLength(in []byte) []byte {
 func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) {
 	switch value.Type() {
 	case timeType:
-		return marshalUTCTime(out, value.Interface().(time.Time))
+		t := value.Interface().(time.Time)
+		if outsideUTCRange(t) {
+			return marshalGeneralizedTime(out, t)
+		} else {
+			return marshalUTCTime(out, t)
+		}
 	case bitStringType:
 		return marshalBitString(out, value.Interface().(BitString))
 	case objectIdentifierType:
@@ -504,7 +542,8 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
 		return StructuralError{"explicit string type given to non-string member"}
 	}
 
-	if tag == tagPrintableString {
+	switch tag {
+	case tagPrintableString:
 		if params.stringType == 0 {
 			// This is a string without an explicit string type. We'll use
 			// a PrintableString if the character set in the string is
@@ -521,6 +560,10 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
 		} else {
 			tag = params.stringType
 		}
+	case tagUTCTime:
+		if outsideUTCRange(v.Interface().(time.Time)) {
+			tag = tagGeneralizedTime
+		}
 	}
 
 	if params.set {
@@ -568,6 +611,14 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
 }
 
 // Marshal returns the ASN.1 encoding of val.
+//
+// In addition to the struct tags recognised by Unmarshal, the following can be
+// used:
+//
+//	ia5:		causes strings to be marshaled as ASN.1, IA5 strings
+//	omitempty:	causes empty slices to be skipped
+//	printable:	causes strings to be marshaled as ASN.1, PrintableString strings.
+//	utf8:		causes strings to be marshaled as ASN.1, UTF8 strings
 func Marshal(val interface{}) ([]byte, error) {
 	var out bytes.Buffer
 	v := reflect.ValueOf(val)
diff --git a/src/pkg/encoding/asn1/marshal_test.go b/src/pkg/encoding/asn1/marshal_test.go
index 763c86d..a15acbe 100644
--- a/src/pkg/encoding/asn1/marshal_test.go
+++ b/src/pkg/encoding/asn1/marshal_test.go
@@ -67,6 +67,14 @@ type marshalTest struct {
 	out string // hex encoded
 }
 
+func farFuture() time.Time {
+	t, err := time.Parse(time.RFC3339, "2100-04-05T12:01:01Z")
+	if err != nil {
+		panic(err)
+	}
+	return t
+}
+
 var marshalTests = []marshalTest{
 	{10, "02010a"},
 	{127, "02017f"},
@@ -83,6 +91,7 @@ var marshalTests = []marshalTest{
 	{time.Unix(0, 0).UTC(), "170d3730303130313030303030305a"},
 	{time.Unix(1258325776, 0).UTC(), "170d3039313131353232353631365a"},
 	{time.Unix(1258325776, 0).In(PST), "17113039313131353134353631362d30383030"},
+	{farFuture(), "180f32313030303430353132303130315a"},
 	{BitString{[]byte{0x80}, 1}, "03020780"},
 	{BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
 	{ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},
diff --git a/src/pkg/encoding/base32/base32.go b/src/pkg/encoding/base32/base32.go
index fe17b73..d770de3 100644
--- a/src/pkg/encoding/base32/base32.go
+++ b/src/pkg/encoding/base32/base32.go
@@ -179,13 +179,11 @@ func (e *encoder) Write(p []byte) (n int, err error) {
 		nn := len(e.out) / 8 * 5
 		if nn > len(p) {
 			nn = len(p)
+			nn -= nn % 5
 		}
-		nn -= nn % 5
-		if nn > 0 {
-			e.enc.Encode(e.out[0:], p[0:nn])
-			if _, e.err = e.w.Write(e.out[0 : nn/5*8]); e.err != nil {
-				return n, e.err
-			}
+		e.enc.Encode(e.out[0:], p[0:nn])
+		if _, e.err = e.w.Write(e.out[0 : nn/5*8]); e.err != nil {
+			return n, e.err
 		}
 		n += nn
 		p = p[nn:]
@@ -268,7 +266,7 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
 				// 7, 5 and 2 are not valid padding lengths, and so 1, 3 and 6 are not
 				// valid dlen values. See RFC 4648 Section 6 "Base 32 Encoding" listing
 				// the five valid padding lengths, and Section 9 "Illustrations and
-				// Examples" for an illustration for how the the 1st, 3rd and 6th base32
+				// Examples" for an illustration for how the 1st, 3rd and 6th base32
 				// src bytes do not yield enough information to decode a dst byte.
 				if dlen == 1 || dlen == 3 || dlen == 6 {
 					return n, false, CorruptInputError(olen - len(src) - 1)
diff --git a/src/pkg/encoding/base32/base32_test.go b/src/pkg/encoding/base32/base32_test.go
index 63298d1..f56b996 100644
--- a/src/pkg/encoding/base32/base32_test.go
+++ b/src/pkg/encoding/base32/base32_test.go
@@ -108,7 +108,7 @@ func TestDecode(t *testing.T) {
 
 func TestDecoder(t *testing.T) {
 	for _, p := range pairs {
-		decoder := NewDecoder(StdEncoding, bytes.NewBufferString(p.encoded))
+		decoder := NewDecoder(StdEncoding, strings.NewReader(p.encoded))
 		dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
 		count, err := decoder.Read(dbuf)
 		if err != nil && err != io.EOF {
@@ -125,7 +125,7 @@ func TestDecoder(t *testing.T) {
 
 func TestDecoderBuffering(t *testing.T) {
 	for bs := 1; bs <= 12; bs++ {
-		decoder := NewDecoder(StdEncoding, bytes.NewBufferString(bigtest.encoded))
+		decoder := NewDecoder(StdEncoding, strings.NewReader(bigtest.encoded))
 		buf := make([]byte, len(bigtest.decoded)+12)
 		var total int
 		for total = 0; total < len(bigtest.decoded); {
@@ -267,13 +267,13 @@ LNEBUWIIDFON2CA3DBMJXXE5LNFY==
 ====`
 	encodedShort := strings.Replace(encoded, "\n", "", -1)
 
-	dec := NewDecoder(StdEncoding, bytes.NewBufferString(encoded))
+	dec := NewDecoder(StdEncoding, strings.NewReader(encoded))
 	res1, err := ioutil.ReadAll(dec)
 	if err != nil {
 		t.Errorf("ReadAll failed: %v", err)
 	}
 
-	dec = NewDecoder(StdEncoding, bytes.NewBufferString(encodedShort))
+	dec = NewDecoder(StdEncoding, strings.NewReader(encodedShort))
 	var res2 []byte
 	res2, err = ioutil.ReadAll(dec)
 	if err != nil {
diff --git a/src/pkg/encoding/base64/base64.go b/src/pkg/encoding/base64/base64.go
index 85e398f..e38c26d 100644
--- a/src/pkg/encoding/base64/base64.go
+++ b/src/pkg/encoding/base64/base64.go
@@ -159,13 +159,11 @@ func (e *encoder) Write(p []byte) (n int, err error) {
 		nn := len(e.out) / 4 * 3
 		if nn > len(p) {
 			nn = len(p)
+			nn -= nn % 3
 		}
-		nn -= nn % 3
-		if nn > 0 {
-			e.enc.Encode(e.out[0:], p[0:nn])
-			if _, e.err = e.w.Write(e.out[0 : nn/3*4]); e.err != nil {
-				return n, e.err
-			}
+		e.enc.Encode(e.out[0:], p[0:nn])
+		if _, e.err = e.w.Write(e.out[0 : nn/3*4]); e.err != nil {
+			return n, e.err
 		}
 		n += nn
 		p = p[nn:]
@@ -226,21 +224,33 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
 		var dbuf [4]byte
 		dlen := 4
 
-		for j := 0; j < 4; {
+		for j := range dbuf {
 			if len(src) == 0 {
 				return n, false, CorruptInputError(olen - len(src) - j)
 			}
 			in := src[0]
 			src = src[1:]
-			if in == '=' && j >= 2 && len(src) < 4 {
+			if in == '=' {
 				// We've reached the end and there's padding
-				if len(src)+j < 4-1 {
-					// not enough padding
-					return n, false, CorruptInputError(olen)
-				}
-				if len(src) > 0 && src[0] != '=' {
+				switch j {
+				case 0, 1:
 					// incorrect padding
 					return n, false, CorruptInputError(olen - len(src) - 1)
+				case 2:
+					// "==" is expected, the first "=" is already consumed.
+					if len(src) == 0 {
+						// not enough padding
+						return n, false, CorruptInputError(olen)
+					}
+					if src[0] != '=' {
+						// incorrect padding
+						return n, false, CorruptInputError(olen - len(src) - 1)
+					}
+					src = src[1:]
+				}
+				if len(src) > 0 {
+					// trailing garbage
+					err = CorruptInputError(olen - len(src))
 				}
 				dlen, end = j, true
 				break
@@ -249,7 +259,6 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
 			if dbuf[j] == 0xFF {
 				return n, false, CorruptInputError(olen - len(src) - 1)
 			}
-			j++
 		}
 
 		// Pack 4x 6-bit source blocks into 3 byte destination
@@ -268,7 +277,7 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
 		n += dlen - 1
 	}
 
-	return n, end, nil
+	return n, end, err
 }
 
 // Decode decodes src using the encoding enc.  It writes at most
diff --git a/src/pkg/encoding/base64/base64_test.go b/src/pkg/encoding/base64/base64_test.go
index 579591a..a075194 100644
--- a/src/pkg/encoding/base64/base64_test.go
+++ b/src/pkg/encoding/base64/base64_test.go
@@ -9,6 +9,7 @@ import (
 	"errors"
 	"io"
 	"io/ioutil"
+	"reflect"
 	"strings"
 	"testing"
 	"time"
@@ -113,7 +114,7 @@ func TestDecode(t *testing.T) {
 
 func TestDecoder(t *testing.T) {
 	for _, p := range pairs {
-		decoder := NewDecoder(StdEncoding, bytes.NewBufferString(p.encoded))
+		decoder := NewDecoder(StdEncoding, strings.NewReader(p.encoded))
 		dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
 		count, err := decoder.Read(dbuf)
 		if err != nil && err != io.EOF {
@@ -130,7 +131,7 @@ func TestDecoder(t *testing.T) {
 
 func TestDecoderBuffering(t *testing.T) {
 	for bs := 1; bs <= 12; bs++ {
-		decoder := NewDecoder(StdEncoding, bytes.NewBufferString(bigtest.encoded))
+		decoder := NewDecoder(StdEncoding, strings.NewReader(bigtest.encoded))
 		buf := make([]byte, len(bigtest.decoded)+12)
 		var total int
 		for total = 0; total < len(bigtest.decoded); {
@@ -149,9 +150,13 @@ func TestDecodeCorrupt(t *testing.T) {
 	}{
 		{"", -1},
 		{"!!!!", 0},
+		{"====", 0},
 		{"x===", 1},
+		{"=AAA", 0},
+		{"A=AA", 1},
 		{"AA=A", 2},
-		{"AAA=AAAA", 3},
+		{"AA==A", 4},
+		{"AAA=AAAA", 4},
 		{"AAAAA", 4},
 		{"AAAAAA", 4},
 		{"A=", 1},
@@ -161,6 +166,7 @@ func TestDecodeCorrupt(t *testing.T) {
 		{"AAA=", -1},
 		{"AAAA", -1},
 		{"AAAAAA=", 7},
+		{"YWJjZA=====", 8},
 	}
 	for _, tc := range testCases {
 		dbuf := make([]byte, StdEncoding.DecodedLen(len(tc.input)))
@@ -308,13 +314,13 @@ bqbPb06551Y4
 `
 	encodedShort := strings.Replace(encoded, "\n", "", -1)
 
-	dec := NewDecoder(StdEncoding, bytes.NewBufferString(encoded))
+	dec := NewDecoder(StdEncoding, strings.NewReader(encoded))
 	res1, err := ioutil.ReadAll(dec)
 	if err != nil {
 		t.Errorf("ReadAll failed: %v", err)
 	}
 
-	dec = NewDecoder(StdEncoding, bytes.NewBufferString(encodedShort))
+	dec = NewDecoder(StdEncoding, strings.NewReader(encodedShort))
 	var res2 []byte
 	res2, err = ioutil.ReadAll(dec)
 	if err != nil {
@@ -325,3 +331,14 @@ bqbPb06551Y4
 		t.Error("Decoded results not equal")
 	}
 }
+
+func TestDecoderIssue7733(t *testing.T) {
+	s, err := StdEncoding.DecodeString("YWJjZA=====")
+	want := CorruptInputError(8)
+	if !reflect.DeepEqual(want, err) {
+		t.Errorf("Error = %v; want CorruptInputError(8)", err)
+	}
+	if string(s) != "abcd" {
+		t.Errorf("DecodeString = %q; want abcd", s)
+	}
+}
diff --git a/src/pkg/encoding/binary/binary.go b/src/pkg/encoding/binary/binary.go
index f3466b9..a569487 100644
--- a/src/pkg/encoding/binary/binary.go
+++ b/src/pkg/encoding/binary/binary.go
@@ -133,6 +133,7 @@ func (bigEndian) GoString() string { return "binary.BigEndian" }
 // When reading into structs, the field data for fields with
 // blank (_) field names is skipped; i.e., blank field names
 // may be used for padding.
+// When reading into a struct, all non-blank fields must be exported.
 func Read(r io.Reader, order ByteOrder, data interface{}) error {
 	// Fast path for basic types and slices.
 	if n := intDataSize(data); n != 0 {
diff --git a/src/pkg/encoding/binary/binary_test.go b/src/pkg/encoding/binary/binary_test.go
index fdfee7d..c80c903 100644
--- a/src/pkg/encoding/binary/binary_test.go
+++ b/src/pkg/encoding/binary/binary_test.go
@@ -111,7 +111,7 @@ func checkResult(t *testing.T, dir string, order ByteOrder, err error, have, wan
 
 func testRead(t *testing.T, order ByteOrder, b []byte, s1 interface{}) {
 	var s2 Struct
-	err := Read(bytes.NewBuffer(b), order, &s2)
+	err := Read(bytes.NewReader(b), order, &s2)
 	checkResult(t, "Read", order, err, s2, s1)
 }
 
@@ -131,7 +131,7 @@ func TestBigEndianPtrWrite(t *testing.T) { testWrite(t, BigEndian, big, &s) }
 
 func TestReadSlice(t *testing.T) {
 	slice := make([]int32, 2)
-	err := Read(bytes.NewBuffer(src), BigEndian, slice)
+	err := Read(bytes.NewReader(src), BigEndian, slice)
 	checkResult(t, "ReadSlice", BigEndian, err, slice, res)
 }
 
@@ -265,6 +265,30 @@ func TestBlankFields(t *testing.T) {
 	}
 }
 
+// An attempt to read into a struct with an unexported field will
+// panic.  This is probably not the best choice, but at this point
+// anything else would be an API change.
+
+type Unexported struct {
+	a int32
+}
+
+func TestUnexportedRead(t *testing.T) {
+	var buf bytes.Buffer
+	u1 := Unexported{a: 1}
+	if err := Write(&buf, LittleEndian, &u1); err != nil {
+		t.Fatal(err)
+	}
+
+	defer func() {
+		if recover() == nil {
+			t.Fatal("did not panic")
+		}
+	}()
+	var u2 Unexported
+	Read(&buf, LittleEndian, &u2)
+}
+
 type byteSliceReader struct {
 	remain []byte
 }
diff --git a/src/pkg/encoding/binary/varint_test.go b/src/pkg/encoding/binary/varint_test.go
index 9476bd5..ca411ec 100644
--- a/src/pkg/encoding/binary/varint_test.go
+++ b/src/pkg/encoding/binary/varint_test.go
@@ -35,7 +35,7 @@ func testVarint(t *testing.T, x int64) {
 		t.Errorf("Varint(%d): got n = %d; want %d", x, m, n)
 	}
 
-	y, err := ReadVarint(bytes.NewBuffer(buf))
+	y, err := ReadVarint(bytes.NewReader(buf))
 	if err != nil {
 		t.Errorf("ReadVarint(%d): %s", x, err)
 	}
@@ -55,7 +55,7 @@ func testUvarint(t *testing.T, x uint64) {
 		t.Errorf("Uvarint(%d): got n = %d; want %d", x, m, n)
 	}
 
-	y, err := ReadUvarint(bytes.NewBuffer(buf))
+	y, err := ReadUvarint(bytes.NewReader(buf))
 	if err != nil {
 		t.Errorf("ReadUvarint(%d): %s", x, err)
 	}
@@ -114,7 +114,7 @@ func TestBufferTooSmall(t *testing.T) {
 			t.Errorf("Uvarint(%v): got x = %d, n = %d", buf, x, n)
 		}
 
-		x, err := ReadUvarint(bytes.NewBuffer(buf))
+		x, err := ReadUvarint(bytes.NewReader(buf))
 		if x != 0 || err != io.EOF {
 			t.Errorf("ReadUvarint(%v): got x = %d, err = %s", buf, x, err)
 		}
@@ -127,7 +127,7 @@ func testOverflow(t *testing.T, buf []byte, n0 int, err0 error) {
 		t.Errorf("Uvarint(%v): got x = %d, n = %d; want 0, %d", buf, x, n, n0)
 	}
 
-	x, err := ReadUvarint(bytes.NewBuffer(buf))
+	x, err := ReadUvarint(bytes.NewReader(buf))
 	if x != 0 || err != err0 {
 		t.Errorf("ReadUvarint(%v): got x = %d, err = %s; want 0, %s", buf, x, err, err0)
 	}
diff --git a/src/pkg/encoding/csv/reader.go b/src/pkg/encoding/csv/reader.go
index b328dcc..d943295 100644
--- a/src/pkg/encoding/csv/reader.go
+++ b/src/pkg/encoding/csv/reader.go
@@ -193,12 +193,6 @@ func (r *Reader) readRune() (rune, error) {
 	return r1, err
 }
 
-// unreadRune puts the last rune read from r back.
-func (r *Reader) unreadRune() {
-	r.r.UnreadRune()
-	r.column--
-}
-
 // skip reads runes up to and including the rune delim or until error.
 func (r *Reader) skip(delim rune) error {
 	for {
diff --git a/src/pkg/encoding/csv/writer_test.go b/src/pkg/encoding/csv/writer_test.go
index 03ca6b0..22b740c 100644
--- a/src/pkg/encoding/csv/writer_test.go
+++ b/src/pkg/encoding/csv/writer_test.go
@@ -26,6 +26,8 @@ var writeTests = []struct {
 	{Input: [][]string{{"abc"}, {"def"}}, Output: "abc\ndef\n"},
 	{Input: [][]string{{"abc\ndef"}}, Output: "\"abc\ndef\"\n"},
 	{Input: [][]string{{"abc\ndef"}}, Output: "\"abc\r\ndef\"\r\n", UseCRLF: true},
+	{Input: [][]string{{"abc\rdef"}}, Output: "\"abcdef\"\r\n", UseCRLF: true},
+	{Input: [][]string{{"abc\rdef"}}, Output: "\"abc\rdef\"\n", UseCRLF: false},
 }
 
 func TestWrite(t *testing.T) {
diff --git a/src/pkg/encoding/gob/codec_test.go b/src/pkg/encoding/gob/codec_test.go
index b40f783..fa57f37 100644
--- a/src/pkg/encoding/gob/codec_test.go
+++ b/src/pkg/encoding/gob/codec_test.go
@@ -1364,11 +1364,7 @@ type DT struct {
 	S     []string
 }
 
-func TestDebugStruct(t *testing.T) {
-	if debugFunc == nil {
-		return
-	}
-	Register(OnTheFly{})
+func newDT() DT {
 	var dt DT
 	dt.A = 17
 	dt.B = "hello"
@@ -1379,6 +1375,15 @@ func TestDebugStruct(t *testing.T) {
 	dt.M = map[string]int{"one": 1, "two": 2}
 	dt.T = [3]int{11, 22, 33}
 	dt.S = []string{"hi", "joe"}
+	return dt
+}
+
+func TestDebugStruct(t *testing.T) {
+	if debugFunc == nil {
+		return
+	}
+	Register(OnTheFly{})
+	dt := newDT()
 	b := new(bytes.Buffer)
 	err := NewEncoder(b).Encode(dt)
 	if err != nil {
@@ -1458,3 +1463,44 @@ func testFuzz(t *testing.T, seed int64, n int, input ...interface{}) {
 		}
 	}
 }
+
+// TestFuzzOneByte tries to decode corrupted input sequences
+// and checks that no panic occurs.
+func TestFuzzOneByte(t *testing.T) {
+	buf := new(bytes.Buffer)
+	Register(OnTheFly{})
+	dt := newDT()
+	if err := NewEncoder(buf).Encode(dt); err != nil {
+		t.Fatal(err)
+	}
+	s := buf.String()
+
+	indices := make([]int, 0, len(s))
+	for i := 0; i < len(s); i++ {
+		switch i {
+		case 14, 167, 231, 265: // a slice length, corruptions are not handled yet.
+			continue
+		}
+		indices = append(indices, i)
+	}
+	if testing.Short() {
+		indices = []int{1, 111, 178} // known fixed panics
+	}
+	for _, i := range indices {
+		for j := 0; j < 256; j += 3 {
+			b := []byte(s)
+			b[i] ^= byte(j)
+			var e DT
+			func() {
+				defer func() {
+					if p := recover(); p != nil {
+						t.Errorf("crash for b[%d] ^= 0x%x", i, j)
+						panic(p)
+					}
+				}()
+				err := NewDecoder(bytes.NewReader(b)).Decode(&e)
+				_ = err
+			}()
+		}
+	}
+}
diff --git a/src/pkg/encoding/gob/decode.go b/src/pkg/encoding/gob/decode.go
index 3e76f4c..d851314 100644
--- a/src/pkg/encoding/gob/decode.go
+++ b/src/pkg/encoding/gob/decode.go
@@ -654,21 +654,20 @@ func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) {
 
 // decodeSlice decodes a slice and stores the slice header through p.
 // Slices are encoded as an unsigned length followed by the elements.
-func (dec *Decoder) decodeSlice(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl error) {
+func (dec *Decoder) decodeSlice(atyp reflect.Type, state *decoderState, p unsafe.Pointer, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl error) {
 	nr := state.decodeUint()
 	n := int(nr)
 	if indir > 0 {
-		up := unsafe.Pointer(p)
-		if *(*unsafe.Pointer)(up) == nil {
+		if *(*unsafe.Pointer)(p) == nil {
 			// Allocate the slice header.
-			*(*unsafe.Pointer)(up) = unsafe.Pointer(new([]unsafe.Pointer))
+			*(*unsafe.Pointer)(p) = unsafe.Pointer(new([]unsafe.Pointer))
 		}
-		p = *(*uintptr)(up)
+		p = *(*unsafe.Pointer)(p)
 	}
 	// Allocate storage for the slice elements, that is, the underlying array,
 	// if the existing slice does not have the capacity.
 	// Always write a header at p.
-	hdrp := (*reflect.SliceHeader)(unsafe.Pointer(p))
+	hdrp := (*reflect.SliceHeader)(p)
 	if hdrp.Cap < n {
 		hdrp.Data = reflect.MakeSlice(atyp, n, n).Pointer()
 		hdrp.Cap = n
@@ -686,7 +685,7 @@ func (dec *Decoder) ignoreSlice(state *decoderState, elemOp decOp) {
 // but first it checks that the assignment will succeed.
 func setInterfaceValue(ivalue reflect.Value, value reflect.Value) {
 	if !value.Type().AssignableTo(ivalue.Type()) {
-		errorf("cannot assign value of type %s to %s", value.Type(), ivalue.Type())
+		errorf("%s is not assignable to type %s", value.Type(), ivalue.Type())
 	}
 	ivalue.Set(value)
 }
@@ -702,6 +701,9 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p un
 	if nr < 0 || nr > 1<<31 { // zero is permissible for anonymous types
 		errorf("invalid type name length %d", nr)
 	}
+	if nr > uint64(state.b.Len()) {
+		errorf("invalid type name length %d: exceeds input size", nr)
+	}
 	b := make([]byte, nr)
 	state.b.Read(b)
 	name := string(b)
@@ -887,7 +889,7 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
 			elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name, inProgress)
 			ovfl := overflow(name)
 			op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
-				state.dec.decodeSlice(t, state, uintptr(p), *elemOp, t.Elem().Size(), i.indir, elemIndir, ovfl)
+				state.dec.decodeSlice(t, state, p, *elemOp, t.Elem().Size(), i.indir, elemIndir, ovfl)
 			}
 
 		case reflect.Struct:
@@ -1238,7 +1240,8 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) {
 	}
 	engine := *enginePtr
 	if st := base; st.Kind() == reflect.Struct && ut.externalDec == 0 {
-		if engine.numInstr == 0 && st.NumField() > 0 && len(dec.wireType[wireId].StructT.Field) > 0 {
+		if engine.numInstr == 0 && st.NumField() > 0 &&
+			dec.wireType[wireId] != nil && len(dec.wireType[wireId].StructT.Field) > 0 {
 			name := base.Name()
 			errorf("type mismatch: no fields matched compiling decoder for %s", name)
 		}
diff --git a/src/pkg/encoding/gob/decoder.go b/src/pkg/encoding/gob/decoder.go
index 04f706c..3a769ec 100644
--- a/src/pkg/encoding/gob/decoder.go
+++ b/src/pkg/encoding/gob/decoder.go
@@ -183,11 +183,13 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
 	return -1
 }
 
-// Decode reads the next value from the connection and stores
+// Decode reads the next value from the input stream and stores
 // it in the data represented by the empty interface value.
 // If e is nil, the value will be discarded. Otherwise,
 // the value underlying e must be a pointer to the
 // correct type for the next data item received.
+// If the input is at EOF, Decode returns io.EOF and
+// does not modify e.
 func (dec *Decoder) Decode(e interface{}) error {
 	if e == nil {
 		return dec.DecodeValue(reflect.Value{})
@@ -202,10 +204,12 @@ func (dec *Decoder) Decode(e interface{}) error {
 	return dec.DecodeValue(value)
 }
 
-// DecodeValue reads the next value from the connection.
+// DecodeValue reads the next value from the input stream.
 // If v is the zero reflect.Value (v.Kind() == Invalid), DecodeValue discards the value.
 // Otherwise, it stores the value into v.  In that case, v must represent
 // a non-nil pointer to data or be an assignable reflect.Value (v.CanSet())
+// If the input is at EOF, DecodeValue returns io.EOF and
+// does not modify e.
 func (dec *Decoder) DecodeValue(v reflect.Value) error {
 	if v.IsValid() {
 		if v.Kind() == reflect.Ptr && !v.IsNil() {
diff --git a/src/pkg/encoding/gob/encode.go b/src/pkg/encoding/gob/encode.go
index d158b64..7831c02 100644
--- a/src/pkg/encoding/gob/encode.go
+++ b/src/pkg/encoding/gob/encode.go
@@ -491,7 +491,7 @@ func isZero(val reflect.Value) bool {
 		return !val.Bool()
 	case reflect.Complex64, reflect.Complex128:
 		return val.Complex() == 0
-	case reflect.Chan, reflect.Func, reflect.Ptr:
+	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr:
 		return val.IsNil()
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 		return val.Int() == 0
diff --git a/src/pkg/encoding/gob/encoder_test.go b/src/pkg/encoding/gob/encoder_test.go
index 4ecf51d..6445ce1 100644
--- a/src/pkg/encoding/gob/encoder_test.go
+++ b/src/pkg/encoding/gob/encoder_test.go
@@ -129,6 +129,8 @@ func TestBadData(t *testing.T) {
 	corruptDataCheck("", io.EOF, t)
 	corruptDataCheck("\x7Fhi", io.ErrUnexpectedEOF, t)
 	corruptDataCheck("\x03now is the time for all good men", errBadType, t)
+	// issue 6323.
+	corruptDataCheck("\x04\x24foo", errRange, t)
 }
 
 // Types not supported at top level by the Encoder.
@@ -630,7 +632,7 @@ func TestSliceReusesMemory(t *testing.T) {
 // Used to crash: negative count in recvMessage.
 func TestBadCount(t *testing.T) {
 	b := []byte{0xfb, 0xa5, 0x82, 0x2f, 0xca, 0x1}
-	if err := NewDecoder(bytes.NewBuffer(b)).Decode(nil); err == nil {
+	if err := NewDecoder(bytes.NewReader(b)).Decode(nil); err == nil {
 		t.Error("expected error from bad count")
 	} else if err.Error() != errBadCount.Error() {
 		t.Error("expected bad count error; got", err)
diff --git a/src/pkg/encoding/gob/gobencdec_test.go b/src/pkg/encoding/gob/gobencdec_test.go
index 0193e2b..157b772 100644
--- a/src/pkg/encoding/gob/gobencdec_test.go
+++ b/src/pkg/encoding/gob/gobencdec_test.go
@@ -705,13 +705,14 @@ func TestGobEncoderExtraIndirect(t *testing.T) {
 }
 
 // Another bug: this caused a crash with the new Go1 Time type.
-// We throw in a gob-encoding array, to test another case of isZero
-
+// We throw in a gob-encoding array, to test another case of isZero,
+// and a struct containing an nil interface, to test a third.
 type isZeroBug struct {
 	T time.Time
 	S string
 	I int
 	A isZeroBugArray
+	F isZeroBugInterface
 }
 
 type isZeroBugArray [2]uint8
@@ -731,8 +732,20 @@ func (a *isZeroBugArray) GobDecode(data []byte) error {
 	return nil
 }
 
+type isZeroBugInterface struct {
+	I interface{}
+}
+
+func (i isZeroBugInterface) GobEncode() (b []byte, e error) {
+	return []byte{}, nil
+}
+
+func (i *isZeroBugInterface) GobDecode(data []byte) error {
+	return nil
+}
+
 func TestGobEncodeIsZero(t *testing.T) {
-	x := isZeroBug{time.Now(), "hello", -55, isZeroBugArray{1, 2}}
+	x := isZeroBug{time.Now(), "hello", -55, isZeroBugArray{1, 2}, isZeroBugInterface{}}
 	b := new(bytes.Buffer)
 	enc := NewEncoder(b)
 	err := enc.Encode(x)
diff --git a/src/pkg/encoding/hex/hex.go b/src/pkg/encoding/hex/hex.go
index 167d00e..d1fc702 100644
--- a/src/pkg/encoding/hex/hex.go
+++ b/src/pkg/encoding/hex/hex.go
@@ -146,6 +146,9 @@ func (h *dumper) Write(data []byte) (n int, err error) {
 			h.buf[12] = ' '
 			h.buf[13] = ' '
 			_, err = h.w.Write(h.buf[4:])
+			if err != nil {
+				return
+			}
 		}
 		Encode(h.buf[:], data[i:i+1])
 		h.buf[2] = ' '
diff --git a/src/pkg/encoding/hex/hex_test.go b/src/pkg/encoding/hex/hex_test.go
index 356f590..b969636 100644
--- a/src/pkg/encoding/hex/hex_test.go
+++ b/src/pkg/encoding/hex/hex_test.go
@@ -38,7 +38,10 @@ func TestEncode(t *testing.T) {
 }
 
 func TestDecode(t *testing.T) {
-	for i, test := range encDecTests {
+	// Case for decoding uppercase hex characters, since
+	// Encode always uses lowercase.
+	decTests := append(encDecTests, encDecTest{"F8F9FAFBFCFDFEFF", []byte{0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}})
+	for i, test := range decTests {
 		dst := make([]byte, DecodedLen(len(test.enc)))
 		n, err := Decode(dst, []byte(test.enc))
 		if err != nil {
@@ -79,6 +82,7 @@ type errTest struct {
 var errTests = []errTest{
 	{"0", "encoding/hex: odd length hex string"},
 	{"0g", "encoding/hex: invalid byte: U+0067 'g'"},
+	{"00gg", "encoding/hex: invalid byte: U+0067 'g'"},
 	{"0\x01", "encoding/hex: invalid byte: U+0001"},
 }
 
diff --git a/src/pkg/encoding/json/decode.go b/src/pkg/encoding/json/decode.go
index 458fb39..af1c908 100644
--- a/src/pkg/encoding/json/decode.go
+++ b/src/pkg/encoding/json/decode.go
@@ -8,6 +8,7 @@
 package json
 
 import (
+	"bytes"
 	"encoding"
 	"encoding/base64"
 	"errors"
@@ -15,7 +16,6 @@ import (
 	"reflect"
 	"runtime"
 	"strconv"
-	"strings"
 	"unicode"
 	"unicode/utf16"
 	"unicode/utf8"
@@ -54,6 +54,11 @@ import (
 // If no more serious errors are encountered, Unmarshal returns
 // an UnmarshalTypeError describing the earliest such error.
 //
+// The JSON null value unmarshals into an interface, map, pointer, or slice
+// by setting that Go value to nil. Because null is often used in JSON to mean
+// ``not present,'' unmarshaling a JSON null into any other Go type has no effect
+// on the value and produces no error.
+//
 // When unmarshaling quoted strings, invalid UTF-8 or
 // invalid UTF-16 surrogate pairs are not treated as an error.
 // Instead, they are replaced by the Unicode replacement
@@ -500,11 +505,11 @@ func (d *decodeState) object(v reflect.Value) {
 			d.error(errPhase)
 		}
 
-		// Read string key.
+		// Read key.
 		start := d.off - 1
 		op = d.scanWhile(scanContinue)
 		item := d.data[start : d.off-1]
-		key, ok := unquote(item)
+		key, ok := unquoteBytes(item)
 		if !ok {
 			d.error(errPhase)
 		}
@@ -526,11 +531,11 @@ func (d *decodeState) object(v reflect.Value) {
 			fields := cachedTypeFields(v.Type())
 			for i := range fields {
 				ff := &fields[i]
-				if ff.name == key {
+				if bytes.Equal(ff.nameBytes, key) {
 					f = ff
 					break
 				}
-				if f == nil && strings.EqualFold(ff.name, key) {
+				if f == nil && ff.equalFold(ff.nameBytes, key) {
 					f = ff
 				}
 			}
@@ -561,6 +566,7 @@ func (d *decodeState) object(v reflect.Value) {
 		if destring {
 			d.value(reflect.ValueOf(&d.tempstr))
 			d.literalStore([]byte(d.tempstr), subv, true)
+			d.tempstr = "" // Zero scratch space for successive values.
 		} else {
 			d.value(subv)
 		}
diff --git a/src/pkg/encoding/json/decode_test.go b/src/pkg/encoding/json/decode_test.go
index 22c5f89..238a87f 100644
--- a/src/pkg/encoding/json/decode_test.go
+++ b/src/pkg/encoding/json/decode_test.go
@@ -1060,6 +1060,21 @@ func TestEmptyString(t *testing.T) {
 	}
 }
 
+// Test that the returned error is non-nil when trying to unmarshal null string into int, for successive ,string option
+// Issue 7046
+func TestNullString(t *testing.T) {
+	type T struct {
+		A int `json:",string"`
+		B int `json:",string"`
+	}
+	data := []byte(`{"A": "1", "B": null}`)
+	var s T
+	err := Unmarshal(data, &s)
+	if err == nil {
+		t.Fatalf("expected error; got %v", s)
+	}
+}
+
 func intp(x int) *int {
 	p := new(int)
 	*p = x
@@ -1110,8 +1125,8 @@ func TestInterfaceSet(t *testing.T) {
 // Issue 2540
 func TestUnmarshalNulls(t *testing.T) {
 	jsonData := []byte(`{
-		"Bool"    : null, 
-		"Int"     : null, 
+		"Bool"    : null,
+		"Int"     : null,
 		"Int8"    : null,
 		"Int16"   : null,
 		"Int32"   : null,
@@ -1316,3 +1331,26 @@ func TestPrefilled(t *testing.T) {
 		}
 	}
 }
+
+var invalidUnmarshalTests = []struct {
+	v    interface{}
+	want string
+}{
+	{nil, "json: Unmarshal(nil)"},
+	{struct{}{}, "json: Unmarshal(non-pointer struct {})"},
+	{(*int)(nil), "json: Unmarshal(nil *int)"},
+}
+
+func TestInvalidUnmarshal(t *testing.T) {
+	buf := []byte(`{"a":"1"}`)
+	for _, tt := range invalidUnmarshalTests {
+		err := Unmarshal(buf, tt.v)
+		if err == nil {
+			t.Errorf("Unmarshal expecting error, got nil")
+			continue
+		}
+		if got := err.Error(); got != tt.want {
+			t.Errorf("Unmarshal = %q; want %q", got, tt.want)
+		}
+	}
+}
diff --git a/src/pkg/encoding/json/encode.go b/src/pkg/encoding/json/encode.go
index 7d6c71d..741ddd8 100644
--- a/src/pkg/encoding/json/encode.go
+++ b/src/pkg/encoding/json/encode.go
@@ -44,6 +44,7 @@ import (
 // if an invalid UTF-8 sequence is encountered.
 // The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e"
 // to keep some browsers from misinterpreting JSON output as HTML.
+// Ampersand "&" is also escaped to "\u0026" for the same reason.
 //
 // Array and slice values encode as JSON arrays, except that
 // []byte encodes as a base64-encoded string, and a nil slice
@@ -241,24 +242,15 @@ type encodeState struct {
 	scratch      [64]byte
 }
 
-// TODO(bradfitz): use a sync.Cache here
-var encodeStatePool = make(chan *encodeState, 8)
+var encodeStatePool sync.Pool
 
 func newEncodeState() *encodeState {
-	select {
-	case e := <-encodeStatePool:
+	if v := encodeStatePool.Get(); v != nil {
+		e := v.(*encodeState)
 		e.Reset()
 		return e
-	default:
-		return new(encodeState)
-	}
-}
-
-func putEncodeState(e *encodeState) {
-	select {
-	case encodeStatePool <- e:
-	default:
 	}
+	return new(encodeState)
 }
 
 func (e *encodeState) marshal(v interface{}) (err error) {
@@ -813,7 +805,7 @@ func (e *encodeState) string(s string) (int, error) {
 				e.WriteByte('r')
 			default:
 				// This encodes bytes < 0x20 except for \n and \r,
-				// as well as < and >. The latter are escaped because they
+				// as well as <, > and &. The latter are escaped because they
 				// can lead to security holes when user-controlled strings
 				// are rendered into JSON and served to some browsers.
 				e.WriteString(`\u00`)
@@ -936,6 +928,9 @@ func (e *encodeState) stringBytes(s []byte) (int, error) {
 // A field represents a single field found in a struct.
 type field struct {
 	name      string
+	nameBytes []byte                 // []byte(name)
+	equalFold func(s, t []byte) bool // bytes.EqualFold or equivalent
+
 	tag       bool
 	index     []int
 	typ       reflect.Type
@@ -943,6 +938,12 @@ type field struct {
 	quoted    bool
 }
 
+func fillField(f field) field {
+	f.nameBytes = []byte(f.name)
+	f.equalFold = foldFunc(f.nameBytes)
+	return f
+}
+
 // byName sorts field by name, breaking ties with depth,
 // then breaking ties with "name came from json tag", then
 // breaking ties with index sequence.
@@ -1042,8 +1043,14 @@ func typeFields(t reflect.Type) []field {
 					if name == "" {
 						name = sf.Name
 					}
-					fields = append(fields, field{name, tagged, index, ft,
-						opts.Contains("omitempty"), opts.Contains("string")})
+					fields = append(fields, fillField(field{
+						name:      name,
+						tag:       tagged,
+						index:     index,
+						typ:       ft,
+						omitEmpty: opts.Contains("omitempty"),
+						quoted:    opts.Contains("string"),
+					}))
 					if count[f.typ] > 1 {
 						// If there were multiple instances, add a second,
 						// so that the annihilation code will see a duplicate.
@@ -1057,7 +1064,7 @@ func typeFields(t reflect.Type) []field {
 				// Record new anonymous struct to explore in next round.
 				nextCount[ft]++
 				if nextCount[ft] == 1 {
-					next = append(next, field{name: ft.Name(), index: index, typ: ft})
+					next = append(next, fillField(field{name: ft.Name(), index: index, typ: ft}))
 				}
 			}
 		}
diff --git a/src/pkg/encoding/json/encode_test.go b/src/pkg/encoding/json/encode_test.go
index 9395db7..2e89a78 100644
--- a/src/pkg/encoding/json/encode_test.go
+++ b/src/pkg/encoding/json/encode_test.go
@@ -25,13 +25,30 @@ type Optionals struct {
 
 	Mr map[string]interface{} `json:"mr"`
 	Mo map[string]interface{} `json:",omitempty"`
+
+	Fr float64 `json:"fr"`
+	Fo float64 `json:"fo,omitempty"`
+
+	Br bool `json:"br"`
+	Bo bool `json:"bo,omitempty"`
+
+	Ur uint `json:"ur"`
+	Uo uint `json:"uo,omitempty"`
+
+	Str struct{} `json:"str"`
+	Sto struct{} `json:"sto,omitempty"`
 }
 
 var optionalsExpected = `{
  "sr": "",
  "omitempty": 0,
  "slr": null,
- "mr": {}
+ "mr": {},
+ "fr": 0,
+ "br": false,
+ "ur": 0,
+ "str": {},
+ "sto": {}
 }`
 
 func TestOmitEmpty(t *testing.T) {
@@ -76,7 +93,7 @@ func TestStringTag(t *testing.T) {
 
 	// Verify that it round-trips.
 	var s2 StringTag
-	err = NewDecoder(bytes.NewBuffer(got)).Decode(&s2)
+	err = NewDecoder(bytes.NewReader(got)).Decode(&s2)
 	if err != nil {
 		t.Fatalf("Decode: %v", err)
 	}
@@ -425,3 +442,13 @@ func TestIssue6458(t *testing.T) {
 		t.Errorf("Marshal(x) = %#q; want %#q", b, want)
 	}
 }
+
+func TestHTMLEscape(t *testing.T) {
+	var b, want bytes.Buffer
+	m := `{"M":"<html>foo &` + "\xe2\x80\xa8 \xe2\x80\xa9" + `</html>"}`
+	want.Write([]byte(`{"M":"\u003chtml\u003efoo \u0026\u2028 \u2029\u003c/html\u003e"}`))
+	HTMLEscape(&b, []byte(m))
+	if !bytes.Equal(b.Bytes(), want.Bytes()) {
+		t.Errorf("HTMLEscape(&b, []byte(m)) = %s; want %s", b.Bytes(), want.Bytes())
+	}
+}
diff --git a/src/pkg/encoding/json/example_test.go b/src/pkg/encoding/json/example_test.go
index ea0bc14..ca4e5ae 100644
--- a/src/pkg/encoding/json/example_test.go
+++ b/src/pkg/encoding/json/example_test.go
@@ -5,6 +5,7 @@
 package json_test
 
 import (
+	"bytes"
 	"encoding/json"
 	"fmt"
 	"io"
@@ -127,3 +128,34 @@ func ExampleRawMessage() {
 	// YCbCr &{255 0 -10}
 	// RGB &{98 218 255}
 }
+
+func ExampleIndent() {
+	type Road struct {
+		Name   string
+		Number int
+	}
+	roads := []Road{
+		{"Diamond Fork", 29},
+		{"Sheep Creek", 51},
+	}
+
+	b, err := json.Marshal(roads)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	var out bytes.Buffer
+	json.Indent(&out, b, "=", "\t")
+	out.WriteTo(os.Stdout)
+	// Output:
+	// [
+	// =	{
+	// =		"Name": "Diamond Fork",
+	// =		"Number": 29
+	// =	},
+	// =	{
+	// =		"Name": "Sheep Creek",
+	// =		"Number": 51
+	// =	}
+	// =]
+}
diff --git a/src/pkg/encoding/json/fold.go b/src/pkg/encoding/json/fold.go
new file mode 100644
index 0000000..d6f77c9
--- /dev/null
+++ b/src/pkg/encoding/json/fold.go
@@ -0,0 +1,143 @@
+// 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 json
+
+import (
+	"bytes"
+	"unicode/utf8"
+)
+
+const (
+	caseMask     = ^byte(0x20) // Mask to ignore case in ASCII.
+	kelvin       = '\u212a'
+	smallLongEss = '\u017f'
+)
+
+// foldFunc returns one of four different case folding equivalence
+// functions, from most general (and slow) to fastest:
+//
+// 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8
+// 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S')
+// 3) asciiEqualFold, no special, but includes non-letters (including _)
+// 4) simpleLetterEqualFold, no specials, no non-letters.
+//
+// The letters S and K are special because they map to 3 runes, not just 2:
+//  * S maps to s and to U+017F 'ſ' Latin small letter long s
+//  * k maps to K and to U+212A 'K' Kelvin sign
+// See http://play.golang.org/p/tTxjOc0OGo
+//
+// The returned function is specialized for matching against s and
+// should only be given s. It's not curried for performance reasons.
+func foldFunc(s []byte) func(s, t []byte) bool {
+	nonLetter := false
+	special := false // special letter
+	for _, b := range s {
+		if b >= utf8.RuneSelf {
+			return bytes.EqualFold
+		}
+		upper := b & caseMask
+		if upper < 'A' || upper > 'Z' {
+			nonLetter = true
+		} else if upper == 'K' || upper == 'S' {
+			// See above for why these letters are special.
+			special = true
+		}
+	}
+	if special {
+		return equalFoldRight
+	}
+	if nonLetter {
+		return asciiEqualFold
+	}
+	return simpleLetterEqualFold
+}
+
+// equalFoldRight is a specialization of bytes.EqualFold when s is
+// known to be all ASCII (including punctuation), but contains an 's',
+// 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t.
+// See comments on foldFunc.
+func equalFoldRight(s, t []byte) bool {
+	for _, sb := range s {
+		if len(t) == 0 {
+			return false
+		}
+		tb := t[0]
+		if tb < utf8.RuneSelf {
+			if sb != tb {
+				sbUpper := sb & caseMask
+				if 'A' <= sbUpper && sbUpper <= 'Z' {
+					if sbUpper != tb&caseMask {
+						return false
+					}
+				} else {
+					return false
+				}
+			}
+			t = t[1:]
+			continue
+		}
+		// sb is ASCII and t is not. t must be either kelvin
+		// sign or long s; sb must be s, S, k, or K.
+		tr, size := utf8.DecodeRune(t)
+		switch sb {
+		case 's', 'S':
+			if tr != smallLongEss {
+				return false
+			}
+		case 'k', 'K':
+			if tr != kelvin {
+				return false
+			}
+		default:
+			return false
+		}
+		t = t[size:]
+
+	}
+	if len(t) > 0 {
+		return false
+	}
+	return true
+}
+
+// asciiEqualFold is a specialization of bytes.EqualFold for use when
+// s is all ASCII (but may contain non-letters) and contains no
+// special-folding letters.
+// See comments on foldFunc.
+func asciiEqualFold(s, t []byte) bool {
+	if len(s) != len(t) {
+		return false
+	}
+	for i, sb := range s {
+		tb := t[i]
+		if sb == tb {
+			continue
+		}
+		if ('a' <= sb && sb <= 'z') || ('A' <= sb && sb <= 'Z') {
+			if sb&caseMask != tb&caseMask {
+				return false
+			}
+		} else {
+			return false
+		}
+	}
+	return true
+}
+
+// simpleLetterEqualFold is a specialization of bytes.EqualFold for
+// use when s is all ASCII letters (no underscores, etc) and also
+// doesn't contain 'k', 'K', 's', or 'S'.
+// See comments on foldFunc.
+func simpleLetterEqualFold(s, t []byte) bool {
+	if len(s) != len(t) {
+		return false
+	}
+	for i, b := range s {
+		if b&caseMask != t[i]&caseMask {
+			return false
+		}
+	}
+	return true
+}
diff --git a/src/pkg/encoding/json/fold_test.go b/src/pkg/encoding/json/fold_test.go
new file mode 100644
index 0000000..9fb9464
--- /dev/null
+++ b/src/pkg/encoding/json/fold_test.go
@@ -0,0 +1,116 @@
+// 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 json
+
+import (
+	"bytes"
+	"strings"
+	"testing"
+	"unicode/utf8"
+)
+
+var foldTests = []struct {
+	fn   func(s, t []byte) bool
+	s, t string
+	want bool
+}{
+	{equalFoldRight, "", "", true},
+	{equalFoldRight, "a", "a", true},
+	{equalFoldRight, "", "a", false},
+	{equalFoldRight, "a", "", false},
+	{equalFoldRight, "a", "A", true},
+	{equalFoldRight, "AB", "ab", true},
+	{equalFoldRight, "AB", "ac", false},
+	{equalFoldRight, "sbkKc", "ſbKKc", true},
+	{equalFoldRight, "SbKkc", "ſbKKc", true},
+	{equalFoldRight, "SbKkc", "ſbKK", false},
+	{equalFoldRight, "e", "é", false},
+	{equalFoldRight, "s", "S", true},
+
+	{simpleLetterEqualFold, "", "", true},
+	{simpleLetterEqualFold, "abc", "abc", true},
+	{simpleLetterEqualFold, "abc", "ABC", true},
+	{simpleLetterEqualFold, "abc", "ABCD", false},
+	{simpleLetterEqualFold, "abc", "xxx", false},
+
+	{asciiEqualFold, "a_B", "A_b", true},
+	{asciiEqualFold, "aa@", "aa`", false}, // verify 0x40 and 0x60 aren't case-equivalent
+}
+
+func TestFold(t *testing.T) {
+	for i, tt := range foldTests {
+		if got := tt.fn([]byte(tt.s), []byte(tt.t)); got != tt.want {
+			t.Errorf("%d. %q, %q = %v; want %v", i, tt.s, tt.t, got, tt.want)
+		}
+		truth := strings.EqualFold(tt.s, tt.t)
+		if truth != tt.want {
+			t.Errorf("strings.EqualFold doesn't agree with case %d", i)
+		}
+	}
+}
+
+func TestFoldAgainstUnicode(t *testing.T) {
+	const bufSize = 5
+	buf1 := make([]byte, 0, bufSize)
+	buf2 := make([]byte, 0, bufSize)
+	var runes []rune
+	for i := 0x20; i <= 0x7f; i++ {
+		runes = append(runes, rune(i))
+	}
+	runes = append(runes, kelvin, smallLongEss)
+
+	funcs := []struct {
+		name   string
+		fold   func(s, t []byte) bool
+		letter bool // must be ASCII letter
+		simple bool // must be simple ASCII letter (not 'S' or 'K')
+	}{
+		{
+			name: "equalFoldRight",
+			fold: equalFoldRight,
+		},
+		{
+			name:   "asciiEqualFold",
+			fold:   asciiEqualFold,
+			simple: true,
+		},
+		{
+			name:   "simpleLetterEqualFold",
+			fold:   simpleLetterEqualFold,
+			simple: true,
+			letter: true,
+		},
+	}
+
+	for _, ff := range funcs {
+		for _, r := range runes {
+			if r >= utf8.RuneSelf {
+				continue
+			}
+			if ff.letter && !isASCIILetter(byte(r)) {
+				continue
+			}
+			if ff.simple && (r == 's' || r == 'S' || r == 'k' || r == 'K') {
+				continue
+			}
+			for _, r2 := range runes {
+				buf1 := append(buf1[:0], 'x')
+				buf2 := append(buf2[:0], 'x')
+				buf1 = buf1[:1+utf8.EncodeRune(buf1[1:bufSize], r)]
+				buf2 = buf2[:1+utf8.EncodeRune(buf2[1:bufSize], r2)]
+				buf1 = append(buf1, 'x')
+				buf2 = append(buf2, 'x')
+				want := bytes.EqualFold(buf1, buf2)
+				if got := ff.fold(buf1, buf2); got != want {
+					t.Errorf("%s(%q, %q) = %v; want %v", ff.name, buf1, buf2, got, want)
+				}
+			}
+		}
+	}
+}
+
+func isASCIILetter(b byte) bool {
+	return ('A' <= b && b <= 'Z') || ('a' <= b && b <= 'z')
+}
diff --git a/src/pkg/encoding/json/indent.go b/src/pkg/encoding/json/indent.go
index 11ef709..e1bacaf 100644
--- a/src/pkg/encoding/json/indent.go
+++ b/src/pkg/encoding/json/indent.go
@@ -69,8 +69,9 @@ func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
 // Each element in a JSON object or array begins on a new,
 // indented line beginning with prefix followed by one or more
 // copies of indent according to the indentation nesting.
-// The data appended to dst has no trailing newline, to make it easier
-// to embed inside other formatted JSON data.
+// The data appended to dst does not begin with the prefix nor
+// any indentation, and has no trailing newline, to make it
+// easier to embed inside other formatted JSON data.
 func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
 	origLen := dst.Len()
 	var scan scanner
diff --git a/src/pkg/encoding/json/scanner_test.go b/src/pkg/encoding/json/scanner_test.go
index 90e45ff..7880342 100644
--- a/src/pkg/encoding/json/scanner_test.go
+++ b/src/pkg/encoding/json/scanner_test.go
@@ -239,23 +239,16 @@ func trim(b []byte) []byte {
 
 var jsonBig []byte
 
-const (
-	big   = 10000
-	small = 100
-)
-
 func initBig() {
-	n := big
+	n := 10000
 	if testing.Short() {
-		n = small
+		n = 100
 	}
-	if len(jsonBig) != n {
-		b, err := Marshal(genValue(n))
-		if err != nil {
-			panic(err)
-		}
-		jsonBig = b
+	b, err := Marshal(genValue(n))
+	if err != nil {
+		panic(err)
 	}
+	jsonBig = b
 }
 
 func genValue(n int) interface{} {
@@ -296,6 +289,9 @@ func genArray(n int) []interface{} {
 	if f > n {
 		f = n
 	}
+	if f < 1 {
+		f = 1
+	}
 	x := make([]interface{}, f)
 	for i := range x {
 		x[i] = genValue(((i+1)*n)/f - (i*n)/f)
diff --git a/src/pkg/encoding/json/stream.go b/src/pkg/encoding/json/stream.go
index 1928aba..1cb289f 100644
--- a/src/pkg/encoding/json/stream.go
+++ b/src/pkg/encoding/json/stream.go
@@ -148,7 +148,8 @@ func NewEncoder(w io.Writer) *Encoder {
 	return &Encoder{w: w}
 }
 
-// Encode writes the JSON encoding of v to the stream.
+// Encode writes the JSON encoding of v to the stream,
+// followed by a newline character.
 //
 // See the documentation for Marshal for details about the
 // conversion of Go values to JSON.
@@ -173,7 +174,7 @@ func (enc *Encoder) Encode(v interface{}) error {
 	if _, err = enc.w.Write(e.Bytes()); err != nil {
 		enc.err = err
 	}
-	putEncodeState(e)
+	encodeStatePool.Put(e)
 	return err
 }
 
diff --git a/src/pkg/encoding/xml/marshal.go b/src/pkg/encoding/xml/marshal.go
index d9522e0..8c63420 100644
--- a/src/pkg/encoding/xml/marshal.go
+++ b/src/pkg/encoding/xml/marshal.go
@@ -184,10 +184,12 @@ var (
 // EncodeToken does not call Flush, because usually it is part of a larger operation
 // such as Encode or EncodeElement (or a custom Marshaler's MarshalXML invoked
 // during those), and those will call Flush when finished.
-//
 // Callers that create an Encoder and then invoke EncodeToken directly, without
 // using Encode or EncodeElement, need to call Flush when finished to ensure
 // that the XML is written to the underlying writer.
+//
+// EncodeToken allows writing a ProcInst with Target set to "xml" only as the first token
+// in the stream.
 func (enc *Encoder) EncodeToken(t Token) error {
 	p := &enc.p
 	switch t := t.(type) {
@@ -210,7 +212,12 @@ func (enc *Encoder) EncodeToken(t Token) error {
 		p.WriteString("-->")
 		return p.cachedWriteError()
 	case ProcInst:
-		if t.Target == "xml" || !isNameString(t.Target) {
+		// First token to be encoded which is also a ProcInst with target of xml
+		// is the xml declaration.  The only ProcInst where target of xml is allowed.
+		if t.Target == "xml" && p.Buffered() != 0 {
+			return fmt.Errorf("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded")
+		}
+		if !isNameString(t.Target) {
 			return fmt.Errorf("xml: EncodeToken of ProcInst with invalid Target")
 		}
 		if bytes.Contains(t.Inst, endProcInst) {
diff --git a/src/pkg/encoding/xml/marshal_test.go b/src/pkg/encoding/xml/marshal_test.go
index d34118a..14f73a7 100644
--- a/src/pkg/encoding/xml/marshal_test.go
+++ b/src/pkg/encoding/xml/marshal_test.go
@@ -314,6 +314,31 @@ type MarshalerStruct struct {
 	Foo MyMarshalerAttrTest `xml:",attr"`
 }
 
+type InnerStruct struct {
+	XMLName Name `xml:"testns outer"`
+}
+
+type OuterStruct struct {
+	InnerStruct
+	IntAttr int `xml:"int,attr"`
+}
+
+type OuterNamedStruct struct {
+	InnerStruct
+	XMLName Name `xml:"outerns test"`
+	IntAttr int  `xml:"int,attr"`
+}
+
+type OuterNamedOrderedStruct struct {
+	XMLName Name `xml:"outerns test"`
+	InnerStruct
+	IntAttr int `xml:"int,attr"`
+}
+
+type OuterOuterStruct struct {
+	OuterStruct
+}
+
 func ifaceptr(x interface{}) interface{} {
 	return &x
 }
@@ -883,6 +908,22 @@ var marshalTests = []struct {
 		ExpectXML: `<MarshalerStruct Foo="hello world"></MarshalerStruct>`,
 		Value:     &MarshalerStruct{},
 	},
+	{
+		ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
+		Value:     &OuterStruct{IntAttr: 10},
+	},
+	{
+		ExpectXML: `<test xmlns="outerns" int="10"></test>`,
+		Value:     &OuterNamedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
+	},
+	{
+		ExpectXML: `<test xmlns="outerns" int="10"></test>`,
+		Value:     &OuterNamedOrderedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
+	},
+	{
+		ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
+		Value:     &OuterOuterStruct{OuterStruct{IntAttr: 10}},
+	},
 }
 
 func TestMarshal(t *testing.T) {
@@ -1149,3 +1190,77 @@ func TestStructPointerMarshal(t *testing.T) {
 		t.Fatal(err)
 	}
 }
+
+var encodeTokenTests = []struct {
+	tok  Token
+	want string
+	ok   bool
+}{
+	{StartElement{Name{"space", "local"}, nil}, "<local xmlns=\"space\">", true},
+	{StartElement{Name{"space", ""}, nil}, "", false},
+	{EndElement{Name{"space", ""}}, "", false},
+	{CharData("foo"), "foo", true},
+	{Comment("foo"), "<!--foo-->", true},
+	{Comment("foo-->"), "", false},
+	{ProcInst{"Target", []byte("Instruction")}, "<?Target Instruction?>", true},
+	{ProcInst{"", []byte("Instruction")}, "", false},
+	{ProcInst{"Target", []byte("Instruction?>")}, "", false},
+	{Directive("foo"), "<!foo>", true},
+	{Directive("foo>"), "", false},
+}
+
+func TestEncodeToken(t *testing.T) {
+	for _, tt := range encodeTokenTests {
+		var buf bytes.Buffer
+		enc := NewEncoder(&buf)
+		err := enc.EncodeToken(tt.tok)
+		switch {
+		case !tt.ok && err == nil:
+			t.Errorf("enc.EncodeToken(%#v): expected error; got none", tt.tok)
+		case tt.ok && err != nil:
+			t.Fatalf("enc.EncodeToken: %v", err)
+		case !tt.ok && err != nil:
+			// expected error, got one
+		}
+		if err := enc.Flush(); err != nil {
+			t.Fatalf("enc.EncodeToken: %v", err)
+		}
+		if got := buf.String(); got != tt.want {
+			t.Errorf("enc.EncodeToken = %s; want: %s", got, tt.want)
+		}
+	}
+}
+
+func TestProcInstEncodeToken(t *testing.T) {
+	var buf bytes.Buffer
+	enc := NewEncoder(&buf)
+
+	if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err != nil {
+		t.Fatalf("enc.EncodeToken: expected to be able to encode xml target ProcInst as first token, %s", err)
+	}
+
+	if err := enc.EncodeToken(ProcInst{"Target", []byte("Instruction")}); err != nil {
+		t.Fatalf("enc.EncodeToken: expected to be able to add non-xml target ProcInst")
+	}
+
+	if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err == nil {
+		t.Fatalf("enc.EncodeToken: expected to not be allowed to encode xml target ProcInst when not first token")
+	}
+}
+
+func TestDecodeEncode(t *testing.T) {
+	var in, out bytes.Buffer
+	in.WriteString(`<?xml version="1.0" encoding="UTF-8"?>
+<?Target Instruction?>
+<root>
+</root>	
+`)
+	dec := NewDecoder(&in)
+	enc := NewEncoder(&out)
+	for tok, err := dec.Token(); err == nil; tok, err = dec.Token() {
+		err = enc.EncodeToken(tok)
+		if err != nil {
+			t.Fatalf("enc.EncodeToken: Unable to encode token (%#v), %v", tok, err)
+		}
+	}
+}
diff --git a/src/pkg/encoding/xml/read.go b/src/pkg/encoding/xml/read.go
index 8890508..75b9f2b 100644
--- a/src/pkg/encoding/xml/read.go
+++ b/src/pkg/encoding/xml/read.go
@@ -112,7 +112,7 @@ import (
 // to a freshly allocated value and then mapping the element to that value.
 //
 func Unmarshal(data []byte, v interface{}) error {
-	return NewDecoder(bytes.NewBuffer(data)).Decode(v)
+	return NewDecoder(bytes.NewReader(data)).Decode(v)
 }
 
 // Decode works like xml.Unmarshal, except it reads the decoder
@@ -284,6 +284,15 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
 		}
 	}
 
+	// Load value from interface, but only if the result will be
+	// usefully addressable.
+	if val.Kind() == reflect.Interface && !val.IsNil() {
+		e := val.Elem()
+		if e.Kind() == reflect.Ptr && !e.IsNil() {
+			val = e
+		}
+	}
+
 	if val.Kind() == reflect.Ptr {
 		if val.IsNil() {
 			val.Set(reflect.New(val.Type().Elem()))
diff --git a/src/pkg/encoding/xml/read_test.go b/src/pkg/encoding/xml/read_test.go
index 1404c90..01f55d0 100644
--- a/src/pkg/encoding/xml/read_test.go
+++ b/src/pkg/encoding/xml/read_test.go
@@ -685,3 +685,30 @@ func TestUnmarshaler(t *testing.T) {
 		t.Errorf("m=%#+v\n", m)
 	}
 }
+
+type Pea struct {
+	Cotelydon string
+}
+
+type Pod struct {
+	Pea interface{} `xml:"Pea"`
+}
+
+// https://code.google.com/p/go/issues/detail?id=6836
+func TestUnmarshalIntoInterface(t *testing.T) {
+	pod := new(Pod)
+	pod.Pea = new(Pea)
+	xml := `<Pod><Pea><Cotelydon>Green stuff</Cotelydon></Pea></Pod>`
+	err := Unmarshal([]byte(xml), pod)
+	if err != nil {
+		t.Fatalf("failed to unmarshal %q: %v", xml, err)
+	}
+	pea, ok := pod.Pea.(*Pea)
+	if !ok {
+		t.Fatalf("unmarshalled into wrong type: have %T want *Pea", pod.Pea)
+	}
+	have, want := pea.Cotelydon, "Green stuff"
+	if have != want {
+		t.Errorf("failed to unmarshal into interface, have %q want %q", have, want)
+	}
+}
diff --git a/src/pkg/encoding/xml/typeinfo.go b/src/pkg/encoding/xml/typeinfo.go
index 83e6540..22248d2 100644
--- a/src/pkg/encoding/xml/typeinfo.go
+++ b/src/pkg/encoding/xml/typeinfo.go
@@ -75,6 +75,9 @@ func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
 					if err != nil {
 						return nil, err
 					}
+					if tinfo.xmlname == nil {
+						tinfo.xmlname = inner.xmlname
+					}
 					for _, finfo := range inner.fields {
 						finfo.idx = append([]int{i}, finfo.idx...)
 						if err := addFieldInfo(typ, tinfo, &finfo); err != nil {
diff --git a/src/pkg/encoding/xml/xml.go b/src/pkg/encoding/xml/xml.go
index 5b9d670..b473cb8 100644
--- a/src/pkg/encoding/xml/xml.go
+++ b/src/pkg/encoding/xml/xml.go
@@ -200,6 +200,8 @@ type Decoder struct {
 }
 
 // NewDecoder creates a new XML parser reading from r.
+// If r does not implement io.ByteReader, NewDecoder will
+// do its own buffering.
 func NewDecoder(r io.Reader) *Decoder {
 	d := &Decoder{
 		ns:       make(map[string]string),
diff --git a/src/pkg/expvar/expvar.go b/src/pkg/expvar/expvar.go
index b065995..9b6dab4 100644
--- a/src/pkg/expvar/expvar.go
+++ b/src/pkg/expvar/expvar.go
@@ -29,6 +29,7 @@ import (
 	"net/http"
 	"os"
 	"runtime"
+	"sort"
 	"strconv"
 	"sync"
 )
@@ -40,8 +41,8 @@ type Var interface {
 
 // Int is a 64-bit integer variable that satisfies the Var interface.
 type Int struct {
-	i  int64
 	mu sync.RWMutex
+	i  int64
 }
 
 func (v *Int) String() string {
@@ -64,8 +65,8 @@ func (v *Int) Set(value int64) {
 
 // Float is a 64-bit float variable that satisfies the Var interface.
 type Float struct {
-	f  float64
 	mu sync.RWMutex
+	f  float64
 }
 
 func (v *Float) String() string {
@@ -90,8 +91,9 @@ func (v *Float) Set(value float64) {
 
 // Map is a string-to-Var map variable that satisfies the Var interface.
 type Map struct {
-	m  map[string]Var
-	mu sync.RWMutex
+	mu   sync.RWMutex
+	m    map[string]Var
+	keys []string // sorted
 }
 
 // KeyValue represents a single entry in a Map.
@@ -106,13 +108,13 @@ func (v *Map) String() string {
 	var b bytes.Buffer
 	fmt.Fprintf(&b, "{")
 	first := true
-	for key, val := range v.m {
+	v.doLocked(func(kv KeyValue) {
 		if !first {
 			fmt.Fprintf(&b, ", ")
 		}
-		fmt.Fprintf(&b, "\"%s\": %v", key, val)
+		fmt.Fprintf(&b, "%q: %v", kv.Key, kv.Value)
 		first = false
-	}
+	})
 	fmt.Fprintf(&b, "}")
 	return b.String()
 }
@@ -122,6 +124,20 @@ func (v *Map) Init() *Map {
 	return v
 }
 
+// updateKeys updates the sorted list of keys in v.keys.
+// must be called with v.mu held.
+func (v *Map) updateKeys() {
+	if len(v.m) == len(v.keys) {
+		// No new key.
+		return
+	}
+	v.keys = v.keys[:0]
+	for k := range v.m {
+		v.keys = append(v.keys, k)
+	}
+	sort.Strings(v.keys)
+}
+
 func (v *Map) Get(key string) Var {
 	v.mu.RLock()
 	defer v.mu.RUnlock()
@@ -132,6 +148,7 @@ func (v *Map) Set(key string, av Var) {
 	v.mu.Lock()
 	defer v.mu.Unlock()
 	v.m[key] = av
+	v.updateKeys()
 }
 
 func (v *Map) Add(key string, delta int64) {
@@ -141,9 +158,11 @@ func (v *Map) Add(key string, delta int64) {
 	if !ok {
 		// check again under the write lock
 		v.mu.Lock()
-		if _, ok = v.m[key]; !ok {
+		av, ok = v.m[key]
+		if !ok {
 			av = new(Int)
 			v.m[key] = av
+			v.updateKeys()
 		}
 		v.mu.Unlock()
 	}
@@ -162,9 +181,11 @@ func (v *Map) AddFloat(key string, delta float64) {
 	if !ok {
 		// check again under the write lock
 		v.mu.Lock()
-		if _, ok = v.m[key]; !ok {
+		av, ok = v.m[key]
+		if !ok {
 			av = new(Float)
 			v.m[key] = av
+			v.updateKeys()
 		}
 		v.mu.Unlock()
 	}
@@ -181,15 +202,21 @@ func (v *Map) AddFloat(key string, delta float64) {
 func (v *Map) Do(f func(KeyValue)) {
 	v.mu.RLock()
 	defer v.mu.RUnlock()
-	for k, v := range v.m {
-		f(KeyValue{k, v})
+	v.doLocked(f)
+}
+
+// doLocked calls f for each entry in the map.
+// v.mu must be held for reads.
+func (v *Map) doLocked(f func(KeyValue)) {
+	for _, k := range v.keys {
+		f(KeyValue{k, v.m[k]})
 	}
 }
 
 // String is a string variable, and satisfies the Var interface.
 type String struct {
-	s  string
 	mu sync.RWMutex
+	s  string
 }
 
 func (v *String) String() string {
@@ -215,8 +242,9 @@ func (f Func) String() string {
 
 // All published variables.
 var (
-	mutex sync.RWMutex
-	vars  map[string]Var = make(map[string]Var)
+	mutex   sync.RWMutex
+	vars    = make(map[string]Var)
+	varKeys []string // sorted
 )
 
 // Publish declares a named exported variable. This should be called from a
@@ -229,6 +257,8 @@ func Publish(name string, v Var) {
 		log.Panicln("Reuse of exported var name:", name)
 	}
 	vars[name] = v
+	varKeys = append(varKeys, name)
+	sort.Strings(varKeys)
 }
 
 // Get retrieves a named exported variable.
@@ -270,8 +300,8 @@ func NewString(name string) *String {
 func Do(f func(KeyValue)) {
 	mutex.RLock()
 	defer mutex.RUnlock()
-	for k, v := range vars {
-		f(KeyValue{k, v})
+	for _, k := range varKeys {
+		f(KeyValue{k, vars[k]})
 	}
 }
 
diff --git a/src/pkg/expvar/expvar_test.go b/src/pkg/expvar/expvar_test.go
index 572c62b..765e3b7 100644
--- a/src/pkg/expvar/expvar_test.go
+++ b/src/pkg/expvar/expvar_test.go
@@ -5,7 +5,10 @@
 package expvar
 
 import (
+	"bytes"
 	"encoding/json"
+	"net/http/httptest"
+	"strconv"
 	"testing"
 )
 
@@ -15,6 +18,7 @@ func RemoveAll() {
 	mutex.Lock()
 	defer mutex.Unlock()
 	vars = make(map[string]Var)
+	varKeys = nil
 }
 
 func TestInt(t *testing.T) {
@@ -93,15 +97,15 @@ func TestMapCounter(t *testing.T) {
 	colors.Add("red", 1)
 	colors.Add("red", 2)
 	colors.Add("blue", 4)
-	colors.AddFloat("green", 4.125)
+	colors.AddFloat(`green "midori"`, 4.125)
 	if x := colors.m["red"].(*Int).i; x != 3 {
 		t.Errorf("colors.m[\"red\"] = %v, want 3", x)
 	}
 	if x := colors.m["blue"].(*Int).i; x != 4 {
 		t.Errorf("colors.m[\"blue\"] = %v, want 4", x)
 	}
-	if x := colors.m["green"].(*Float).f; x != 4.125 {
-		t.Errorf("colors.m[\"green\"] = %v, want 3.14", x)
+	if x := colors.m[`green "midori"`].(*Float).f; x != 4.125 {
+		t.Errorf("colors.m[`green \"midori\"] = %v, want 3.14", x)
 	}
 
 	// colors.String() should be '{"red":3, "blue":4}',
@@ -139,3 +143,25 @@ func TestFunc(t *testing.T) {
 		t.Errorf(`f.String() = %q, want %q`, s, exp)
 	}
 }
+
+func TestHandler(t *testing.T) {
+	RemoveAll()
+	m := NewMap("map1")
+	m.Add("a", 1)
+	m.Add("z", 2)
+	m2 := NewMap("map2")
+	for i := 0; i < 9; i++ {
+		m2.Add(strconv.Itoa(i), int64(i))
+	}
+	rr := httptest.NewRecorder()
+	rr.Body = new(bytes.Buffer)
+	expvarHandler(rr, nil)
+	want := `{
+"map1": {"a": 1, "z": 2},
+"map2": {"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8}
+}
+`
+	if got := rr.Body.String(); got != want {
+		t.Errorf("HTTP handler wrote:\n%s\nWant:\n%s", got, want)
+	}
+}
diff --git a/src/pkg/flag/flag.go b/src/pkg/flag/flag.go
index e7c863e..cd2a165 100644
--- a/src/pkg/flag/flag.go
+++ b/src/pkg/flag/flag.go
@@ -50,7 +50,8 @@
 	("-" is a non-flag argument) or after the terminator "--".
 
 	Integer flags accept 1234, 0664, 0x1234 and may be negative.
-	Boolean flags may be 1, 0, t, f, true, false, TRUE, FALSE, True, False.
+	Boolean flags may be:
+		1, 0, t, f, T, F, true, false, TRUE, FALSE, True, False
 	Duration flags accept any input valid for time.ParseDuration.
 
 	The default set of command-line flags is controlled by
@@ -269,7 +270,6 @@ type FlagSet struct {
 	actual        map[string]*Flag
 	formal        map[string]*Flag
 	args          []string // arguments after flags
-	exitOnError   bool     // does the program exit if there's an error?
 	errorHandling ErrorHandling
 	output        io.Writer // nil means stderr; use out() accessor
 }
@@ -755,7 +755,7 @@ func (f *FlagSet) parseOne() (bool, error) {
 	if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg
 		if has_value {
 			if err := fv.Set(value); err != nil {
-				return false, f.failf("invalid boolean value %q for  -%s: %v", value, name, err)
+				return false, f.failf("invalid boolean value %q for -%s: %v", value, name, err)
 			}
 		} else {
 			fv.Set("true")
diff --git a/src/pkg/fmt/doc.go b/src/pkg/fmt/doc.go
index 095fd03..02642d6 100644
--- a/src/pkg/fmt/doc.go
+++ b/src/pkg/fmt/doc.go
@@ -37,6 +37,7 @@
 		%e	scientific notation, e.g. -1234.456e+78
 		%E	scientific notation, e.g. -1234.456E+78
 		%f	decimal point but no exponent, e.g. 123.456
+		%F	synonym for %f
 		%g	whichever of %e or %f produces more compact output
 		%G	whichever of %E or %f produces more compact output
 	String and slice of bytes:
@@ -50,23 +51,39 @@
 	There is no 'u' flag.  Integers are printed unsigned if they have unsigned type.
 	Similarly, there is no need to specify the size of the operand (int8, int64).
 
-	The width and precision control formatting and are in units of Unicode
-	code points.  (This differs from C's printf where the units are numbers
+	Width is specified by an optional decimal number immediately following the verb.
+	If absent, the width is whatever is necessary to represent the value.
+	Precision is specified after the (optional) width by a period followed by a
+	decimal number. If no period is present, a default precision is used.
+	A period with no following number specifies a precision of zero.
+	Examples:
+		%f:    default width, default precision
+		%9f    width 9, default precision
+		%.2f   default width, precision 2
+		%9.2f  width 9, precision 2
+		%9.f   width 9, precision 0
+
+	Width and precision are measured in units of Unicode code points.
+	(This differs from C's printf where the units are numbers
 	of bytes.) Either or both of the flags may be replaced with the
 	character '*', causing their values to be obtained from the next
 	operand, which must be of type int.
 
-	For numeric values, width sets the minimum width of the field and
+	For most values, width is the minimum number of characters to output,
+	padding the formatted form with spaces if necessary.
+	For strings, precision is the maximum number of characters to output,
+	truncating if necessary.
+
+	For floating-point values, width sets the minimum width of the field and
 	precision sets the number of places after the decimal, if appropriate,
 	except that for %g/%G it sets the total number of digits. For example,
 	given 123.45 the format %6.2f prints 123.45 while %.4g prints 123.5.
 	The default precision for %e and %f is 6; for %g it is the smallest
 	number of digits necessary to identify the value uniquely.
 
-	For most values, width is the minimum number of characters to output,
-	padding the formatted form with spaces if necessary.
-	For strings, precision is the maximum number of characters to output,
-	truncating if necessary.
+	For complex numbers, the width and precision apply to the two
+	components independently and the result is parenthesized, so %f applied
+	to 1.2+3.4i produces (1.200000+3.400000i).
 
 	Other flags:
 		+	always print a sign for numeric values;
@@ -98,20 +115,33 @@
 		fmt.Printf("%v\n", i)
 	will print 23.
 
-	If an operand implements interface Formatter, that interface
-	can be used for fine control of formatting.
+	Except when printed using the verbs %T and %p, special
+	formatting considerations apply for operands that implement
+	certain interfaces. In order of application:
+
+	1. If an operand implements the Formatter interface, it will
+	be invoked. Formatter provides fine control of formatting.
+
+	2. If the %v verb is used with the # flag (%#v) and the operand
+	implements the GoStringer interface, that will be invoked.
 
 	If the format (which is implicitly %v for Println etc.) is valid
-	for a string (%s %q %v %x %X), the following two rules also apply:
+	for a string (%s %q %v %x %X), the following two rules apply:
 
-	1. If an operand implements the error interface, the Error method
-	will be used to convert the object to a string, which will then
+	3. If an operand implements the error interface, the Error method
+	will be invoked to convert the object to a string, which will then
 	be formatted as required by the verb (if any).
 
-	2. If an operand implements method String() string, that method
-	will be used to convert the object to a string, which will then
+	4. If an operand implements method String() string, that method
+	will be invoked to convert the object to a string, which will then
 	be formatted as required by the verb (if any).
 
+	For compound operands such as slices and structs, the format
+	applies to the elements of each operand, recursively, not to the
+	operand as a whole. Thus %q will quote each element of a slice
+	of strings, and %6.2f will control formatting for each element
+	of a floating-point array.
+
 	To avoid recursion in cases such as
 		type X string
 		func (x X) String() string { return Sprintf("<%s>", x) }
diff --git a/src/pkg/fmt/fmt_test.go b/src/pkg/fmt/fmt_test.go
index bf50675..7e3d06b 100644
--- a/src/pkg/fmt/fmt_test.go
+++ b/src/pkg/fmt/fmt_test.go
@@ -220,6 +220,12 @@ var fmtTests = []struct {
 	{"%+.3e", 0.0, "+0.000e+00"},
 	{"%+.3e", 1.0, "+1.000e+00"},
 	{"%+.3f", -1.0, "-1.000"},
+	{"%+.3F", -1.0, "-1.000"},
+	{"%+.3F", float32(-1.0), "-1.000"},
+	{"%+07.2f", 1.0, "+001.00"},
+	{"%+07.2f", -1.0, "-001.00"},
+	{"%+10.2f", +1.0, "     +1.00"},
+	{"%+10.2f", -1.0, "     -1.00"},
 	{"% .3E", -1.0, "-1.000E+00"},
 	{"% .3e", 1.0, " 1.000e+00"},
 	{"%+.3g", 0.0, "+0"},
@@ -239,6 +245,8 @@ var fmtTests = []struct {
 	{"%+.3g", 1 + 2i, "(+1+2i)"},
 	{"%.3e", 0i, "(0.000e+00+0.000e+00i)"},
 	{"%.3f", 0i, "(0.000+0.000i)"},
+	{"%.3F", 0i, "(0.000+0.000i)"},
+	{"%.3F", complex64(0i), "(0.000+0.000i)"},
 	{"%.3g", 0i, "(0+0i)"},
 	{"%.3e", 1 + 2i, "(1.000e+00+2.000e+00i)"},
 	{"%.3f", 1 + 2i, "(1.000+2.000i)"},
@@ -397,6 +405,8 @@ var fmtTests = []struct {
 	{"%#v", "foo", `"foo"`},
 	{"%#v", barray, `[5]fmt_test.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`},
 	{"%#v", bslice, `[]fmt_test.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`},
+	{"%#v", []byte(nil), "[]byte(nil)"},
+	{"%#v", []int32(nil), "[]int32(nil)"},
 
 	// slices with other formats
 	{"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`},
@@ -495,18 +505,85 @@ var fmtTests = []struct {
 	{"%v", map[float64]int{math.NaN(): 1, math.NaN(): 2}, "map[NaN:<nil> NaN:<nil>]"},
 
 	// Used to crash because nByte didn't allow for a sign.
-	{"%b", int64(-1 << 63), "-1000000000000000000000000000000000000000000000000000000000000000"},
+	{"%b", int64(-1 << 63), zeroFill("-1", 63, "")},
 
 	// Used to panic.
-	{"%0100d", 1, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"},
-	{"%0100d", -1, "-000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"},
-	{"%0.100f", 1.0, "1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
-	{"%0.100f", -1.0, "-1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
+	{"%0100d", 1, zeroFill("", 100, "1")},
+	{"%0100d", -1, zeroFill("-", 99, "1")},
+	{"%0.100f", 1.0, zeroFill("1.", 100, "")},
+	{"%0.100f", -1.0, zeroFill("-1.", 100, "")},
+
+	// Comparison of padding rules with C printf.
+	/*
+		C program:
+		#include <stdio.h>
+
+		char *format[] = {
+			"[%.2f]",
+			"[% .2f]",
+			"[%+.2f]",
+			"[%7.2f]",
+			"[% 7.2f]",
+			"[%+7.2f]",
+			"[%07.2f]",
+			"[% 07.2f]",
+			"[%+07.2f]",
+		};
+
+		int main(void) {
+			int i;
+			for(i = 0; i < 9; i++) {
+				printf("%s: ", format[i]);
+				printf(format[i], 1.0);
+				printf(" ");
+				printf(format[i], -1.0);
+				printf("\n");
+			}
+		}
 
-	// Zero padding floats used to put the minus sign in the middle.
-	{"%020f", -1.0, "-000000000001.000000"},
+		Output:
+			[%.2f]: [1.00] [-1.00]
+			[% .2f]: [ 1.00] [-1.00]
+			[%+.2f]: [+1.00] [-1.00]
+			[%7.2f]: [   1.00] [  -1.00]
+			[% 7.2f]: [   1.00] [  -1.00]
+			[%+7.2f]: [  +1.00] [  -1.00]
+			[%07.2f]: [0001.00] [-001.00]
+			[% 07.2f]: [ 001.00] [-001.00]
+			[%+07.2f]: [+001.00] [-001.00]
+	*/
+	{"%.2f", 1.0, "1.00"},
+	{"%.2f", -1.0, "-1.00"},
+	{"% .2f", 1.0, " 1.00"},
+	{"% .2f", -1.0, "-1.00"},
+	{"%+.2f", 1.0, "+1.00"},
+	{"%+.2f", -1.0, "-1.00"},
+	{"%7.2f", 1.0, "   1.00"},
+	{"%7.2f", -1.0, "  -1.00"},
+	{"% 7.2f", 1.0, "   1.00"},
+	{"% 7.2f", -1.0, "  -1.00"},
+	{"%+7.2f", 1.0, "  +1.00"},
+	{"%+7.2f", -1.0, "  -1.00"},
+	{"%07.2f", 1.0, "0001.00"},
+	{"%07.2f", -1.0, "-001.00"},
+	{"% 07.2f", 1.0, " 001.00"},
+	{"% 07.2f", -1.0, "-001.00"},
+	{"%+07.2f", 1.0, "+001.00"},
+	{"%+07.2f", -1.0, "-001.00"},
+
+	// Complex numbers: exhaustively tested in TestComplexFormatting.
+	{"%7.2f", 1 + 2i, "(   1.00  +2.00i)"},
+	{"%+07.2f", -1 - 2i, "(-001.00-002.00i)"},
+	// Zero padding does not apply to infinities.
+	{"%020f", math.Inf(-1), "                -Inf"},
+	{"%020f", math.Inf(+1), "                +Inf"},
+	{"% 020f", math.Inf(-1), "                -Inf"},
+	{"% 020f", math.Inf(+1), "                 Inf"},
+	{"%+020f", math.Inf(-1), "                -Inf"},
+	{"%+020f", math.Inf(+1), "                +Inf"},
 	{"%20f", -1.0, "           -1.000000"},
-	{"%0100f", -1.0, "-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.000000"},
+	// Make sure we can handle very large widths.
+	{"%0100f", -1.0, zeroFill("-", 99, "1.000000")},
 
 	// Complex fmt used to leave the plus flag set for future entries in the array
 	// causing +2+0i and +3+0i instead of 2+0i and 3+0i.
@@ -515,6 +592,43 @@ var fmtTests = []struct {
 
 	// Incomplete format specification caused crash.
 	{"%.", 3, "%!.(int=3)"},
+
+	// Used to panic with out-of-bounds for very large numeric representations.
+	// nByte is set to handle one bit per uint64 in %b format, with a negative number.
+	// See issue 6777.
+	{"%#064x", 1, zeroFill("0x", 64, "1")},
+	{"%#064x", -1, zeroFill("-0x", 63, "1")},
+	{"%#064b", 1, zeroFill("", 64, "1")},
+	{"%#064b", -1, zeroFill("-", 63, "1")},
+	{"%#064o", 1, zeroFill("", 64, "1")},
+	{"%#064o", -1, zeroFill("-", 63, "1")},
+	{"%#064d", 1, zeroFill("", 64, "1")},
+	{"%#064d", -1, zeroFill("-", 63, "1")},
+	// Test that we handle the crossover above the size of uint64
+	{"%#072x", 1, zeroFill("0x", 72, "1")},
+	{"%#072x", -1, zeroFill("-0x", 71, "1")},
+	{"%#072b", 1, zeroFill("", 72, "1")},
+	{"%#072b", -1, zeroFill("-", 71, "1")},
+	{"%#072o", 1, zeroFill("", 72, "1")},
+	{"%#072o", -1, zeroFill("-", 71, "1")},
+	{"%#072d", 1, zeroFill("", 72, "1")},
+	{"%#072d", -1, zeroFill("-", 71, "1")},
+
+	// Padding for complex numbers. Has been bad, then fixed, then bad again.
+	{"%+10.2f", +104.66 + 440.51i, "(   +104.66   +440.51i)"},
+	{"%+10.2f", -104.66 + 440.51i, "(   -104.66   +440.51i)"},
+	{"%+10.2f", +104.66 - 440.51i, "(   +104.66   -440.51i)"},
+	{"%+10.2f", -104.66 - 440.51i, "(   -104.66   -440.51i)"},
+	{"%+010.2f", +104.66 + 440.51i, "(+000104.66+000440.51i)"},
+	{"%+010.2f", -104.66 + 440.51i, "(-000104.66+000440.51i)"},
+	{"%+010.2f", +104.66 - 440.51i, "(+000104.66-000440.51i)"},
+	{"%+010.2f", -104.66 - 440.51i, "(-000104.66-000440.51i)"},
+}
+
+// zeroFill generates zero-filled strings of the specified width. The length
+// of the suffix (but not the prefix) is compensated for in the width calculation.
+func zeroFill(prefix string, width int, suffix string) string {
+	return prefix + strings.Repeat("0", width-len(suffix)) + suffix
 }
 
 func TestSprintf(t *testing.T) {
@@ -554,6 +668,50 @@ func TestSprintf(t *testing.T) {
 	}
 }
 
+// TestComplexFormatting checks that a complex always formats to the same
+// thing as if done by hand with two singleton prints.
+func TestComplexFormatting(t *testing.T) {
+	var yesNo = []bool{true, false}
+	var signs = []float64{1, 0, -1}
+	for _, plus := range yesNo {
+		for _, zero := range yesNo {
+			for _, space := range yesNo {
+				for _, char := range "fFeEgG" {
+					realFmt := "%"
+					if zero {
+						realFmt += "0"
+					}
+					if space {
+						realFmt += " "
+					}
+					if plus {
+						realFmt += "+"
+					}
+					realFmt += "10.2"
+					realFmt += string(char)
+					// Imaginary part always has a sign, so force + and ignore space.
+					imagFmt := "%"
+					if zero {
+						imagFmt += "0"
+					}
+					imagFmt += "+"
+					imagFmt += "10.2"
+					imagFmt += string(char)
+					for _, realSign := range signs {
+						for _, imagSign := range signs {
+							one := Sprintf(realFmt, complex(realSign, imagSign))
+							two := Sprintf("("+realFmt+imagFmt+"i)", realSign, imagSign)
+							if one != two {
+								t.Error(f, one, two)
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
 type SE []interface{} // slice of empty; notational compactness.
 
 var reorderTests = []struct {
@@ -604,47 +762,61 @@ func TestReorder(t *testing.T) {
 }
 
 func BenchmarkSprintfEmpty(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		Sprintf("")
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			Sprintf("")
+		}
+	})
 }
 
 func BenchmarkSprintfString(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		Sprintf("%s", "hello")
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			Sprintf("%s", "hello")
+		}
+	})
 }
 
 func BenchmarkSprintfInt(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		Sprintf("%d", 5)
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			Sprintf("%d", 5)
+		}
+	})
 }
 
 func BenchmarkSprintfIntInt(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		Sprintf("%d %d", 5, 6)
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			Sprintf("%d %d", 5, 6)
+		}
+	})
 }
 
 func BenchmarkSprintfPrefixedInt(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6)
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6)
+		}
+	})
 }
 
 func BenchmarkSprintfFloat(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		Sprintf("%g", 5.23184)
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			Sprintf("%g", 5.23184)
+		}
+	})
 }
 
 func BenchmarkManyArgs(b *testing.B) {
-	var buf bytes.Buffer
-	for i := 0; i < b.N; i++ {
-		buf.Reset()
-		Fprintf(&buf, "%2d/%2d/%2d %d:%d:%d %s %s\n", 3, 4, 5, 11, 12, 13, "hello", "world")
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		var buf bytes.Buffer
+		for pb.Next() {
+			buf.Reset()
+			Fprintf(&buf, "%2d/%2d/%2d %d:%d:%d %s %s\n", 3, 4, 5, 11, 12, 13, "hello", "world")
+		}
+	})
 }
 
 var mallocBuf bytes.Buffer
diff --git a/src/pkg/fmt/format.go b/src/pkg/fmt/format.go
index 2e2b071..a89c542 100644
--- a/src/pkg/fmt/format.go
+++ b/src/pkg/fmt/format.go
@@ -5,12 +5,15 @@
 package fmt
 
 import (
+	"math"
 	"strconv"
 	"unicode/utf8"
 )
 
 const (
-	nByte = 65 // %b of an int64, plus a sign.
+	// %b of an int64, plus a sign.
+	// Hex can add 0x and we handle it specially.
+	nByte = 65
 
 	ldigits = "0123456789abcdef"
 	udigits = "0123456789ABCDEF"
@@ -160,9 +163,16 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
 	}
 
 	var buf []byte = f.intbuf[0:]
-	if f.widPresent && f.wid > nByte {
-		// We're going to need a bigger boat.
-		buf = make([]byte, f.wid)
+	if f.widPresent {
+		width := f.wid
+		if base == 16 && f.sharp {
+			// Also adds "0x".
+			width += 2
+		}
+		if width > nByte {
+			// We're going to need a bigger boat.
+			buf = make([]byte, width)
+		}
 	}
 
 	negative := signedness == signed && a < 0
@@ -351,35 +361,48 @@ func doPrec(f *fmt, def int) int {
 
 // formatFloat formats a float64; it is an efficient equivalent to  f.pad(strconv.FormatFloat()...).
 func (f *fmt) formatFloat(v float64, verb byte, prec, n int) {
-	// We leave one byte at the beginning of f.intbuf for a sign if needed,
-	// and make it a space, which we might be able to use.
-	f.intbuf[0] = ' '
-	slice := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n)
-	// Add a plus sign or space to the floating-point string representation if missing and required.
-	// The formatted number starts at slice[1].
-	switch slice[1] {
-	case '-', '+':
-		// If we're zero padding, want the sign before the leading zeros.
-		// Achieve this by writing the sign out and padding the postive number.
-		if f.zero && f.widPresent && f.wid > len(slice) {
-			f.buf.WriteByte(slice[1])
-			f.wid--
-			f.pad(slice[2:])
-			return
+	// Format number, reserving space for leading + sign if needed.
+	num := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n)
+	if num[1] == '-' || num[1] == '+' {
+		num = num[1:]
+	} else {
+		num[0] = '+'
+	}
+	// Special handling for infinity, which doesn't look like a number so shouldn't be padded with zeros.
+	if math.IsInf(v, 0) {
+		if f.zero {
+			defer func() { f.zero = true }()
+			f.zero = false
 		}
-		// We're set; drop the leading space.
-		slice = slice[1:]
-	default:
-		// There's no sign, but we might need one.
-		if f.plus {
-			slice[0] = '+'
-		} else if f.space {
-			// space is already there
-		} else {
-			slice = slice[1:]
+	}
+	// num is now a signed version of the number.
+	// If we're zero padding, want the sign before the leading zeros.
+	// Achieve this by writing the sign out and then padding the unsigned number.
+	if f.zero && f.widPresent && f.wid > len(num) {
+		if f.space && v >= 0 {
+			f.buf.WriteByte(' ') // This is what C does: even with zero, f.space means space.
+			f.wid--
+		} else if f.plus || v < 0 {
+			f.buf.WriteByte(num[0])
+			f.wid--
 		}
+		f.pad(num[1:])
+		return
+	}
+	// f.space says to replace a leading + with a space.
+	if f.space && num[0] == '+' {
+		num[0] = ' '
+		f.pad(num)
+		return
 	}
-	f.pad(slice)
+	// Now we know the sign is attached directly to the number, if present at all.
+	// We want a sign if asked for, if it's negative, or if it's infinity (+Inf vs. -Inf).
+	if f.plus || num[0] == '-' || math.IsInf(v, 0) {
+		f.pad(num)
+		return
+	}
+	// No sign to show and the number is positive; just print the unsigned number.
+	f.pad(num[1:])
 }
 
 // fmt_e64 formats a float64 in the form -1.23e+12.
@@ -424,60 +447,46 @@ func (f *fmt) fmt_fb32(v float32) { f.formatFloat(float64(v), 'b', 0, 32) }
 
 // fmt_c64 formats a complex64 according to the verb.
 func (f *fmt) fmt_c64(v complex64, verb rune) {
-	f.buf.WriteByte('(')
-	r := real(v)
-	oldPlus := f.plus
-	for i := 0; ; i++ {
-		switch verb {
-		case 'b':
-			f.fmt_fb32(r)
-		case 'e':
-			f.fmt_e32(r)
-		case 'E':
-			f.fmt_E32(r)
-		case 'f':
-			f.fmt_f32(r)
-		case 'g':
-			f.fmt_g32(r)
-		case 'G':
-			f.fmt_G32(r)
-		}
-		if i != 0 {
-			break
-		}
-		f.plus = true
-		r = imag(v)
-	}
-	f.plus = oldPlus
-	f.buf.Write(irparenBytes)
+	f.fmt_complex(float64(real(v)), float64(imag(v)), 32, verb)
 }
 
 // fmt_c128 formats a complex128 according to the verb.
 func (f *fmt) fmt_c128(v complex128, verb rune) {
+	f.fmt_complex(real(v), imag(v), 64, verb)
+}
+
+// fmt_complex formats a complex number as (r+ji).
+func (f *fmt) fmt_complex(r, j float64, size int, verb rune) {
 	f.buf.WriteByte('(')
-	r := real(v)
 	oldPlus := f.plus
+	oldSpace := f.space
+	oldWid := f.wid
 	for i := 0; ; i++ {
 		switch verb {
 		case 'b':
-			f.fmt_fb64(r)
+			f.formatFloat(r, 'b', 0, size)
 		case 'e':
-			f.fmt_e64(r)
+			f.formatFloat(r, 'e', doPrec(f, 6), size)
 		case 'E':
-			f.fmt_E64(r)
-		case 'f':
-			f.fmt_f64(r)
+			f.formatFloat(r, 'E', doPrec(f, 6), size)
+		case 'f', 'F':
+			f.formatFloat(r, 'f', doPrec(f, 6), size)
 		case 'g':
-			f.fmt_g64(r)
+			f.formatFloat(r, 'g', doPrec(f, -1), size)
 		case 'G':
-			f.fmt_G64(r)
+			f.formatFloat(r, 'G', doPrec(f, -1), size)
 		}
 		if i != 0 {
 			break
 		}
+		// Imaginary part always has a sign.
 		f.plus = true
-		r = imag(v)
+		f.space = false
+		f.wid = oldWid
+		r = j
 	}
+	f.space = oldSpace
 	f.plus = oldPlus
+	f.wid = oldWid
 	f.buf.Write(irparenBytes)
 }
diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go
index 1ea816d..302661f 100644
--- a/src/pkg/fmt/print.go
+++ b/src/pkg/fmt/print.go
@@ -124,45 +124,13 @@ type pp struct {
 	fmt        fmt
 }
 
-// A cache holds a set of reusable objects.
-// The slice is a stack (LIFO).
-// If more are needed, the cache creates them by calling new.
-type cache struct {
-	mu    sync.Mutex
-	saved []interface{}
-	new   func() interface{}
+var ppFree = sync.Pool{
+	New: func() interface{} { return new(pp) },
 }
 
-func (c *cache) put(x interface{}) {
-	c.mu.Lock()
-	if len(c.saved) < cap(c.saved) {
-		c.saved = append(c.saved, x)
-	}
-	c.mu.Unlock()
-}
-
-func (c *cache) get() interface{} {
-	c.mu.Lock()
-	n := len(c.saved)
-	if n == 0 {
-		c.mu.Unlock()
-		return c.new()
-	}
-	x := c.saved[n-1]
-	c.saved = c.saved[0 : n-1]
-	c.mu.Unlock()
-	return x
-}
-
-func newCache(f func() interface{}) *cache {
-	return &cache{saved: make([]interface{}, 0, 100), new: f}
-}
-
-var ppFree = newCache(func() interface{} { return new(pp) })
-
 // newPrinter allocates a new pp struct or grab a cached one.
 func newPrinter() *pp {
-	p := ppFree.get().(*pp)
+	p := ppFree.Get().(*pp)
 	p.panicking = false
 	p.erroring = false
 	p.fmt.init(&p.buf)
@@ -178,7 +146,7 @@ func (p *pp) free() {
 	p.buf = p.buf[:0]
 	p.arg = nil
 	p.value = reflect.Value{}
-	ppFree.put(p)
+	ppFree.Put(p)
 }
 
 func (p *pp) Width() (wid int, ok bool) { return p.fmt.wid, p.fmt.widPresent }
@@ -479,7 +447,7 @@ func (p *pp) fmtFloat32(v float32, verb rune) {
 		p.fmt.fmt_e32(v)
 	case 'E':
 		p.fmt.fmt_E32(v)
-	case 'f':
+	case 'f', 'F':
 		p.fmt.fmt_f32(v)
 	case 'g', 'v':
 		p.fmt.fmt_g32(v)
@@ -498,7 +466,7 @@ func (p *pp) fmtFloat64(v float64, verb rune) {
 		p.fmt.fmt_e64(v)
 	case 'E':
 		p.fmt.fmt_E64(v)
-	case 'f':
+	case 'f', 'F':
 		p.fmt.fmt_f64(v)
 	case 'g', 'v':
 		p.fmt.fmt_g64(v)
@@ -555,6 +523,15 @@ func (p *pp) fmtString(v string, verb rune, goSyntax bool) {
 func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, typ reflect.Type, depth int) {
 	if verb == 'v' || verb == 'd' {
 		if goSyntax {
+			if v == nil {
+				if typ == nil {
+					p.buf.WriteString("[]byte(nil)")
+				} else {
+					p.buf.WriteString(typ.String())
+					p.buf.Write(nilParenBytes)
+				}
+				return
+			}
 			if typ == nil {
 				p.buf.Write(bytesBytes)
 			} else {
diff --git a/src/pkg/fmt/scan.go b/src/pkg/fmt/scan.go
index 5b1be58..8a337e4 100644
--- a/src/pkg/fmt/scan.go
+++ b/src/pkg/fmt/scan.go
@@ -11,6 +11,7 @@ import (
 	"os"
 	"reflect"
 	"strconv"
+	"sync"
 	"unicode/utf8"
 )
 
@@ -283,7 +284,6 @@ var space = [][2]uint16{
 	{0x0085, 0x0085},
 	{0x00a0, 0x00a0},
 	{0x1680, 0x1680},
-	{0x180e, 0x180e},
 	{0x2000, 0x200a},
 	{0x2028, 0x2029},
 	{0x202f, 0x202f},
@@ -380,7 +380,9 @@ func (r *readRune) ReadRune() (rr rune, size int, err error) {
 	return
 }
 
-var ssFree = newCache(func() interface{} { return new(ss) })
+var ssFree = sync.Pool{
+	New: func() interface{} { return new(ss) },
+}
 
 // newScanState allocates a new ss struct or grab a cached one.
 func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
@@ -395,7 +397,7 @@ func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
 		return
 	}
 
-	s = ssFree.get().(*ss)
+	s = ssFree.Get().(*ss)
 	if rr, ok := r.(io.RuneReader); ok {
 		s.rr = rr
 	} else {
@@ -427,7 +429,7 @@ func (s *ss) free(old ssave) {
 	}
 	s.buf = s.buf[:0]
 	s.rr = nil
-	ssFree.put(s)
+	ssFree.Put(s)
 }
 
 // skipSpace skips spaces and maybe newlines.
diff --git a/src/pkg/go/ast/commentmap.go b/src/pkg/go/ast/commentmap.go
index 1fb4867..ac999d6 100644
--- a/src/pkg/go/ast/commentmap.go
+++ b/src/pkg/go/ast/commentmap.go
@@ -149,7 +149,7 @@ func NewCommentMap(fset *token.FileSet, node Node, comments []*CommentGroup) Com
 
 	// set up comment reader r
 	tmp := make([]*CommentGroup, len(comments))
-	copy(tmp, comments) // don't change incomming comments
+	copy(tmp, comments) // don't change incoming comments
 	sortComments(tmp)
 	r := commentListReader{fset: fset, list: tmp} // !r.eol() because len(comments) > 0
 	r.next()
diff --git a/src/pkg/go/ast/example_test.go b/src/pkg/go/ast/example_test.go
index 632bfcf..d2e734f 100644
--- a/src/pkg/go/ast/example_test.go
+++ b/src/pkg/go/ast/example_test.go
@@ -5,8 +5,10 @@
 package ast_test
 
 import (
+	"bytes"
 	"fmt"
 	"go/ast"
+	"go/format"
 	"go/parser"
 	"go/token"
 )
@@ -134,3 +136,75 @@ func main() {
 	//     57  .  }
 	//     58  }
 }
+
+// This example illustrates how to remove a variable declaration
+// in a Go program while maintaining correct comment association
+// using an ast.CommentMap.
+func ExampleCommentMap() {
+	// src is the input for which we create the AST that we
+	// are going to manipulate.
+	src := `
+// This is the package comment.
+package main
+
+// This comment is associated with the hello constant.
+const hello = "Hello, World!" // line comment 1
+
+// This comment is associated with the foo variable.
+var foo = hello // line comment 2 
+
+// This comment is associated with the main function.
+func main() {
+	fmt.Println(hello) // line comment 3
+}
+`
+
+	// Create the AST by parsing src.
+	fset := token.NewFileSet() // positions are relative to fset
+	f, err := parser.ParseFile(fset, "src.go", src, parser.ParseComments)
+	if err != nil {
+		panic(err)
+	}
+
+	// Create an ast.CommentMap from the ast.File's comments.
+	// This helps keeping the association between comments
+	// and AST nodes.
+	cmap := ast.NewCommentMap(fset, f, f.Comments)
+
+	// Remove the first variable declaration from the list of declarations.
+	f.Decls = removeFirstVarDecl(f.Decls)
+
+	// Use the comment map to filter comments that don't belong anymore
+	// (the comments associated with the variable declaration), and create
+	// the new comments list.
+	f.Comments = cmap.Filter(f).Comments()
+
+	// Print the modified AST.
+	var buf bytes.Buffer
+	if err := format.Node(&buf, fset, f); err != nil {
+		panic(err)
+	}
+	fmt.Printf("%s", buf.Bytes())
+
+	// output:
+	// // This is the package comment.
+	// package main
+	//
+	// // This comment is associated with the hello constant.
+	// const hello = "Hello, World!" // line comment 1
+	//
+	// // This comment is associated with the main function.
+	// func main() {
+	// 	fmt.Println(hello) // line comment 3
+	// }
+}
+
+func removeFirstVarDecl(list []ast.Decl) []ast.Decl {
+	for i, decl := range list {
+		if gen, ok := decl.(*ast.GenDecl); ok && gen.Tok == token.VAR {
+			copy(list[i:], list[i+1:])
+			return list[:len(list)-1]
+		}
+	}
+	panic("variable declaration not found")
+}
diff --git a/src/pkg/go/build/build.go b/src/pkg/go/build/build.go
index 50d2fb4..412abea 100644
--- a/src/pkg/go/build/build.go
+++ b/src/pkg/go/build/build.go
@@ -292,10 +292,10 @@ func defaultContext() Context {
 	// say "+build go1.x", and code that should only be built before Go 1.x
 	// (perhaps it is the stub to use in that case) should say "+build !go1.x".
 	//
-	// When we reach Go 1.3 the line will read
-	//	c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3"}
+	// When we reach Go 1.4 the line will read
+	//	c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4"}
 	// and so on.
-	c.ReleaseTags = []string{"go1.1", "go1.2"}
+	c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3"}
 
 	switch os.Getenv("CGO_ENABLED") {
 	case "1":
@@ -303,8 +303,7 @@ func defaultContext() Context {
 	case "0":
 		c.CgoEnabled = false
 	default:
-		// golang.org/issue/5141
-		// cgo should be disabled for cross compilation builds
+		// cgo must be explicitly enabled for cross compilation builds
 		if runtime.GOARCH == c.GOARCH && runtime.GOOS == c.GOOS {
 			c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH]
 			break
@@ -358,6 +357,7 @@ type Package struct {
 	IgnoredGoFiles []string // .go source files ignored for this build
 	CFiles         []string // .c source files
 	CXXFiles       []string // .cc, .cpp and .cxx source files
+	MFiles         []string // .m (Objective-C) source files
 	HFiles         []string // .h, .hh, .hpp and .hxx source files
 	SFiles         []string // .s source files
 	SwigFiles      []string // .swig files
@@ -622,6 +622,9 @@ Found:
 		case ".cc", ".cpp", ".cxx":
 			p.CXXFiles = append(p.CXXFiles, name)
 			continue
+		case ".m":
+			p.MFiles = append(p.MFiles, name)
+			continue
 		case ".h", ".hh", ".hpp", ".hxx":
 			p.HFiles = append(p.HFiles, name)
 			continue
@@ -789,7 +792,7 @@ func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map
 	}
 
 	switch ext {
-	case ".go", ".c", ".cc", ".cxx", ".cpp", ".s", ".h", ".hh", ".hpp", ".hxx", ".S", ".swig", ".swigcxx":
+	case ".go", ".c", ".cc", ".cxx", ".cpp", ".m", ".s", ".h", ".hh", ".hpp", ".hxx", ".S", ".swig", ".swigcxx":
 		// tentatively okay - read to make sure
 	case ".syso":
 		// binary, no reading
@@ -1207,7 +1210,7 @@ func ArchChar(goarch string) (string, error) {
 	switch goarch {
 	case "386":
 		return "8", nil
-	case "amd64":
+	case "amd64", "amd64p32":
 		return "6", nil
 	case "arm":
 		return "5", nil
diff --git a/src/pkg/go/build/deps_test.go b/src/pkg/go/build/deps_test.go
index dd162c7..7421e14 100644
--- a/src/pkg/go/build/deps_test.go
+++ b/src/pkg/go/build/deps_test.go
@@ -8,6 +8,7 @@
 package build
 
 import (
+	"runtime"
 	"sort"
 	"testing"
 )
@@ -29,7 +30,7 @@ var pkgDeps = map[string][]string{
 	"errors":      {},
 	"io":          {"errors", "sync"},
 	"runtime":     {"unsafe"},
-	"sync":        {"sync/atomic", "unsafe"},
+	"sync":        {"runtime", "sync/atomic", "unsafe"},
 	"sync/atomic": {"unsafe"},
 	"unsafe":      {},
 
@@ -125,7 +126,7 @@ var pkgDeps = map[string][]string{
 	"os":            {"L1", "os", "syscall", "time"},
 	"path/filepath": {"L2", "os", "syscall"},
 	"io/ioutil":     {"L2", "os", "path/filepath", "time"},
-	"os/exec":       {"L2", "os", "syscall"},
+	"os/exec":       {"L2", "os", "path/filepath", "syscall"},
 	"os/signal":     {"L2", "os", "syscall"},
 
 	// OS enables basic operating system functionality,
@@ -301,7 +302,7 @@ var pkgDeps = map[string][]string{
 	// SSL/TLS.
 	"crypto/tls": {
 		"L4", "CRYPTO-MATH", "CGO", "OS",
-		"crypto/x509", "encoding/pem", "net", "syscall",
+		"container/list", "crypto/x509", "encoding/pem", "net", "syscall",
 	},
 	"crypto/x509": {
 		"L4", "CRYPTO-MATH", "OS", "CGO",
@@ -359,7 +360,7 @@ func allowed(pkg string) map[string]bool {
 }
 
 var bools = []bool{false, true}
-var geese = []string{"darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "plan9", "windows"}
+var geese = []string{"darwin", "dragonfly", "freebsd", "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris", "windows"}
 var goarches = []string{"386", "amd64", "arm"}
 
 type osPkg struct {
@@ -374,6 +375,11 @@ var allowedErrors = map[osPkg]bool{
 }
 
 func TestDependencies(t *testing.T) {
+	if runtime.GOOS == "nacl" {
+		// NaCl tests run in a limited file system and we do not
+		// provide access to every source file.
+		t.Skip("skipping on NaCl")
+	}
 	var all []string
 
 	for k := range pkgDeps {
@@ -387,6 +393,9 @@ func TestDependencies(t *testing.T) {
 			if isMacro(pkg) {
 				continue
 			}
+			if pkg == "runtime/cgo" && !ctxt.CgoEnabled {
+				continue
+			}
 			p, err := ctxt.Import(pkg, "", 0)
 			if err != nil {
 				if allowedErrors[osPkg{ctxt.GOOS, pkg}] {
diff --git a/src/pkg/go/build/doc.go b/src/pkg/go/build/doc.go
index b2f04ea..f17f76c 100644
--- a/src/pkg/go/build/doc.go
+++ b/src/pkg/go/build/doc.go
@@ -57,11 +57,15 @@
 //
 // Build Constraints
 //
-// A build constraint is a line comment beginning with the directive +build
+// A build constraint, also known as a build tag, is a line comment that begins
+//
+//	// +build
+//
 // that lists the conditions under which a file should be included in the package.
 // Constraints may appear in any kind of source file (not just Go), but
 // they must appear near the top of the file, preceded
-// only by blank lines and other line comments.
+// only by blank lines and other line comments. These rules mean that in Go
+// files a build constraint must appear before the package clause.
 //
 // To distinguish build constraints from package documentation, a series of
 // build constraints must be followed by a blank line.
@@ -95,6 +99,7 @@
 //	- "cgo", if ctxt.CgoEnabled is true
 //	- "go1.1", from Go version 1.1 onward
 //	- "go1.2", from Go version 1.2 onward
+//	- "go1.3", from Go version 1.3 onward
 //	- any additional words listed in ctxt.BuildTags
 //
 // If a file's name, after stripping the extension and a possible _test suffix,
diff --git a/src/pkg/go/build/syslist.go b/src/pkg/go/build/syslist.go
index e1fbf63..5c42b94 100644
--- a/src/pkg/go/build/syslist.go
+++ b/src/pkg/go/build/syslist.go
@@ -4,5 +4,5 @@
 
 package build
 
-const goosList = "darwin dragonfly freebsd linux netbsd openbsd plan9 windows "
-const goarchList = "386 amd64 arm "
+const goosList = "darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows "
+const goarchList = "386 amd64 amd64p32 arm "
diff --git a/src/pkg/go/doc/comment.go b/src/pkg/go/doc/comment.go
index 5c8c43e..f414ca4 100644
--- a/src/pkg/go/doc/comment.go
+++ b/src/pkg/go/doc/comment.go
@@ -45,13 +45,13 @@ func commentEscape(w io.Writer, text string, nice bool) {
 
 const (
 	// Regexp for Go identifiers
-	identRx = `[a-zA-Z_][a-zA-Z_0-9]*` // TODO(gri) ASCII only for now - fix this
+	identRx = `[\pL_][\pL_0-9]*`
 
 	// Regexp for URLs
-	protocol = `(https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prospero):`
+	protocol = `https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prospero`
 	hostPart = `[a-zA-Z0-9_@\-]+`
-	filePart = `[a-zA-Z0-9_?%#~&/\-+=]+`
-	urlRx    = protocol + `//` + // http://
+	filePart = `[a-zA-Z0-9_?%#~&/\-+=()]+` // parentheses may not be matching; see pairedParensPrefixLen
+	urlRx    = `(` + protocol + `)://` +   // http://
 		hostPart + `([.:]` + hostPart + `)*/?` + // //www.google.com:8080/
 		filePart + `([:.,]` + filePart + `)*`
 )
@@ -73,6 +73,29 @@ var (
 	html_endh   = []byte("</h3>\n")
 )
 
+// pairedParensPrefixLen returns the length of the longest prefix of s containing paired parentheses.
+func pairedParensPrefixLen(s string) int {
+	parens := 0
+	l := len(s)
+	for i, ch := range s {
+		switch ch {
+		case '(':
+			if parens == 0 {
+				l = i
+			}
+			parens++
+		case ')':
+			parens--
+			if parens == 0 {
+				l = len(s)
+			} else if parens < 0 {
+				return i
+			}
+		}
+	}
+	return l
+}
+
 // Emphasize and escape a line of text for HTML. URLs are converted into links;
 // if the URL also appears in the words map, the link is taken from the map (if
 // the corresponding map value is the empty string, the URL is not converted
@@ -92,18 +115,26 @@ func emphasize(w io.Writer, line string, words map[string]string, nice bool) {
 		// write text before match
 		commentEscape(w, line[0:m[0]], nice)
 
-		// analyze match
+		// adjust match if necessary
 		match := line[m[0]:m[1]]
+		if n := pairedParensPrefixLen(match); n < len(match) {
+			// match contains unpaired parentheses (rare);
+			// redo matching with shortened line for correct indices
+			m = matchRx.FindStringSubmatchIndex(line[:m[0]+n])
+			match = match[:n]
+		}
+
+		// analyze match
 		url := ""
 		italics := false
 		if words != nil {
-			url, italics = words[string(match)]
+			url, italics = words[match]
 		}
 		if m[2] >= 0 {
 			// match against first parenthesized sub-regexp; must be match against urlRx
 			if !italics {
 				// no alternative URL in words list, use match instead
-				url = string(match)
+				url = match
 			}
 			italics = false // don't italicize URLs
 		}
@@ -392,7 +423,9 @@ func ToText(w io.Writer, text string, indent, preIndent string, width int) {
 		case opPre:
 			w.Write(nl)
 			for _, line := range b.lines {
-				if !isBlank(line) {
+				if isBlank(line) {
+					w.Write([]byte("\n"))
+				} else {
 					w.Write([]byte(preIndent))
 					w.Write([]byte(line))
 				}
diff --git a/src/pkg/go/doc/comment_test.go b/src/pkg/go/doc/comment_test.go
index aa21b8d..ad65c2a 100644
--- a/src/pkg/go/doc/comment_test.go
+++ b/src/pkg/go/doc/comment_test.go
@@ -42,8 +42,9 @@ func TestIsHeading(t *testing.T) {
 }
 
 var blocksTests = []struct {
-	in  string
-	out []block
+	in   string
+	out  []block
+	text string
 }{
 	{
 		in: `Para 1.
@@ -59,6 +60,22 @@ Para 3.
 	pre1
 
 Para 4.
+
+	pre
+	pre1
+
+	pre2
+
+Para 5.
+
+
+	pre
+
+
+	pre1
+	pre2
+
+Para 6.
 	pre
 	pre2
 `,
@@ -69,8 +86,44 @@ Para 4.
 			{opPara, []string{"Para 3.\n"}},
 			{opPre, []string{"pre\n", "pre1\n"}},
 			{opPara, []string{"Para 4.\n"}},
+			{opPre, []string{"pre\n", "pre1\n", "\n", "pre2\n"}},
+			{opPara, []string{"Para 5.\n"}},
+			{opPre, []string{"pre\n", "\n", "\n", "pre1\n", "pre2\n"}},
+			{opPara, []string{"Para 6.\n"}},
 			{opPre, []string{"pre\n", "pre2\n"}},
 		},
+		text: `.   Para 1. Para 1 line 2.
+
+.   Para 2.
+
+
+.   Section
+
+.   Para 3.
+
+$	pre
+$	pre1
+
+.   Para 4.
+
+$	pre
+$	pre1
+
+$	pre2
+
+.   Para 5.
+
+$	pre
+
+
+$	pre1
+$	pre2
+
+.   Para 6.
+
+$	pre
+$	pre2
+`,
 	},
 }
 
@@ -83,14 +136,28 @@ func TestBlocks(t *testing.T) {
 	}
 }
 
+func TestToText(t *testing.T) {
+	var buf bytes.Buffer
+	for i, tt := range blocksTests {
+		ToText(&buf, tt.in, ".   ", "$\t", 40)
+		if have := buf.String(); have != tt.text {
+			t.Errorf("#%d: mismatch\nhave: %s\nwant: %s\nhave vs want:\n%q\n%q", i, have, tt.text, have, tt.text)
+		}
+		buf.Reset()
+	}
+}
+
 var emphasizeTests = []struct {
-	in  string
-	out string
+	in, out string
 }{
 	{"http://www.google.com/", `<a href="http://www.google.com/">http://www.google.com/</a>`},
 	{"https://www.google.com/", `<a href="https://www.google.com/">https://www.google.com/</a>`},
 	{"http://www.google.com/path.", `<a href="http://www.google.com/path">http://www.google.com/path</a>.`},
+	{"http://en.wikipedia.org/wiki/Camellia_(cipher)", `<a href="http://en.wikipedia.org/wiki/Camellia_(cipher)">http://en.wikipedia.org/wiki/Camellia_(cipher)</a>`},
 	{"(http://www.google.com/)", `(<a href="http://www.google.com/">http://www.google.com/</a>)`},
+	{"http://gmail.com)", `<a href="http://gmail.com">http://gmail.com</a>)`},
+	{"((http://gmail.com))", `((<a href="http://gmail.com">http://gmail.com</a>))`},
+	{"http://gmail.com ((http://gmail.com)) ()", `<a href="http://gmail.com">http://gmail.com</a> ((<a href="http://gmail.com">http://gmail.com</a>)) ()`},
 	{"Foo bar http://example.com/ quux!", `Foo bar <a href="http://example.com/">http://example.com/</a> quux!`},
 	{"Hello http://example.com/%2f/ /world.", `Hello <a href="http://example.com/%2f/">http://example.com/%2f/</a> /world.`},
 	{"Lorem http: ipsum //host/path", "Lorem http: ipsum //host/path"},
@@ -107,3 +174,34 @@ func TestEmphasize(t *testing.T) {
 		}
 	}
 }
+
+var pairedParensPrefixLenTests = []struct {
+	in, out string
+}{
+	{"", ""},
+	{"foo", "foo"},
+	{"()", "()"},
+	{"foo()", "foo()"},
+	{"foo()()()", "foo()()()"},
+	{"foo()((()()))", "foo()((()()))"},
+	{"foo()((()()))bar", "foo()((()()))bar"},
+	{"foo)", "foo"},
+	{"foo))", "foo"},
+	{"foo)))))", "foo"},
+	{"(foo", ""},
+	{"((foo", ""},
+	{"(((((foo", ""},
+	{"(foo)", "(foo)"},
+	{"((((foo))))", "((((foo))))"},
+	{"foo()())", "foo()()"},
+	{"foo((()())", "foo"},
+	{"foo((()())) (() foo ", "foo((()())) "},
+}
+
+func TestPairedParensPrefixLen(t *testing.T) {
+	for i, tt := range pairedParensPrefixLenTests {
+		if out := tt.in[:pairedParensPrefixLen(tt.in)]; out != tt.out {
+			t.Errorf("#%d: mismatch\nhave: %q\nwant: %q", i, out, tt.out)
+		}
+	}
+}
diff --git a/src/pkg/go/doc/example.go b/src/pkg/go/doc/example.go
index 2358ed3..c414e54 100644
--- a/src/pkg/go/doc/example.go
+++ b/src/pkg/go/doc/example.go
@@ -32,6 +32,17 @@ type Example struct {
 
 // Examples returns the examples found in the files, sorted by Name field.
 // The Order fields record the order in which the examples were encountered.
+//
+// Playable Examples must be in a package whose name ends in "_test".
+// An Example is "playable" (the Play field is non-nil) in either of these
+// circumstances:
+//   - The example function is self-contained: the function references only
+//     identifiers from other packages (or predeclared identifiers, such as
+//     "int") and the test file does not include a dot import.
+//   - The entire test file is the example: the file contains exactly one
+//     example function, zero test or benchmark functions, and at least one
+//     top-level function, type, variable, or constant declaration other
+//     than the example function.
 func Examples(files ...*ast.File) []*Example {
 	var list []*Example
 	for _, file := range files {
@@ -244,7 +255,7 @@ func playExample(file *ast.File, body *ast.BlockStmt) *ast.File {
 		}
 	}
 
-	// Strip "Output:" commment and adjust body end position.
+	// Strip "Output:" comment and adjust body end position.
 	body, comments = stripOutputComment(body, comments)
 
 	// Synthesize import declaration.
@@ -307,7 +318,7 @@ func playExampleFile(file *ast.File) *ast.File {
 	return &f
 }
 
-// stripOutputComment finds and removes an "Output:" commment from body
+// stripOutputComment finds and removes an "Output:" comment from body
 // and comments, and adjusts the body block's end position.
 func stripOutputComment(body *ast.BlockStmt, comments []*ast.CommentGroup) (*ast.BlockStmt, []*ast.CommentGroup) {
 	// Do nothing if no "Output:" comment found.
diff --git a/src/pkg/go/parser/error_test.go b/src/pkg/go/parser/error_test.go
index d4d4f90..8506077 100644
--- a/src/pkg/go/parser/error_test.go
+++ b/src/pkg/go/parser/error_test.go
@@ -59,8 +59,11 @@ func getPos(filename string, offset int) token.Pos {
 
 // ERROR comments must be of the form /* ERROR "rx" */ and rx is
 // a regular expression that matches the expected error message.
+// The special form /* ERROR HERE "rx" */ must be used for error
+// messages that appear immediately after a token, rather than at
+// a token's position.
 //
-var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`)
+var errRx = regexp.MustCompile(`^/\* *ERROR *(HERE)? *"([^"]*)" *\*/$`)
 
 // expectedErrors collects the regular expressions of ERROR comments found
 // in files and returns them as a map of error positions to error messages.
@@ -74,6 +77,7 @@ func expectedErrors(t *testing.T, filename string, src []byte) map[token.Pos]str
 	// not match the position information collected by the parser
 	s.Init(getFile(filename), src, nil, scanner.ScanComments)
 	var prev token.Pos // position of last non-comment, non-semicolon token
+	var here token.Pos // position immediately after the token at position prev
 
 	for {
 		pos, tok, lit := s.Scan()
@@ -82,11 +86,22 @@ func expectedErrors(t *testing.T, filename string, src []byte) map[token.Pos]str
 			return errors
 		case token.COMMENT:
 			s := errRx.FindStringSubmatch(lit)
-			if len(s) == 2 {
-				errors[prev] = string(s[1])
+			if len(s) == 3 {
+				pos := prev
+				if s[1] == "HERE" {
+					pos = here
+				}
+				errors[pos] = string(s[2])
 			}
 		default:
 			prev = pos
+			var l int // token length
+			if tok.IsLiteral() {
+				l = len(lit)
+			} else {
+				l = len(tok.String())
+			}
+			here = prev + token.Pos(l)
 		}
 	}
 }
diff --git a/src/pkg/go/parser/interface.go b/src/pkg/go/parser/interface.go
index 0f83ca9..57da4dd 100644
--- a/src/pkg/go/parser/interface.go
+++ b/src/pkg/go/parser/interface.go
@@ -182,6 +182,13 @@ func ParseExpr(x string) (ast.Expr, error) {
 	p.closeScope()
 	assert(p.topScope == nil, "unbalanced scopes")
 
+	// If a semicolon was inserted, consume it;
+	// report an error if there's more tokens.
+	if p.tok == token.SEMICOLON {
+		p.next()
+	}
+	p.expect(token.EOF)
+
 	if p.errors.Len() > 0 {
 		p.errors.Sort()
 		return nil, p.errors.Err()
diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go
index c452331..00dd532 100644
--- a/src/pkg/go/parser/parser.go
+++ b/src/pkg/go/parser/parser.go
@@ -492,6 +492,26 @@ func syncDecl(p *parser) {
 	}
 }
 
+// safePos returns a valid file position for a given position: If pos
+// is valid to begin with, safePos returns pos. If pos is out-of-range,
+// safePos returns the EOF position.
+//
+// This is hack to work around "artificial" end positions in the AST which
+// are computed by adding 1 to (presumably valid) token positions. If the
+// token positions are invalid due to parse errors, the resulting end position
+// may be past the file's EOF position, which would lead to panics if used
+// later on.
+//
+func (p *parser) safePos(pos token.Pos) (res token.Pos) {
+	defer func() {
+		if recover() != nil {
+			res = token.Pos(p.file.Base() + p.file.Size()) // EOF position
+		}
+	}()
+	_ = p.file.Offset(pos) // trigger a panic if position is out-of-range
+	return pos
+}
+
 // ----------------------------------------------------------------------------
 // Identifiers
 
@@ -679,7 +699,7 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
 		if n := len(list); n > 1 || !isTypeName(deref(typ)) {
 			pos := typ.Pos()
 			p.errorExpected(pos, "anonymous field")
-			typ = &ast.BadExpr{From: pos, To: list[n-1].End()}
+			typ = &ast.BadExpr{From: pos, To: p.safePos(list[n-1].End())}
 		}
 	}
 
@@ -1168,16 +1188,19 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
 		defer un(trace(p, "IndexOrSlice"))
 	}
 
+	const N = 3 // change the 3 to 2 to disable 3-index slices
 	lbrack := p.expect(token.LBRACK)
 	p.exprLev++
-	var index [3]ast.Expr // change the 3 to 2 to disable slice expressions w/ cap
+	var index [N]ast.Expr
+	var colons [N - 1]token.Pos
 	if p.tok != token.COLON {
 		index[0] = p.parseRhs()
 	}
 	ncolons := 0
-	for p.tok == token.COLON && ncolons < len(index)-1 {
-		p.next()
+	for p.tok == token.COLON && ncolons < len(colons) {
+		colons[ncolons] = p.pos
 		ncolons++
+		p.next()
 		if p.tok != token.COLON && p.tok != token.RBRACK && p.tok != token.EOF {
 			index[ncolons] = p.parseRhs()
 		}
@@ -1187,7 +1210,21 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
 
 	if ncolons > 0 {
 		// slice expression
-		return &ast.SliceExpr{X: x, Lbrack: lbrack, Low: index[0], High: index[1], Max: index[2], Slice3: ncolons == 2, Rbrack: rbrack}
+		slice3 := false
+		if ncolons == 2 {
+			slice3 = true
+			// Check presence of 2nd and 3rd index here rather than during type-checking
+			// to prevent erroneous programs from passing through gofmt (was issue 7305).
+			if index[1] == nil {
+				p.error(colons[0], "2nd index required in 3-index slice")
+				index[1] = &ast.BadExpr{From: colons[0] + 1, To: colons[1]}
+			}
+			if index[2] == nil {
+				p.error(colons[1], "3rd index required in 3-index slice")
+				index[2] = &ast.BadExpr{From: colons[1] + 1, To: rbrack}
+			}
+		}
+		return &ast.SliceExpr{X: x, Lbrack: lbrack, Low: index[0], High: index[1], Max: index[2], Slice3: slice3, Rbrack: rbrack}
 	}
 
 	return &ast.IndexExpr{X: x, Lbrack: lbrack, Index: index[0], Rbrack: rbrack}
@@ -1320,7 +1357,7 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
 	default:
 		// all other nodes are not proper expressions
 		p.errorExpected(x.Pos(), "expression")
-		x = &ast.BadExpr{From: x.Pos(), To: x.End()}
+		x = &ast.BadExpr{From: x.Pos(), To: p.safePos(x.End())}
 	}
 	return x
 }
@@ -1383,7 +1420,7 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
 	case *ast.ArrayType:
 		if len, isEllipsis := t.Len.(*ast.Ellipsis); isEllipsis {
 			p.error(len.Pos(), "expected array length, found '...'")
-			x = &ast.BadExpr{From: x.Pos(), To: x.End()}
+			x = &ast.BadExpr{From: x.Pos(), To: p.safePos(x.End())}
 		}
 	}
 
@@ -1669,14 +1706,14 @@ func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
 	return &ast.ExprStmt{X: x[0]}, false
 }
 
-func (p *parser) parseCallExpr() *ast.CallExpr {
+func (p *parser) parseCallExpr(callType string) *ast.CallExpr {
 	x := p.parseRhsOrType() // could be a conversion: (some type)(x)
 	if call, isCall := x.(*ast.CallExpr); isCall {
 		return call
 	}
 	if _, isBad := x.(*ast.BadExpr); !isBad {
 		// only report error if it's a new one
-		p.errorExpected(x.Pos(), "function/method call")
+		p.error(p.safePos(x.End()), fmt.Sprintf("function must be invoked in %s statement", callType))
 	}
 	return nil
 }
@@ -1687,7 +1724,7 @@ func (p *parser) parseGoStmt() ast.Stmt {
 	}
 
 	pos := p.expect(token.GO)
-	call := p.parseCallExpr()
+	call := p.parseCallExpr("go")
 	p.expectSemi()
 	if call == nil {
 		return &ast.BadStmt{From: pos, To: pos + 2} // len("go")
@@ -1702,7 +1739,7 @@ func (p *parser) parseDeferStmt() ast.Stmt {
 	}
 
 	pos := p.expect(token.DEFER)
-	call := p.parseCallExpr()
+	call := p.parseCallExpr("defer")
 	p.expectSemi()
 	if call == nil {
 		return &ast.BadStmt{From: pos, To: pos + 5} // len("defer")
@@ -1745,15 +1782,15 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
 	return &ast.BranchStmt{TokPos: pos, Tok: tok, Label: label}
 }
 
-func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
+func (p *parser) makeExpr(s ast.Stmt, kind string) ast.Expr {
 	if s == nil {
 		return nil
 	}
 	if es, isExpr := s.(*ast.ExprStmt); isExpr {
 		return p.checkExpr(es.X)
 	}
-	p.error(s.Pos(), "expected condition, found simple statement")
-	return &ast.BadExpr{From: s.Pos(), To: s.End()}
+	p.error(s.Pos(), fmt.Sprintf("expected %s, found simple statement (missing parentheses around composite literal?)", kind))
+	return &ast.BadExpr{From: s.Pos(), To: p.safePos(s.End())}
 }
 
 func (p *parser) parseIfStmt() *ast.IfStmt {
@@ -1779,7 +1816,7 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
 				p.next()
 				x = p.parseRhs()
 			} else {
-				x = p.makeExpr(s)
+				x = p.makeExpr(s, "boolean expression")
 				s = nil
 			}
 		}
@@ -1910,7 +1947,7 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
 		return &ast.TypeSwitchStmt{Switch: pos, Init: s1, Assign: s2, Body: body}
 	}
 
-	return &ast.SwitchStmt{Switch: pos, Init: s1, Tag: p.makeExpr(s2), Body: body}
+	return &ast.SwitchStmt{Switch: pos, Init: s1, Tag: p.makeExpr(s2, "switch expression"), Body: body}
 }
 
 func (p *parser) parseCommClause() *ast.CommClause {
@@ -2035,7 +2072,7 @@ func (p *parser) parseForStmt() ast.Stmt {
 			key = as.Lhs[0]
 		default:
 			p.errorExpected(as.Lhs[0].Pos(), "1 or 2 expressions")
-			return &ast.BadStmt{From: pos, To: body.End()}
+			return &ast.BadStmt{From: pos, To: p.safePos(body.End())}
 		}
 		// parseSimpleStmt returned a right-hand side that
 		// is a single unary expression of the form "range x"
@@ -2055,7 +2092,7 @@ func (p *parser) parseForStmt() ast.Stmt {
 	return &ast.ForStmt{
 		For:  pos,
 		Init: s1,
-		Cond: p.makeExpr(s2),
+		Cond: p.makeExpr(s2, "boolean or range expression"),
 		Post: s3,
 		Body: body,
 	}
@@ -2282,7 +2319,7 @@ func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
 			p.errorExpected(base.Pos(), "(unqualified) identifier")
 		}
 		par.List = []*ast.Field{
-			{Type: &ast.BadExpr{From: recv.Pos(), To: recv.End()}},
+			{Type: &ast.BadExpr{From: recv.Pos(), To: p.safePos(recv.End())}},
 		}
 	}
 
diff --git a/src/pkg/go/parser/parser_test.go b/src/pkg/go/parser/parser_test.go
index 0a34b7e..2797ea5 100644
--- a/src/pkg/go/parser/parser_test.go
+++ b/src/pkg/go/parser/parser_test.go
@@ -78,7 +78,7 @@ func TestParseExpr(t *testing.T) {
 	}
 	// sanity check
 	if _, ok := x.(*ast.BinaryExpr); !ok {
-		t.Errorf("ParseExpr(%s): got %T, expected *ast.BinaryExpr", src, x)
+		t.Errorf("ParseExpr(%s): got %T, want *ast.BinaryExpr", src, x)
 	}
 
 	// a valid type expression
@@ -89,17 +89,24 @@ func TestParseExpr(t *testing.T) {
 	}
 	// sanity check
 	if _, ok := x.(*ast.StructType); !ok {
-		t.Errorf("ParseExpr(%s): got %T, expected *ast.StructType", src, x)
+		t.Errorf("ParseExpr(%s): got %T, want *ast.StructType", src, x)
 	}
 
 	// an invalid expression
 	src = "a + *"
 	_, err = ParseExpr(src)
 	if err == nil {
-		t.Fatalf("ParseExpr(%s): %v", src, err)
+		t.Fatalf("ParseExpr(%s): got no error", src)
+	}
+
+	// a valid expression followed by extra tokens is invalid
+	src = "a[i] := x"
+	_, err = ParseExpr(src)
+	if err == nil {
+		t.Fatalf("ParseExpr(%s): got no error", src)
 	}
 
-	// it must not crash
+	// ParseExpr must not crash
 	for _, src := range valids {
 		ParseExpr(src)
 	}
diff --git a/src/pkg/go/parser/short_test.go b/src/pkg/go/parser/short_test.go
index 0ef0c56..b794060 100644
--- a/src/pkg/go/parser/short_test.go
+++ b/src/pkg/go/parser/short_test.go
@@ -48,14 +48,14 @@ var invalids = []string{
 	`package p; func f() { if { /* ERROR "expected operand" */ } };`,
 	`package p; func f() { if ; { /* ERROR "expected operand" */ } };`,
 	`package p; func f() { if f(); { /* ERROR "expected operand" */ } };`,
-	`package p; func f() { if _ /* ERROR "expected condition" */ = range x; true {} };`,
-	`package p; func f() { switch _ /* ERROR "expected condition" */ = range x; true {} };`,
+	`package p; func f() { if _ /* ERROR "expected boolean expression" */ = range x; true {} };`,
+	`package p; func f() { switch _ /* ERROR "expected switch expression" */ = range x; true {} };`,
 	`package p; func f() { for _ = range x ; /* ERROR "expected '{'" */ ; {} };`,
 	`package p; func f() { for ; ; _ = range /* ERROR "expected operand" */ x {} };`,
-	`package p; func f() { for ; _ /* ERROR "expected condition" */ = range x ; {} };`,
-	`package p; func f() { switch t /* ERROR "expected condition" */ = t.(type) {} };`,
-	`package p; func f() { switch t /* ERROR "expected condition" */ , t = t.(type) {} };`,
-	`package p; func f() { switch t /* ERROR "expected condition" */ = t.(type), t {} };`,
+	`package p; func f() { for ; _ /* ERROR "expected boolean or range expression" */ = range x ; {} };`,
+	`package p; func f() { switch t /* ERROR "expected switch expression" */ = t.(type) {} };`,
+	`package p; func f() { switch t /* ERROR "expected switch expression" */ , t = t.(type) {} };`,
+	`package p; func f() { switch t /* ERROR "expected switch expression" */ = t.(type), t {} };`,
 	`package p; var a = [ /* ERROR "expected expression" */ 1]int;`,
 	`package p; var a = [ /* ERROR "expected expression" */ ...]int;`,
 	`package p; var a = struct /* ERROR "expected expression" */ {}`,
@@ -76,8 +76,19 @@ var invalids = []string{
 	`package p; func f() { _ = x = /* ERROR "expected '=='" */ 0 {}};`,
 	`package p; func f() { _ = 1 == func()int { var x bool; x = x = /* ERROR "expected '=='" */ true; return x }() };`,
 	`package p; func f() { var s []int; _ = s[] /* ERROR "expected operand" */ };`,
-	`package p; func f() { var s []int; _ = s[::: /* ERROR "expected ']'" */ ] };`,
+	`package p; func f() { var s []int; _ = s[i:j: /* ERROR "3rd index required" */ ] };`,
+	`package p; func f() { var s []int; _ = s[i: /* ERROR "2nd index required" */ :k] };`,
+	`package p; func f() { var s []int; _ = s[i: /* ERROR "2nd index required" */ :] };`,
+	`package p; func f() { var s []int; _ = s[: /* ERROR "2nd index required" */ :] };`,
+	`package p; func f() { var s []int; _ = s[: /* ERROR "2nd index required" */ ::] };`,
 	`package p; func f() { var s []int; _ = s[i:j:k: /* ERROR "expected ']'" */ l] };`,
+	`package p; func f() { for x /* ERROR "boolean or range expression" */ = []string {} }`,
+	`package p; func f() { for x /* ERROR "boolean or range expression" */ := []string {} }`,
+	`package p; func f() { for i /* ERROR "boolean or range expression" */ , x = []string {} }`,
+	`package p; func f() { for i /* ERROR "boolean or range expression" */ , x := []string {} }`,
+	`package p; func f() { go f /* ERROR HERE "function must be invoked" */ }`,
+	`package p; func f() { defer func() {} /* ERROR HERE "function must be invoked" */ }`,
+	`package p; func f() { go func() { func() { f(x func /* ERROR "expected '\)'" */ (){}) } } }`,
 }
 
 func TestInvalid(t *testing.T) {
diff --git a/src/pkg/go/printer/nodes.go b/src/pkg/go/printer/nodes.go
index 583c6c3..04b5f1a 100644
--- a/src/pkg/go/printer/nodes.go
+++ b/src/pkg/go/printer/nodes.go
@@ -378,10 +378,6 @@ func (p *printer) setLineComment(text string) {
 	p.setComment(&ast.CommentGroup{List: []*ast.Comment{{Slash: token.NoPos, Text: text}}})
 }
 
-func (p *printer) isMultiLine(n ast.Node) bool {
-	return p.lineFor(n.End())-p.lineFor(n.Pos()) > 0
-}
-
 func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
 	lbrace := fields.Opening
 	list := fields.List
@@ -428,13 +424,14 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
 		if len(list) == 1 {
 			sep = blank
 		}
-		newSection := false
+		var line int
 		for i, f := range list {
 			if i > 0 {
-				p.linebreak(p.lineFor(f.Pos()), 1, ignore, newSection)
+				p.linebreak(p.lineFor(f.Pos()), 1, ignore, p.linesFrom(line) > 0)
 			}
 			extraTabs := 0
 			p.setComment(f.Doc)
+			p.recordLine(&line)
 			if len(f.Names) > 0 {
 				// named fields
 				p.identList(f.Names, false)
@@ -460,7 +457,6 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
 				}
 				p.setComment(f.Comment)
 			}
-			newSection = p.isMultiLine(f)
 		}
 		if isIncomplete {
 			if len(list) > 0 {
@@ -472,12 +468,13 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
 
 	} else { // interface
 
-		newSection := false
+		var line int
 		for i, f := range list {
 			if i > 0 {
-				p.linebreak(p.lineFor(f.Pos()), 1, ignore, newSection)
+				p.linebreak(p.lineFor(f.Pos()), 1, ignore, p.linesFrom(line) > 0)
 			}
 			p.setComment(f.Doc)
+			p.recordLine(&line)
 			if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
 				// method
 				p.expr(f.Names[0])
@@ -487,7 +484,6 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
 				p.expr(f.Type)
 			}
 			p.setComment(f.Comment)
-			newSection = p.isMultiLine(f)
 		}
 		if isIncomplete {
 			if len(list) > 0 {
@@ -826,10 +822,16 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
 		}
 		p.print(x.Lbrace, token.LBRACE)
 		p.exprList(x.Lbrace, x.Elts, 1, commaTerm, x.Rbrace)
-		// do not insert extra line breaks because of comments before
-		// the closing '}' as it might break the code if there is no
-		// trailing ','
-		p.print(noExtraLinebreak, x.Rbrace, token.RBRACE, noExtraLinebreak)
+		// do not insert extra line break following a /*-style comment
+		// before the closing '}' as it might break the code if there
+		// is no trailing ','
+		mode := noExtraLinebreak
+		// do not insert extra blank following a /*-style comment
+		// before the closing '}' unless the literal is empty
+		if len(x.Elts) > 0 {
+			mode |= noExtraBlank
+		}
+		p.print(mode, x.Rbrace, token.RBRACE, mode)
 
 	case *ast.Ellipsis:
 		p.print(token.ELLIPSIS)
@@ -901,20 +903,31 @@ func (p *printer) stmtList(list []ast.Stmt, nindent int, nextIsRBrace bool) {
 	if nindent > 0 {
 		p.print(indent)
 	}
-	multiLine := false
+	var line int
 	i := 0
 	for _, s := range list {
 		// ignore empty statements (was issue 3466)
 		if _, isEmpty := s.(*ast.EmptyStmt); !isEmpty {
-			// _indent == 0 only for lists of switch/select case clauses;
+			// nindent == 0 only for lists of switch/select case clauses;
 			// in those cases each clause is a new section
 			if len(p.output) > 0 {
 				// only print line break if we are not at the beginning of the output
 				// (i.e., we are not printing only a partial program)
-				p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || nindent == 0 || multiLine)
+				p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || nindent == 0 || p.linesFrom(line) > 0)
 			}
+			p.recordLine(&line)
 			p.stmt(s, nextIsRBrace && i == len(list)-1)
-			multiLine = p.isMultiLine(s)
+			// labeled statements put labels on a separate line, but here
+			// we only care about the start line of the actual statement
+			// without label - correct line for each label
+			for t := s; ; {
+				lt, _ := t.(*ast.LabeledStmt)
+				if lt == nil {
+					break
+				}
+				line++
+				t = lt.Stmt
+			}
 			i++
 		}
 	}
@@ -1375,22 +1388,22 @@ func (p *printer) genDecl(d *ast.GenDecl) {
 				// two or more grouped const/var declarations:
 				// determine if the type column must be kept
 				keepType := keepTypeColumn(d.Specs)
-				newSection := false
+				var line int
 				for i, s := range d.Specs {
 					if i > 0 {
-						p.linebreak(p.lineFor(s.Pos()), 1, ignore, newSection)
+						p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0)
 					}
+					p.recordLine(&line)
 					p.valueSpec(s.(*ast.ValueSpec), keepType[i])
-					newSection = p.isMultiLine(s)
 				}
 			} else {
-				newSection := false
+				var line int
 				for i, s := range d.Specs {
 					if i > 0 {
-						p.linebreak(p.lineFor(s.Pos()), 1, ignore, newSection)
+						p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0)
 					}
+					p.recordLine(&line)
 					p.spec(s, n, false)
-					newSection = p.isMultiLine(s)
 				}
 			}
 			p.print(unindent, formfeed)
@@ -1448,13 +1461,16 @@ func (p *printer) bodySize(b *ast.BlockStmt, maxSize int) int {
 		// opening and closing brace are on different lines - don't make it a one-liner
 		return maxSize + 1
 	}
-	if len(b.List) > 5 || p.commentBefore(p.posFor(pos2)) {
-		// too many statements or there is a comment inside - don't make it a one-liner
+	if len(b.List) > 5 {
+		// too many statements - don't make it a one-liner
 		return maxSize + 1
 	}
 	// otherwise, estimate body size
-	bodySize := 0
+	bodySize := p.commentSizeBefore(p.posFor(pos2))
 	for i, s := range b.List {
+		if bodySize > maxSize {
+			break // no need to continue
+		}
 		if i > 0 {
 			bodySize += 2 // space for a semicolon and blank
 		}
@@ -1488,7 +1504,7 @@ func (p *printer) adjBlock(headerSize int, sep whiteSpace, b *ast.BlockStmt) {
 			}
 			p.print(blank)
 		}
-		p.print(b.Rbrace, token.RBRACE)
+		p.print(noExtraLinebreak, b.Rbrace, token.RBRACE, noExtraLinebreak)
 		return
 	}
 
diff --git a/src/pkg/go/printer/printer.go b/src/pkg/go/printer/printer.go
index e06d2ed..280c697 100644
--- a/src/pkg/go/printer/printer.go
+++ b/src/pkg/go/printer/printer.go
@@ -39,9 +39,17 @@ const (
 type pmode int
 
 const (
-	noExtraLinebreak pmode = 1 << iota
+	noExtraBlank     pmode = 1 << iota // disables extra blank after /*-style comment
+	noExtraLinebreak                   // disables extra line break after /*-style comment
 )
 
+type commentInfo struct {
+	cindex         int               // current comment index
+	comment        *ast.CommentGroup // = printer.comments[cindex]; or nil
+	commentOffset  int               // = printer.posFor(printer.comments[cindex].List[0].Pos()).Offset; or infinity
+	commentNewline bool              // true if the comment group contains newlines
+}
+
 type printer struct {
 	// Configuration (does not change after initialization)
 	Config
@@ -52,7 +60,8 @@ type printer struct {
 	indent      int          // current indentation
 	mode        pmode        // current printer mode
 	impliedSemi bool         // if set, a linebreak implies a semicolon
-	lastTok     token.Token  // the last token printed (token.ILLEGAL if it's whitespace)
+	lastTok     token.Token  // last token printed (token.ILLEGAL if it's whitespace)
+	prevOpen    token.Token  // previous non-brace "open" token (, [, or token.ILLEGAL
 	wsbuf       []whiteSpace // delayed white space
 
 	// Positions
@@ -61,19 +70,17 @@ type printer struct {
 	// white space). If there's a difference and SourcePos is set in
 	// ConfigMode, //line comments are used in the output to restore
 	// original source positions for a reader.
-	pos  token.Position // current position in AST (source) space
-	out  token.Position // current position in output space
-	last token.Position // value of pos after calling writeString
+	pos     token.Position // current position in AST (source) space
+	out     token.Position // current position in output space
+	last    token.Position // value of pos after calling writeString
+	linePtr *int           // if set, record out.Line for the next token in *linePtr
 
 	// The list of all source comments, in order of appearance.
 	comments        []*ast.CommentGroup // may be nil
-	cindex          int                 // current comment index
 	useNodeComments bool                // if not set, ignore lead and line comments of nodes
 
 	// Information about p.comments[p.cindex]; set up by nextComment.
-	comment        *ast.CommentGroup // = p.comments[p.cindex]; or nil
-	commentOffset  int               // = p.posFor(p.comments[p.cindex].List[0].Pos()).Offset; or infinity
-	commentNewline bool              // true if the comment group contains newlines
+	commentInfo
 
 	// Cache of already computed node sizes.
 	nodeSizes map[ast.Node]int
@@ -93,6 +100,14 @@ func (p *printer) init(cfg *Config, fset *token.FileSet, nodeSizes map[ast.Node]
 	p.cachedPos = -1
 }
 
+func (p *printer) internalError(msg ...interface{}) {
+	if debug {
+		fmt.Print(p.pos.String() + ": ")
+		fmt.Println(msg...)
+		panic("go/printer")
+	}
+}
+
 // commentsHaveNewline reports whether a list of comments belonging to
 // an *ast.CommentGroup contains newlines. Because the position information
 // may only be partially correct, we also have to read the comment text.
@@ -129,12 +144,49 @@ func (p *printer) nextComment() {
 	p.commentOffset = infinity
 }
 
-func (p *printer) internalError(msg ...interface{}) {
-	if debug {
-		fmt.Print(p.pos.String() + ": ")
-		fmt.Println(msg...)
-		panic("go/printer")
+// commentBefore returns true iff the current comment group occurs
+// before the next position in the source code and printing it does
+// not introduce implicit semicolons.
+//
+func (p *printer) commentBefore(next token.Position) bool {
+	return p.commentOffset < next.Offset && (!p.impliedSemi || !p.commentNewline)
+}
+
+// commentSizeBefore returns the estimated size of the
+// comments on the same line before the next position.
+//
+func (p *printer) commentSizeBefore(next token.Position) int {
+	// save/restore current p.commentInfo (p.nextComment() modifies it)
+	defer func(info commentInfo) {
+		p.commentInfo = info
+	}(p.commentInfo)
+
+	size := 0
+	for p.commentBefore(next) {
+		for _, c := range p.comment.List {
+			size += len(c.Text)
+		}
+		p.nextComment()
 	}
+	return size
+}
+
+// recordLine records the output line number for the next non-whitespace
+// token in *linePtr. It is used to compute an accurate line number for a
+// formatted construct, independent of pending (not yet emitted) whitespace
+// or comments.
+//
+func (p *printer) recordLine(linePtr *int) {
+	p.linePtr = linePtr
+}
+
+// linesFrom returns the number of output lines between the current
+// output line and the line argument, ignoring any pending (not yet
+// emitted) whitespace or comments. It is used to compute an accurate
+// size (in number of lines) for a formatted construct.
+//
+func (p *printer) linesFrom(line int) int {
+	return p.out.Line - line
 }
 
 func (p *printer) posFor(pos token.Pos) token.Position {
@@ -675,10 +727,14 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (wro
 
 	if last != nil {
 		// if the last comment is a /*-style comment and the next item
-		// follows on the same line but is not a comma or a "closing"
-		// token, add an extra blank for separation
-		if last.Text[1] == '*' && p.lineFor(last.Pos()) == next.Line && tok != token.COMMA &&
-			tok != token.RPAREN && tok != token.RBRACK && tok != token.RBRACE {
+		// follows on the same line but is not a comma, and not a "closing"
+		// token immediately following its corresponding "opening" token,
+		// add an extra blank for separation unless explicitly disabled
+		if p.mode&noExtraBlank == 0 &&
+			last.Text[1] == '*' && p.lineFor(last.Pos()) == next.Line &&
+			tok != token.COMMA &&
+			(tok != token.RPAREN || p.prevOpen == token.LPAREN) &&
+			(tok != token.RBRACK || p.prevOpen == token.LBRACK) {
 			p.writeByte(' ', 1)
 		}
 		// ensure that there is a line break after a //-style comment,
@@ -735,12 +791,8 @@ func (p *printer) writeWhitespace(n int) {
 	}
 
 	// shift remaining entries down
-	i := 0
-	for ; n < len(p.wsbuf); n++ {
-		p.wsbuf[i] = p.wsbuf[n]
-		i++
-	}
-	p.wsbuf = p.wsbuf[0:i]
+	l := copy(p.wsbuf, p.wsbuf[n:])
+	p.wsbuf = p.wsbuf[:l]
 }
 
 // ----------------------------------------------------------------------------
@@ -790,6 +842,17 @@ func (p *printer) print(args ...interface{}) {
 		var isLit bool
 		var impliedSemi bool // value for p.impliedSemi after this arg
 
+		// record previous opening token, if any
+		switch p.lastTok {
+		case token.ILLEGAL:
+			// ignore (white space)
+		case token.LPAREN, token.LBRACK:
+			p.prevOpen = p.lastTok
+		default:
+			// other tokens followed any opening token
+			p.prevOpen = token.ILLEGAL
+		}
+
 		switch x := arg.(type) {
 		case pmode:
 			// toggle printer mode
@@ -899,19 +962,17 @@ func (p *printer) print(args ...interface{}) {
 			}
 		}
 
+		// the next token starts now - record its line number if requested
+		if p.linePtr != nil {
+			*p.linePtr = p.out.Line
+			p.linePtr = nil
+		}
+
 		p.writeString(next, data, isLit)
 		p.impliedSemi = impliedSemi
 	}
 }
 
-// commentBefore returns true iff the current comment group occurs
-// before the next position in the source code and printing it does
-// not introduce implicit semicolons.
-//
-func (p *printer) commentBefore(next token.Position) (result bool) {
-	return p.commentOffset < next.Offset && (!p.impliedSemi || !p.commentNewline)
-}
-
 // flush prints any pending comments and whitespace occurring textually
 // before the position of the next token tok. The flush result indicates
 // if a newline was written or if a formfeed was dropped from the whitespace
diff --git a/src/pkg/go/printer/printer_test.go b/src/pkg/go/printer/printer_test.go
index 8454ac1..306928a 100644
--- a/src/pkg/go/printer/printer_test.go
+++ b/src/pkg/go/printer/printer_test.go
@@ -63,7 +63,7 @@ func format(src []byte, mode checkMode) ([]byte, error) {
 		return nil, fmt.Errorf("print: %s", err)
 	}
 
-	// make sure formated output is syntactically correct
+	// make sure formatted output is syntactically correct
 	res := buf.Bytes()
 	if _, err := parser.ParseFile(fset, "", res, 0); err != nil {
 		return nil, fmt.Errorf("re-parse: %s\n%s", err, buf.Bytes())
@@ -179,7 +179,7 @@ func check(t *testing.T, source, golden string, mode checkMode) {
 		// test running past time out
 		t.Errorf("%s: running too slowly", source)
 	case <-cc:
-		// test finished within alloted time margin
+		// test finished within allotted time margin
 	}
 }
 
@@ -212,7 +212,7 @@ func TestFiles(t *testing.T) {
 	}
 }
 
-// TestLineComments, using a simple test case, checks that consequtive line
+// TestLineComments, using a simple test case, checks that consecutive line
 // comments are properly terminated with a newline even if the AST position
 // information is incorrect.
 //
diff --git a/src/pkg/go/printer/testdata/comments.golden b/src/pkg/go/printer/testdata/comments.golden
index 610a42a..b1af795 100644
--- a/src/pkg/go/printer/testdata/comments.golden
+++ b/src/pkg/go/printer/testdata/comments.golden
@@ -494,16 +494,21 @@ func _() {
 func _( /* this */ x /* is */ /* an */ int) {
 }
 
-func _( /* no params */)	{}
+func _( /* no params - extra blank before and after comment */ )	{}
+func _(a, b int /* params - no extra blank after comment */)		{}
+
+func _()	{ f( /* no args - extra blank before and after comment */ ) }
+func _()	{ f(a, b /* args - no extra blank after comment */) }
 
 func _() {
-	f( /* no args */)
+	f( /* no args - extra blank before and after comment */ )
+	f(a, b /* args - no extra blank after comment */)
 }
 
 func ( /* comment1 */ T /* comment2 */) _()	{}
 
-func _() { /* one-line functions with comments are formatted as multi-line functions */
-}
+func _()	{ /* "short-ish one-line functions with comments are formatted as multi-line functions */ }
+func _()	{ x := 0; /* comment */ y = x /* comment */ }
 
 func _() {
 	_ = 0
diff --git a/src/pkg/go/printer/testdata/comments.input b/src/pkg/go/printer/testdata/comments.input
index d121dd4..983e2b2 100644
--- a/src/pkg/go/printer/testdata/comments.input
+++ b/src/pkg/go/printer/testdata/comments.input
@@ -500,15 +500,21 @@ func _() {
 func _(/* this */x/* is *//* an */ int) {
 }
 
-func _(/* no params */) {}
+func _(/* no params - extra blank before and after comment */) {}
+func _(a, b int /* params - no extra blank after comment */) {}
+
+func _() { f(/* no args - extra blank before and after comment */) }
+func _() { f(a, b /* args - no extra blank after comment */) }
 
 func _() {
-	f(/* no args */)
+	f(/* no args - extra blank before and after comment */)
+	f(a, b /* args - no extra blank after comment */)
 }
 
 func (/* comment1 */ T /* comment2 */) _() {}
 
-func _() { /* one-line functions with comments are formatted as multi-line functions */ }
+func _() { /* "short-ish one-line functions with comments are formatted as multi-line functions */ }
+func _() { x := 0; /* comment */ y = x /* comment */ }
 
 func _() {
 	_ = 0
diff --git a/src/pkg/go/printer/testdata/comments2.golden b/src/pkg/go/printer/testdata/comments2.golden
index d3b50bf..7676a26 100644
--- a/src/pkg/go/printer/testdata/comments2.golden
+++ b/src/pkg/go/printer/testdata/comments2.golden
@@ -77,3 +77,29 @@ func main() {
 		println("test")
 	}
 }
+
+func issue5623() {
+L:
+	_ = yyyyyyyyyyyyyyyy			// comment - should be aligned
+	_ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx	/* comment */
+
+	_ = yyyyyyyyyyyyyyyy			/* comment - should be aligned */
+	_ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx	// comment
+
+LLLLLLL:
+	_ = yyyyyyyyyyyyyyyy			// comment - should be aligned
+	_ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx	// comment
+
+LL:
+LLLLL:
+	_ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx	/* comment */
+	_ = yyyyyyyyyyyyyyyy			/* comment - should be aligned */
+
+	_ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx	// comment
+	_ = yyyyyyyyyyyyyyyy			// comment - should be aligned
+
+	// test case from issue
+label:
+	mask := uint64(1)<<c - 1		// Allocation mask
+	used := atomic.LoadUint64(&h.used)	// Current allocations
+}
diff --git a/src/pkg/go/printer/testdata/comments2.input b/src/pkg/go/printer/testdata/comments2.input
index 6f8c85c..4a055c8 100644
--- a/src/pkg/go/printer/testdata/comments2.input
+++ b/src/pkg/go/printer/testdata/comments2.input
@@ -76,4 +76,30 @@ prints test 5 times
    for i := 0; i < 5; i++ {
       println("test")
    }
-}
\ No newline at end of file
+}
+
+func issue5623() {
+L:
+   _ = yyyyyyyyyyyyyyyy // comment - should be aligned
+   _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx /* comment */
+
+   _ = yyyyyyyyyyyyyyyy /* comment - should be aligned */
+   _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment
+
+LLLLLLL:
+   _ = yyyyyyyyyyyyyyyy // comment - should be aligned
+   _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment
+
+LL:
+LLLLL:
+   _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx /* comment */
+   _ = yyyyyyyyyyyyyyyy /* comment - should be aligned */
+
+   _ = xxxxxxxxxxxxxxxxxxxxxxxxxxxx // comment
+   _ = yyyyyyyyyyyyyyyy // comment - should be aligned
+
+// test case from issue
+label:
+   mask := uint64(1)<<c - 1 // Allocation mask
+   used := atomic.LoadUint64(&h.used) // Current allocations
+}
diff --git a/src/pkg/go/printer/testdata/declarations.golden b/src/pkg/go/printer/testdata/declarations.golden
index 0331615..a27f21f 100644
--- a/src/pkg/go/printer/testdata/declarations.golden
+++ b/src/pkg/go/printer/testdata/declarations.golden
@@ -397,6 +397,21 @@ func _() {
 	}
 }
 
+// use the formatted output rather than the input to decide when to align
+// (was issue 4505)
+const (
+	short		= 2 * (1 + 2)
+	aMuchLongerName	= 3
+)
+
+var (
+	short		= X{}
+	aMuchLongerName	= X{}
+
+	x1	= X{}	// foo
+	x2	= X{}	// foo
+)
+
 func _() {
 	type (
 		xxxxxx	int
@@ -723,7 +738,8 @@ func _() int {
 }
 
 // making function declarations safe for new semicolon rules
-func _() { /* multi-line func because of comment */
+func _()	{ /* single-line function because of "short-ish" comment */ }
+func _() { /* multi-line function because of "long-ish" comment - much more comment text is following here */ /* and more */
 }
 
 func _() {
diff --git a/src/pkg/go/printer/testdata/declarations.input b/src/pkg/go/printer/testdata/declarations.input
index dbdbdfe..d9951d3 100644
--- a/src/pkg/go/printer/testdata/declarations.input
+++ b/src/pkg/go/printer/testdata/declarations.input
@@ -409,6 +409,24 @@ func _() {
 	}
 }
 
+// use the formatted output rather than the input to decide when to align
+// (was issue 4505)
+const (
+	short = 2 * (
+	1 + 2)
+	aMuchLongerName = 3
+)
+
+var (
+	short = X{
+	}
+	aMuchLongerName = X{}
+
+	x1 = X{} // foo
+	x2 = X{
+	} // foo
+)
+
 func _() {
 	type (
 		xxxxxx int
@@ -737,7 +755,8 @@ func _() int {
 
 
 // making function declarations safe for new semicolon rules
-func _() { /* multi-line func because of comment */ }
+func _() { /* single-line function because of "short-ish" comment */ }
+func _() { /* multi-line function because of "long-ish" comment - much more comment text is following here */ /* and more */ }
 
 func _() {
 /* multi-line func because block is on multiple lines */ }
diff --git a/src/pkg/go/scanner/scanner.go b/src/pkg/go/scanner/scanner.go
index 1e259d5..cec82ea 100644
--- a/src/pkg/go/scanner/scanner.go
+++ b/src/pkg/go/scanner/scanner.go
@@ -148,11 +148,14 @@ func (s *Scanner) interpretLineComment(text []byte) {
 		// get filename and line number, if any
 		if i := bytes.LastIndex(text, []byte{':'}); i > 0 {
 			if line, err := strconv.Atoi(string(text[i+1:])); err == nil && line > 0 {
-				// valid //line filename:line comment;
-				filename := filepath.Clean(string(text[len(prefix):i]))
-				if !filepath.IsAbs(filename) {
-					// make filename relative to current directory
-					filename = filepath.Join(s.dir, filename)
+				// valid //line filename:line comment
+				filename := string(bytes.TrimSpace(text[len(prefix):i]))
+				if filename != "" {
+					filename = filepath.Clean(filename)
+					if !filepath.IsAbs(filename) {
+						// make filename relative to current directory
+						filename = filepath.Join(s.dir, filename)
+					}
 				}
 				// update scanner position
 				s.file.AddLineInfo(s.lineOffset+len(text)+1, filename, line) // +len(text)+1 since comment applies to next line
@@ -358,73 +361,94 @@ exit:
 	return tok, string(s.src[offs:s.offset])
 }
 
-func (s *Scanner) scanEscape(quote rune) {
+// scanEscape parses an escape sequence where rune is the accepted
+// escaped quote. In case of a syntax error, it stops at the offending
+// character (without consuming it) and returns false. Otherwise
+// it returns true.
+func (s *Scanner) scanEscape(quote rune) bool {
 	offs := s.offset
 
-	var i, base, max uint32
+	var n int
+	var base, max uint32
 	switch s.ch {
 	case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote:
 		s.next()
-		return
+		return true
 	case '0', '1', '2', '3', '4', '5', '6', '7':
-		i, base, max = 3, 8, 255
+		n, base, max = 3, 8, 255
 	case 'x':
 		s.next()
-		i, base, max = 2, 16, 255
+		n, base, max = 2, 16, 255
 	case 'u':
 		s.next()
-		i, base, max = 4, 16, unicode.MaxRune
+		n, base, max = 4, 16, unicode.MaxRune
 	case 'U':
 		s.next()
-		i, base, max = 8, 16, unicode.MaxRune
+		n, base, max = 8, 16, unicode.MaxRune
 	default:
-		s.next() // always make progress
-		s.error(offs, "unknown escape sequence")
-		return
+		msg := "unknown escape sequence"
+		if s.ch < 0 {
+			msg = "escape sequence not terminated"
+		}
+		s.error(offs, msg)
+		return false
 	}
 
 	var x uint32
-	for ; i > 0 && s.ch != quote && s.ch >= 0; i-- {
+	for n > 0 {
 		d := uint32(digitVal(s.ch))
 		if d >= base {
-			s.error(s.offset, "illegal character in escape sequence")
-			break
+			msg := fmt.Sprintf("illegal character %#U in escape sequence", s.ch)
+			if s.ch < 0 {
+				msg = "escape sequence not terminated"
+			}
+			s.error(s.offset, msg)
+			return false
 		}
 		x = x*base + d
 		s.next()
+		n--
 	}
-	// in case of an error, consume remaining chars
-	for ; i > 0 && s.ch != quote && s.ch >= 0; i-- {
-		s.next()
-	}
+
 	if x > max || 0xD800 <= x && x < 0xE000 {
 		s.error(offs, "escape sequence is invalid Unicode code point")
+		return false
 	}
+
+	return true
 }
 
-func (s *Scanner) scanChar() string {
+func (s *Scanner) scanRune() string {
 	// '\'' opening already consumed
 	offs := s.offset - 1
 
+	valid := true
 	n := 0
-	for s.ch != '\'' {
+	for {
 		ch := s.ch
-		n++
-		s.next()
 		if ch == '\n' || ch < 0 {
-			s.error(offs, "character literal not terminated")
-			n = 1
+			// only report error if we don't have one already
+			if valid {
+				s.error(offs, "rune literal not terminated")
+				valid = false
+			}
 			break
 		}
+		s.next()
+		if ch == '\'' {
+			break
+		}
+		n++
 		if ch == '\\' {
-			s.scanEscape('\'')
+			if !s.scanEscape('\'') {
+				valid = false
+			}
+			// continue to read to closing quote
 		}
 	}
 
-	s.next()
-
-	if n != 1 {
-		s.error(offs, "illegal character literal")
+	if valid && n != 1 {
+		s.error(offs, "illegal rune literal")
 	}
 
 	return string(s.src[offs:s.offset])
@@ -434,11 +458,14 @@ func (s *Scanner) scanString() string {
 	// '"' opening already consumed
 	offs := s.offset - 1
 
-	for s.ch != '"' {
+	for {
 		ch := s.ch
-		s.next()
 		if ch == '\n' || ch < 0 {
-			s.error(offs, "string not terminated")
+			s.error(offs, "string literal not terminated")
+			break
+		}
+		s.next()
+		if ch == '"' {
 			break
 		}
 		if ch == '\\' {
@@ -446,8 +473,6 @@ func (s *Scanner) scanString() string {
 		}
 	}
 
-	s.next()
-
 	return string(s.src[offs:s.offset])
 }
 
@@ -468,20 +493,21 @@ func (s *Scanner) scanRawString() string {
 	offs := s.offset - 1
 
 	hasCR := false
-	for s.ch != '`' {
+	for {
 		ch := s.ch
+		if ch < 0 {
+			s.error(offs, "raw string literal not terminated")
+			break
+		}
 		s.next()
+		if ch == '`' {
+			break
+		}
 		if ch == '\r' {
 			hasCR = true
 		}
-		if ch < 0 {
-			s.error(offs, "string not terminated")
-			break
-		}
 	}
 
-	s.next()
-
 	lit := s.src[offs:s.offset]
 	if hasCR {
 		lit = stripCR(lit)
@@ -617,7 +643,7 @@ scanAgain:
 		case '\'':
 			insertSemi = true
 			tok = token.CHAR
-			lit = s.scanChar()
+			lit = s.scanRune()
 		case '`':
 			insertSemi = true
 			tok = token.STRING
diff --git a/src/pkg/go/scanner/scanner_test.go b/src/pkg/go/scanner/scanner_test.go
index 8c64c2b..fc450d8 100644
--- a/src/pkg/go/scanner/scanner_test.go
+++ b/src/pkg/go/scanner/scanner_test.go
@@ -493,9 +493,9 @@ var segments = []segment{
 	{"\nline3  //line File1.go:100", filepath.Join("dir", "TestLineComments"), 3}, // bad line comment, ignored
 	{"\nline4", filepath.Join("dir", "TestLineComments"), 4},
 	{"\n//line File1.go:100\n  line100", filepath.Join("dir", "File1.go"), 100},
+	{"\n//line  \t :42\n  line1", "", 42},
 	{"\n//line File2.go:200\n  line200", filepath.Join("dir", "File2.go"), 200},
-	{"\n//line :1\n  line1", "dir", 1},
-	{"\n//line foo:42\n  line42", filepath.Join("dir", "foo"), 42},
+	{"\n//line foo\t:42\n  line42", filepath.Join("dir", "foo"), 42},
 	{"\n //line foo:42\n  line44", filepath.Join("dir", "foo"), 44},           // bad line comment, ignored
 	{"\n//line foo 42\n  line46", filepath.Join("dir", "foo"), 46},            // bad line comment, ignored
 	{"\n//line foo:42 extra text\n  line48", filepath.Join("dir", "foo"), 48}, // bad line comment, ignored
@@ -631,7 +631,7 @@ type errorCollector struct {
 	pos token.Position // last error position encountered
 }
 
-func checkError(t *testing.T, src string, tok token.Token, pos int, err string) {
+func checkError(t *testing.T, src string, tok token.Token, pos int, lit, err string) {
 	var s Scanner
 	var h errorCollector
 	eh := func(pos token.Position, msg string) {
@@ -640,13 +640,12 @@ func checkError(t *testing.T, src string, tok token.Token, pos int, err string)
 		h.pos = pos
 	}
 	s.Init(fset.AddFile("", fset.Base(), len(src)), []byte(src), eh, ScanComments|dontInsertSemis)
-	_, tok0, _ := s.Scan()
-	_, tok1, _ := s.Scan()
+	_, tok0, lit0 := s.Scan()
 	if tok0 != tok {
 		t.Errorf("%q: got %s, expected %s", src, tok0, tok)
 	}
-	if tok1 != token.EOF {
-		t.Errorf("%q: got %s, expected EOF", src, tok1)
+	if tok0 != token.ILLEGAL && lit0 != lit {
+		t.Errorf("%q: got literal %q, expected %q", src, lit0, lit)
 	}
 	cnt := 0
 	if err != "" {
@@ -667,43 +666,71 @@ var errors = []struct {
 	src string
 	tok token.Token
 	pos int
+	lit string
 	err string
 }{
-	{"\a", token.ILLEGAL, 0, "illegal character U+0007"},
-	{`#`, token.ILLEGAL, 0, "illegal character U+0023 '#'"},
-	{`…`, token.ILLEGAL, 0, "illegal character U+2026 '…'"},
-	{`' '`, token.CHAR, 0, ""},
-	{`''`, token.CHAR, 0, "illegal character literal"},
-	{`'\8'`, token.CHAR, 2, "unknown escape sequence"},
-	{`'\08'`, token.CHAR, 3, "illegal character in escape sequence"},
-	{`'\x0g'`, token.CHAR, 4, "illegal character in escape sequence"},
-	{`'\Uffffffff'`, token.CHAR, 2, "escape sequence is invalid Unicode code point"},
-	{`'`, token.CHAR, 0, "character literal not terminated"},
-	{`""`, token.STRING, 0, ""},
-	{`"`, token.STRING, 0, "string not terminated"},
-	{"``", token.STRING, 0, ""},
-	{"`", token.STRING, 0, "string not terminated"},
-	{"/**/", token.COMMENT, 0, ""},
-	{"/*", token.COMMENT, 0, "comment not terminated"},
-	{"077", token.INT, 0, ""},
-	{"078.", token.FLOAT, 0, ""},
-	{"07801234567.", token.FLOAT, 0, ""},
-	{"078e0", token.FLOAT, 0, ""},
-	{"078", token.INT, 0, "illegal octal number"},
-	{"07800000009", token.INT, 0, "illegal octal number"},
-	{"0x", token.INT, 0, "illegal hexadecimal number"},
-	{"0X", token.INT, 0, "illegal hexadecimal number"},
-	{"\"abc\x00def\"", token.STRING, 4, "illegal character NUL"},
-	{"\"abc\x80def\"", token.STRING, 4, "illegal UTF-8 encoding"},
-	{"\ufeff\ufeff", token.ILLEGAL, 3, "illegal byte order mark"},            // only first BOM is ignored
-	{"//\ufeff", token.COMMENT, 2, "illegal byte order mark"},                // only first BOM is ignored
-	{"'\ufeff" + `'`, token.CHAR, 1, "illegal byte order mark"},              // only first BOM is ignored
-	{`"` + "abc\ufeffdef" + `"`, token.STRING, 4, "illegal byte order mark"}, // only first BOM is ignored
+	{"\a", token.ILLEGAL, 0, "", "illegal character U+0007"},
+	{`#`, token.ILLEGAL, 0, "", "illegal character U+0023 '#'"},
+	{`…`, token.ILLEGAL, 0, "", "illegal character U+2026 '…'"},
+	{`' '`, token.CHAR, 0, `' '`, ""},
+	{`''`, token.CHAR, 0, `''`, "illegal rune literal"},
+	{`'12'`, token.CHAR, 0, `'12'`, "illegal rune literal"},
+	{`'123'`, token.CHAR, 0, `'123'`, "illegal rune literal"},
+	{`'\0'`, token.CHAR, 3, `'\0'`, "illegal character U+0027 ''' in escape sequence"},
+	{`'\07'`, token.CHAR, 4, `'\07'`, "illegal character U+0027 ''' in escape sequence"},
+	{`'\8'`, token.CHAR, 2, `'\8'`, "unknown escape sequence"},
+	{`'\08'`, token.CHAR, 3, `'\08'`, "illegal character U+0038 '8' in escape sequence"},
+	{`'\x'`, token.CHAR, 3, `'\x'`, "illegal character U+0027 ''' in escape sequence"},
+	{`'\x0'`, token.CHAR, 4, `'\x0'`, "illegal character U+0027 ''' in escape sequence"},
+	{`'\x0g'`, token.CHAR, 4, `'\x0g'`, "illegal character U+0067 'g' in escape sequence"},
+	{`'\u'`, token.CHAR, 3, `'\u'`, "illegal character U+0027 ''' in escape sequence"},
+	{`'\u0'`, token.CHAR, 4, `'\u0'`, "illegal character U+0027 ''' in escape sequence"},
+	{`'\u00'`, token.CHAR, 5, `'\u00'`, "illegal character U+0027 ''' in escape sequence"},
+	{`'\u000'`, token.CHAR, 6, `'\u000'`, "illegal character U+0027 ''' in escape sequence"},
+	{`'\u000`, token.CHAR, 6, `'\u000`, "escape sequence not terminated"},
+	{`'\u0000'`, token.CHAR, 0, `'\u0000'`, ""},
+	{`'\U'`, token.CHAR, 3, `'\U'`, "illegal character U+0027 ''' in escape sequence"},
+	{`'\U0'`, token.CHAR, 4, `'\U0'`, "illegal character U+0027 ''' in escape sequence"},
+	{`'\U00'`, token.CHAR, 5, `'\U00'`, "illegal character U+0027 ''' in escape sequence"},
+	{`'\U000'`, token.CHAR, 6, `'\U000'`, "illegal character U+0027 ''' in escape sequence"},
+	{`'\U0000'`, token.CHAR, 7, `'\U0000'`, "illegal character U+0027 ''' in escape sequence"},
+	{`'\U00000'`, token.CHAR, 8, `'\U00000'`, "illegal character U+0027 ''' in escape sequence"},
+	{`'\U000000'`, token.CHAR, 9, `'\U000000'`, "illegal character U+0027 ''' in escape sequence"},
+	{`'\U0000000'`, token.CHAR, 10, `'\U0000000'`, "illegal character U+0027 ''' in escape sequence"},
+	{`'\U0000000`, token.CHAR, 10, `'\U0000000`, "escape sequence not terminated"},
+	{`'\U00000000'`, token.CHAR, 0, `'\U00000000'`, ""},
+	{`'\Uffffffff'`, token.CHAR, 2, `'\Uffffffff'`, "escape sequence is invalid Unicode code point"},
+	{`'`, token.CHAR, 0, `'`, "rune literal not terminated"},
+	{`'\`, token.CHAR, 2, `'\`, "escape sequence not terminated"},
+	{"'\n", token.CHAR, 0, "'", "rune literal not terminated"},
+	{"'\n   ", token.CHAR, 0, "'", "rune literal not terminated"},
+	{`""`, token.STRING, 0, `""`, ""},
+	{`"abc`, token.STRING, 0, `"abc`, "string literal not terminated"},
+	{"\"abc\n", token.STRING, 0, `"abc`, "string literal not terminated"},
+	{"\"abc\n   ", token.STRING, 0, `"abc`, "string literal not terminated"},
+	{"``", token.STRING, 0, "``", ""},
+	{"`", token.STRING, 0, "`", "raw string literal not terminated"},
+	{"/**/", token.COMMENT, 0, "/**/", ""},
+	{"/*", token.COMMENT, 0, "/*", "comment not terminated"},
+	{"077", token.INT, 0, "077", ""},
+	{"078.", token.FLOAT, 0, "078.", ""},
+	{"07801234567.", token.FLOAT, 0, "07801234567.", ""},
+	{"078e0", token.FLOAT, 0, "078e0", ""},
+	{"078", token.INT, 0, "078", "illegal octal number"},
+	{"07800000009", token.INT, 0, "07800000009", "illegal octal number"},
+	{"0x", token.INT, 0, "0x", "illegal hexadecimal number"},
+	{"0X", token.INT, 0, "0X", "illegal hexadecimal number"},
+	{"\"abc\x00def\"", token.STRING, 4, "\"abc\x00def\"", "illegal character NUL"},
+	{"\"abc\x80def\"", token.STRING, 4, "\"abc\x80def\"", "illegal UTF-8 encoding"},
+	{"\ufeff\ufeff", token.ILLEGAL, 3, "\ufeff\ufeff", "illegal byte order mark"},                        // only first BOM is ignored
+	{"//\ufeff", token.COMMENT, 2, "//\ufeff", "illegal byte order mark"},                                // only first BOM is ignored
+	{"'\ufeff" + `'`, token.CHAR, 1, "'\ufeff" + `'`, "illegal byte order mark"},                         // only first BOM is ignored
+	{`"` + "abc\ufeffdef" + `"`, token.STRING, 4, `"` + "abc\ufeffdef" + `"`, "illegal byte order mark"}, // only first BOM is ignored
 }
 
 func TestScanErrors(t *testing.T) {
 	for _, e := range errors {
-		checkError(t, e.src, e.tok, e.pos, e.err)
+		checkError(t, e.src, e.tok, e.pos, e.lit, e.err)
 	}
 }
 
diff --git a/src/pkg/hash/crc32/crc32_amd64.go b/src/pkg/hash/crc32/crc32_amd64.go
deleted file mode 100644
index b5bc6d3..0000000
--- a/src/pkg/hash/crc32/crc32_amd64.go
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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.
-
-package crc32
-
-// This file contains the code to call the SSE 4.2 version of the Castagnoli
-// CRC.
-
-// haveSSE42 is defined in crc_amd64.s and uses CPUID to test for SSE 4.2
-// support.
-func haveSSE42() bool
-
-// castagnoliSSE42 is defined in crc_amd64.s and uses the SSE4.2 CRC32
-// instruction.
-func castagnoliSSE42(crc uint32, p []byte) uint32
-
-var sse42 = haveSSE42()
-
-func updateCastagnoli(crc uint32, p []byte) uint32 {
-	if sse42 {
-		return castagnoliSSE42(crc, p)
-	}
-	return update(crc, castagnoliTable, p)
-}
diff --git a/src/pkg/hash/crc32/crc32_amd64p32.s b/src/pkg/hash/crc32/crc32_amd64p32.s
new file mode 100644
index 0000000..e34f208
--- /dev/null
+++ b/src/pkg/hash/crc32/crc32_amd64p32.s
@@ -0,0 +1,64 @@
+// 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.
+
+#include "../../../cmd/ld/textflag.h"
+
+// func castagnoliSSE42(crc uint32, p []byte) uint32
+TEXT ·castagnoliSSE42(SB),NOSPLIT,$0
+	MOVL crc+0(FP), AX  // CRC value
+	MOVL p+4(FP), SI  // data pointer
+	MOVL p_len+8(FP), CX  // len(p)
+
+	NOTL AX
+
+	/* If there's less than 8 bytes to process, we do it byte-by-byte. */
+	CMPQ CX, $8
+	JL cleanup
+
+	/* Process individual bytes until the input is 8-byte aligned. */
+startup:
+	MOVQ SI, BX
+	ANDQ $7, BX
+	JZ aligned
+
+	CRC32B (SI), AX
+	DECQ CX
+	INCQ SI
+	JMP startup
+
+aligned:
+	/* The input is now 8-byte aligned and we can process 8-byte chunks. */
+	CMPQ CX, $8
+	JL cleanup
+
+	CRC32Q (SI), AX
+	ADDQ $8, SI
+	SUBQ $8, CX
+	JMP aligned
+
+cleanup:
+	/* We may have some bytes left over that we process one at a time. */
+	CMPQ CX, $0
+	JE done
+
+	CRC32B (SI), AX
+	INCQ SI
+	DECQ CX
+	JMP cleanup
+
+done:
+	NOTL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func haveSSE42() bool
+TEXT ·haveSSE42(SB),NOSPLIT,$0
+	XORQ AX, AX
+	INCL AX
+	CPUID
+	SHRQ $20, CX
+	ANDQ $1, CX
+	MOVB CX, ret+0(FP)
+	RET
+
diff --git a/src/pkg/hash/crc32/crc32_amd64x.go b/src/pkg/hash/crc32/crc32_amd64x.go
new file mode 100644
index 0000000..b7e3599
--- /dev/null
+++ b/src/pkg/hash/crc32/crc32_amd64x.go
@@ -0,0 +1,27 @@
+// 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.
+
+// +build amd64 amd64p32
+
+package crc32
+
+// This file contains the code to call the SSE 4.2 version of the Castagnoli
+// CRC.
+
+// haveSSE42 is defined in crc_amd64.s and uses CPUID to test for SSE 4.2
+// support.
+func haveSSE42() bool
+
+// castagnoliSSE42 is defined in crc_amd64.s and uses the SSE4.2 CRC32
+// instruction.
+func castagnoliSSE42(crc uint32, p []byte) uint32
+
+var sse42 = haveSSE42()
+
+func updateCastagnoli(crc uint32, p []byte) uint32 {
+	if sse42 {
+		return castagnoliSSE42(crc, p)
+	}
+	return update(crc, castagnoliTable, p)
+}
diff --git a/src/pkg/hash/fnv/fnv.go b/src/pkg/hash/fnv/fnv.go
index b5ecd4a..c020661 100644
--- a/src/pkg/hash/fnv/fnv.go
+++ b/src/pkg/hash/fnv/fnv.go
@@ -4,7 +4,8 @@
 
 // Package fnv implements FNV-1 and FNV-1a, non-cryptographic hash functions
 // created by Glenn Fowler, Landon Curt Noll, and Phong Vo.
-// See http://isthe.com/chongo/tech/comp/fnv/.
+// See
+// http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function.
 package fnv
 
 import (
diff --git a/src/pkg/html/escape_test.go b/src/pkg/html/escape_test.go
index b405d4b..2d7ad8a 100644
--- a/src/pkg/html/escape_test.go
+++ b/src/pkg/html/escape_test.go
@@ -64,6 +64,24 @@ var unescapeTests = []unescapeTest{
 		"Footnote&#x87;",
 		"Footnote‡",
 	},
+	// Handle single ampersand.
+	{
+		"copySingleAmpersand",
+		"&",
+		"&",
+	},
+	// Handle ampersand followed by non-entity.
+	{
+		"copyAmpersandNonEntity",
+		"text &test",
+		"text &test",
+	},
+	// Handle "&#".
+	{
+		"copyAmpersandHash",
+		"text &#",
+		"text &#",
+	},
 }
 
 func TestUnescape(t *testing.T) {
diff --git a/src/pkg/html/template/attr.go b/src/pkg/html/template/attr.go
index 3ea0288..d65d340 100644
--- a/src/pkg/html/template/attr.go
+++ b/src/pkg/html/template/attr.go
@@ -90,7 +90,7 @@ var attrTypeMap = map[string]contentType{
 	"name":            contentTypePlain,
 	"novalidate":      contentTypeUnsafe,
 	// Skip handler names from
-	// http://www.w3.org/TR/html5/Overview.html#event-handlers-on-elements-document-objects-and-window-objects
+	// http://www.w3.org/TR/html5/webappapis.html#event-handlers-on-elements,-document-objects,-and-window-objects
 	// since we have special handling in attrType.
 	"open":        contentTypePlain,
 	"optimum":     contentTypePlain,
@@ -160,7 +160,7 @@ func attrType(name string) contentType {
 
 	// Heuristics to prevent "javascript:..." injection in custom
 	// data attributes and custom attributes like g:tweetUrl.
-	// http://www.w3.org/TR/html5/elements.html#embedding-custom-non-visible-data-with-the-data-attributes:
+	// http://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes
 	// "Custom data attributes are intended to store custom data
 	//  private to the page or application, for which there are no
 	//  more appropriate attributes or elements."
diff --git a/src/pkg/html/template/content.go b/src/pkg/html/template/content.go
index 41b1116..3715ed5 100644
--- a/src/pkg/html/template/content.go
+++ b/src/pkg/html/template/content.go
@@ -16,7 +16,8 @@ type (
 	//   2. The CSS3 rule production, such as `a[href=~"https:"].foo#bar`.
 	//   3. CSS3 declaration productions, such as `color: red; margin: 2px`.
 	//   4. The CSS3 value production, such as `rgba(0, 0, 255, 127)`.
-	// See http://www.w3.org/TR/css3-syntax/#style
+	// See http://www.w3.org/TR/css3-syntax/#parsing and
+	// https://web.archive.org/web/20090211114933/http://w3.org/TR/css3-syntax#style
 	CSS string
 
 	// HTML encapsulates a known safe HTML document fragment.
diff --git a/src/pkg/html/template/context.go b/src/pkg/html/template/context.go
index eb47e2b..59e794d 100644
--- a/src/pkg/html/template/context.go
+++ b/src/pkg/html/template/context.go
@@ -13,7 +13,7 @@ import (
 //
 // The zero value of type context is the start context for a template that
 // produces an HTML fragment as defined at
-// http://www.w3.org/TR/html5/the-end.html#parsing-html-fragments
+// http://www.w3.org/TR/html5/syntax.html#the-end
 // where the context element is null.
 type context struct {
 	state   state
@@ -96,7 +96,7 @@ const (
 	// stateHTMLCmt occurs inside an <!-- HTML comment -->.
 	stateHTMLCmt
 	// stateRCDATA occurs inside an RCDATA element (<textarea> or <title>)
-	// as described at http://dev.w3.org/html5/spec/syntax.html#elements-0
+	// as described at http://www.w3.org/TR/html5/syntax.html#elements-0
 	stateRCDATA
 	// stateAttr occurs inside an HTML attribute whose content is text.
 	stateAttr
diff --git a/src/pkg/html/template/escape.go b/src/pkg/html/template/escape.go
index 9ae9749..4e37982 100644
--- a/src/pkg/html/template/escape.go
+++ b/src/pkg/html/template/escape.go
@@ -40,10 +40,14 @@ func escapeTemplates(tmpl *Template, names ...string) error {
 			}
 			return err
 		}
-		tmpl.escaped = true
-		tmpl.Tree = tmpl.text.Tree
 	}
 	e.commit()
+	for _, name := range names {
+		if t := tmpl.set[name]; t != nil {
+			t.escaped = true
+			t.Tree = t.text.Tree
+		}
+	}
 	return nil
 }
 
@@ -207,6 +211,18 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
 	return c
 }
 
+// allIdents returns the names of the identifiers under the Ident field of the node,
+// which might be a singleton (Identifier) or a slice (Field).
+func allIdents(node parse.Node) []string {
+	switch node := node.(type) {
+	case *parse.IdentifierNode:
+		return []string{node.Ident}
+	case *parse.FieldNode:
+		return node.Ident
+	}
+	panic("unidentified node type in allIdents")
+}
+
 // ensurePipelineContains ensures that the pipeline has commands with
 // the identifiers in s in order.
 // If the pipeline already has some of the sanitizers, do not interfere.
@@ -229,27 +245,31 @@ func ensurePipelineContains(p *parse.PipeNode, s []string) {
 		idents = p.Cmds[i+1:]
 	}
 	dups := 0
-	for _, id := range idents {
-		if escFnsEq(s[dups], (id.Args[0].(*parse.IdentifierNode)).Ident) {
-			dups++
-			if dups == len(s) {
-				return
+	for _, idNode := range idents {
+		for _, ident := range allIdents(idNode.Args[0]) {
+			if escFnsEq(s[dups], ident) {
+				dups++
+				if dups == len(s) {
+					return
+				}
 			}
 		}
 	}
 	newCmds := make([]*parse.CommandNode, n-len(idents), n+len(s)-dups)
 	copy(newCmds, p.Cmds)
 	// Merge existing identifier commands with the sanitizers needed.
-	for _, id := range idents {
-		pos := id.Args[0].Position()
-		i := indexOfStr((id.Args[0].(*parse.IdentifierNode)).Ident, s, escFnsEq)
-		if i != -1 {
-			for _, name := range s[:i] {
-				newCmds = appendCmd(newCmds, newIdentCmd(name, pos))
+	for _, idNode := range idents {
+		pos := idNode.Args[0].Position()
+		for _, ident := range allIdents(idNode.Args[0]) {
+			i := indexOfStr(ident, s, escFnsEq)
+			if i != -1 {
+				for _, name := range s[:i] {
+					newCmds = appendCmd(newCmds, newIdentCmd(name, pos))
+				}
+				s = s[i+1:]
 			}
-			s = s[i+1:]
 		}
-		newCmds = appendCmd(newCmds, id)
+		newCmds = appendCmd(newCmds, idNode)
 	}
 	// Create any remaining sanitizers.
 	for _, name := range s {
@@ -664,7 +684,7 @@ func contextAfterText(c context, s []byte) (context, int) {
 		i = len(s)
 	}
 	if c.delim == delimSpaceOrTagEnd {
-		// http://www.w3.org/TR/html5/tokenization.html#attribute-value-unquoted-state
+		// http://www.w3.org/TR/html5/syntax.html#attribute-value-(unquoted)-state
 		// lists the runes below as error characters.
 		// Error out because HTML parsers may differ on whether
 		// "<a id= onclick=f("     ends inside id's or onclick's value,
diff --git a/src/pkg/html/template/escape_test.go b/src/pkg/html/template/escape_test.go
index 58383a6..3ccf93e 100644
--- a/src/pkg/html/template/escape_test.go
+++ b/src/pkg/html/template/escape_test.go
@@ -1649,6 +1649,38 @@ func TestEmptyTemplate(t *testing.T) {
 	}
 }
 
+type Issue7379 int
+
+func (Issue7379) SomeMethod(x int) string {
+	return fmt.Sprintf("<%d>", x)
+}
+
+// This is a test for issue 7379: type assertion error caused panic, and then
+// the code to handle the panic breaks escaping. It's hard to see the second
+// problem once the first is fixed, but its fix is trivial so we let that go. See
+// the discussion for issue 7379.
+func TestPipeToMethodIsEscaped(t *testing.T) {
+	tmpl := Must(New("x").Parse("<html>{{0 | .SomeMethod}}</html>\n"))
+	tryExec := func() string {
+		defer func() {
+			panicValue := recover()
+			if panicValue != nil {
+				t.Errorf("panicked: %v\n", panicValue)
+			}
+		}()
+		var b bytes.Buffer
+		tmpl.Execute(&b, Issue7379(0))
+		return b.String()
+	}
+	for i := 0; i < 3; i++ {
+		str := tryExec()
+		const expect = "<html><0></html>\n"
+		if str != expect {
+			t.Errorf("expected %q got %q", expect, str)
+		}
+	}
+}
+
 func BenchmarkEscapedExecute(b *testing.B) {
 	tmpl := Must(New("t").Parse(`<a onclick="alert('{{.}}')">{{.}}</a>`))
 	var buf bytes.Buffer
diff --git a/src/pkg/html/template/html.go b/src/pkg/html/template/html.go
index f25f107..9c069ef 100644
--- a/src/pkg/html/template/html.go
+++ b/src/pkg/html/template/html.go
@@ -50,12 +50,12 @@ func htmlEscaper(args ...interface{}) string {
 // htmlReplacementTable contains the runes that need to be escaped
 // inside a quoted attribute value or in a text node.
 var htmlReplacementTable = []string{
-	// http://www.w3.org/TR/html5/tokenization.html#attribute-value-unquoted-state: "
+	// http://www.w3.org/TR/html5/syntax.html#attribute-value-(unquoted)-state
 	// U+0000 NULL Parse error. Append a U+FFFD REPLACEMENT
 	// CHARACTER character to the current attribute's value.
 	// "
 	// and similarly
-	// http://www.w3.org/TR/html5/tokenization.html#before-attribute-value-state
+	// http://www.w3.org/TR/html5/syntax.html#before-attribute-value-state
 	0:    "\uFFFD",
 	'"':  """,
 	'&':  "&",
diff --git a/src/pkg/html/template/js.go b/src/pkg/html/template/js.go
index d594e0a..999a61e 100644
--- a/src/pkg/html/template/js.go
+++ b/src/pkg/html/template/js.go
@@ -99,7 +99,7 @@ func nextJSCtx(s []byte, preceding jsCtx) jsCtx {
 	return jsCtxDivOp
 }
 
-// regexPrecederKeywords is a set of reserved JS keywords that can precede a
+// regexpPrecederKeywords is a set of reserved JS keywords that can precede a
 // regular expression in JS source.
 var regexpPrecederKeywords = map[string]bool{
 	"break":      true,
diff --git a/src/pkg/html/template/template.go b/src/pkg/html/template/template.go
index 11cc34a..d389658 100644
--- a/src/pkg/html/template/template.go
+++ b/src/pkg/html/template/template.go
@@ -62,6 +62,10 @@ func (t *Template) escape() error {
 
 // Execute applies a parsed template to the specified data object,
 // writing the output to wr.
+// If an error occurs executing the template or writing its output,
+// execution stops, but partial results may already have been written to
+// the output writer.
+// A template may be executed safely in parallel.
 func (t *Template) Execute(wr io.Writer, data interface{}) error {
 	if err := t.escape(); err != nil {
 		return err
@@ -71,6 +75,10 @@ func (t *Template) Execute(wr io.Writer, data interface{}) error {
 
 // ExecuteTemplate applies the template associated with t that has the given
 // name to the specified data object and writes the output to wr.
+// If an error occurs executing the template or writing its output,
+// execution stops, but partial results may already have been written to
+// the output writer.
+// A template may be executed safely in parallel.
 func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
 	tmpl, err := t.lookupAndEscapeTemplate(name)
 	if err != nil {
diff --git a/src/pkg/image/color/palette/gen.go b/src/pkg/image/color/palette/gen.go
index f20c021..4f4d883 100644
--- a/src/pkg/image/color/palette/gen.go
+++ b/src/pkg/image/color/palette/gen.go
@@ -14,6 +14,10 @@ import (
 )
 
 func main() {
+	fmt.Println(`// 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.`)
+	fmt.Println()
 	fmt.Println("// generated by go run gen.go; DO NOT EDIT")
 	fmt.Println()
 	fmt.Println("// Package palette provides standard color palettes.")
diff --git a/src/pkg/image/color/palette/palette.go b/src/pkg/image/color/palette/palette.go
index 3aba740..f761e53 100644
--- a/src/pkg/image/color/palette/palette.go
+++ b/src/pkg/image/color/palette/palette.go
@@ -1,3 +1,7 @@
+// 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.
+
 // generated by go run gen.go; DO NOT EDIT
 
 // Package palette provides standard color palettes.
diff --git a/src/pkg/image/gif/reader.go b/src/pkg/image/gif/reader.go
index 8b0298a..926710a 100644
--- a/src/pkg/image/gif/reader.go
+++ b/src/pkg/image/gif/reader.go
@@ -79,7 +79,8 @@ type decoder struct {
 	imageFields byte
 
 	// From graphics control.
-	transparentIndex byte
+	transparentIndex    byte
+	hasTransparentIndex bool
 
 	// Computed.
 	pixelSize      uint
@@ -175,11 +176,12 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
 				if err != nil {
 					return err
 				}
-				// TODO: do we set transparency in this map too? That would be
-				// d.setTransparency(m.Palette)
 			} else {
 				m.Palette = d.globalColorMap
 			}
+			if d.hasTransparentIndex && int(d.transparentIndex) < len(m.Palette) {
+				m.Palette[d.transparentIndex] = color.RGBA{}
+			}
 			litWidth, err := d.r.ReadByte()
 			if err != nil {
 				return err
@@ -228,7 +230,11 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
 
 			d.image = append(d.image, m)
 			d.delay = append(d.delay, d.delayTime)
-			d.delayTime = 0 // TODO: is this correct, or should we hold on to the value?
+			// The GIF89a spec, Section 23 (Graphic Control Extension) says:
+			// "The scope of this extension is the first graphic rendering block
+			// to follow." We therefore reset the GCE fields to zero.
+			d.delayTime = 0
+			d.hasTransparentIndex = false
 
 		case sTrailer:
 			if len(d.image) == 0 {
@@ -339,17 +345,11 @@ func (d *decoder) readGraphicControl() error {
 	d.delayTime = int(d.tmp[2]) | int(d.tmp[3])<<8
 	if d.flags&gcTransparentColorSet != 0 {
 		d.transparentIndex = d.tmp[4]
-		d.setTransparency(d.globalColorMap)
+		d.hasTransparentIndex = true
 	}
 	return nil
 }
 
-func (d *decoder) setTransparency(colorMap color.Palette) {
-	if int(d.transparentIndex) < len(colorMap) {
-		colorMap[d.transparentIndex] = color.RGBA{}
-	}
-}
-
 func (d *decoder) newImageFromDescriptor() (*image.Paletted, error) {
 	if _, err := io.ReadFull(d.r, d.tmp[0:9]); err != nil {
 		return nil, fmt.Errorf("gif: can't read image descriptor: %s", err)
diff --git a/src/pkg/image/gif/reader_test.go b/src/pkg/image/gif/reader_test.go
index 0986713..fc2041e 100644
--- a/src/pkg/image/gif/reader_test.go
+++ b/src/pkg/image/gif/reader_test.go
@@ -1,3 +1,7 @@
+// 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 gif
 
 import (
diff --git a/src/pkg/image/jpeg/huffman.go b/src/pkg/image/jpeg/huffman.go
index 9b731fd..f53d873 100644
--- a/src/pkg/image/jpeg/huffman.go
+++ b/src/pkg/image/jpeg/huffman.go
@@ -37,6 +37,9 @@ func (d *decoder) ensureNBits(n int) error {
 	for d.b.n < n {
 		c, err := d.r.ReadByte()
 		if err != nil {
+			if err == io.EOF {
+				return FormatError("short Huffman data")
+			}
 			return err
 		}
 		d.b.a = d.b.a<<8 | uint32(c)
@@ -50,6 +53,9 @@ func (d *decoder) ensureNBits(n int) error {
 		if c == 0xff {
 			c, err = d.r.ReadByte()
 			if err != nil {
+				if err == io.EOF {
+					return FormatError("short Huffman data")
+				}
 				return err
 			}
 			if c != 0x00 {
diff --git a/src/pkg/image/jpeg/reader_test.go b/src/pkg/image/jpeg/reader_test.go
index e951e03..926bb04 100644
--- a/src/pkg/image/jpeg/reader_test.go
+++ b/src/pkg/image/jpeg/reader_test.go
@@ -28,6 +28,7 @@ func TestDecodeProgressive(t *testing.T) {
 		"../testdata/video-001.q50.444",
 		"../testdata/video-005.gray.q50",
 		"../testdata/video-005.gray.q50.2x2",
+		"../testdata/video-001.separate.dc.progression",
 	}
 	for _, tc := range testCases {
 		m0, err := decodeFile(tc + ".jpeg")
@@ -44,6 +45,12 @@ func TestDecodeProgressive(t *testing.T) {
 			t.Errorf("%s: bounds differ: %v and %v", tc, m0.Bounds(), m1.Bounds())
 			continue
 		}
+		// All of the video-*.jpeg files are 150x103.
+		if m0.Bounds() != image.Rect(0, 0, 150, 103) {
+			t.Errorf("%s: bad bounds: %v", tc, m0.Bounds())
+			continue
+		}
+
 		switch m0 := m0.(type) {
 		case *image.YCbCr:
 			m1 := m1.(*image.YCbCr)
@@ -84,18 +91,15 @@ func decodeFile(filename string) (image.Image, error) {
 
 // check checks that the two pix data are equal, within the given bounds.
 func check(bounds image.Rectangle, pix0, pix1 []byte, stride0, stride1 int) error {
-	if len(pix0) != len(pix1) {
-		return fmt.Errorf("len(pix) %d and %d differ", len(pix0), len(pix1))
-	}
-	if stride0 != stride1 {
-		return fmt.Errorf("strides %d and %d differ", stride0, stride1)
+	if stride0 <= 0 || stride0%8 != 0 {
+		return fmt.Errorf("bad stride %d", stride0)
 	}
-	if stride0%8 != 0 {
-		return fmt.Errorf("stride %d is not a multiple of 8", stride0)
+	if stride1 <= 0 || stride1%8 != 0 {
+		return fmt.Errorf("bad stride %d", stride1)
 	}
 	// Compare the two pix data, one 8x8 block at a time.
-	for y := 0; y < len(pix0)/stride0; y += 8 {
-		for x := 0; x < stride0; x += 8 {
+	for y := 0; y < len(pix0)/stride0 && y < len(pix1)/stride1; y += 8 {
+		for x := 0; x < stride0 && x < stride1; x += 8 {
 			if x >= bounds.Max.X || y >= bounds.Max.Y {
 				// We don't care if the two pix data differ if the 8x8 block is
 				// entirely outside of the image's bounds. For example, this can
@@ -108,8 +112,9 @@ func check(bounds image.Rectangle, pix0, pix1 []byte, stride0, stride1 int) erro
 
 			for j := 0; j < 8; j++ {
 				for i := 0; i < 8; i++ {
-					index := (y+j)*stride0 + (x + i)
-					if pix0[index] != pix1[index] {
+					index0 := (y+j)*stride0 + (x + i)
+					index1 := (y+j)*stride1 + (x + i)
+					if pix0[index0] != pix1[index1] {
 						return fmt.Errorf("blocks at (%d, %d) differ:\n%sand\n%s", x, y,
 							pixString(pix0, stride0, x, y),
 							pixString(pix1, stride1, x, y),
diff --git a/src/pkg/image/jpeg/scan.go b/src/pkg/image/jpeg/scan.go
index a69ed17..559235d 100644
--- a/src/pkg/image/jpeg/scan.go
+++ b/src/pkg/image/jpeg/scan.go
@@ -141,25 +141,30 @@ func (d *decoder) processSOS(n int) error {
 				for j := 0; j < d.comp[compIndex].h*d.comp[compIndex].v; j++ {
 					// The blocks are traversed one MCU at a time. For 4:2:0 chroma
 					// subsampling, there are four Y 8x8 blocks in every 16x16 MCU.
+					//
 					// For a baseline 32x16 pixel image, the Y blocks visiting order is:
 					//	0 1 4 5
 					//	2 3 6 7
 					//
-					// For progressive images, the DC data blocks (zigStart == 0) are traversed
-					// as above, but AC data blocks are traversed left to right, top to bottom:
+					// For progressive images, the interleaved scans (those with nComp > 1)
+					// are traversed as above, but non-interleaved scans are traversed left
+					// to right, top to bottom:
 					//	0 1 2 3
 					//	4 5 6 7
+					// Only DC scans (zigStart == 0) can be interleaved. AC scans must have
+					// only one component.
 					//
-					// To further complicate matters, there is no AC data for any blocks that
-					// are inside the image at the MCU level but outside the image at the pixel
-					// level. For example, a 24x16 pixel 4:2:0 progressive image consists of
-					// two 16x16 MCUs. The earlier scans will process 8 Y blocks:
+					// To further complicate matters, for non-interleaved scans, there is no
+					// data for any blocks that are inside the image at the MCU level but
+					// outside the image at the pixel level. For example, a 24x16 pixel 4:2:0
+					// progressive image consists of two 16x16 MCUs. The interleaved scans
+					// will process 8 Y blocks:
 					//	0 1 4 5
 					//	2 3 6 7
-					// The later scans will process only 6 Y blocks:
+					// The non-interleaved scans will process only 6 Y blocks:
 					//	0 1 2
 					//	3 4 5
-					if zigStart == 0 {
+					if nComp != 1 {
 						mx0, my0 = d.comp[compIndex].h*mx, d.comp[compIndex].v*my
 						if h0 == 1 {
 							my0 += j
diff --git a/src/pkg/image/png/reader.go b/src/pkg/image/png/reader.go
index a6bf86e..dfe2991 100644
--- a/src/pkg/image/png/reader.go
+++ b/src/pkg/image/png/reader.go
@@ -505,8 +505,14 @@ func (d *decoder) decode() (image.Image, error) {
 	}
 
 	// Check for EOF, to verify the zlib checksum.
-	n, err := r.Read(pr[:1])
-	if err != io.EOF {
+	n := 0
+	for i := 0; n == 0 && err == nil; i++ {
+		if i == 100 {
+			return nil, io.ErrNoProgress
+		}
+		n, err = r.Read(pr[:1])
+	}
+	if err != nil && err != io.EOF {
 		return nil, FormatError(err.Error())
 	}
 	if n != 0 || d.idatLength != 0 {
diff --git a/src/pkg/image/testdata/video-001.separate.dc.progression.jpeg b/src/pkg/image/testdata/video-001.separate.dc.progression.jpeg
new file mode 100644
index 0000000..107f0fa
Binary files /dev/null and b/src/pkg/image/testdata/video-001.separate.dc.progression.jpeg differ
diff --git a/src/pkg/image/testdata/video-001.separate.dc.progression.progressive.jpeg b/src/pkg/image/testdata/video-001.separate.dc.progression.progressive.jpeg
new file mode 100644
index 0000000..a1d493e
Binary files /dev/null and b/src/pkg/image/testdata/video-001.separate.dc.progression.progressive.jpeg differ
diff --git a/src/pkg/io/io.go b/src/pkg/io/io.go
index f7073ff..022fdb6 100644
--- a/src/pkg/io/io.go
+++ b/src/pkg/io/io.go
@@ -74,6 +74,7 @@ type Reader interface {
 // It returns the number of bytes written from p (0 <= n <= len(p))
 // and any error encountered that caused the write to stop early.
 // Write must return a non-nil error if it returns n < len(p).
+// Write must not modify the slice data, even temporarily.
 type Writer interface {
 	Write(p []byte) (n int, err error)
 }
diff --git a/src/pkg/io/io_test.go b/src/pkg/io/io_test.go
index bd7a82f..57db1fb 100644
--- a/src/pkg/io/io_test.go
+++ b/src/pkg/io/io_test.go
@@ -281,6 +281,8 @@ func TestSectionReader_ReadAt(t *testing.T) {
 		{data: dat, off: 3, n: len(dat), bufLen: len(dat) / 2, at: 2, exp: dat[5 : 5+len(dat)/2], err: nil},
 		{data: dat, off: 3, n: len(dat) / 2, bufLen: len(dat)/2 - 2, at: 2, exp: dat[5 : 5+len(dat)/2-2], err: nil},
 		{data: dat, off: 3, n: len(dat) / 2, bufLen: len(dat)/2 + 2, at: 2, exp: dat[5 : 5+len(dat)/2-2], err: EOF},
+		{data: dat, off: 0, n: 0, bufLen: 0, at: -1, exp: "", err: EOF},
+		{data: dat, off: 0, n: 0, bufLen: 0, at: 1, exp: "", err: EOF},
 	}
 	for i, tt := range tests {
 		r := strings.NewReader(tt.data)
@@ -319,3 +321,21 @@ func TestSectionReader_Seek(t *testing.T) {
 		t.Errorf("Read = %v, %v; want 0, EOF", n, err)
 	}
 }
+
+func TestSectionReader_Size(t *testing.T) {
+	tests := []struct {
+		data string
+		want int64
+	}{
+		{"a long sample data, 1234567890", 30},
+		{"", 0},
+	}
+
+	for _, tt := range tests {
+		r := strings.NewReader(tt.data)
+		sr := NewSectionReader(r, 0, int64(len(tt.data)))
+		if got := sr.Size(); got != tt.want {
+			t.Errorf("Size = %v; want %v", got, tt.want)
+		}
+	}
+}
diff --git a/src/pkg/io/ioutil/blackhole.go b/src/pkg/io/ioutil/blackhole.go
deleted file mode 100644
index 101d2c1..0000000
--- a/src/pkg/io/ioutil/blackhole.go
+++ /dev/null
@@ -1,23 +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.
-
-package ioutil
-
-var blackHoleBuf = make(chan []byte, 1)
-
-func blackHole() []byte {
-	select {
-	case b := <-blackHoleBuf:
-		return b
-	default:
-	}
-	return make([]byte, 8192)
-}
-
-func blackHolePut(p []byte) {
-	select {
-	case blackHoleBuf <- p:
-	default:
-	}
-}
diff --git a/src/pkg/io/ioutil/ioutil.go b/src/pkg/io/ioutil/ioutil.go
index b2508b7..909a815 100644
--- a/src/pkg/io/ioutil/ioutil.go
+++ b/src/pkg/io/ioutil/ioutil.go
@@ -10,6 +10,7 @@ import (
 	"io"
 	"os"
 	"sort"
+	"sync"
 )
 
 // readAll reads from r until an error or EOF and returns the data it read
@@ -136,14 +137,21 @@ func (devNull) WriteString(s string) (int, error) {
 	return len(s), nil
 }
 
+var blackHolePool = sync.Pool{
+	New: func() interface{} {
+		b := make([]byte, 8192)
+		return &b
+	},
+}
+
 func (devNull) ReadFrom(r io.Reader) (n int64, err error) {
-	buf := blackHole()
-	defer blackHolePut(buf)
+	bufp := blackHolePool.Get().(*[]byte)
 	readSize := 0
 	for {
-		readSize, err = r.Read(buf)
+		readSize, err = r.Read(*bufp)
 		n += int64(readSize)
 		if err != nil {
+			blackHolePool.Put(bufp)
 			if err == io.EOF {
 				return n, nil
 			}
diff --git a/src/pkg/io/multi.go b/src/pkg/io/multi.go
index 2c7e816..e26cc53 100644
--- a/src/pkg/io/multi.go
+++ b/src/pkg/io/multi.go
@@ -26,9 +26,12 @@ func (mr *multiReader) Read(p []byte) (n int, err error) {
 
 // MultiReader returns a Reader that's the logical concatenation of
 // the provided input readers.  They're read sequentially.  Once all
-// inputs are drained, Read will return EOF.
+// inputs have returned EOF, Read will return EOF.  If any of the readers
+// return a non-nil, non-EOF error, Read will return that error.
 func MultiReader(readers ...Reader) Reader {
-	return &multiReader{readers}
+	r := make([]Reader, len(readers))
+	copy(r, readers)
+	return &multiReader{r}
 }
 
 type multiWriter struct {
@@ -52,5 +55,7 @@ func (t *multiWriter) Write(p []byte) (n int, err error) {
 // MultiWriter creates a writer that duplicates its writes to all the
 // provided writers, similar to the Unix tee(1) command.
 func MultiWriter(writers ...Writer) Writer {
-	return &multiWriter{writers}
+	w := make([]Writer, len(writers))
+	copy(w, writers)
+	return &multiWriter{w}
 }
diff --git a/src/pkg/io/multi_test.go b/src/pkg/io/multi_test.go
index eb717f7..56c6769 100644
--- a/src/pkg/io/multi_test.go
+++ b/src/pkg/io/multi_test.go
@@ -9,6 +9,7 @@ import (
 	"crypto/sha1"
 	"fmt"
 	. "io"
+	"io/ioutil"
 	"strings"
 	"testing"
 )
@@ -86,3 +87,29 @@ func TestMultiWriter(t *testing.T) {
 		t.Errorf("expected %q; got %q", sourceString, sink.String())
 	}
 }
+
+// Test that MultiReader copies the input slice and is insulated from future modification.
+func TestMultiReaderCopy(t *testing.T) {
+	slice := []Reader{strings.NewReader("hello world")}
+	r := MultiReader(slice...)
+	slice[0] = nil
+	data, err := ioutil.ReadAll(r)
+	if err != nil || string(data) != "hello world" {
+		t.Errorf("ReadAll() = %q, %v, want %q, nil", data, err, "hello world")
+	}
+}
+
+// Test that MultiWriter copies the input slice and is insulated from future modification.
+func TestMultiWriterCopy(t *testing.T) {
+	var buf bytes.Buffer
+	slice := []Writer{&buf}
+	w := MultiWriter(slice...)
+	slice[0] = nil
+	n, err := w.Write([]byte("hello world"))
+	if err != nil || n != 11 {
+		t.Errorf("Write(`hello world`) = %d, %v, want 11, nil", n, err)
+	}
+	if buf.String() != "hello world" {
+		t.Errorf("buf.String() = %q, want %q", buf.String(), "hello world")
+	}
+}
diff --git a/src/pkg/log/example_test.go b/src/pkg/log/example_test.go
new file mode 100644
index 0000000..74385a3
--- /dev/null
+++ b/src/pkg/log/example_test.go
@@ -0,0 +1,21 @@
+// 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 log_test
+
+import (
+	"bytes"
+	"fmt"
+	"log"
+)
+
+func ExampleLogger() {
+	var buf bytes.Buffer
+	logger := log.New(&buf, "logger: ", log.Lshortfile)
+	logger.Print("Hello, log file!")
+
+	fmt.Print(&buf)
+	// Output:
+	// logger: example_test.go:16: Hello, log file!
+}
diff --git a/src/pkg/log/syslog/syslog.go b/src/pkg/log/syslog/syslog.go
index 0cbfa90..5e09599 100644
--- a/src/pkg/log/syslog/syslog.go
+++ b/src/pkg/log/syslog/syslog.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 !windows,!plan9
+// +build !windows,!nacl,!plan9
 
 // Package syslog provides a simple interface to the system log
 // service. It can send messages to the syslog daemon using UNIX
@@ -115,9 +115,10 @@ func New(priority Priority, tag string) (w *Writer, err error) {
 }
 
 // Dial establishes a connection to a log daemon by connecting to
-// address raddr on the network net.  Each write to the returned
+// address raddr on the specified network.  Each write to the returned
 // writer sends a log message with the given facility, severity and
 // tag.
+// If network is empty, Dial will connect to the local syslog server.
 func Dial(network, raddr string, priority Priority, tag string) (*Writer, error) {
 	if priority < 0 || priority > LOG_LOCAL7|LOG_DEBUG {
 		return nil, errors.New("log/syslog: invalid priority")
diff --git a/src/pkg/log/syslog/syslog_test.go b/src/pkg/log/syslog/syslog_test.go
index 760a5c7..24a460f 100644
--- a/src/pkg/log/syslog/syslog_test.go
+++ b/src/pkg/log/syslog/syslog_test.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 !windows,!plan9
+// +build !windows,!nacl,!plan9
 
 package syslog
 
diff --git a/src/pkg/log/syslog/syslog_unix.go b/src/pkg/log/syslog/syslog_unix.go
index 28a294a..f6d2f1b 100644
--- a/src/pkg/log/syslog/syslog_unix.go
+++ b/src/pkg/log/syslog/syslog_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 !windows,!plan9
+// +build !windows,!nacl,!plan9
 
 package syslog
 
diff --git a/src/pkg/math/abs_amd64p32.s b/src/pkg/math/abs_amd64p32.s
new file mode 100644
index 0000000..08c8c6b
--- /dev/null
+++ b/src/pkg/math/abs_amd64p32.s
@@ -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 "abs_amd64.s"
diff --git a/src/pkg/math/asin_amd64p32.s b/src/pkg/math/asin_amd64p32.s
new file mode 100644
index 0000000..2751c47
--- /dev/null
+++ b/src/pkg/math/asin_amd64p32.s
@@ -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 "asin_amd64.s"
diff --git a/src/pkg/math/atan2_amd64p32.s b/src/pkg/math/atan2_amd64p32.s
new file mode 100644
index 0000000..3fdc03c
--- /dev/null
+++ b/src/pkg/math/atan2_amd64p32.s
@@ -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 "atan2_amd64.s"
diff --git a/src/pkg/math/atan_amd64p32.s b/src/pkg/math/atan_amd64p32.s
new file mode 100644
index 0000000..1c1f6ce
--- /dev/null
+++ b/src/pkg/math/atan_amd64p32.s
@@ -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 "atan_amd64.s"
diff --git a/src/pkg/math/big/arith.go b/src/pkg/math/big/arith.go
index f316806..3d5a868 100644
--- a/src/pkg/math/big/arith.go
+++ b/src/pkg/math/big/arith.go
@@ -131,12 +131,11 @@ func divWW_g(u1, u0, v Word) (q, r Word) {
 	q1 := un32 / vn1
 	rhat := un32 - q1*vn1
 
-again1:
-	if q1 >= _B2 || q1*vn0 > _B2*rhat+un1 {
+	for q1 >= _B2 || q1*vn0 > _B2*rhat+un1 {
 		q1--
 		rhat += vn1
-		if rhat < _B2 {
-			goto again1
+		if rhat >= _B2 {
+			break
 		}
 	}
 
@@ -144,12 +143,11 @@ again1:
 	q0 := un21 / vn1
 	rhat = un21 - q0*vn1
 
-again2:
-	if q0 >= _B2 || q0*vn0 > _B2*rhat+un0 {
+	for q0 >= _B2 || q0*vn0 > _B2*rhat+un0 {
 		q0--
 		rhat += vn1
-		if rhat < _B2 {
-			goto again2
+		if rhat >= _B2 {
+			break
 		}
 	}
 
diff --git a/src/pkg/math/big/arith_amd64p32.s b/src/pkg/math/big/arith_amd64p32.s
new file mode 100644
index 0000000..227870a
--- /dev/null
+++ b/src/pkg/math/big/arith_amd64p32.s
@@ -0,0 +1,41 @@
+// 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 "../../../cmd/ld/textflag.h"
+
+TEXT ·mulWW(SB),NOSPLIT,$0
+	JMP ·mulWW_g(SB)
+
+TEXT ·divWW(SB),NOSPLIT,$0
+	JMP ·divWW_g(SB)
+
+TEXT ·addVV(SB),NOSPLIT,$0
+	JMP ·addVV_g(SB)
+
+TEXT ·subVV(SB),NOSPLIT,$0
+	JMP ·subVV_g(SB)
+
+TEXT ·addVW(SB),NOSPLIT,$0
+	JMP ·addVW_g(SB)
+
+TEXT ·subVW(SB),NOSPLIT,$0
+	JMP ·subVW_g(SB)
+
+TEXT ·shlVU(SB),NOSPLIT,$0
+	JMP ·shlVU_g(SB)
+
+TEXT ·shrVU(SB),NOSPLIT,$0
+	JMP ·shrVU_g(SB)
+
+TEXT ·mulAddVWW(SB),NOSPLIT,$0
+	JMP ·mulAddVWW_g(SB)
+
+TEXT ·addMulVVW(SB),NOSPLIT,$0
+	JMP ·addMulVVW_g(SB)
+
+TEXT ·divWVW(SB),NOSPLIT,$0
+	JMP ·divWVW_g(SB)
+
+TEXT ·bitLen(SB),NOSPLIT,$0
+	JMP ·bitLen_g(SB)
diff --git a/src/pkg/math/big/arith_arm.s b/src/pkg/math/big/arith_arm.s
index ecf55b3..8d36761 100644
--- a/src/pkg/math/big/arith_arm.s
+++ b/src/pkg/math/big/arith_arm.s
@@ -7,31 +7,26 @@
 // This file provides fast assembly versions for the elementary
 // arithmetic operations on vectors implemented in arith.go.
 
-#define CFLAG 29	// bit position of carry flag
-
 // func addVV(z, x, y []Word) (c Word)
 TEXT ·addVV(SB),NOSPLIT,$0
-	MOVW	$0, R0
+	ADD.S	$0, R0		// clear carry flag
 	MOVW	z+0(FP), R1
+	MOVW	z_len+4(FP), R4
 	MOVW	x+12(FP), R2
 	MOVW	y+24(FP), R3
-	MOVW	z_len+4(FP), R4
-	MOVW	R4<<2, R4
-	ADD	R1, R4
+	ADD	R4<<2, R1, R4
 	B E1
 L1:
 	MOVW.P	4(R2), R5
 	MOVW.P	4(R3), R6
-	MOVW	R0, CPSR
 	ADC.S	R6, R5
 	MOVW.P	R5, 4(R1)
-	MOVW	CPSR, R0
 E1:
-	CMP	R1, R4
+	TEQ	R1, R4
 	BNE L1
 
-	MOVW	R0>>CFLAG, R0
-	AND	$1, R0
+	MOVW	$0, R0
+	MOVW.CS	$1, R0
 	MOVW	R0, c+36(FP)
 	RET
 
@@ -39,28 +34,24 @@ E1:
 // func subVV(z, x, y []Word) (c Word)
 // (same as addVV except for SBC instead of ADC and label names)
 TEXT ·subVV(SB),NOSPLIT,$0
-	MOVW	$(1<<CFLAG), R0
+	SUB.S	$0, R0		// clear borrow flag
 	MOVW	z+0(FP), R1
+	MOVW	z_len+4(FP), R4
 	MOVW	x+12(FP), R2
 	MOVW	y+24(FP), R3
-	MOVW	z_len+4(FP), R4
-	MOVW	R4<<2, R4
-	ADD	R1, R4
+	ADD	R4<<2, R1, R4
 	B E2
 L2:
 	MOVW.P	4(R2), R5
 	MOVW.P	4(R3), R6
-	MOVW	R0, CPSR
 	SBC.S	R6, R5
 	MOVW.P	R5, 4(R1)
-	MOVW	CPSR, R0
 E2:
-	CMP	R1, R4
+	TEQ	R1, R4
 	BNE L2
 
-	MOVW	R0>>CFLAG, R0
-	AND	$1, R0
-	EOR	$1, R0
+	MOVW	$0, R0
+	MOVW.CC	$1, R0
 	MOVW	R0, c+36(FP)
 	RET
 
@@ -68,12 +59,11 @@ E2:
 // func addVW(z, x []Word, y Word) (c Word)
 TEXT ·addVW(SB),NOSPLIT,$0
 	MOVW	z+0(FP), R1
+	MOVW	z_len+4(FP), R4
 	MOVW	x+12(FP), R2
 	MOVW	y+24(FP), R3
-	MOVW	z_len+4(FP), R4
-	MOVW	R4<<2, R4
-	ADD	R1, R4
-	CMP	R1, R4
+	ADD	R4<<2, R1, R4
+	TEQ	R1, R4
 	BNE L3a
 	MOVW	R3, c+28(FP)
 	RET
@@ -81,20 +71,17 @@ L3a:
 	MOVW.P	4(R2), R5
 	ADD.S	R3, R5
 	MOVW.P	R5, 4(R1)
-	MOVW	CPSR, R0
 	B	E3
 L3:
 	MOVW.P	4(R2), R5
-	MOVW	R0, CPSR
 	ADC.S	$0, R5
 	MOVW.P	R5, 4(R1)
-	MOVW	CPSR, R0
 E3:
-	CMP	R1, R4
+	TEQ	R1, R4
 	BNE	L3
 
-	MOVW	R0>>CFLAG, R0
-	AND	$1, R0
+	MOVW	$0, R0
+	MOVW.CS	$1, R0
 	MOVW	R0, c+28(FP)
 	RET
 
@@ -102,12 +89,11 @@ E3:
 // func subVW(z, x []Word, y Word) (c Word)
 TEXT ·subVW(SB),NOSPLIT,$0
 	MOVW	z+0(FP), R1
+	MOVW	z_len+4(FP), R4
 	MOVW	x+12(FP), R2
 	MOVW	y+24(FP), R3
-	MOVW	z_len+4(FP), R4
-	MOVW	R4<<2, R4
-	ADD	R1, R4
-	CMP	R1, R4
+	ADD	R4<<2, R1, R4
+	TEQ	R1, R4
 	BNE L4a
 	MOVW	R3, c+28(FP)
 	RET
@@ -115,21 +101,17 @@ L4a:
 	MOVW.P	4(R2), R5
 	SUB.S	R3, R5
 	MOVW.P	R5, 4(R1)
-	MOVW	CPSR, R0
 	B	E4
 L4:
 	MOVW.P	4(R2), R5
-	MOVW	R0, CPSR
 	SBC.S	$0, R5
 	MOVW.P	R5, 4(R1)
-	MOVW	CPSR, R0
 E4:
-	CMP	R1, R4
+	TEQ	R1, R4
 	BNE	L4
 
-	MOVW	R0>>CFLAG, R0
-	AND	$1, R0
-	EOR	$1, R0
+	MOVW	$0, R0
+	MOVW.CC	$1, R0
 	MOVW	R0, c+28(FP)
 	RET
 
@@ -137,16 +119,15 @@ E4:
 // func shlVU(z, x []Word, s uint) (c Word)
 TEXT ·shlVU(SB),NOSPLIT,$0
 	MOVW	z_len+4(FP), R5
-	CMP	$0, R5
+	TEQ	$0, R5
 	BEQ	X7
 	
 	MOVW	z+0(FP), R1
 	MOVW	x+12(FP), R2
-	MOVW	R5<<2, R5
-	ADD	R5, R2
-	ADD	R1, R5
+	ADD	R5<<2, R2, R2
+	ADD	R5<<2, R1, R5
 	MOVW	s+24(FP), R3
-	CMP	$0, R3	// shift 0 is special
+	TEQ	$0, R3	// shift 0 is special
 	BEQ	Y7
 	ADD	$4, R1	// stop one word early
 	MOVW	$32, R4
@@ -165,7 +146,7 @@ L7:
 	MOVW.W	R7, -4(R5)
 	MOVW	R6<<R3, R7
 E7:
-	CMP	R1, R5
+	TEQ	R1, R5
 	BNE	L7
 
 	MOVW	R7, -4(R5)
@@ -174,7 +155,7 @@ E7:
 Y7:	// copy loop, because shift 0 == shift 32
 	MOVW.W	-4(R2), R6
 	MOVW.W	R6, -4(R5)
-	CMP	R1, R5
+	TEQ	R1, R5
 	BNE Y7
 
 X7:
@@ -186,15 +167,14 @@ X7:
 // func shrVU(z, x []Word, s uint) (c Word)
 TEXT ·shrVU(SB),NOSPLIT,$0
 	MOVW	z_len+4(FP), R5
-	CMP	$0, R5
+	TEQ	$0, R5
 	BEQ	X6
 
 	MOVW	z+0(FP), R1
 	MOVW	x+12(FP), R2
-	MOVW	R5<<2, R5
-	ADD	R1, R5
+	ADD	R5<<2, R1, R5
 	MOVW	s+24(FP), R3
-	CMP	$0, R3	// shift 0 is special
+	TEQ	$0, R3	// shift 0 is special
 	BEQ Y6
 	SUB	$4, R5	// stop one word early
 	MOVW	$32, R4
@@ -215,7 +195,7 @@ L6:
 	MOVW.P	R7, 4(R1)
 	MOVW	R6>>R3, R7
 E6:
-	CMP	R1, R5
+	TEQ	R1, R5
 	BNE	L6
 
 	MOVW	R7, 0(R1)
@@ -224,7 +204,7 @@ E6:
 Y6:	// copy loop, because shift 0 == shift 32
 	MOVW.P	4(R2), R6
 	MOVW.P	R6, 4(R1)
-	CMP R1, R5
+	TEQ R1, R5
 	BNE Y6
 
 X6:
@@ -237,12 +217,11 @@ X6:
 TEXT ·mulAddVWW(SB),NOSPLIT,$0
 	MOVW	$0, R0
 	MOVW	z+0(FP), R1
+	MOVW	z_len+4(FP), R5
 	MOVW	x+12(FP), R2
 	MOVW	y+24(FP), R3
 	MOVW	r+28(FP), R4
-	MOVW	z_len+4(FP), R5
-	MOVW	R5<<2, R5
-	ADD	R1, R5
+	ADD	R5<<2, R1, R5
 	B E8
 
 	// word loop
@@ -254,7 +233,7 @@ L8:
 	MOVW.P	R6, 4(R1)
 	MOVW	R7, R4
 E8:
-	CMP	R1, R5
+	TEQ	R1, R5
 	BNE	L8
 
 	MOVW	R4, c+32(FP)
@@ -265,11 +244,10 @@ E8:
 TEXT ·addMulVVW(SB),NOSPLIT,$0
 	MOVW	$0, R0
 	MOVW	z+0(FP), R1
+	MOVW	z_len+4(FP), R5
 	MOVW	x+12(FP), R2
 	MOVW	y+24(FP), R3
-	MOVW	z_len+4(FP), R5
-	MOVW	R5<<2, R5
-	ADD	R1, R5
+	ADD	R5<<2, R1, R5
 	MOVW	$0, R4
 	B E9
 
@@ -285,7 +263,7 @@ L9:
 	MOVW.P	R6, 4(R1)
 	MOVW	R7, R4
 E9:
-	CMP	R1, R5
+	TEQ	R1, R5
 	BNE	L9
 
 	MOVW	R4, c+28(FP)
@@ -317,7 +295,6 @@ TEXT ·mulWW(SB),NOSPLIT,$0
 TEXT ·bitLen(SB),NOSPLIT,$0
 	MOVW	x+0(FP), R0
 	CLZ 	R0, R0
-	MOVW	$32, R1
-	SUB.S	R0, R1
-	MOVW	R1, n+4(FP)
+	RSB	$32, R0
+	MOVW	R0, n+4(FP)
 	RET
diff --git a/src/pkg/math/big/int.go b/src/pkg/math/big/int.go
index 7bbb152..269949d 100644
--- a/src/pkg/math/big/int.go
+++ b/src/pkg/math/big/int.go
@@ -576,21 +576,22 @@ func (x *Int) BitLen() int {
 }
 
 // Exp sets z = x**y mod |m| (i.e. the sign of m is ignored), and returns z.
-// If y <= 0, the result is 1; if m == nil or m == 0, z = x**y.
+// If y <= 0, the result is 1 mod |m|; if m == nil or m == 0, z = x**y.
 // See Knuth, volume 2, section 4.6.3.
 func (z *Int) Exp(x, y, m *Int) *Int {
-	if y.neg || len(y.abs) == 0 {
-		return z.SetInt64(1)
+	var yWords nat
+	if !y.neg {
+		yWords = y.abs
 	}
-	// y > 0
+	// y >= 0
 
 	var mWords nat
 	if m != nil {
 		mWords = m.abs // m.abs may be nil for m == 0
 	}
 
-	z.abs = z.abs.expNN(x.abs, y.abs, mWords)
-	z.neg = len(z.abs) > 0 && x.neg && y.abs[0]&1 == 1 // 0 has no sign
+	z.abs = z.abs.expNN(x.abs, yWords, mWords)
+	z.neg = len(z.abs) > 0 && x.neg && len(yWords) > 0 && yWords[0]&1 == 1 // 0 has no sign
 	return z
 }
 
@@ -982,17 +983,29 @@ func (z *Int) GobDecode(buf []byte) error {
 }
 
 // MarshalJSON implements the json.Marshaler interface.
-func (x *Int) MarshalJSON() ([]byte, error) {
+func (z *Int) MarshalJSON() ([]byte, error) {
 	// TODO(gri): get rid of the []byte/string conversions
-	return []byte(x.String()), nil
+	return []byte(z.String()), nil
 }
 
 // UnmarshalJSON implements the json.Unmarshaler interface.
-func (z *Int) UnmarshalJSON(x []byte) error {
+func (z *Int) UnmarshalJSON(text []byte) error {
 	// TODO(gri): get rid of the []byte/string conversions
-	_, ok := z.SetString(string(x), 0)
-	if !ok {
-		return fmt.Errorf("math/big: cannot unmarshal %s into a *big.Int", x)
+	if _, ok := z.SetString(string(text), 0); !ok {
+		return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
+	}
+	return nil
+}
+
+// MarshalText implements the encoding.TextMarshaler interface
+func (z *Int) MarshalText() (text []byte, err error) {
+	return []byte(z.String()), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface
+func (z *Int) UnmarshalText(text []byte) error {
+	if _, ok := z.SetString(string(text), 0); !ok {
+		return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
 	}
 	return nil
 }
diff --git a/src/pkg/math/big/int_test.go b/src/pkg/math/big/int_test.go
index 87b975d..299dc72 100644
--- a/src/pkg/math/big/int_test.go
+++ b/src/pkg/math/big/int_test.go
@@ -9,6 +9,7 @@ import (
 	"encoding/gob"
 	"encoding/hex"
 	"encoding/json"
+	"encoding/xml"
 	"fmt"
 	"math/rand"
 	"testing"
@@ -767,6 +768,19 @@ var expTests = []struct {
 	x, y, m string
 	out     string
 }{
+	// y <= 0
+	{"0", "0", "", "1"},
+	{"1", "0", "", "1"},
+	{"-10", "0", "", "1"},
+	{"1234", "-1", "", "1"},
+
+	// m == 1
+	{"0", "0", "1", "0"},
+	{"1", "0", "1", "0"},
+	{"-10", "0", "1", "0"},
+	{"1234", "-1", "1", "0"},
+
+	// misc
 	{"5", "-7", "", "1"},
 	{"-5", "-7", "", "1"},
 	{"5", "0", "", "1"},
@@ -1528,6 +1542,58 @@ func TestIntJSONEncoding(t *testing.T) {
 	}
 }
 
+var intVals = []string{
+	"-141592653589793238462643383279502884197169399375105820974944592307816406286",
+	"-1415926535897932384626433832795028841971",
+	"-141592653589793",
+	"-1",
+	"0",
+	"1",
+	"141592653589793",
+	"1415926535897932384626433832795028841971",
+	"141592653589793238462643383279502884197169399375105820974944592307816406286",
+}
+
+func TestIntJSONEncodingTextMarshaller(t *testing.T) {
+	for _, num := range intVals {
+		var tx Int
+		tx.SetString(num, 0)
+		b, err := json.Marshal(&tx)
+		if err != nil {
+			t.Errorf("marshaling of %s failed: %s", &tx, err)
+			continue
+		}
+		var rx Int
+		if err := json.Unmarshal(b, &rx); err != nil {
+			t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+			continue
+		}
+		if rx.Cmp(&tx) != 0 {
+			t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+		}
+	}
+}
+
+func TestIntXMLEncodingTextMarshaller(t *testing.T) {
+	for _, num := range intVals {
+		var tx Int
+		tx.SetString(num, 0)
+		b, err := xml.Marshal(&tx)
+		if err != nil {
+			t.Errorf("marshaling of %s failed: %s", &tx, err)
+			continue
+		}
+		var rx Int
+		if err := xml.Unmarshal(b, &rx); err != nil {
+			t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+			continue
+		}
+		if rx.Cmp(&tx) != 0 {
+			t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+		}
+	}
+}
+
 func TestIssue2607(t *testing.T) {
 	// This code sequence used to hang.
 	n := NewInt(10)
diff --git a/src/pkg/math/big/nat.go b/src/pkg/math/big/nat.go
index 6874900..16a87f5 100644
--- a/src/pkg/math/big/nat.go
+++ b/src/pkg/math/big/nat.go
@@ -1233,10 +1233,15 @@ func (z nat) expNN(x, y, m nat) nat {
 		z = nil
 	}
 
+	// x**y mod 1 == 0
+	if len(m) == 1 && m[0] == 1 {
+		return z.setWord(0)
+	}
+	// m == 0 || m > 1
+
+	// x**0 == 1
 	if len(y) == 0 {
-		z = z.make(1)
-		z[0] = 1
-		return z
+		return z.setWord(1)
 	}
 	// y > 0
 
diff --git a/src/pkg/math/big/nat_test.go b/src/pkg/math/big/nat_test.go
index 1d4dfe8..a2ae533 100644
--- a/src/pkg/math/big/nat_test.go
+++ b/src/pkg/math/big/nat_test.go
@@ -437,20 +437,11 @@ func BenchmarkStringPiParallel(b *testing.B) {
 	if x.decimalString() != pi {
 		panic("benchmark incorrect: conversion failed")
 	}
-	n := runtime.GOMAXPROCS(0)
-	m := b.N / n // n*m <= b.N due to flooring, but the error is neglibible (n is not very large)
-	c := make(chan int, n)
-	for i := 0; i < n; i++ {
-		go func() {
-			for j := 0; j < m; j++ {
-				x.decimalString()
-			}
-			c <- 0
-		}()
-	}
-	for i := 0; i < n; i++ {
-		<-c
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			x.decimalString()
+		}
+	})
 }
 
 func BenchmarkScan10Base2(b *testing.B)     { ScanHelper(b, 2, 10, 10) }
@@ -723,6 +714,12 @@ var expNNTests = []struct {
 	x, y, m string
 	out     string
 }{
+	{"0", "0", "0", "1"},
+	{"0", "0", "1", "0"},
+	{"1", "1", "1", "0"},
+	{"2", "1", "1", "0"},
+	{"2", "2", "1", "0"},
+	{"10", "100000000000", "1", "0"},
 	{"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
 	{"0x8000000000000000", "2", "6719", "4944"},
 	{"0x8000000000000000", "3", "6719", "5447"},
@@ -750,7 +747,7 @@ func TestExpNN(t *testing.T) {
 
 		z := nat(nil).expNN(x, y, m)
 		if z.cmp(out) != 0 {
-			t.Errorf("#%d got %v want %v", i, z, out)
+			t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString())
 		}
 	}
 }
diff --git a/src/pkg/math/big/rat.go b/src/pkg/math/big/rat.go
index 7faee61..f0973b3 100644
--- a/src/pkg/math/big/rat.go
+++ b/src/pkg/math/big/rat.go
@@ -47,7 +47,7 @@ func (z *Rat) SetFloat64(f float64) *Rat {
 
 	shift := 52 - exp
 
-	// Optimisation (?): partially pre-normalise.
+	// Optimization (?): partially pre-normalise.
 	for mantissa&1 == 0 && shift > 0 {
 		mantissa >>= 1
 		shift--
@@ -477,7 +477,7 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
 	return z, true
 }
 
-// String returns a string representation of z in the form "a/b" (even if b == 1).
+// String returns a string representation of x in the form "a/b" (even if b == 1).
 func (x *Rat) String() string {
 	s := "/1"
 	if len(x.b.abs) != 0 {
@@ -486,7 +486,7 @@ func (x *Rat) String() string {
 	return x.a.String() + s
 }
 
-// RatString returns a string representation of z in the form "a/b" if b != 1,
+// RatString returns a string representation of x in the form "a/b" if b != 1,
 // and in the form "a" if b == 1.
 func (x *Rat) RatString() string {
 	if x.IsInt() {
@@ -495,7 +495,7 @@ func (x *Rat) RatString() string {
 	return x.String()
 }
 
-// FloatString returns a string representation of z in decimal form with prec
+// FloatString returns a string representation of x in decimal form with prec
 // digits of precision after the decimal point and the last digit rounded.
 func (x *Rat) FloatString(prec int) string {
 	if x.IsInt() {
@@ -585,3 +585,16 @@ func (z *Rat) GobDecode(buf []byte) error {
 	z.b.abs = z.b.abs.setBytes(buf[i:])
 	return nil
 }
+
+// MarshalText implements the encoding.TextMarshaler interface
+func (r *Rat) MarshalText() (text []byte, err error) {
+	return []byte(r.RatString()), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface
+func (r *Rat) UnmarshalText(text []byte) error {
+	if _, ok := r.SetString(string(text)); !ok {
+		return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Rat", text)
+	}
+	return nil
+}
diff --git a/src/pkg/math/big/rat_test.go b/src/pkg/math/big/rat_test.go
index 0d43263..414a67d 100644
--- a/src/pkg/math/big/rat_test.go
+++ b/src/pkg/math/big/rat_test.go
@@ -7,6 +7,8 @@ package big
 import (
 	"bytes"
 	"encoding/gob"
+	"encoding/json"
+	"encoding/xml"
 	"fmt"
 	"math"
 	"strconv"
@@ -433,6 +435,69 @@ func TestGobEncodingNilRatInSlice(t *testing.T) {
 	}
 }
 
+var ratNums = []string{
+	"-141592653589793238462643383279502884197169399375105820974944592307816406286",
+	"-1415926535897932384626433832795028841971",
+	"-141592653589793",
+	"-1",
+	"0",
+	"1",
+	"141592653589793",
+	"1415926535897932384626433832795028841971",
+	"141592653589793238462643383279502884197169399375105820974944592307816406286",
+}
+
+var ratDenoms = []string{
+	"1",
+	"718281828459045",
+	"7182818284590452353602874713526624977572",
+	"718281828459045235360287471352662497757247093699959574966967627724076630353",
+}
+
+func TestRatJSONEncoding(t *testing.T) {
+	for _, num := range ratNums {
+		for _, denom := range ratDenoms {
+			var tx Rat
+			tx.SetString(num + "/" + denom)
+			b, err := json.Marshal(&tx)
+			if err != nil {
+				t.Errorf("marshaling of %s failed: %s", &tx, err)
+				continue
+			}
+			var rx Rat
+			if err := json.Unmarshal(b, &rx); err != nil {
+				t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+				continue
+			}
+			if rx.Cmp(&tx) != 0 {
+				t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+			}
+		}
+	}
+}
+
+func TestRatXMLEncoding(t *testing.T) {
+	for _, num := range ratNums {
+		for _, denom := range ratDenoms {
+			var tx Rat
+			tx.SetString(num + "/" + denom)
+			b, err := xml.Marshal(&tx)
+			if err != nil {
+				t.Errorf("marshaling of %s failed: %s", &tx, err)
+				continue
+			}
+			var rx Rat
+			if err := xml.Unmarshal(b, &rx); err != nil {
+				t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+				continue
+			}
+			if rx.Cmp(&tx) != 0 {
+				t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+			}
+		}
+	}
+}
+
 func TestIssue2379(t *testing.T) {
 	// 1) no aliasing
 	q := NewRat(3, 2)
diff --git a/src/pkg/math/cmplx/cmath_test.go b/src/pkg/math/cmplx/cmath_test.go
index 610ca8c..f285646 100644
--- a/src/pkg/math/cmplx/cmath_test.go
+++ b/src/pkg/math/cmplx/cmath_test.go
@@ -656,6 +656,19 @@ func TestPolar(t *testing.T) {
 	}
 }
 func TestPow(t *testing.T) {
+	// Special cases for Pow(0, c).
+	var zero = complex(0, 0)
+	zeroPowers := [][2]complex128{
+		{0, 1 + 0i},
+		{1.5, 0 + 0i},
+		{-1.5, complex(math.Inf(0), 0)},
+		{-1.5 + 1.5i, Inf()},
+	}
+	for _, zp := range zeroPowers {
+		if f := Pow(zero, zp[0]); f != zp[1] {
+			t.Errorf("Pow(%g, %g) = %g, want %g", zero, zp[0], f, zp[1])
+		}
+	}
 	var a = complex(3.0, 3.0)
 	for i := 0; i < len(vc); i++ {
 		if f := Pow(a, vc[i]); !cSoclose(pow[i], f, 4e-15) {
diff --git a/src/pkg/math/cmplx/pow.go b/src/pkg/math/cmplx/pow.go
index 4dbc583..1630b87 100644
--- a/src/pkg/math/cmplx/pow.go
+++ b/src/pkg/math/cmplx/pow.go
@@ -43,7 +43,25 @@ import "math"
 //    IEEE      -10,+10     30000       9.4e-15     1.5e-15
 
 // Pow returns x**y, the base-x exponential of y.
+// For generalized compatibility with math.Pow:
+//	Pow(0, ±0) returns 1+0i
+//	Pow(0, c) for real(c)<0 returns Inf+0i if imag(c) is zero, otherwise Inf+Inf i.
 func Pow(x, y complex128) complex128 {
+	if x == 0 { // Guaranteed also true for x == -0.
+		r, i := real(y), imag(y)
+		switch {
+		case r == 0:
+			return 1
+		case r < 0:
+			if i == 0 {
+				return complex(math.Inf(1), 0)
+			}
+			return Inf()
+		case r > 0:
+			return 0
+		}
+		panic("not reached")
+	}
 	modulus := Abs(x)
 	if modulus == 0 {
 		return complex(0, 0)
diff --git a/src/pkg/math/cmplx/sqrt.go b/src/pkg/math/cmplx/sqrt.go
index 179b539..4ef6807 100644
--- a/src/pkg/math/cmplx/sqrt.go
+++ b/src/pkg/math/cmplx/sqrt.go
@@ -54,6 +54,7 @@ import "math"
 //    IEEE      -10,+10   1,000,000     2.9e-16     6.1e-17
 
 // Sqrt returns the square root of x.
+// The result r is chosen so that real(r) ≥ 0 and imag(r) has the same sign as imag(x).
 func Sqrt(x complex128) complex128 {
 	if imag(x) == 0 {
 		if real(x) == 0 {
diff --git a/src/pkg/math/dim_amd64p32.s b/src/pkg/math/dim_amd64p32.s
new file mode 100644
index 0000000..e5e3447
--- /dev/null
+++ b/src/pkg/math/dim_amd64p32.s
@@ -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 "dim_amd64.s"
diff --git a/src/pkg/math/exp2_amd64p32.s b/src/pkg/math/exp2_amd64p32.s
new file mode 100644
index 0000000..4d38309
--- /dev/null
+++ b/src/pkg/math/exp2_amd64p32.s
@@ -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 "exp2_amd64.s"
diff --git a/src/pkg/math/exp_amd64p32.s b/src/pkg/math/exp_amd64p32.s
new file mode 100644
index 0000000..98ac2e9
--- /dev/null
+++ b/src/pkg/math/exp_amd64p32.s
@@ -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 "exp_amd64.s"
diff --git a/src/pkg/math/expm1_amd64p32.s b/src/pkg/math/expm1_amd64p32.s
new file mode 100644
index 0000000..709ebef
--- /dev/null
+++ b/src/pkg/math/expm1_amd64p32.s
@@ -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 "expm1_amd64.s"
diff --git a/src/pkg/math/floor_amd64p32.s b/src/pkg/math/floor_amd64p32.s
new file mode 100644
index 0000000..5b87d7a
--- /dev/null
+++ b/src/pkg/math/floor_amd64p32.s
@@ -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 "floor_amd64.s"
diff --git a/src/pkg/math/frexp_amd64p32.s b/src/pkg/math/frexp_amd64p32.s
new file mode 100644
index 0000000..fbb5645
--- /dev/null
+++ b/src/pkg/math/frexp_amd64p32.s
@@ -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 "frexp_amd64.s"
diff --git a/src/pkg/math/hypot_amd64p32.s b/src/pkg/math/hypot_amd64p32.s
new file mode 100644
index 0000000..b84542a
--- /dev/null
+++ b/src/pkg/math/hypot_amd64p32.s
@@ -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 "hypot_amd64.s"
diff --git a/src/pkg/math/ldexp_amd64p32.s b/src/pkg/math/ldexp_amd64p32.s
new file mode 100644
index 0000000..9aa9d9d
--- /dev/null
+++ b/src/pkg/math/ldexp_amd64p32.s
@@ -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 "ldexp_amd64.s"
diff --git a/src/pkg/math/log10_amd64p32.s b/src/pkg/math/log10_amd64p32.s
new file mode 100644
index 0000000..bf43841
--- /dev/null
+++ b/src/pkg/math/log10_amd64p32.s
@@ -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 "log10_amd64.s"
diff --git a/src/pkg/math/log1p_amd64p32.s b/src/pkg/math/log1p_amd64p32.s
new file mode 100644
index 0000000..a14b5e3
--- /dev/null
+++ b/src/pkg/math/log1p_amd64p32.s
@@ -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 "log1p_amd64.s"
diff --git a/src/pkg/math/log_amd64p32.s b/src/pkg/math/log_amd64p32.s
new file mode 100644
index 0000000..5058d60
--- /dev/null
+++ b/src/pkg/math/log_amd64p32.s
@@ -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 "log_amd64.s"
diff --git a/src/pkg/math/mod_amd64p32.s b/src/pkg/math/mod_amd64p32.s
new file mode 100644
index 0000000..c1b2311
--- /dev/null
+++ b/src/pkg/math/mod_amd64p32.s
@@ -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 "mod_amd64.s"
diff --git a/src/pkg/math/modf_amd64p32.s b/src/pkg/math/modf_amd64p32.s
new file mode 100644
index 0000000..5508c25
--- /dev/null
+++ b/src/pkg/math/modf_amd64p32.s
@@ -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 "modf_amd64.s"
diff --git a/src/pkg/math/rand/rand.go b/src/pkg/math/rand/rand.go
index 2157cdb..3ffb5c4 100644
--- a/src/pkg/math/rand/rand.go
+++ b/src/pkg/math/rand/rand.go
@@ -60,6 +60,9 @@ func (r *Rand) Int63n(n int64) int64 {
 	if n <= 0 {
 		panic("invalid argument to Int63n")
 	}
+	if n&(n-1) == 0 { // n is power of two, can mask
+		return r.Int63() & (n - 1)
+	}
 	max := int64((1 << 63) - 1 - (1<<63)%uint64(n))
 	v := r.Int63()
 	for v > max {
@@ -74,6 +77,9 @@ func (r *Rand) Int31n(n int32) int32 {
 	if n <= 0 {
 		panic("invalid argument to Int31n")
 	}
+	if n&(n-1) == 0 { // n is power of two, can mask
+		return r.Int31() & (n - 1)
+	}
 	max := int32((1 << 31) - 1 - (1<<31)%uint32(n))
 	v := r.Int31()
 	for v > max {
@@ -95,20 +101,54 @@ func (r *Rand) Intn(n int) int {
 }
 
 // Float64 returns, as a float64, a pseudo-random number in [0.0,1.0).
-func (r *Rand) Float64() float64 { return float64(r.Int63()) / (1 << 63) }
+func (r *Rand) Float64() float64 {
+	// A clearer, simpler implementation would be:
+	//	return float64(r.Int63n(1<<53)) / (1<<53)
+	// However, Go 1 shipped with
+	//	return float64(r.Int63()) / (1 << 63)
+	// and we want to preserve that value stream.
+	//
+	// There is one bug in the value stream: r.Int63() may be so close
+	// to 1<<63 that the division rounds up to 1.0, and we've guaranteed
+	// that the result is always less than 1.0. To fix that, we treat the
+	// range as cyclic and map 1 back to 0. This is justified by observing
+	// that while some of the values rounded down to 0, nothing was
+	// rounding up to 0, so 0 was underrepresented in the results.
+	// Mapping 1 back to zero restores some balance.
+	// (The balance is not perfect because the implementation
+	// returns denormalized numbers for very small r.Int63(),
+	// and those steal from what would normally be 0 results.)
+	// The remapping only happens 1/2⁵³ of the time, so most clients
+	// will not observe it anyway.
+	f := float64(r.Int63()) / (1 << 63)
+	if f == 1 {
+		f = 0
+	}
+	return f
+}
 
 // Float32 returns, as a float32, a pseudo-random number in [0.0,1.0).
-func (r *Rand) Float32() float32 { return float32(r.Float64()) }
+func (r *Rand) Float32() float32 {
+	// Same rationale as in Float64: we want to preserve the Go 1 value
+	// stream except we want to fix it not to return 1.0
+	// There is a double rounding going on here, but the argument for
+	// mapping 1 to 0 still applies: 0 was underrepresented before,
+	// so mapping 1 to 0 doesn't cause too many 0s.
+	// This only happens 1/2²⁴ of the time (plus the 1/2⁵³ of the time in Float64).
+	f := float32(r.Float64())
+	if f == 1 {
+		f = 0
+	}
+	return f
+}
 
 // Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n).
 func (r *Rand) Perm(n int) []int {
 	m := make([]int, n)
 	for i := 0; i < n; i++ {
-		m[i] = i
-	}
-	for i := 0; i < n; i++ {
 		j := r.Intn(i + 1)
-		m[i], m[j] = m[j], m[i]
+		m[i] = m[j]
+		m[j] = i
 	}
 	return m
 }
diff --git a/src/pkg/math/rand/rand_test.go b/src/pkg/math/rand/rand_test.go
index 4d3abdb..ab0dc49 100644
--- a/src/pkg/math/rand/rand_test.go
+++ b/src/pkg/math/rand/rand_test.go
@@ -322,6 +322,17 @@ func TestExpTables(t *testing.T) {
 	}
 }
 
+// For issue 6721, the problem came after 7533753 calls, so check 10e6.
+func TestFloat32(t *testing.T) {
+	r := New(NewSource(1))
+	for ct := 0; ct < 10e6; ct++ {
+		f := r.Float32()
+		if f >= 1 {
+			t.Fatal("Float32() should be in range [0,1). ct:", ct, "f:", f)
+		}
+	}
+}
+
 // Benchmarks
 
 func BenchmarkInt63Threadsafe(b *testing.B) {
@@ -357,3 +368,31 @@ func BenchmarkInt31n1000(b *testing.B) {
 		r.Int31n(1000)
 	}
 }
+
+func BenchmarkFloat32(b *testing.B) {
+	r := New(NewSource(1))
+	for n := b.N; n > 0; n-- {
+		r.Float32()
+	}
+}
+
+func BenchmarkFloat64(b *testing.B) {
+	r := New(NewSource(1))
+	for n := b.N; n > 0; n-- {
+		r.Float64()
+	}
+}
+
+func BenchmarkPerm3(b *testing.B) {
+	r := New(NewSource(1))
+	for n := b.N; n > 0; n-- {
+		r.Perm(3)
+	}
+}
+
+func BenchmarkPerm30(b *testing.B) {
+	r := New(NewSource(1))
+	for n := b.N; n > 0; n-- {
+		r.Perm(30)
+	}
+}
diff --git a/src/pkg/math/rand/regress_test.go b/src/pkg/math/rand/regress_test.go
new file mode 100644
index 0000000..2b012af
--- /dev/null
+++ b/src/pkg/math/rand/regress_test.go
@@ -0,0 +1,355 @@
+// 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 random number sequences generated by a specific seed
+// do not change from version to version.
+//
+// Do NOT make changes to the golden outputs. If bugs need to be fixed
+// in the underlying code, find ways to fix them that do not affect the
+// outputs.
+
+package rand_test
+
+import (
+	"flag"
+	"fmt"
+	. "math/rand"
+	"reflect"
+	"testing"
+)
+
+var printgolden = flag.Bool("printgolden", false, "print golden results for regression test")
+
+func TestRegress(t *testing.T) {
+	var int32s = []int32{1, 10, 32, 1 << 20, 1<<20 + 1, 1000000000, 1 << 30, 1<<31 - 2, 1<<31 - 1}
+	var int64s = []int64{1, 10, 32, 1 << 20, 1<<20 + 1, 1000000000, 1 << 30, 1<<31 - 2, 1<<31 - 1, 1000000000000000000, 1 << 60, 1<<63 - 2, 1<<63 - 1}
+	var permSizes = []int{0, 1, 5, 8, 9, 10, 16}
+	r := New(NewSource(0))
+
+	rv := reflect.ValueOf(r)
+	n := rv.NumMethod()
+	p := 0
+	if *printgolden {
+		fmt.Printf("var regressGolden = []interface{}{\n")
+	}
+	for i := 0; i < n; i++ {
+		m := rv.Type().Method(i)
+		mv := rv.Method(i)
+		mt := mv.Type()
+		if mt.NumOut() == 0 {
+			continue
+		}
+		if mt.NumOut() != 1 {
+			t.Fatalf("unexpected result count for r.%s", m.Name)
+		}
+		r.Seed(0)
+		for repeat := 0; repeat < 20; repeat++ {
+			var args []reflect.Value
+			var argstr string
+			if mt.NumIn() == 1 {
+				var x interface{}
+				switch mt.In(0).Kind() {
+				default:
+					t.Fatalf("unexpected argument type for r.%s", m.Name)
+
+				case reflect.Int:
+					if m.Name == "Perm" {
+						x = permSizes[repeat%len(permSizes)]
+						break
+					}
+					big := int64s[repeat%len(int64s)]
+					if int64(int(big)) != big {
+						r.Int63n(big) // what would happen on 64-bit machine, to keep stream in sync
+						if *printgolden {
+							fmt.Printf("\tskipped, // must run printgolden on 64-bit machine\n")
+						}
+						p++
+						continue
+					}
+					x = int(big)
+
+				case reflect.Int32:
+					x = int32s[repeat%len(int32s)]
+
+				case reflect.Int64:
+					x = int64s[repeat%len(int64s)]
+				}
+				argstr = fmt.Sprint(x)
+				args = append(args, reflect.ValueOf(x))
+			}
+			out := mv.Call(args)[0].Interface()
+			if m.Name == "Int" || m.Name == "Intn" {
+				out = int64(out.(int))
+			}
+			if *printgolden {
+				var val string
+				big := int64(1 << 60)
+				if int64(int(big)) != big && (m.Name == "Int" || m.Name == "Intn") {
+					// 32-bit machine cannot print 64-bit results
+					val = "truncated"
+				} else if reflect.TypeOf(out).Kind() == reflect.Slice {
+					val = fmt.Sprintf("%#v", out)
+				} else {
+					val = fmt.Sprintf("%T(%v)", out, out)
+				}
+				fmt.Printf("\t%s, // %s(%s)\n", val, m.Name, argstr)
+			} else {
+				want := regressGolden[p]
+				if m.Name == "Int" {
+					want = int64(int(uint(want.(int64)) << 1 >> 1))
+				}
+				if !reflect.DeepEqual(out, want) {
+					t.Errorf("r.%s(%s) = %v, want %v", m.Name, argstr, out, want)
+				}
+			}
+			p++
+		}
+	}
+	if *printgolden {
+		fmt.Printf("}\n")
+	}
+}
+
+var regressGolden = []interface{}{
+	float64(4.668112973579268),    // ExpFloat64()
+	float64(0.1601593871172866),   // ExpFloat64()
+	float64(3.0465834105636),      // ExpFloat64()
+	float64(0.06385839451671879),  // ExpFloat64()
+	float64(1.8578917487258961),   // ExpFloat64()
+	float64(0.784676123472182),    // ExpFloat64()
+	float64(0.11225477361256932),  // ExpFloat64()
+	float64(0.20173283329802255),  // ExpFloat64()
+	float64(0.3468619496201105),   // ExpFloat64()
+	float64(0.35601103454384536),  // ExpFloat64()
+	float64(0.888376329507869),    // ExpFloat64()
+	float64(1.4081362450365698),   // ExpFloat64()
+	float64(1.0077753823151994),   // ExpFloat64()
+	float64(0.23594100766227588),  // ExpFloat64()
+	float64(2.777245612300007),    // ExpFloat64()
+	float64(0.5202997830662377),   // ExpFloat64()
+	float64(1.2842705247770294),   // ExpFloat64()
+	float64(0.030307408362776206), // ExpFloat64()
+	float64(2.204156824853721),    // ExpFloat64()
+	float64(2.09891923895058),     // ExpFloat64()
+	float32(0.94519615),           // Float32()
+	float32(0.24496509),           // Float32()
+	float32(0.65595627),           // Float32()
+	float32(0.05434384),           // Float32()
+	float32(0.3675872),            // Float32()
+	float32(0.28948045),           // Float32()
+	float32(0.1924386),            // Float32()
+	float32(0.65533215),           // Float32()
+	float32(0.8971697),            // Float32()
+	float32(0.16735445),           // Float32()
+	float32(0.28858566),           // Float32()
+	float32(0.9026048),            // Float32()
+	float32(0.84978026),           // Float32()
+	float32(0.2730468),            // Float32()
+	float32(0.6090802),            // Float32()
+	float32(0.253656),             // Float32()
+	float32(0.7746542),            // Float32()
+	float32(0.017480763),          // Float32()
+	float32(0.78707397),           // Float32()
+	float32(0.7993937),            // Float32()
+	float64(0.9451961492941164),   // Float64()
+	float64(0.24496508529377975),  // Float64()
+	float64(0.6559562651954052),   // Float64()
+	float64(0.05434383959970039),  // Float64()
+	float64(0.36758720663245853),  // Float64()
+	float64(0.2894804331565928),   // Float64()
+	float64(0.19243860967493215),  // Float64()
+	float64(0.6553321508148324),   // Float64()
+	float64(0.897169713149801),    // Float64()
+	float64(0.16735444255905835),  // Float64()
+	float64(0.2885856518054551),   // Float64()
+	float64(0.9026048462705047),   // Float64()
+	float64(0.8497802817628735),   // Float64()
+	float64(0.2730468047134829),   // Float64()
+	float64(0.6090801919903561),   // Float64()
+	float64(0.25365600644283687),  // Float64()
+	float64(0.7746542391859803),   // Float64()
+	float64(0.017480762156647272), // Float64()
+	float64(0.7870739563039942),   // Float64()
+	float64(0.7993936979594545),   // Float64()
+	int64(8717895732742165505),    // Int()
+	int64(2259404117704393152),    // Int()
+	int64(6050128673802995827),    // Int()
+	int64(501233450539197794),     // Int()
+	int64(3390393562759376202),    // Int()
+	int64(2669985732393126063),    // Int()
+	int64(1774932891286980153),    // Int()
+	int64(6044372234677422456),    // Int()
+	int64(8274930044578894929),    // Int()
+	int64(1543572285742637646),    // Int()
+	int64(2661732831099943416),    // Int()
+	int64(8325060299420976708),    // Int()
+	int64(7837839688282259259),    // Int()
+	int64(2518412263346885298),    // Int()
+	int64(5617773211005988520),    // Int()
+	int64(2339563716805116249),    // Int()
+	int64(7144924247938981575),    // Int()
+	int64(161231572858529631),     // Int()
+	int64(7259475919510918339),    // Int()
+	int64(7373105480197164748),    // Int()
+	int32(2029793274),             // Int31()
+	int32(526058514),              // Int31()
+	int32(1408655353),             // Int31()
+	int32(116702506),              // Int31()
+	int32(789387515),              // Int31()
+	int32(621654496),              // Int31()
+	int32(413258767),              // Int31()
+	int32(1407315077),             // Int31()
+	int32(1926657288),             // Int31()
+	int32(359390928),              // Int31()
+	int32(619732968),              // Int31()
+	int32(1938329147),             // Int31()
+	int32(1824889259),             // Int31()
+	int32(586363548),              // Int31()
+	int32(1307989752),             // Int31()
+	int32(544722126),              // Int31()
+	int32(1663557311),             // Int31()
+	int32(37539650),               // Int31()
+	int32(1690228450),             // Int31()
+	int32(1716684894),             // Int31()
+	int32(0),                      // Int31n(1)
+	int32(4),                      // Int31n(10)
+	int32(25),                     // Int31n(32)
+	int32(310570),                 // Int31n(1048576)
+	int32(857611),                 // Int31n(1048577)
+	int32(621654496),              // Int31n(1000000000)
+	int32(413258767),              // Int31n(1073741824)
+	int32(1407315077),             // Int31n(2147483646)
+	int32(1926657288),             // Int31n(2147483647)
+	int32(0),                      // Int31n(1)
+	int32(8),                      // Int31n(10)
+	int32(27),                     // Int31n(32)
+	int32(367019),                 // Int31n(1048576)
+	int32(209005),                 // Int31n(1048577)
+	int32(307989752),              // Int31n(1000000000)
+	int32(544722126),              // Int31n(1073741824)
+	int32(1663557311),             // Int31n(2147483646)
+	int32(37539650),               // Int31n(2147483647)
+	int32(0),                      // Int31n(1)
+	int32(4),                      // Int31n(10)
+	int64(8717895732742165505),    // Int63()
+	int64(2259404117704393152),    // Int63()
+	int64(6050128673802995827),    // Int63()
+	int64(501233450539197794),     // Int63()
+	int64(3390393562759376202),    // Int63()
+	int64(2669985732393126063),    // Int63()
+	int64(1774932891286980153),    // Int63()
+	int64(6044372234677422456),    // Int63()
+	int64(8274930044578894929),    // Int63()
+	int64(1543572285742637646),    // Int63()
+	int64(2661732831099943416),    // Int63()
+	int64(8325060299420976708),    // Int63()
+	int64(7837839688282259259),    // Int63()
+	int64(2518412263346885298),    // Int63()
+	int64(5617773211005988520),    // Int63()
+	int64(2339563716805116249),    // Int63()
+	int64(7144924247938981575),    // Int63()
+	int64(161231572858529631),     // Int63()
+	int64(7259475919510918339),    // Int63()
+	int64(7373105480197164748),    // Int63()
+	int64(0),                      // Int63n(1)
+	int64(2),                      // Int63n(10)
+	int64(19),                     // Int63n(32)
+	int64(959842),                 // Int63n(1048576)
+	int64(688912),                 // Int63n(1048577)
+	int64(393126063),              // Int63n(1000000000)
+	int64(89212473),               // Int63n(1073741824)
+	int64(834026388),              // Int63n(2147483646)
+	int64(1577188963),             // Int63n(2147483647)
+	int64(543572285742637646),     // Int63n(1000000000000000000)
+	int64(355889821886249464),     // Int63n(1152921504606846976)
+	int64(8325060299420976708),    // Int63n(9223372036854775806)
+	int64(7837839688282259259),    // Int63n(9223372036854775807)
+	int64(0),                      // Int63n(1)
+	int64(0),                      // Int63n(10)
+	int64(25),                     // Int63n(32)
+	int64(679623),                 // Int63n(1048576)
+	int64(882178),                 // Int63n(1048577)
+	int64(510918339),              // Int63n(1000000000)
+	int64(782454476),              // Int63n(1073741824)
+	int64(0),                      // Intn(1)
+	int64(4),                      // Intn(10)
+	int64(25),                     // Intn(32)
+	int64(310570),                 // Intn(1048576)
+	int64(857611),                 // Intn(1048577)
+	int64(621654496),              // Intn(1000000000)
+	int64(413258767),              // Intn(1073741824)
+	int64(1407315077),             // Intn(2147483646)
+	int64(1926657288),             // Intn(2147483647)
+	int64(543572285742637646),     // Intn(1000000000000000000)
+	int64(355889821886249464),     // Intn(1152921504606846976)
+	int64(8325060299420976708),    // Intn(9223372036854775806)
+	int64(7837839688282259259),    // Intn(9223372036854775807)
+	int64(0),                      // Intn(1)
+	int64(2),                      // Intn(10)
+	int64(14),                     // Intn(32)
+	int64(515775),                 // Intn(1048576)
+	int64(839455),                 // Intn(1048577)
+	int64(690228450),              // Intn(1000000000)
+	int64(642943070),              // Intn(1073741824)
+	float64(-0.28158587086436215), // NormFloat64()
+	float64(0.570933095808067),    // NormFloat64()
+	float64(-1.6920196326157044),  // NormFloat64()
+	float64(0.1996229111693099),   // NormFloat64()
+	float64(1.9195199291234621),   // NormFloat64()
+	float64(0.8954838794918353),   // NormFloat64()
+	float64(0.41457072128813166),  // NormFloat64()
+	float64(-0.48700161491544713), // NormFloat64()
+	float64(-0.1684059662402393),  // NormFloat64()
+	float64(0.37056410998929545),  // NormFloat64()
+	float64(1.0156889027029008),   // NormFloat64()
+	float64(-0.5174422210625114),  // NormFloat64()
+	float64(-0.5565834214413804),  // NormFloat64()
+	float64(0.778320596648391),    // NormFloat64()
+	float64(-1.8970718197702225),  // NormFloat64()
+	float64(0.5229525761688676),   // NormFloat64()
+	float64(-1.5515595563231523),  // NormFloat64()
+	float64(0.0182029289376123),   // NormFloat64()
+	float64(-0.6820951356608795),  // NormFloat64()
+	float64(-0.5987943422687668),  // NormFloat64()
+	[]int{},                                                     // Perm(0)
+	[]int{0},                                                    // Perm(1)
+	[]int{0, 4, 1, 3, 2},                                        // Perm(5)
+	[]int{3, 1, 0, 4, 7, 5, 2, 6},                               // Perm(8)
+	[]int{5, 0, 3, 6, 7, 4, 2, 1, 8},                            // Perm(9)
+	[]int{4, 5, 0, 2, 6, 9, 3, 1, 8, 7},                         // Perm(10)
+	[]int{14, 2, 0, 8, 3, 5, 13, 12, 1, 4, 6, 7, 11, 9, 15, 10}, // Perm(16)
+	[]int{},                                                     // Perm(0)
+	[]int{0},                                                    // Perm(1)
+	[]int{3, 0, 1, 2, 4},                                        // Perm(5)
+	[]int{5, 1, 2, 0, 4, 7, 3, 6},                               // Perm(8)
+	[]int{4, 0, 6, 8, 1, 5, 2, 7, 3},                            // Perm(9)
+	[]int{8, 6, 1, 7, 5, 4, 3, 2, 9, 0},                         // Perm(10)
+	[]int{0, 3, 13, 2, 15, 4, 10, 1, 8, 14, 7, 6, 12, 9, 5, 11}, // Perm(16)
+	[]int{},                             // Perm(0)
+	[]int{0},                            // Perm(1)
+	[]int{0, 4, 2, 1, 3},                // Perm(5)
+	[]int{2, 1, 7, 0, 6, 3, 4, 5},       // Perm(8)
+	[]int{8, 7, 5, 3, 4, 6, 0, 1, 2},    // Perm(9)
+	[]int{1, 0, 2, 5, 7, 6, 9, 8, 3, 4}, // Perm(10)
+	uint32(4059586549),                  // Uint32()
+	uint32(1052117029),                  // Uint32()
+	uint32(2817310706),                  // Uint32()
+	uint32(233405013),                   // Uint32()
+	uint32(1578775030),                  // Uint32()
+	uint32(1243308993),                  // Uint32()
+	uint32(826517535),                   // Uint32()
+	uint32(2814630155),                  // Uint32()
+	uint32(3853314576),                  // Uint32()
+	uint32(718781857),                   // Uint32()
+	uint32(1239465936),                  // Uint32()
+	uint32(3876658295),                  // Uint32()
+	uint32(3649778518),                  // Uint32()
+	uint32(1172727096),                  // Uint32()
+	uint32(2615979505),                  // Uint32()
+	uint32(1089444252),                  // Uint32()
+	uint32(3327114623),                  // Uint32()
+	uint32(75079301),                    // Uint32()
+	uint32(3380456901),                  // Uint32()
+	uint32(3433369789),                  // Uint32()
+}
diff --git a/src/pkg/math/remainder_amd64p32.s b/src/pkg/math/remainder_amd64p32.s
new file mode 100644
index 0000000..cd5cf55
--- /dev/null
+++ b/src/pkg/math/remainder_amd64p32.s
@@ -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 "remainder_amd64.s"
diff --git a/src/pkg/math/sin_amd64p32.s b/src/pkg/math/sin_amd64p32.s
new file mode 100644
index 0000000..9f93eba
--- /dev/null
+++ b/src/pkg/math/sin_amd64p32.s
@@ -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 "sin_amd64.s"
diff --git a/src/pkg/math/sincos_amd64p32.s b/src/pkg/math/sincos_amd64p32.s
new file mode 100644
index 0000000..360e94d
--- /dev/null
+++ b/src/pkg/math/sincos_amd64p32.s
@@ -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 "sincos_amd64.s"
diff --git a/src/pkg/math/sqrt_amd64p32.s b/src/pkg/math/sqrt_amd64p32.s
new file mode 100644
index 0000000..d83a286
--- /dev/null
+++ b/src/pkg/math/sqrt_amd64p32.s
@@ -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 "sqrt_amd64.s"
diff --git a/src/pkg/math/tan_amd64p32.s b/src/pkg/math/tan_amd64p32.s
new file mode 100644
index 0000000..9b3f70d
--- /dev/null
+++ b/src/pkg/math/tan_amd64p32.s
@@ -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 "tan_amd64.s"
diff --git a/src/pkg/mime/mediatype.go b/src/pkg/mime/mediatype.go
index 608f759..ad63f9b 100644
--- a/src/pkg/mime/mediatype.go
+++ b/src/pkg/mime/mediatype.go
@@ -8,6 +8,7 @@ import (
 	"bytes"
 	"errors"
 	"fmt"
+	"sort"
 	"strings"
 	"unicode"
 )
@@ -31,7 +32,14 @@ func FormatMediaType(t string, param map[string]string) string {
 	b.WriteByte('/')
 	b.WriteString(strings.ToLower(sub))
 
-	for attribute, value := range param {
+	attrs := make([]string, 0, len(param))
+	for a := range param {
+		attrs = append(attrs, a)
+	}
+	sort.Strings(attrs)
+
+	for _, attribute := range attrs {
+		value := param[attribute]
 		b.WriteByte(';')
 		b.WriteByte(' ')
 		if !isToken(attribute) {
diff --git a/src/pkg/mime/mediatype_test.go b/src/pkg/mime/mediatype_test.go
index 2951144..026bfa4 100644
--- a/src/pkg/mime/mediatype_test.go
+++ b/src/pkg/mime/mediatype_test.go
@@ -293,6 +293,7 @@ var formatTests = []formatTest{
 	{"foo/BAR", map[string]string{"": "empty attribute"}, ""},
 	{"foo/BAR", map[string]string{"bad attribute": "baz"}, ""},
 	{"foo/BAR", map[string]string{"nonascii": "not an ascii character: ä"}, ""},
+	{"foo/bar", map[string]string{"a": "av", "b": "bv", "c": "cv"}, "foo/bar; a=av; b=bv; c=cv"},
 }
 
 func TestFormatMediaType(t *testing.T) {
diff --git a/src/pkg/mime/multipart/example_test.go b/src/pkg/mime/multipart/example_test.go
new file mode 100644
index 0000000..26135b7
--- /dev/null
+++ b/src/pkg/mime/multipart/example_test.go
@@ -0,0 +1,53 @@
+// 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 multipart_test
+
+import (
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"mime"
+	"mime/multipart"
+	"net/mail"
+	"strings"
+)
+
+func ExampleNewReader() {
+	msg := &mail.Message{
+		Header: map[string][]string{
+			"Content-Type": []string{"multipart/mixed; boundary=foo"},
+		},
+		Body: strings.NewReader(
+			"--foo\r\nFoo: one\r\n\r\nA section\r\n" +
+				"--foo\r\nFoo: two\r\n\r\nAnd another\r\n" +
+				"--foo--\r\n"),
+	}
+	mediaType, params, err := mime.ParseMediaType(msg.Header.Get("Content-Type"))
+	if err != nil {
+		log.Fatal(err)
+	}
+	if strings.HasPrefix(mediaType, "multipart/") {
+		mr := multipart.NewReader(msg.Body, params["boundary"])
+		for {
+			p, err := mr.NextPart()
+			if err == io.EOF {
+				return
+			}
+			if err != nil {
+				log.Fatal(err)
+			}
+			slurp, err := ioutil.ReadAll(p)
+			if err != nil {
+				log.Fatal(err)
+			}
+			fmt.Printf("Part %q: %q\n", p.Header.Get("Foo"), slurp)
+		}
+	}
+
+	// Output:
+	// Part "one": "A section"
+	// Part "two": "And another"
+}
diff --git a/src/pkg/mime/multipart/formdata_test.go b/src/pkg/mime/multipart/formdata_test.go
index 4bc4649..6e2388b 100644
--- a/src/pkg/mime/multipart/formdata_test.go
+++ b/src/pkg/mime/multipart/formdata_test.go
@@ -9,12 +9,13 @@ import (
 	"io"
 	"os"
 	"regexp"
+	"strings"
 	"testing"
 )
 
 func TestReadForm(t *testing.T) {
 	testBody := regexp.MustCompile("\n").ReplaceAllString(message, "\r\n")
-	b := bytes.NewBufferString(testBody)
+	b := strings.NewReader(testBody)
 	r := NewReader(b, boundary)
 	f, err := r.ReadForm(25)
 	if err != nil {
diff --git a/src/pkg/mime/multipart/multipart.go b/src/pkg/mime/multipart/multipart.go
index 2b4f5b4..7382efa 100644
--- a/src/pkg/mime/multipart/multipart.go
+++ b/src/pkg/mime/multipart/multipart.go
@@ -81,12 +81,16 @@ func (p *Part) parseContentDisposition() {
 	}
 }
 
-// NewReader creates a new multipart Reader reading from reader using the
+// NewReader creates a new multipart Reader reading from r using the
 // given MIME boundary.
-func NewReader(reader io.Reader, boundary string) *Reader {
+//
+// The boundary is usually obtained from the "boundary" parameter of
+// the message's "Content-Type" header. Use mime.ParseMediaType to
+// parse such headers.
+func NewReader(r io.Reader, boundary string) *Reader {
 	b := []byte("\r\n--" + boundary + "--")
 	return &Reader{
-		bufReader: bufio.NewReader(reader),
+		bufReader: bufio.NewReader(r),
 
 		nl:               b[:2],
 		nlDashBoundary:   b[:len(b)-2],
diff --git a/src/pkg/mime/multipart/quotedprintable_test.go b/src/pkg/mime/multipart/quotedprintable_test.go
index 8a95f7f..c4de3eb 100644
--- a/src/pkg/mime/multipart/quotedprintable_test.go
+++ b/src/pkg/mime/multipart/quotedprintable_test.go
@@ -131,7 +131,7 @@ func TestQPExhaustive(t *testing.T) {
 					return
 				}
 				if strings.HasSuffix(errStr, "0x0a") || strings.HasSuffix(errStr, "0x0d") {
-					// bunch of cases; since whitespace at the end of of a line before \n is removed.
+					// bunch of cases; since whitespace at the end of a line before \n is removed.
 					return
 				}
 			}
diff --git a/src/pkg/mime/type_unix.go b/src/pkg/mime/type_unix.go
index 713e301..1d39431 100644
--- a/src/pkg/mime/type_unix.go
+++ b/src/pkg/mime/type_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 mime
 
diff --git a/src/pkg/net/cgo_bsd.go b/src/pkg/net/cgo_bsd.go
index 388eab4..3090d30 100644
--- a/src/pkg/net/cgo_bsd.go
+++ b/src/pkg/net/cgo_bsd.go
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // +build !netgo
-// +build darwin dragonfly freebsd
+// +build darwin dragonfly freebsd solaris
 
 package net
 
diff --git a/src/pkg/net/cgo_unix_test.go b/src/pkg/net/cgo_unix_test.go
new file mode 100644
index 0000000..33566ce
--- /dev/null
+++ b/src/pkg/net/cgo_unix_test.go
@@ -0,0 +1,24 @@
+// 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 cgo,!netgo
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+package net
+
+import "testing"
+
+func TestCgoLookupIP(t *testing.T) {
+	host := "localhost"
+	_, err, ok := cgoLookupIP(host)
+	if !ok {
+		t.Errorf("cgoLookupIP must not be a placeholder")
+	}
+	if err != nil {
+		t.Errorf("cgoLookupIP failed: %v", err)
+	}
+	if _, err := goLookupIP(host); err != nil {
+		t.Errorf("goLookupIP failed: %v", err)
+	}
+}
diff --git a/src/pkg/net/conn_test.go b/src/pkg/net/conn_test.go
index 98bd695..37bb4e2 100644
--- a/src/pkg/net/conn_test.go
+++ b/src/pkg/net/conn_test.go
@@ -16,11 +16,11 @@ import (
 
 var connTests = []struct {
 	net  string
-	addr func() string
+	addr string
 }{
-	{"tcp", func() string { return "127.0.0.1:0" }},
-	{"unix", testUnixAddr},
-	{"unixpacket", testUnixAddr},
+	{"tcp", "127.0.0.1:0"},
+	{"unix", testUnixAddr()},
+	{"unixpacket", testUnixAddr()},
 }
 
 // someTimeout is used just to test that net.Conn implementations
@@ -31,18 +31,21 @@ const someTimeout = 10 * time.Second
 func TestConnAndListener(t *testing.T) {
 	for _, tt := range connTests {
 		switch tt.net {
-		case "unix", "unixpacket":
+		case "unix":
 			switch runtime.GOOS {
-			case "plan9", "windows":
+			case "nacl", "plan9", "windows":
 				continue
 			}
-			if tt.net == "unixpacket" && runtime.GOOS != "linux" {
+		case "unixpacket":
+			switch runtime.GOOS {
+			case "darwin", "nacl", "openbsd", "plan9", "windows":
+				continue
+			case "freebsd": // FreeBSD 8 doesn't support unixpacket
 				continue
 			}
 		}
 
-		addr := tt.addr()
-		ln, err := Listen(tt.net, addr)
+		ln, err := Listen(tt.net, tt.addr)
 		if err != nil {
 			t.Fatalf("Listen failed: %v", err)
 		}
@@ -52,8 +55,10 @@ func TestConnAndListener(t *testing.T) {
 			case "unix", "unixpacket":
 				os.Remove(addr)
 			}
-		}(ln, tt.net, addr)
-		ln.Addr()
+		}(ln, tt.net, tt.addr)
+		if ln.Addr().Network() != tt.net {
+			t.Fatalf("got %v; expected %v", ln.Addr().Network(), tt.net)
+		}
 
 		done := make(chan int)
 		go transponder(t, ln, done)
@@ -63,8 +68,9 @@ func TestConnAndListener(t *testing.T) {
 			t.Fatalf("Dial failed: %v", err)
 		}
 		defer c.Close()
-		c.LocalAddr()
-		c.RemoteAddr()
+		if c.LocalAddr().Network() != tt.net || c.LocalAddr().Network() != tt.net {
+			t.Fatalf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), tt.net, tt.net)
+		}
 		c.SetDeadline(time.Now().Add(someTimeout))
 		c.SetReadDeadline(time.Now().Add(someTimeout))
 		c.SetWriteDeadline(time.Now().Add(someTimeout))
@@ -96,8 +102,11 @@ func transponder(t *testing.T, ln Listener, done chan<- int) {
 		return
 	}
 	defer c.Close()
-	c.LocalAddr()
-	c.RemoteAddr()
+	network := ln.Addr().Network()
+	if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network {
+		t.Errorf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network)
+		return
+	}
 	c.SetDeadline(time.Now().Add(someTimeout))
 	c.SetReadDeadline(time.Now().Add(someTimeout))
 	c.SetWriteDeadline(time.Now().Add(someTimeout))
diff --git a/src/pkg/net/dial.go b/src/pkg/net/dial.go
index 6304818..93569c2 100644
--- a/src/pkg/net/dial.go
+++ b/src/pkg/net/dial.go
@@ -44,6 +44,12 @@ type Dialer struct {
 	// destination is a host name that has multiple address family
 	// DNS records.
 	DualStack bool
+
+	// KeepAlive specifies the keep-alive period for an active
+	// network connection.
+	// If zero, keep-alives are not enabled. Network protocols
+	// that do not support keep-alives ignore this field.
+	KeepAlive time.Duration
 }
 
 // Return either now+Timeout or Deadline, whichever comes first.
@@ -162,9 +168,19 @@ func (d *Dialer) Dial(network, address string) (Conn, error) {
 			return dialMulti(network, address, d.LocalAddr, ras, deadline)
 		}
 	}
-	return dial(network, ra.toAddr(), dialer, d.deadline())
+	c, err := dial(network, ra.toAddr(), dialer, d.deadline())
+	if d.KeepAlive > 0 && err == nil {
+		if tc, ok := c.(*TCPConn); ok {
+			tc.SetKeepAlive(true)
+			tc.SetKeepAlivePeriod(d.KeepAlive)
+			testHookSetKeepAlive()
+		}
+	}
+	return c, err
 }
 
+var testHookSetKeepAlive = func() {} // changed by dial_test.go
+
 // dialMulti attempts to establish connections to each destination of
 // the list of addresses. It will return the first established
 // connection and close the other connections. Otherwise it returns
@@ -172,7 +188,6 @@ func (d *Dialer) Dial(network, address string) (Conn, error) {
 func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Conn, error) {
 	type racer struct {
 		Conn
-		Addr
 		error
 	}
 	// Sig controls the flow of dial results on lane. It passes a
@@ -184,7 +199,7 @@ func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Con
 		go func(ra Addr) {
 			c, err := dialSingle(net, addr, la, ra, deadline)
 			if _, ok := <-sig; ok {
-				lane <- racer{c, ra, err}
+				lane <- racer{c, err}
 			} else if err == nil {
 				// We have to return the resources
 				// that belong to the other
@@ -195,7 +210,6 @@ func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Con
 		}(ra.toAddr())
 	}
 	defer close(sig)
-	var failAddr Addr
 	lastErr := errTimeout
 	nracers := len(ras)
 	for nracers > 0 {
@@ -205,12 +219,11 @@ func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Con
 			if racer.error == nil {
 				return racer.Conn, nil
 			}
-			failAddr = racer.Addr
 			lastErr = racer.error
 			nracers--
 		}
 	}
-	return nil, &OpError{Op: "dial", Net: net, Addr: failAddr, Err: lastErr}
+	return nil, lastErr
 }
 
 // dialSingle attempts to establish and returns a single connection to
diff --git a/src/pkg/net/dial_test.go b/src/pkg/net/dial_test.go
index f1d813f..f9260fd 100644
--- a/src/pkg/net/dial_test.go
+++ b/src/pkg/net/dial_test.go
@@ -58,7 +58,7 @@ func TestDialTimeout(t *testing.T) {
 				errc <- err
 			}()
 		}
-	case "darwin", "windows":
+	case "darwin", "plan9", "windows":
 		// At least OS X 10.7 seems to accept any number of
 		// connections, ignoring listen's backlog, so resort
 		// to connecting to a hopefully-dead 127/8 address.
@@ -141,13 +141,13 @@ func TestSelfConnect(t *testing.T) {
 		n = 1000
 	}
 	switch runtime.GOOS {
-	case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "windows":
+	case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "solaris", "windows":
 		// Non-Linux systems take a long time to figure
 		// out that there is nothing listening on localhost.
 		n = 100
 	}
 	for i := 0; i < n; i++ {
-		c, err := Dial("tcp", addr)
+		c, err := DialTimeout("tcp", addr, time.Millisecond)
 		if err == nil {
 			c.Close()
 			t.Errorf("#%d: Dial %q succeeded", i, addr)
@@ -425,60 +425,6 @@ func numFD() int {
 	panic("numFDs not implemented on " + runtime.GOOS)
 }
 
-// Assert that a failed Dial attempt does not leak
-// runtime.PollDesc structures
-func TestDialFailPDLeak(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode")
-	}
-	if runtime.GOOS == "windows" && runtime.GOARCH == "386" {
-		// Just skip the test because it takes too long.
-		t.Skipf("skipping test on %q/%q", runtime.GOOS, runtime.GOARCH)
-	}
-
-	maxprocs := runtime.GOMAXPROCS(0)
-	loops := 10 + maxprocs
-	// 500 is enough to turn over the chunk of pollcache.
-	// See allocPollDesc in runtime/netpoll.goc.
-	const count = 500
-	var old runtime.MemStats // used by sysdelta
-	runtime.ReadMemStats(&old)
-	sysdelta := func() uint64 {
-		var new runtime.MemStats
-		runtime.ReadMemStats(&new)
-		delta := old.Sys - new.Sys
-		old = new
-		return delta
-	}
-	d := &Dialer{Timeout: time.Nanosecond} // don't bother TCP with handshaking
-	failcount := 0
-	for i := 0; i < loops; i++ {
-		var wg sync.WaitGroup
-		for i := 0; i < count; i++ {
-			wg.Add(1)
-			go func() {
-				defer wg.Done()
-				if c, err := d.Dial("tcp", "127.0.0.1:1"); err == nil {
-					t.Error("dial should not succeed")
-					c.Close()
-				}
-			}()
-		}
-		wg.Wait()
-		if t.Failed() {
-			t.FailNow()
-		}
-		if delta := sysdelta(); delta > 0 {
-			failcount++
-		}
-		// there are always some allocations on the first loop
-		if failcount > maxprocs+2 {
-			t.Error("detected possible memory leak in runtime")
-			t.FailNow()
-		}
-	}
-}
-
 func TestDialer(t *testing.T) {
 	ln, err := Listen("tcp4", "127.0.0.1:0")
 	if err != nil {
@@ -555,3 +501,36 @@ func TestDialDualStackLocalhost(t *testing.T) {
 		}
 	}
 }
+
+func TestDialerKeepAlive(t *testing.T) {
+	ln := newLocalListener(t)
+	defer ln.Close()
+	defer func() {
+		testHookSetKeepAlive = func() {}
+	}()
+	go func() {
+		for {
+			c, err := ln.Accept()
+			if err != nil {
+				return
+			}
+			c.Close()
+		}
+	}()
+	for _, keepAlive := range []bool{false, true} {
+		got := false
+		testHookSetKeepAlive = func() { got = true }
+		var d Dialer
+		if keepAlive {
+			d.KeepAlive = 30 * time.Second
+		}
+		c, err := d.Dial("tcp", ln.Addr().String())
+		if err != nil {
+			t.Fatal(err)
+		}
+		c.Close()
+		if got != keepAlive {
+			t.Errorf("Dialer.KeepAlive = %v: SetKeepAlive called = %v, want %v", d.KeepAlive, got, !got)
+		}
+	}
+}
diff --git a/src/pkg/net/dialgoogle_test.go b/src/pkg/net/dialgoogle_test.go
index b4ebad0..df5895a 100644
--- a/src/pkg/net/dialgoogle_test.go
+++ b/src/pkg/net/dialgoogle_test.go
@@ -104,31 +104,7 @@ var googleaddrsipv4 = []string{
 	"[::ffff:%02x%02x:%02x%02x]:80",
 	"[0:0:0:0:0000:ffff:%d.%d.%d.%d]:80",
 	"[0:0:0:0:000000:ffff:%d.%d.%d.%d]:80",
-	"[0:0:0:0:0:ffff::%d.%d.%d.%d]:80",
-}
-
-func TestDNSThreadLimit(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
-	}
-
-	const N = 10000
-	c := make(chan int, N)
-	for i := 0; i < N; i++ {
-		go func(i int) {
-			LookupIP(fmt.Sprintf("%d.net-test.golang.org", i))
-			c <- 1
-		}(i)
-	}
-	// Don't bother waiting for the stragglers; stop at 0.9 N.
-	for i := 0; i < N*9/10; i++ {
-		if i%100 == 0 {
-			//println("TestDNSThreadLimit:", i)
-		}
-		<-c
-	}
-
-	// If we're still here, it worked.
+	"[0:0:0:0::ffff:%d.%d.%d.%d]:80",
 }
 
 func TestDialGoogleIPv4(t *testing.T) {
diff --git a/src/pkg/net/dnsclient.go b/src/pkg/net/dnsclient.go
index 01db437..9bffa11 100644
--- a/src/pkg/net/dnsclient.go
+++ b/src/pkg/net/dnsclient.go
@@ -191,10 +191,10 @@ func (addrs byPriorityWeight) shuffleByWeight() {
 	}
 	for sum > 0 && len(addrs) > 1 {
 		s := 0
-		n := rand.Intn(sum + 1)
+		n := rand.Intn(sum)
 		for i := range addrs {
 			s += int(addrs[i].Weight)
-			if s >= n {
+			if s > n {
 				if i > 0 {
 					t := addrs[i]
 					copy(addrs[1:i+1], addrs[0:i])
diff --git a/src/pkg/net/dnsclient_test.go b/src/pkg/net/dnsclient_test.go
new file mode 100644
index 0000000..435eb35
--- /dev/null
+++ b/src/pkg/net/dnsclient_test.go
@@ -0,0 +1,69 @@
+// 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 net
+
+import (
+	"math/rand"
+	"testing"
+)
+
+func checkDistribution(t *testing.T, data []*SRV, margin float64) {
+	sum := 0
+	for _, srv := range data {
+		sum += int(srv.Weight)
+	}
+
+	results := make(map[string]int)
+
+	count := 1000
+	for j := 0; j < count; j++ {
+		d := make([]*SRV, len(data))
+		copy(d, data)
+		byPriorityWeight(d).shuffleByWeight()
+		key := d[0].Target
+		results[key] = results[key] + 1
+	}
+
+	actual := results[data[0].Target]
+	expected := float64(count) * float64(data[0].Weight) / float64(sum)
+	diff := float64(actual) - expected
+	t.Logf("actual: %v diff: %v e: %v m: %v", actual, diff, expected, margin)
+	if diff < 0 {
+		diff = -diff
+	}
+	if diff > (expected * margin) {
+		t.Errorf("missed target weight: expected %v, %v", expected, actual)
+	}
+}
+
+func testUniformity(t *testing.T, size int, margin float64) {
+	rand.Seed(1)
+	data := make([]*SRV, size)
+	for i := 0; i < size; i++ {
+		data[i] = &SRV{Target: string('a' + i), Weight: 1}
+	}
+	checkDistribution(t, data, margin)
+}
+
+func TestUniformity(t *testing.T) {
+	testUniformity(t, 2, 0.05)
+	testUniformity(t, 3, 0.10)
+	testUniformity(t, 10, 0.20)
+	testWeighting(t, 0.05)
+}
+
+func testWeighting(t *testing.T, margin float64) {
+	rand.Seed(1)
+	data := []*SRV{
+		{Target: "a", Weight: 60},
+		{Target: "b", Weight: 30},
+		{Target: "c", Weight: 10},
+	}
+	checkDistribution(t, data, margin)
+}
+
+func TestWeighting(t *testing.T) {
+	testWeighting(t, 0.05)
+}
diff --git a/src/pkg/net/dnsclient_unix.go b/src/pkg/net/dnsclient_unix.go
index 16cf420..3713efd 100644
--- a/src/pkg/net/dnsclient_unix.go
+++ b/src/pkg/net/dnsclient_unix.go
@@ -2,13 +2,12 @@
 // 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
 
 // DNS client: see RFC 1035.
 // Has to be linked into package net for Dial.
 
 // TODO(rsc):
-//	Check periodically whether /etc/resolv.conf has changed.
 //	Could potentially handle many outstanding lookups faster.
 //	Could have a small cache.
 //	Random UDP source port (net.Dial should do that for us).
@@ -19,6 +18,7 @@ package net
 import (
 	"io"
 	"math/rand"
+	"os"
 	"sync"
 	"time"
 )
@@ -156,32 +156,90 @@ func convertRR_AAAA(records []dnsRR) []IP {
 	return addrs
 }
 
-var cfg *dnsConfig
-var dnserr error
+var cfg struct {
+	ch        chan struct{}
+	mu        sync.RWMutex // protects dnsConfig and dnserr
+	dnsConfig *dnsConfig
+	dnserr    error
+}
+var onceLoadConfig sync.Once
 
-func loadConfig() { cfg, dnserr = dnsReadConfig() }
+// Assume dns config file is /etc/resolv.conf here
+func loadDefaultConfig() {
+	loadConfig("/etc/resolv.conf", 5*time.Second, nil)
+}
 
-var onceLoadConfig sync.Once
+func loadConfig(resolvConfPath string, reloadTime time.Duration, quit <-chan chan struct{}) {
+	var mtime time.Time
+	cfg.ch = make(chan struct{}, 1)
+	if fi, err := os.Stat(resolvConfPath); err != nil {
+		cfg.dnserr = err
+	} else {
+		mtime = fi.ModTime()
+		cfg.dnsConfig, cfg.dnserr = dnsReadConfig(resolvConfPath)
+	}
+	go func() {
+		for {
+			time.Sleep(reloadTime)
+			select {
+			case qresp := <-quit:
+				qresp <- struct{}{}
+				return
+			case <-cfg.ch:
+			}
+
+			// In case of error, we keep the previous config
+			fi, err := os.Stat(resolvConfPath)
+			if err != nil {
+				continue
+			}
+			// If the resolv.conf mtime didn't change, do not reload
+			m := fi.ModTime()
+			if m.Equal(mtime) {
+				continue
+			}
+			mtime = m
+			// In case of error, we keep the previous config
+			ncfg, err := dnsReadConfig(resolvConfPath)
+			if err != nil || len(ncfg.servers) == 0 {
+				continue
+			}
+			cfg.mu.Lock()
+			cfg.dnsConfig = ncfg
+			cfg.dnserr = nil
+			cfg.mu.Unlock()
+		}
+	}()
+}
 
 func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error) {
 	if !isDomainName(name) {
 		return name, nil, &DNSError{Err: "invalid domain name", Name: name}
 	}
-	onceLoadConfig.Do(loadConfig)
-	if dnserr != nil || cfg == nil {
-		err = dnserr
+	onceLoadConfig.Do(loadDefaultConfig)
+
+	select {
+	case cfg.ch <- struct{}{}:
+	default:
+	}
+
+	cfg.mu.RLock()
+	defer cfg.mu.RUnlock()
+
+	if cfg.dnserr != nil || cfg.dnsConfig == nil {
+		err = cfg.dnserr
 		return
 	}
 	// If name is rooted (trailing dot) or has enough dots,
 	// try it by itself first.
 	rooted := len(name) > 0 && name[len(name)-1] == '.'
-	if rooted || count(name, '.') >= cfg.ndots {
+	if rooted || count(name, '.') >= cfg.dnsConfig.ndots {
 		rname := name
 		if !rooted {
 			rname += "."
 		}
 		// Can try as ordinary name.
-		cname, addrs, err = tryOneName(cfg, rname, qtype)
+		cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
 		if err == nil {
 			return
 		}
@@ -191,12 +249,12 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error)
 	}
 
 	// Otherwise, try suffixes.
-	for i := 0; i < len(cfg.search); i++ {
-		rname := name + "." + cfg.search[i]
+	for i := 0; i < len(cfg.dnsConfig.search); i++ {
+		rname := name + "." + cfg.dnsConfig.search[i]
 		if rname[len(rname)-1] != '.' {
 			rname += "."
 		}
-		cname, addrs, err = tryOneName(cfg, rname, qtype)
+		cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
 		if err == nil {
 			return
 		}
@@ -207,7 +265,7 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error)
 	if !rooted {
 		rname += "."
 	}
-	cname, addrs, err = tryOneName(cfg, rname, qtype)
+	cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
 	if err == nil {
 		return
 	}
@@ -232,11 +290,6 @@ func goLookupHost(name string) (addrs []string, err error) {
 	if len(addrs) > 0 {
 		return
 	}
-	onceLoadConfig.Do(loadConfig)
-	if dnserr != nil || cfg == nil {
-		err = dnserr
-		return
-	}
 	ips, err := goLookupIP(name)
 	if err != nil {
 		return
@@ -267,11 +320,6 @@ func goLookupIP(name string) (addrs []IP, err error) {
 			return
 		}
 	}
-	onceLoadConfig.Do(loadConfig)
-	if dnserr != nil || cfg == nil {
-		err = dnserr
-		return
-	}
 	var records []dnsRR
 	var cname string
 	var err4, err6 error
@@ -307,11 +355,6 @@ func goLookupIP(name string) (addrs []IP, err error) {
 // depending on our lookup code, so that Go and C get the same
 // answers.
 func goLookupCNAME(name string) (cname string, err error) {
-	onceLoadConfig.Do(loadConfig)
-	if dnserr != nil || cfg == nil {
-		err = dnserr
-		return
-	}
 	_, rr, err := lookup(name, dnsTypeCNAME)
 	if err != nil {
 		return
diff --git a/src/pkg/net/dnsclient_unix_test.go b/src/pkg/net/dnsclient_unix_test.go
index 47dcb56..2350142 100644
--- a/src/pkg/net/dnsclient_unix_test.go
+++ b/src/pkg/net/dnsclient_unix_test.go
@@ -2,12 +2,18 @@
 // 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 netbsd openbsd solaris
 
 package net
 
 import (
+	"io"
+	"io/ioutil"
+	"os"
+	"path"
+	"reflect"
 	"testing"
+	"time"
 )
 
 func TestTCPLookup(t *testing.T) {
@@ -25,3 +31,129 @@ func TestTCPLookup(t *testing.T) {
 		t.Fatalf("exchange failed: %v", err)
 	}
 }
+
+type resolvConfTest struct {
+	*testing.T
+	dir     string
+	path    string
+	started bool
+	quitc   chan chan struct{}
+}
+
+func newResolvConfTest(t *testing.T) *resolvConfTest {
+	dir, err := ioutil.TempDir("", "resolvConfTest")
+	if err != nil {
+		t.Fatalf("could not create temp dir: %v", err)
+	}
+
+	// Disable the default loadConfig
+	onceLoadConfig.Do(func() {})
+
+	r := &resolvConfTest{
+		T:     t,
+		dir:   dir,
+		path:  path.Join(dir, "resolv.conf"),
+		quitc: make(chan chan struct{}),
+	}
+
+	return r
+}
+
+func (r *resolvConfTest) Start() {
+	loadConfig(r.path, 100*time.Millisecond, r.quitc)
+	r.started = true
+}
+
+func (r *resolvConfTest) SetConf(s string) {
+	// Make sure the file mtime will be different once we're done here,
+	// even on systems with coarse (1s) mtime resolution.
+	time.Sleep(time.Second)
+
+	f, err := os.OpenFile(r.path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
+	if err != nil {
+		r.Fatalf("failed to create temp file %s: %v", r.path, err)
+	}
+	if _, err := io.WriteString(f, s); err != nil {
+		f.Close()
+		r.Fatalf("failed to write temp file: %v", err)
+	}
+	f.Close()
+
+	if r.started {
+		cfg.ch <- struct{}{} // fill buffer
+		cfg.ch <- struct{}{} // wait for reload to begin
+		cfg.ch <- struct{}{} // wait for reload to complete
+	}
+}
+
+func (r *resolvConfTest) WantServers(want []string) {
+	cfg.mu.RLock()
+	defer cfg.mu.RUnlock()
+	if got := cfg.dnsConfig.servers; !reflect.DeepEqual(got, want) {
+		r.Fatalf("Unexpected dns server loaded, got %v want %v", got, want)
+	}
+}
+
+func (r *resolvConfTest) Close() {
+	resp := make(chan struct{})
+	r.quitc <- resp
+	<-resp
+	if err := os.RemoveAll(r.dir); err != nil {
+		r.Logf("failed to remove temp dir %s: %v", r.dir, err)
+	}
+}
+
+func TestReloadResolvConfFail(t *testing.T) {
+	if testing.Short() || !*testExternal {
+		t.Skip("skipping test to avoid external network")
+	}
+
+	r := newResolvConfTest(t)
+	defer r.Close()
+
+	// resolv.conf.tmp does not exist yet
+	r.Start()
+	if _, err := goLookupIP("golang.org"); err == nil {
+		t.Fatal("goLookupIP(missing) succeeded")
+	}
+
+	r.SetConf("nameserver 8.8.8.8")
+	if _, err := goLookupIP("golang.org"); err != nil {
+		t.Fatalf("goLookupIP(missing; good) failed: %v", err)
+	}
+
+	// Using a bad resolv.conf while we had a good
+	// one before should not update the config
+	r.SetConf("")
+	if _, err := goLookupIP("golang.org"); err != nil {
+		t.Fatalf("goLookupIP(missing; good; bad) failed: %v", err)
+	}
+}
+
+func TestReloadResolvConfChange(t *testing.T) {
+	if testing.Short() || !*testExternal {
+		t.Skip("skipping test to avoid external network")
+	}
+
+	r := newResolvConfTest(t)
+	defer r.Close()
+
+	r.SetConf("nameserver 8.8.8.8")
+	r.Start()
+
+	if _, err := goLookupIP("golang.org"); err != nil {
+		t.Fatalf("goLookupIP(good) failed: %v", err)
+	}
+	r.WantServers([]string{"[8.8.8.8]"})
+
+	// Using a bad resolv.conf when we had a good one
+	// before should not update the config
+	r.SetConf("")
+	if _, err := goLookupIP("golang.org"); err != nil {
+		t.Fatalf("goLookupIP(good; bad) failed: %v", err)
+	}
+
+	// A new good config should get picked up
+	r.SetConf("nameserver 8.8.4.4")
+	r.WantServers([]string{"[8.8.4.4]"})
+}
diff --git a/src/pkg/net/dnsconfig_unix.go b/src/pkg/net/dnsconfig_unix.go
index 2f0f6c0..af28825 100644
--- a/src/pkg/net/dnsconfig_unix.go
+++ b/src/pkg/net/dnsconfig_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
 
 // Read system DNS config from /etc/resolv.conf
 
@@ -20,14 +20,13 @@ type dnsConfig struct {
 // See resolv.conf(5) on a Linux machine.
 // TODO(rsc): Supposed to call uname() and chop the beginning
 // of the host name to get the default search domain.
-// We assume it's in resolv.conf anyway.
-func dnsReadConfig() (*dnsConfig, error) {
-	file, err := open("/etc/resolv.conf")
+func dnsReadConfig(filename string) (*dnsConfig, error) {
+	file, err := open(filename)
 	if err != nil {
 		return nil, &DNSConfigError{err}
 	}
 	conf := new(dnsConfig)
-	conf.servers = make([]string, 3)[0:0] // small, but the standard limit
+	conf.servers = make([]string, 0, 3) // small, but the standard limit
 	conf.search = make([]string, 0)
 	conf.ndots = 1
 	conf.timeout = 5
diff --git a/src/pkg/net/dnsconfig_unix_test.go b/src/pkg/net/dnsconfig_unix_test.go
new file mode 100644
index 0000000..37ed493
--- /dev/null
+++ b/src/pkg/net/dnsconfig_unix_test.go
@@ -0,0 +1,46 @@
+// 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 darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package net
+
+import "testing"
+
+func TestDNSReadConfig(t *testing.T) {
+	dnsConfig, err := dnsReadConfig("testdata/resolv.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if len(dnsConfig.servers) != 1 {
+		t.Errorf("len(dnsConfig.servers) = %d; want %d", len(dnsConfig.servers), 1)
+	}
+	if dnsConfig.servers[0] != "[192.168.1.1]" {
+		t.Errorf("dnsConfig.servers[0] = %s; want %s", dnsConfig.servers[0], "[192.168.1.1]")
+	}
+
+	if len(dnsConfig.search) != 1 {
+		t.Errorf("len(dnsConfig.search) = %d; want %d", len(dnsConfig.search), 1)
+	}
+	if dnsConfig.search[0] != "Home" {
+		t.Errorf("dnsConfig.search[0] = %s; want %s", dnsConfig.search[0], "Home")
+	}
+
+	if dnsConfig.ndots != 5 {
+		t.Errorf("dnsConfig.ndots = %d; want %d", dnsConfig.ndots, 5)
+	}
+
+	if dnsConfig.timeout != 10 {
+		t.Errorf("dnsConfig.timeout = %d; want %d", dnsConfig.timeout, 10)
+	}
+
+	if dnsConfig.attempts != 3 {
+		t.Errorf("dnsConfig.attempts = %d; want %d", dnsConfig.attempts, 3)
+	}
+
+	if dnsConfig.rotate != true {
+		t.Errorf("dnsConfig.rotate = %t; want %t", dnsConfig.rotate, true)
+	}
+}
diff --git a/src/pkg/net/fd_mutex_test.go b/src/pkg/net/fd_mutex_test.go
index 8383084..c34ec59 100644
--- a/src/pkg/net/fd_mutex_test.go
+++ b/src/pkg/net/fd_mutex_test.go
@@ -63,7 +63,8 @@ func TestMutexCloseUnblock(t *testing.T) {
 	for i := 0; i < 4; i++ {
 		go func() {
 			if mu.RWLock(true) {
-				t.Fatal("broken")
+				t.Error("broken")
+				return
 			}
 			c <- true
 		}()
@@ -138,36 +139,44 @@ func TestMutexStress(t *testing.T) {
 				switch r.Intn(3) {
 				case 0:
 					if !mu.Incref() {
-						t.Fatal("broken")
+						t.Error("broken")
+						return
 					}
 					if mu.Decref() {
-						t.Fatal("broken")
+						t.Error("broken")
+						return
 					}
 				case 1:
 					if !mu.RWLock(true) {
-						t.Fatal("broken")
+						t.Error("broken")
+						return
 					}
 					// Ensure that it provides mutual exclusion for readers.
 					if readState[0] != readState[1] {
-						t.Fatal("broken")
+						t.Error("broken")
+						return
 					}
 					readState[0]++
 					readState[1]++
 					if mu.RWUnlock(true) {
-						t.Fatal("broken")
+						t.Error("broken")
+						return
 					}
 				case 2:
 					if !mu.RWLock(false) {
-						t.Fatal("broken")
+						t.Error("broken")
+						return
 					}
 					// Ensure that it provides mutual exclusion for writers.
 					if writeState[0] != writeState[1] {
-						t.Fatal("broken")
+						t.Error("broken")
+						return
 					}
 					writeState[0]++
 					writeState[1]++
 					if mu.RWUnlock(false) {
-						t.Fatal("broken")
+						t.Error("broken")
+						return
 					}
 				}
 			}
diff --git a/src/pkg/net/fd_plan9.go b/src/pkg/net/fd_plan9.go
index acc8294..5fe8eff 100644
--- a/src/pkg/net/fd_plan9.go
+++ b/src/pkg/net/fd_plan9.go
@@ -13,12 +13,23 @@ import (
 
 // Network file descritor.
 type netFD struct {
-	proto, name, dir string
-	ctl, data        *os.File
-	laddr, raddr     Addr
+	// locking/lifetime of sysfd + serialize access to Read and Write methods
+	fdmu fdMutex
+
+	// immutable until Close
+	proto        string
+	n            string
+	dir          string
+	ctl, data    *os.File
+	laddr, raddr Addr
 }
 
+var (
+	netdir string // default network
+)
+
 func sysInit() {
+	netdir = "/net"
 }
 
 func dial(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline time.Time) (Conn, error) {
@@ -27,16 +38,99 @@ func dial(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline ti
 	return dialChannel(net, ra, dialer, deadline)
 }
 
-func newFD(proto, name string, ctl, data *os.File, laddr, raddr Addr) *netFD {
-	return &netFD{proto, name, "/net/" + proto + "/" + name, ctl, data, laddr, raddr}
+func newFD(proto, name string, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) {
+	return &netFD{proto: proto, n: name, dir: netdir + "/" + proto + "/" + name, ctl: ctl, data: data, laddr: laddr, raddr: raddr}, nil
+}
+
+func (fd *netFD) init() error {
+	// stub for future fd.pd.Init(fd)
+	return nil
+}
+
+func (fd *netFD) name() string {
+	var ls, rs string
+	if fd.laddr != nil {
+		ls = fd.laddr.String()
+	}
+	if fd.raddr != nil {
+		rs = fd.raddr.String()
+	}
+	return fd.proto + ":" + ls + "->" + rs
 }
 
 func (fd *netFD) ok() bool { return fd != nil && fd.ctl != nil }
 
+func (fd *netFD) destroy() {
+	if !fd.ok() {
+		return
+	}
+	err := fd.ctl.Close()
+	if fd.data != nil {
+		if err1 := fd.data.Close(); err1 != nil && err == nil {
+			err = err1
+		}
+	}
+	fd.ctl = nil
+	fd.data = nil
+}
+
+// Add a reference to this fd.
+// Returns an error if the fd cannot be used.
+func (fd *netFD) incref() error {
+	if !fd.fdmu.Incref() {
+		return errClosing
+	}
+	return nil
+}
+
+// Remove a reference to this FD and close if we've been asked to do so
+// (and there are no references left).
+func (fd *netFD) decref() {
+	if fd.fdmu.Decref() {
+		fd.destroy()
+	}
+}
+
+// Add a reference to this fd and lock for reading.
+// Returns an error if the fd cannot be used.
+func (fd *netFD) readLock() error {
+	if !fd.fdmu.RWLock(true) {
+		return errClosing
+	}
+	return nil
+}
+
+// Unlock for reading and remove a reference to this FD.
+func (fd *netFD) readUnlock() {
+	if fd.fdmu.RWUnlock(true) {
+		fd.destroy()
+	}
+}
+
+// Add a reference to this fd and lock for writing.
+// Returns an error if the fd cannot be used.
+func (fd *netFD) writeLock() error {
+	if !fd.fdmu.RWLock(false) {
+		return errClosing
+	}
+	return nil
+}
+
+// Unlock for writing and remove a reference to this FD.
+func (fd *netFD) writeUnlock() {
+	if fd.fdmu.RWUnlock(false) {
+		fd.destroy()
+	}
+}
+
 func (fd *netFD) Read(b []byte) (n int, err error) {
 	if !fd.ok() || fd.data == nil {
 		return 0, syscall.EINVAL
 	}
+	if err := fd.readLock(); err != nil {
+		return 0, err
+	}
+	defer fd.readUnlock()
 	n, err = fd.data.Read(b)
 	if fd.proto == "udp" && err == io.EOF {
 		n = 0
@@ -49,17 +143,21 @@ func (fd *netFD) Write(b []byte) (n int, err error) {
 	if !fd.ok() || fd.data == nil {
 		return 0, syscall.EINVAL
 	}
+	if err := fd.writeLock(); err != nil {
+		return 0, err
+	}
+	defer fd.writeUnlock()
 	return fd.data.Write(b)
 }
 
-func (fd *netFD) CloseRead() error {
+func (fd *netFD) closeRead() error {
 	if !fd.ok() {
 		return syscall.EINVAL
 	}
 	return syscall.EPLAN9
 }
 
-func (fd *netFD) CloseWrite() error {
+func (fd *netFD) closeWrite() error {
 	if !fd.ok() {
 		return syscall.EINVAL
 	}
@@ -67,6 +165,9 @@ func (fd *netFD) CloseWrite() error {
 }
 
 func (fd *netFD) Close() error {
+	if !fd.fdmu.IncrefAndClose() {
+		return errClosing
+	}
 	if !fd.ok() {
 		return syscall.EINVAL
 	}
diff --git a/src/pkg/net/fd_poll_nacl.go b/src/pkg/net/fd_poll_nacl.go
new file mode 100644
index 0000000..a3701f8
--- /dev/null
+++ b/src/pkg/net/fd_poll_nacl.go
@@ -0,0 +1,94 @@
+// 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 net
+
+import (
+	"syscall"
+	"time"
+)
+
+type pollDesc struct {
+	fd      *netFD
+	closing bool
+}
+
+func (pd *pollDesc) Init(fd *netFD) error { pd.fd = fd; return nil }
+
+func (pd *pollDesc) Close() {}
+
+func (pd *pollDesc) Lock() {}
+
+func (pd *pollDesc) Unlock() {}
+
+func (pd *pollDesc) Wakeup() {}
+
+func (pd *pollDesc) Evict() bool {
+	pd.closing = true
+	if pd.fd != nil {
+		syscall.StopIO(pd.fd.sysfd)
+	}
+	return false
+}
+
+func (pd *pollDesc) Prepare(mode int) error {
+	if pd.closing {
+		return errClosing
+	}
+	return nil
+}
+
+func (pd *pollDesc) PrepareRead() error { return pd.Prepare('r') }
+
+func (pd *pollDesc) PrepareWrite() error { return pd.Prepare('w') }
+
+func (pd *pollDesc) Wait(mode int) error {
+	if pd.closing {
+		return errClosing
+	}
+	return errTimeout
+}
+
+func (pd *pollDesc) WaitRead() error { return pd.Wait('r') }
+
+func (pd *pollDesc) WaitWrite() error { return pd.Wait('w') }
+
+func (pd *pollDesc) WaitCanceled(mode int) {}
+
+func (pd *pollDesc) WaitCanceledRead() {}
+
+func (pd *pollDesc) WaitCanceledWrite() {}
+
+func (fd *netFD) setDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'r'+'w')
+}
+
+func (fd *netFD) setReadDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'r')
+}
+
+func (fd *netFD) setWriteDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'w')
+}
+
+func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
+	d := t.UnixNano()
+	if t.IsZero() {
+		d = 0
+	}
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	switch mode {
+	case 'r':
+		syscall.SetReadDeadline(fd.sysfd, d)
+	case 'w':
+		syscall.SetWriteDeadline(fd.sysfd, d)
+	case 'r' + 'w':
+		syscall.SetReadDeadline(fd.sysfd, d)
+		syscall.SetWriteDeadline(fd.sysfd, d)
+	}
+	fd.decref()
+	return nil
+}
diff --git a/src/pkg/net/fd_poll_runtime.go b/src/pkg/net/fd_poll_runtime.go
index e2b2768..2bddc83 100644
--- a/src/pkg/net/fd_poll_runtime.go
+++ b/src/pkg/net/fd_poll_runtime.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 windows
+// +build darwin dragonfly freebsd linux netbsd openbsd windows solaris
 
 package net
 
@@ -12,6 +12,9 @@ import (
 	"time"
 )
 
+// runtimeNano returns the current value of the runtime clock in nanoseconds.
+func runtimeNano() int64
+
 func runtime_pollServerInit()
 func runtime_pollOpen(fd uintptr) (uintptr, int)
 func runtime_pollClose(ctx uintptr)
@@ -128,7 +131,7 @@ func (fd *netFD) setWriteDeadline(t time.Time) error {
 }
 
 func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
-	d := t.UnixNano()
+	d := runtimeNano() + int64(t.Sub(time.Now()))
 	if t.IsZero() {
 		d = 0
 	}
diff --git a/src/pkg/net/fd_unix.go b/src/pkg/net/fd_unix.go
index 9ed4f75..b82ecd1 100644
--- a/src/pkg/net/fd_unix.go
+++ b/src/pkg/net/fd_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 net
 
@@ -75,19 +75,47 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr) error {
 	if err := fd.pd.PrepareWrite(); err != nil {
 		return err
 	}
+	switch err := syscall.Connect(fd.sysfd, ra); err {
+	case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
+	case nil, syscall.EISCONN:
+		return nil
+	case syscall.EINVAL:
+		// On Solaris we can see EINVAL if the socket has
+		// already been accepted and closed by the server.
+		// Treat this as a successful connection--writes to
+		// the socket will see EOF.  For details and a test
+		// case in C see http://golang.org/issue/6828.
+		if runtime.GOOS == "solaris" {
+			return nil
+		}
+		fallthrough
+	default:
+		return err
+	}
 	for {
-		err := syscall.Connect(fd.sysfd, ra)
-		if err == nil || err == syscall.EISCONN {
-			break
+		// Performing multiple connect system calls on a
+		// non-blocking socket under Unix variants does not
+		// necessarily result in earlier errors being
+		// returned. Instead, once runtime-integrated network
+		// poller tells us that the socket is ready, get the
+		// SO_ERROR socket option to see if the connection
+		// succeeded or failed. See issue 7474 for further
+		// details.
+		if err := fd.pd.WaitWrite(); err != nil {
+			return err
 		}
-		if err != syscall.EINPROGRESS && err != syscall.EALREADY && err != syscall.EINTR {
+		nerr, err := syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
+		if err != nil {
 			return err
 		}
-		if err = fd.pd.WaitWrite(); err != nil {
+		switch err := syscall.Errno(nerr); err {
+		case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
+		case syscall.Errno(0), syscall.EISCONN:
+			return nil
+		default:
 			return err
 		}
 	}
-	return nil
 }
 
 func (fd *netFD) destroy() {
@@ -180,11 +208,11 @@ func (fd *netFD) shutdown(how int) error {
 	return nil
 }
 
-func (fd *netFD) CloseRead() error {
+func (fd *netFD) closeRead() error {
 	return fd.shutdown(syscall.SHUT_RD)
 }
 
-func (fd *netFD) CloseWrite() error {
+func (fd *netFD) closeWrite() error {
 	return fd.shutdown(syscall.SHUT_WR)
 }
 
@@ -215,7 +243,7 @@ func (fd *netFD) Read(p []byte) (n int, err error) {
 	return
 }
 
-func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
+func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
 	if err := fd.readLock(); err != nil {
 		return 0, nil, err
 	}
@@ -242,7 +270,7 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
 	return
 }
 
-func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
+func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
 	if err := fd.readLock(); err != nil {
 		return 0, 0, 0, nil, err
 	}
@@ -313,7 +341,7 @@ func (fd *netFD) Write(p []byte) (nn int, err error) {
 	return nn, err
 }
 
-func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
+func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
 	if err := fd.writeLock(); err != nil {
 		return 0, err
 	}
@@ -338,7 +366,7 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
 	return
 }
 
-func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
+func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
 	if err := fd.writeLock(); err != nil {
 		return 0, 0, err
 	}
@@ -347,7 +375,7 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
 		return 0, 0, &OpError{"write", fd.net, fd.raddr, err}
 	}
 	for {
-		err = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0)
+		n, err = syscall.SendmsgN(fd.sysfd, p, oob, sa, 0)
 		if err == syscall.EAGAIN {
 			if err = fd.pd.WaitWrite(); err == nil {
 				continue
@@ -356,7 +384,6 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
 		break
 	}
 	if err == nil {
-		n = len(p)
 		oobn = len(oob)
 	} else {
 		err = &OpError{"write", fd.net, fd.raddr, err}
@@ -455,7 +482,6 @@ func dupCloseOnExecOld(fd int) (newfd int, err error) {
 func (fd *netFD) dup() (f *os.File, err error) {
 	ns, err := dupCloseOnExec(fd.sysfd)
 	if err != nil {
-		syscall.ForkLock.RUnlock()
 		return nil, &OpError{"dup", fd.net, fd.laddr, err}
 	}
 
diff --git a/src/pkg/net/fd_unix_test.go b/src/pkg/net/fd_unix_test.go
index 65d3e69..fe8e8ff 100644
--- a/src/pkg/net/fd_unix_test.go
+++ b/src/pkg/net/fd_unix_test.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 netbsd openbsd solaris
 
 package net
 
diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go
index 630fc5e..a1f6bc5 100644
--- a/src/pkg/net/fd_windows.go
+++ b/src/pkg/net/fd_windows.go
@@ -119,7 +119,7 @@ func (o *operation) InitBuf(buf []byte) {
 	o.buf.Len = uint32(len(buf))
 	o.buf.Buf = nil
 	if len(buf) != 0 {
-		o.buf.Buf = (*byte)(unsafe.Pointer(&buf[0]))
+		o.buf.Buf = &buf[0]
 	}
 }
 
@@ -431,11 +431,11 @@ func (fd *netFD) shutdown(how int) error {
 	return nil
 }
 
-func (fd *netFD) CloseRead() error {
+func (fd *netFD) closeRead() error {
 	return fd.shutdown(syscall.SHUT_RD)
 }
 
-func (fd *netFD) CloseWrite() error {
+func (fd *netFD) closeWrite() error {
 	return fd.shutdown(syscall.SHUT_WR)
 }
 
@@ -458,7 +458,7 @@ func (fd *netFD) Read(buf []byte) (int, error) {
 	return n, err
 }
 
-func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) {
+func (fd *netFD) readFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) {
 	if len(buf) == 0 {
 		return 0, nil, nil
 	}
@@ -497,7 +497,7 @@ func (fd *netFD) Write(buf []byte) (int, error) {
 	})
 }
 
-func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
+func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) {
 	if len(buf) == 0 {
 		return 0, nil
 	}
@@ -628,10 +628,10 @@ func (fd *netFD) dup() (*os.File, error) {
 
 var errNoSupport = errors.New("address family not supported")
 
-func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
+func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
 	return 0, 0, 0, nil, errNoSupport
 }
 
-func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
+func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
 	return 0, 0, errNoSupport
 }
diff --git a/src/pkg/net/file_plan9.go b/src/pkg/net/file_plan9.go
index f6ee1c2..068f088 100644
--- a/src/pkg/net/file_plan9.go
+++ b/src/pkg/net/file_plan9.go
@@ -43,7 +43,7 @@ func newFileFD(f *os.File) (net *netFD, err error) {
 	}
 	comp := splitAtBytes(path, "/")
 	n := len(comp)
-	if n < 3 || comp[0] != "net" {
+	if n < 3 || comp[0][0:3] != "net" {
 		return nil, syscall.EPLAN9
 	}
 
@@ -58,7 +58,7 @@ func newFileFD(f *os.File) (net *netFD, err error) {
 		}
 		defer close(fd)
 
-		dir := "/net/" + comp[n-2]
+		dir := netdir + "/" + comp[n-2]
 		ctl = os.NewFile(uintptr(fd), dir+"/"+file)
 		ctl.Seek(0, 0)
 		var buf [16]byte
@@ -71,19 +71,19 @@ func newFileFD(f *os.File) (net *netFD, err error) {
 		if len(comp) < 4 {
 			return nil, errors.New("could not find control file for connection")
 		}
-		dir := "/net/" + comp[1] + "/" + name
+		dir := netdir + "/" + comp[1] + "/" + name
 		ctl, err = os.OpenFile(dir+"/ctl", os.O_RDWR, 0)
 		if err != nil {
 			return nil, err
 		}
 		defer close(int(ctl.Fd()))
 	}
-	dir := "/net/" + comp[1] + "/" + name
+	dir := netdir + "/" + comp[1] + "/" + name
 	laddr, err := readPlan9Addr(comp[1], dir+"/local")
 	if err != nil {
 		return nil, err
 	}
-	return newFD(comp[1], name, ctl, nil, laddr, nil), nil
+	return newFD(comp[1], name, ctl, nil, laddr, nil)
 }
 
 func newFileConn(f *os.File) (c Conn, err error) {
diff --git a/src/pkg/net/file_test.go b/src/pkg/net/file_test.go
index acaf188..d81bca7 100644
--- a/src/pkg/net/file_test.go
+++ b/src/pkg/net/file_test.go
@@ -174,12 +174,14 @@ var filePacketConnTests = []struct {
 
 	{net: "udp6", addr: "[::1]", ipv6: true},
 
+	{net: "ip4:icmp", addr: "127.0.0.1"},
+
 	{net: "unixgram", addr: "@gotest3/net", linux: true},
 }
 
 func TestFilePacketConn(t *testing.T) {
 	switch runtime.GOOS {
-	case "plan9", "windows":
+	case "nacl", "plan9", "windows":
 		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
@@ -187,6 +189,10 @@ func TestFilePacketConn(t *testing.T) {
 		if skipServerTest(tt.net, "unixgram", tt.addr, tt.ipv6, false, tt.linux) {
 			continue
 		}
+		if os.Getuid() != 0 && tt.net == "ip4:icmp" {
+			t.Log("skipping test; must be root")
+			continue
+		}
 		testFilePacketConnListen(t, tt.net, tt.addr)
 		switch tt.addr {
 		case "", "0.0.0.0", "[::ffff:0.0.0.0]", "[::]":
diff --git a/src/pkg/net/file_unix.go b/src/pkg/net/file_unix.go
index 8fe1b0e..07b3ecf 100644
--- a/src/pkg/net/file_unix.go
+++ b/src/pkg/net/file_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 net
 
@@ -129,6 +129,8 @@ func FilePacketConn(f *os.File) (c PacketConn, err error) {
 	switch fd.laddr.(type) {
 	case *UDPAddr:
 		return newUDPConn(fd), nil
+	case *IPAddr:
+		return newIPConn(fd), nil
 	case *UnixAddr:
 		return newUnixConn(fd), nil
 	}
diff --git a/src/pkg/net/hosts_test.go b/src/pkg/net/hosts_test.go
index b07ed0b..2fe358e 100644
--- a/src/pkg/net/hosts_test.go
+++ b/src/pkg/net/hosts_test.go
@@ -41,7 +41,7 @@ func TestLookupStaticHost(t *testing.T) {
 		if len(ips) != len(tt.ips) {
 			t.Errorf("# of hosts = %v; want %v",
 				len(ips), len(tt.ips))
-			return
+			continue
 		}
 		for k, v := range ips {
 			if tt.ips[k].String() != v {
diff --git a/src/pkg/net/http/cgi/host.go b/src/pkg/net/http/cgi/host.go
index d27cc4d..ec95a97 100644
--- a/src/pkg/net/http/cgi/host.go
+++ b/src/pkg/net/http/cgi/host.go
@@ -214,12 +214,17 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 		internalError(err)
 		return
 	}
+	if hook := testHookStartProcess; hook != nil {
+		hook(cmd.Process)
+	}
 	defer cmd.Wait()
 	defer stdoutRead.Close()
 
 	linebody := bufio.NewReaderSize(stdoutRead, 1024)
 	headers := make(http.Header)
 	statusCode := 0
+	headerLines := 0
+	sawBlankLine := false
 	for {
 		line, isPrefix, err := linebody.ReadLine()
 		if isPrefix {
@@ -236,8 +241,10 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 			return
 		}
 		if len(line) == 0 {
+			sawBlankLine = true
 			break
 		}
+		headerLines++
 		parts := strings.SplitN(string(line), ":", 2)
 		if len(parts) < 2 {
 			h.printf("cgi: bogus header line: %s", string(line))
@@ -263,6 +270,11 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 			headers.Add(header, val)
 		}
 	}
+	if headerLines == 0 || !sawBlankLine {
+		rw.WriteHeader(http.StatusInternalServerError)
+		h.printf("cgi: no headers")
+		return
+	}
 
 	if loc := headers.Get("Location"); loc != "" {
 		if strings.HasPrefix(loc, "/") && h.PathLocationHandler != nil {
@@ -274,6 +286,12 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 		}
 	}
 
+	if statusCode == 0 && headers.Get("Content-Type") == "" {
+		rw.WriteHeader(http.StatusInternalServerError)
+		h.printf("cgi: missing required Content-Type in headers")
+		return
+	}
+
 	if statusCode == 0 {
 		statusCode = http.StatusOK
 	}
@@ -292,6 +310,13 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 	_, err = io.Copy(rw, linebody)
 	if err != nil {
 		h.printf("cgi: copy error: %v", err)
+		// And kill the child CGI process so we don't hang on
+		// the deferred cmd.Wait above if the error was just
+		// the client (rw) going away. If it was a read error
+		// (because the child died itself), then the extra
+		// kill of an already-dead process is harmless (the PID
+		// won't be reused until the Wait above).
+		cmd.Process.Kill()
 	}
 }
 
@@ -348,3 +373,5 @@ func upperCaseAndUnderscore(r rune) rune {
 	// TODO: other transformations in spec or practice?
 	return r
 }
+
+var testHookStartProcess func(*os.Process) // nil except for some tests
diff --git a/src/pkg/net/http/cgi/matryoshka_test.go b/src/pkg/net/http/cgi/matryoshka_test.go
index e1a78c8..18c4803 100644
--- a/src/pkg/net/http/cgi/matryoshka_test.go
+++ b/src/pkg/net/http/cgi/matryoshka_test.go
@@ -9,15 +9,25 @@
 package cgi
 
 import (
+	"bytes"
+	"errors"
 	"fmt"
+	"io"
 	"net/http"
+	"net/http/httptest"
 	"os"
+	"runtime"
 	"testing"
+	"time"
 )
 
 // This test is a CGI host (testing host.go) that runs its own binary
 // as a child process testing the other half of CGI (child.go).
 func TestHostingOurselves(t *testing.T) {
+	if runtime.GOOS == "nacl" {
+		t.Skip("skipping on nacl")
+	}
+
 	h := &Handler{
 		Path: os.Args[0],
 		Root: "/test.go",
@@ -51,8 +61,88 @@ func TestHostingOurselves(t *testing.T) {
 	}
 }
 
-// Test that a child handler only writing headers works.
+type customWriterRecorder struct {
+	w io.Writer
+	*httptest.ResponseRecorder
+}
+
+func (r *customWriterRecorder) Write(p []byte) (n int, err error) {
+	return r.w.Write(p)
+}
+
+type limitWriter struct {
+	w io.Writer
+	n int
+}
+
+func (w *limitWriter) Write(p []byte) (n int, err error) {
+	if len(p) > w.n {
+		p = p[:w.n]
+	}
+	if len(p) > 0 {
+		n, err = w.w.Write(p)
+		w.n -= n
+	}
+	if w.n == 0 {
+		err = errors.New("past write limit")
+	}
+	return
+}
+
+// If there's an error copying the child's output to the parent, test
+// that we kill the child.
+func TestKillChildAfterCopyError(t *testing.T) {
+	if runtime.GOOS == "nacl" {
+		t.Skip("skipping on nacl")
+	}
+
+	defer func() { testHookStartProcess = nil }()
+	proc := make(chan *os.Process, 1)
+	testHookStartProcess = func(p *os.Process) {
+		proc <- p
+	}
+
+	h := &Handler{
+		Path: os.Args[0],
+		Root: "/test.go",
+		Args: []string{"-test.run=TestBeChildCGIProcess"},
+	}
+	req, _ := http.NewRequest("GET", "http://example.com/test.cgi?write-forever=1", nil)
+	rec := httptest.NewRecorder()
+	var out bytes.Buffer
+	const writeLen = 50 << 10
+	rw := &customWriterRecorder{&limitWriter{&out, writeLen}, rec}
+
+	donec := make(chan bool, 1)
+	go func() {
+		h.ServeHTTP(rw, req)
+		donec <- true
+	}()
+
+	select {
+	case <-donec:
+		if out.Len() != writeLen || out.Bytes()[0] != 'a' {
+			t.Errorf("unexpected output: %q", out.Bytes())
+		}
+	case <-time.After(5 * time.Second):
+		t.Errorf("timeout. ServeHTTP hung and didn't kill the child process?")
+		select {
+		case p := <-proc:
+			p.Kill()
+			t.Logf("killed process")
+		default:
+			t.Logf("didn't kill process")
+		}
+	}
+}
+
+// Test that a child handler writing only headers works.
+// golang.org/issue/7196
 func TestChildOnlyHeaders(t *testing.T) {
+	if runtime.GOOS == "nacl" {
+		t.Skip("skipping on nacl")
+	}
+
 	h := &Handler{
 		Path: os.Args[0],
 		Root: "/test.go",
@@ -67,18 +157,63 @@ func TestChildOnlyHeaders(t *testing.T) {
 	}
 }
 
+// golang.org/issue/7198
+func Test500WithNoHeaders(t *testing.T)     { want500Test(t, "/immediate-disconnect") }
+func Test500WithNoContentType(t *testing.T) { want500Test(t, "/no-content-type") }
+func Test500WithEmptyHeaders(t *testing.T)  { want500Test(t, "/empty-headers") }
+
+func want500Test(t *testing.T, path string) {
+	h := &Handler{
+		Path: os.Args[0],
+		Root: "/test.go",
+		Args: []string{"-test.run=TestBeChildCGIProcess"},
+	}
+	expectedMap := map[string]string{
+		"_body": "",
+	}
+	replay := runCgiTest(t, h, "GET "+path+" HTTP/1.0\nHost: example.com\n\n", expectedMap)
+	if replay.Code != 500 {
+		t.Errorf("Got code %d; want 500", replay.Code)
+	}
+}
+
+type neverEnding byte
+
+func (b neverEnding) Read(p []byte) (n int, err error) {
+	for i := range p {
+		p[i] = byte(b)
+	}
+	return len(p), nil
+}
+
 // Note: not actually a test.
 func TestBeChildCGIProcess(t *testing.T) {
 	if os.Getenv("REQUEST_METHOD") == "" {
 		// Not in a CGI environment; skipping test.
 		return
 	}
+	switch os.Getenv("REQUEST_URI") {
+	case "/immediate-disconnect":
+		os.Exit(0)
+	case "/no-content-type":
+		fmt.Printf("Content-Length: 6\n\nHello\n")
+		os.Exit(0)
+	case "/empty-headers":
+		fmt.Printf("\nHello")
+		os.Exit(0)
+	}
 	Serve(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
 		rw.Header().Set("X-Test-Header", "X-Test-Value")
 		req.ParseForm()
 		if req.FormValue("no-body") == "1" {
 			return
 		}
+		if req.FormValue("write-forever") == "1" {
+			io.Copy(rw, neverEnding('a'))
+			for {
+				time.Sleep(5 * time.Second) // hang forever, until killed
+			}
+		}
 		fmt.Fprintf(rw, "test=Hello CGI-in-CGI\n")
 		for k, vv := range req.Form {
 			for _, v := range vv {
diff --git a/src/pkg/net/http/chunked.go b/src/pkg/net/http/chunked.go
index 91db017..749f29d 100644
--- a/src/pkg/net/http/chunked.go
+++ b/src/pkg/net/http/chunked.go
@@ -4,13 +4,14 @@
 
 // The wire protocol for HTTP's "chunked" Transfer-Encoding.
 
-// This code is duplicated in httputil/chunked.go.
+// This code is duplicated in net/http and net/http/httputil.
 // Please make any changes in both files.
 
 package http
 
 import (
 	"bufio"
+	"bytes"
 	"errors"
 	"fmt"
 	"io"
@@ -57,26 +58,45 @@ func (cr *chunkedReader) beginChunk() {
 	}
 }
 
-func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
-	if cr.err != nil {
-		return 0, cr.err
+func (cr *chunkedReader) chunkHeaderAvailable() bool {
+	n := cr.r.Buffered()
+	if n > 0 {
+		peek, _ := cr.r.Peek(n)
+		return bytes.IndexByte(peek, '\n') >= 0
 	}
-	if cr.n == 0 {
-		cr.beginChunk()
-		if cr.err != nil {
-			return 0, cr.err
+	return false
+}
+
+func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
+	for cr.err == nil {
+		if cr.n == 0 {
+			if n > 0 && !cr.chunkHeaderAvailable() {
+				// We've read enough. Don't potentially block
+				// reading a new chunk header.
+				break
+			}
+			cr.beginChunk()
+			continue
 		}
-	}
-	if uint64(len(b)) > cr.n {
-		b = b[0:cr.n]
-	}
-	n, cr.err = cr.r.Read(b)
-	cr.n -= uint64(n)
-	if cr.n == 0 && cr.err == nil {
-		// end of chunk (CRLF)
-		if _, cr.err = io.ReadFull(cr.r, cr.buf[:]); cr.err == nil {
-			if cr.buf[0] != '\r' || cr.buf[1] != '\n' {
-				cr.err = errors.New("malformed chunked encoding")
+		if len(b) == 0 {
+			break
+		}
+		rbuf := b
+		if uint64(len(rbuf)) > cr.n {
+			rbuf = rbuf[:cr.n]
+		}
+		var n0 int
+		n0, cr.err = cr.r.Read(rbuf)
+		n += n0
+		b = b[n0:]
+		cr.n -= uint64(n0)
+		// If we're at the end of a chunk, read the next two
+		// bytes to verify they are "\r\n".
+		if cr.n == 0 && cr.err == nil {
+			if _, cr.err = io.ReadFull(cr.r, cr.buf[:2]); cr.err == nil {
+				if cr.buf[0] != '\r' || cr.buf[1] != '\n' {
+					cr.err = errors.New("malformed chunked encoding")
+				}
 			}
 		}
 	}
diff --git a/src/pkg/net/http/chunked_test.go b/src/pkg/net/http/chunked_test.go
index 0b18c7b..3454479 100644
--- a/src/pkg/net/http/chunked_test.go
+++ b/src/pkg/net/http/chunked_test.go
@@ -2,17 +2,18 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// This code is duplicated in httputil/chunked_test.go.
+// This code is duplicated in net/http and net/http/httputil.
 // Please make any changes in both files.
 
 package http
 
 import (
+	"bufio"
 	"bytes"
 	"fmt"
 	"io"
 	"io/ioutil"
-	"runtime"
+	"strings"
 	"testing"
 )
 
@@ -41,9 +42,77 @@ func TestChunk(t *testing.T) {
 	}
 }
 
+func TestChunkReadMultiple(t *testing.T) {
+	// Bunch of small chunks, all read together.
+	{
+		var b bytes.Buffer
+		w := newChunkedWriter(&b)
+		w.Write([]byte("foo"))
+		w.Write([]byte("bar"))
+		w.Close()
+
+		r := newChunkedReader(&b)
+		buf := make([]byte, 10)
+		n, err := r.Read(buf)
+		if n != 6 || err != io.EOF {
+			t.Errorf("Read = %d, %v; want 6, EOF", n, err)
+		}
+		buf = buf[:n]
+		if string(buf) != "foobar" {
+			t.Errorf("Read = %q; want %q", buf, "foobar")
+		}
+	}
+
+	// One big chunk followed by a little chunk, but the small bufio.Reader size
+	// should prevent the second chunk header from being read.
+	{
+		var b bytes.Buffer
+		w := newChunkedWriter(&b)
+		// fillBufChunk is 11 bytes + 3 bytes header + 2 bytes footer = 16 bytes,
+		// the same as the bufio ReaderSize below (the minimum), so even
+		// though we're going to try to Read with a buffer larger enough to also
+		// receive "foo", the second chunk header won't be read yet.
+		const fillBufChunk = "0123456789a"
+		const shortChunk = "foo"
+		w.Write([]byte(fillBufChunk))
+		w.Write([]byte(shortChunk))
+		w.Close()
+
+		r := newChunkedReader(bufio.NewReaderSize(&b, 16))
+		buf := make([]byte, len(fillBufChunk)+len(shortChunk))
+		n, err := r.Read(buf)
+		if n != len(fillBufChunk) || err != nil {
+			t.Errorf("Read = %d, %v; want %d, nil", n, err, len(fillBufChunk))
+		}
+		buf = buf[:n]
+		if string(buf) != fillBufChunk {
+			t.Errorf("Read = %q; want %q", buf, fillBufChunk)
+		}
+
+		n, err = r.Read(buf)
+		if n != len(shortChunk) || err != io.EOF {
+			t.Errorf("Read = %d, %v; want %d, EOF", n, err, len(shortChunk))
+		}
+	}
+
+	// And test that we see an EOF chunk, even though our buffer is already full:
+	{
+		r := newChunkedReader(bufio.NewReader(strings.NewReader("3\r\nfoo\r\n0\r\n")))
+		buf := make([]byte, 3)
+		n, err := r.Read(buf)
+		if n != 3 || err != io.EOF {
+			t.Errorf("Read = %d, %v; want 3, EOF", n, err)
+		}
+		if string(buf) != "foo" {
+			t.Errorf("buf = %q; want foo", buf)
+		}
+	}
+}
+
 func TestChunkReaderAllocs(t *testing.T) {
-	// temporarily set GOMAXPROCS to 1 as we are testing memory allocations
-	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+	if testing.Short() {
+		t.Skip("skipping in short mode")
+	}
 	var buf bytes.Buffer
 	w := newChunkedWriter(&buf)
 	a, b, c := []byte("aaaaaa"), []byte("bbbbbbbbbbbb"), []byte("cccccccccccccccccccccccc")
@@ -52,26 +121,23 @@ func TestChunkReaderAllocs(t *testing.T) {
 	w.Write(c)
 	w.Close()
 
-	r := newChunkedReader(&buf)
 	readBuf := make([]byte, len(a)+len(b)+len(c)+1)
-
-	var ms runtime.MemStats
-	runtime.ReadMemStats(&ms)
-	m0 := ms.Mallocs
-
-	n, err := io.ReadFull(r, readBuf)
-
-	runtime.ReadMemStats(&ms)
-	mallocs := ms.Mallocs - m0
-	if mallocs > 1 {
-		t.Errorf("%d mallocs; want <= 1", mallocs)
-	}
-
-	if n != len(readBuf)-1 {
-		t.Errorf("read %d bytes; want %d", n, len(readBuf)-1)
-	}
-	if err != io.ErrUnexpectedEOF {
-		t.Errorf("read error = %v; want ErrUnexpectedEOF", err)
+	byter := bytes.NewReader(buf.Bytes())
+	bufr := bufio.NewReader(byter)
+	mallocs := testing.AllocsPerRun(100, func() {
+		byter.Seek(0, 0)
+		bufr.Reset(byter)
+		r := newChunkedReader(bufr)
+		n, err := io.ReadFull(r, readBuf)
+		if n != len(readBuf)-1 {
+			t.Fatalf("read %d bytes; want %d", n, len(readBuf)-1)
+		}
+		if err != io.ErrUnexpectedEOF {
+			t.Fatalf("read error = %v; want ErrUnexpectedEOF", err)
+		}
+	})
+	if mallocs > 1.5 {
+		t.Errorf("mallocs = %v; want 1", mallocs)
 	}
 }
 
diff --git a/src/pkg/net/http/client.go b/src/pkg/net/http/client.go
index 22f2e86..a5a3abe 100644
--- a/src/pkg/net/http/client.go
+++ b/src/pkg/net/http/client.go
@@ -14,9 +14,12 @@ import (
 	"errors"
 	"fmt"
 	"io"
+	"io/ioutil"
 	"log"
 	"net/url"
 	"strings"
+	"sync"
+	"time"
 )
 
 // A Client is an HTTP client. Its zero value (DefaultClient) is a
@@ -52,6 +55,20 @@ type Client struct {
 	// If Jar is nil, cookies are not sent in requests and ignored
 	// in responses.
 	Jar CookieJar
+
+	// Timeout specifies a time limit for requests made by this
+	// Client. The timeout includes connection time, any
+	// redirects, and reading the response body. The timer remains
+	// running after Get, Head, Post, or Do return and will
+	// interrupt reading of the Response.Body.
+	//
+	// A Timeout of zero means no timeout.
+	//
+	// The Client's Transport must support the CancelRequest
+	// method or Client will return errors when attempting to make
+	// a request with Get, Head, Post, or Do. Client's default
+	// Transport (DefaultTransport) supports CancelRequest.
+	Timeout time.Duration
 }
 
 // DefaultClient is the default Client and is used by Get, Head, and Post.
@@ -74,8 +91,9 @@ type RoundTripper interface {
 	// authentication, or cookies.
 	//
 	// RoundTrip should not modify the request, except for
-	// consuming and closing the Body. The request's URL and
-	// Header fields are guaranteed to be initialized.
+	// consuming and closing the Body, including on errors. The
+	// request's URL and Header fields are guaranteed to be
+	// initialized.
 	RoundTrip(*Request) (*Response, error)
 }
 
@@ -97,7 +115,7 @@ func (c *Client) send(req *Request) (*Response, error) {
 			req.AddCookie(cookie)
 		}
 	}
-	resp, err := send(req, c.Transport)
+	resp, err := send(req, c.transport())
 	if err != nil {
 		return nil, err
 	}
@@ -123,6 +141,9 @@ func (c *Client) send(req *Request) (*Response, error) {
 // (typically Transport) may not be able to re-use a persistent TCP
 // connection to the server for a subsequent "keep-alive" request.
 //
+// The request Body, if non-nil, will be closed by the underlying
+// Transport, even on errors.
+//
 // Generally Get, Post, or PostForm will be used instead of Do.
 func (c *Client) Do(req *Request) (resp *Response, err error) {
 	if req.Method == "GET" || req.Method == "HEAD" {
@@ -134,22 +155,28 @@ func (c *Client) Do(req *Request) (resp *Response, err error) {
 	return c.send(req)
 }
 
+func (c *Client) transport() RoundTripper {
+	if c.Transport != nil {
+		return c.Transport
+	}
+	return DefaultTransport
+}
+
 // send issues an HTTP request.
 // Caller should close resp.Body when done reading from it.
 func send(req *Request, t RoundTripper) (resp *Response, err error) {
 	if t == nil {
-		t = DefaultTransport
-		if t == nil {
-			err = errors.New("http: no Client.Transport or DefaultTransport")
-			return
-		}
+		req.closeBody()
+		return nil, errors.New("http: no Client.Transport or DefaultTransport")
 	}
 
 	if req.URL == nil {
+		req.closeBody()
 		return nil, errors.New("http: nil Request.URL")
 	}
 
 	if req.RequestURI != "" {
+		req.closeBody()
 		return nil, errors.New("http: Request.RequestURI can't be set in client requests.")
 	}
 
@@ -257,21 +284,40 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
 	var via []*Request
 
 	if ireq.URL == nil {
+		ireq.closeBody()
 		return nil, errors.New("http: nil Request.URL")
 	}
 
+	var reqmu sync.Mutex // guards req
 	req := ireq
+
+	var timer *time.Timer
+	if c.Timeout > 0 {
+		type canceler interface {
+			CancelRequest(*Request)
+		}
+		tr, ok := c.transport().(canceler)
+		if !ok {
+			return nil, fmt.Errorf("net/http: Client Transport of type %T doesn't support CancelRequest; Timeout not supported", c.transport())
+		}
+		timer = time.AfterFunc(c.Timeout, func() {
+			reqmu.Lock()
+			defer reqmu.Unlock()
+			tr.CancelRequest(req)
+		})
+	}
+
 	urlStr := "" // next relative or absolute URL to fetch (after first request)
 	redirectFailed := false
 	for redirect := 0; ; redirect++ {
 		if redirect != 0 {
-			req = new(Request)
-			req.Method = ireq.Method
+			nreq := new(Request)
+			nreq.Method = ireq.Method
 			if ireq.Method == "POST" || ireq.Method == "PUT" {
-				req.Method = "GET"
+				nreq.Method = "GET"
 			}
-			req.Header = make(Header)
-			req.URL, err = base.Parse(urlStr)
+			nreq.Header = make(Header)
+			nreq.URL, err = base.Parse(urlStr)
 			if err != nil {
 				break
 			}
@@ -279,15 +325,18 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
 				// Add the Referer header.
 				lastReq := via[len(via)-1]
 				if lastReq.URL.Scheme != "https" {
-					req.Header.Set("Referer", lastReq.URL.String())
+					nreq.Header.Set("Referer", lastReq.URL.String())
 				}
 
-				err = redirectChecker(req, via)
+				err = redirectChecker(nreq, via)
 				if err != nil {
 					redirectFailed = true
 					break
 				}
 			}
+			reqmu.Lock()
+			req = nreq
+			reqmu.Unlock()
 		}
 
 		urlStr = req.URL.String()
@@ -296,6 +345,12 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
 		}
 
 		if shouldRedirect(resp.StatusCode) {
+			// Read the body if small so underlying TCP connection will be re-used.
+			// No need to check for errors: if it fails, Transport won't reuse it anyway.
+			const maxBodySlurpSize = 2 << 10
+			if resp.ContentLength == -1 || resp.ContentLength <= maxBodySlurpSize {
+				io.CopyN(ioutil.Discard, resp.Body, maxBodySlurpSize)
+			}
 			resp.Body.Close()
 			if urlStr = resp.Header.Get("Location"); urlStr == "" {
 				err = errors.New(fmt.Sprintf("%d response missing Location header", resp.StatusCode))
@@ -305,7 +360,10 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
 			via = append(via, req)
 			continue
 		}
-		return
+		if timer != nil {
+			resp.Body = &cancelTimerBody{timer, resp.Body}
+		}
+		return resp, nil
 	}
 
 	method := ireq.Method
@@ -349,7 +407,7 @@ func Post(url string, bodyType string, body io.Reader) (resp *Response, err erro
 // Caller should close resp.Body when done reading from it.
 //
 // If the provided body is also an io.Closer, it is closed after the
-// body is successfully written to the server.
+// request.
 func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
 	req, err := NewRequest("POST", url, body)
 	if err != nil {
@@ -408,3 +466,22 @@ func (c *Client) Head(url string) (resp *Response, err error) {
 	}
 	return c.doFollowingRedirects(req, shouldRedirectGet)
 }
+
+type cancelTimerBody struct {
+	t  *time.Timer
+	rc io.ReadCloser
+}
+
+func (b *cancelTimerBody) Read(p []byte) (n int, err error) {
+	n, err = b.rc.Read(p)
+	if err == io.EOF {
+		b.t.Stop()
+	}
+	return
+}
+
+func (b *cancelTimerBody) Close() error {
+	err := b.rc.Close()
+	b.t.Stop()
+	return err
+}
diff --git a/src/pkg/net/http/client_test.go b/src/pkg/net/http/client_test.go
index 997d041..6392c1b 100644
--- a/src/pkg/net/http/client_test.go
+++ b/src/pkg/net/http/client_test.go
@@ -15,14 +15,18 @@ import (
 	"fmt"
 	"io"
 	"io/ioutil"
+	"log"
 	"net"
 	. "net/http"
 	"net/http/httptest"
 	"net/url"
+	"reflect"
+	"sort"
 	"strconv"
 	"strings"
 	"sync"
 	"testing"
+	"time"
 )
 
 var robotsTxtHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -54,6 +58,13 @@ func pedanticReadAll(r io.Reader) (b []byte, err error) {
 	}
 }
 
+type chanWriter chan string
+
+func (w chanWriter) Write(p []byte) (n int, err error) {
+	w <- string(p)
+	return len(p), nil
+}
+
 func TestClient(t *testing.T) {
 	defer afterTest(t)
 	ts := httptest.NewServer(robotsTxtHandler)
@@ -373,24 +384,6 @@ func (j *TestJar) Cookies(u *url.URL) []*Cookie {
 	return j.perURL[u.Host]
 }
 
-func TestRedirectCookiesOnRequest(t *testing.T) {
-	defer afterTest(t)
-	var ts *httptest.Server
-	ts = httptest.NewServer(echoCookiesRedirectHandler)
-	defer ts.Close()
-	c := &Client{}
-	req, _ := NewRequest("GET", ts.URL, nil)
-	req.AddCookie(expectedCookies[0])
-	// TODO: Uncomment when an implementation of a RFC6265 cookie jar lands.
-	_ = c
-	// resp, _ := c.Do(req)
-	// matchReturnedCookies(t, expectedCookies, resp.Cookies())
-
-	req, _ = NewRequest("GET", ts.URL, nil)
-	// resp, _ = c.Do(req)
-	// matchReturnedCookies(t, expectedCookies[1:], resp.Cookies())
-}
-
 func TestRedirectCookiesJar(t *testing.T) {
 	defer afterTest(t)
 	var ts *httptest.Server
@@ -410,8 +403,8 @@ func TestRedirectCookiesJar(t *testing.T) {
 }
 
 func matchReturnedCookies(t *testing.T, expected, given []*Cookie) {
-	t.Logf("Received cookies: %v", given)
 	if len(given) != len(expected) {
+		t.Logf("Received cookies: %v", given)
 		t.Errorf("Expected %d cookies, got %d", len(expected), len(given))
 	}
 	for _, ec := range expected {
@@ -582,6 +575,8 @@ func TestClientInsecureTransport(t *testing.T) {
 	ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
 		w.Write([]byte("Hello"))
 	}))
+	errc := make(chanWriter, 10) // but only expecting 1
+	ts.Config.ErrorLog = log.New(errc, "", 0)
 	defer ts.Close()
 
 	// TODO(bradfitz): add tests for skipping hostname checks too?
@@ -603,6 +598,16 @@ func TestClientInsecureTransport(t *testing.T) {
 			res.Body.Close()
 		}
 	}
+
+	select {
+	case v := <-errc:
+		if !strings.Contains(v, "TLS handshake error") {
+			t.Errorf("expected an error log message containing 'TLS handshake error'; got %q", v)
+		}
+	case <-time.After(5 * time.Second):
+		t.Errorf("timeout waiting for logged error")
+	}
+
 }
 
 func TestClientErrorWithRequestURI(t *testing.T) {
@@ -653,6 +658,8 @@ func TestClientWithIncorrectTLSServerName(t *testing.T) {
 	defer afterTest(t)
 	ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
 	defer ts.Close()
+	errc := make(chanWriter, 10) // but only expecting 1
+	ts.Config.ErrorLog = log.New(errc, "", 0)
 
 	trans := newTLSTransport(t, ts)
 	trans.TLSClientConfig.ServerName = "badserver"
@@ -664,6 +671,14 @@ func TestClientWithIncorrectTLSServerName(t *testing.T) {
 	if !strings.Contains(err.Error(), "127.0.0.1") || !strings.Contains(err.Error(), "badserver") {
 		t.Errorf("wanted error mentioning 127.0.0.1 and badserver; got error: %v", err)
 	}
+	select {
+	case v := <-errc:
+		if !strings.Contains(v, "TLS handshake error") {
+			t.Errorf("expected an error log message containing 'TLS handshake error'; got %q", v)
+		}
+	case <-time.After(5 * time.Second):
+		t.Errorf("timeout waiting for logged error")
+	}
 }
 
 // Test for golang.org/issue/5829; the Transport should respect TLSClientConfig.ServerName
@@ -696,6 +711,33 @@ func TestTransportUsesTLSConfigServerName(t *testing.T) {
 	res.Body.Close()
 }
 
+func TestResponseSetsTLSConnectionState(t *testing.T) {
+	defer afterTest(t)
+	ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		w.Write([]byte("Hello"))
+	}))
+	defer ts.Close()
+
+	tr := newTLSTransport(t, ts)
+	tr.TLSClientConfig.CipherSuites = []uint16{tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA}
+	tr.Dial = func(netw, addr string) (net.Conn, error) {
+		return net.Dial(netw, ts.Listener.Addr().String())
+	}
+	defer tr.CloseIdleConnections()
+	c := &Client{Transport: tr}
+	res, err := c.Get("https://example.com/")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer res.Body.Close()
+	if res.TLS == nil {
+		t.Fatal("Response didn't set TLS Connection State.")
+	}
+	if got, want := res.TLS.CipherSuite, tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA; got != want {
+		t.Errorf("TLS Cipher Suite = %d; want %d", got, want)
+	}
+}
+
 // Verify Response.ContentLength is populated. http://golang.org/issue/4126
 func TestClientHeadContentLength(t *testing.T) {
 	defer afterTest(t)
@@ -799,3 +841,198 @@ func TestBasicAuth(t *testing.T) {
 		t.Errorf("Invalid auth %q", auth)
 	}
 }
+
+func TestClientTimeout(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping in short mode")
+	}
+	defer afterTest(t)
+	sawRoot := make(chan bool, 1)
+	sawSlow := make(chan bool, 1)
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		if r.URL.Path == "/" {
+			sawRoot <- true
+			Redirect(w, r, "/slow", StatusFound)
+			return
+		}
+		if r.URL.Path == "/slow" {
+			w.Write([]byte("Hello"))
+			w.(Flusher).Flush()
+			sawSlow <- true
+			time.Sleep(2 * time.Second)
+			return
+		}
+	}))
+	defer ts.Close()
+	const timeout = 500 * time.Millisecond
+	c := &Client{
+		Timeout: timeout,
+	}
+
+	res, err := c.Get(ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	select {
+	case <-sawRoot:
+		// good.
+	default:
+		t.Fatal("handler never got / request")
+	}
+
+	select {
+	case <-sawSlow:
+		// good.
+	default:
+		t.Fatal("handler never got /slow request")
+	}
+
+	errc := make(chan error, 1)
+	go func() {
+		_, err := ioutil.ReadAll(res.Body)
+		errc <- err
+		res.Body.Close()
+	}()
+
+	const failTime = timeout * 2
+	select {
+	case err := <-errc:
+		if err == nil {
+			t.Error("expected error from ReadAll")
+		}
+		// Expected error.
+	case <-time.After(failTime):
+		t.Errorf("timeout after %v waiting for timeout of %v", failTime, timeout)
+	}
+}
+
+func TestClientRedirectEatsBody(t *testing.T) {
+	defer afterTest(t)
+	saw := make(chan string, 2)
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		saw <- r.RemoteAddr
+		if r.URL.Path == "/" {
+			Redirect(w, r, "/foo", StatusFound) // which includes a body
+		}
+	}))
+	defer ts.Close()
+
+	res, err := Get(ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = ioutil.ReadAll(res.Body)
+	if err != nil {
+		t.Fatal(err)
+	}
+	res.Body.Close()
+
+	var first string
+	select {
+	case first = <-saw:
+	default:
+		t.Fatal("server didn't see a request")
+	}
+
+	var second string
+	select {
+	case second = <-saw:
+	default:
+		t.Fatal("server didn't see a second request")
+	}
+
+	if first != second {
+		t.Fatal("server saw different client ports before & after the redirect")
+	}
+}
+
+// eofReaderFunc is an io.Reader that runs itself, and then returns io.EOF.
+type eofReaderFunc func()
+
+func (f eofReaderFunc) Read(p []byte) (n int, err error) {
+	f()
+	return 0, io.EOF
+}
+
+func TestClientTrailers(t *testing.T) {
+	defer afterTest(t)
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		w.Header().Set("Connection", "close")
+		w.Header().Set("Trailer", "Server-Trailer-A, Server-Trailer-B")
+		w.Header().Add("Trailer", "Server-Trailer-C")
+
+		var decl []string
+		for k := range r.Trailer {
+			decl = append(decl, k)
+		}
+		sort.Strings(decl)
+
+		slurp, err := ioutil.ReadAll(r.Body)
+		if err != nil {
+			t.Errorf("Server reading request body: %v", err)
+		}
+		if string(slurp) != "foo" {
+			t.Errorf("Server read request body %q; want foo", slurp)
+		}
+		if r.Trailer == nil {
+			io.WriteString(w, "nil Trailer")
+		} else {
+			fmt.Fprintf(w, "decl: %v, vals: %s, %s",
+				decl,
+				r.Trailer.Get("Client-Trailer-A"),
+				r.Trailer.Get("Client-Trailer-B"))
+		}
+
+		// TODO: golang.org/issue/7759: there's no way yet for
+		// the server to set trailers without hijacking, so do
+		// that for now, just to test the client.  Later, in
+		// Go 1.4, it should be implicit that any mutations
+		// to w.Header() after the initial write are the
+		// trailers to be sent, if and only if they were
+		// previously declared with w.Header().Set("Trailer",
+		// ..keys..)
+		w.(Flusher).Flush()
+		conn, buf, _ := w.(Hijacker).Hijack()
+		t := Header{}
+		t.Set("Server-Trailer-A", "valuea")
+		t.Set("Server-Trailer-C", "valuec") // skipping B
+		buf.WriteString("0\r\n")            // eof
+		t.Write(buf)
+		buf.WriteString("\r\n") // end of trailers
+		buf.Flush()
+		conn.Close()
+	}))
+	defer ts.Close()
+
+	var req *Request
+	req, _ = NewRequest("POST", ts.URL, io.MultiReader(
+		eofReaderFunc(func() {
+			req.Trailer["Client-Trailer-A"] = []string{"valuea"}
+		}),
+		strings.NewReader("foo"),
+		eofReaderFunc(func() {
+			req.Trailer["Client-Trailer-B"] = []string{"valueb"}
+		}),
+	))
+	req.Trailer = Header{
+		"Client-Trailer-A": nil, //  to be set later
+		"Client-Trailer-B": nil, //  to be set later
+	}
+	req.ContentLength = -1
+	res, err := DefaultClient.Do(req)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := wantBody(res, err, "decl: [Client-Trailer-A Client-Trailer-B], vals: valuea, valueb"); err != nil {
+		t.Error(err)
+	}
+	want := Header{
+		"Server-Trailer-A": []string{"valuea"},
+		"Server-Trailer-B": nil,
+		"Server-Trailer-C": []string{"valuec"},
+	}
+	if !reflect.DeepEqual(res.Trailer, want) {
+		t.Errorf("Response trailers = %#v; want %#v", res.Trailer, want)
+	}
+}
diff --git a/src/pkg/net/http/cookie.go b/src/pkg/net/http/cookie.go
index 8b01c50..dc60ba8 100644
--- a/src/pkg/net/http/cookie.go
+++ b/src/pkg/net/http/cookie.go
@@ -76,11 +76,7 @@ func readSetCookies(h Header) []*Cookie {
 				attr, val = attr[:j], attr[j+1:]
 			}
 			lowerAttr := strings.ToLower(attr)
-			parseCookieValueFn := parseCookieValue
-			if lowerAttr == "expires" {
-				parseCookieValueFn = parseCookieExpiresValue
-			}
-			val, success = parseCookieValueFn(val)
+			val, success = parseCookieValue(val)
 			if !success {
 				c.Unparsed = append(c.Unparsed, parts[i])
 				continue
@@ -94,7 +90,6 @@ func readSetCookies(h Header) []*Cookie {
 				continue
 			case "domain":
 				c.Domain = val
-				// TODO: Add domain parsing
 				continue
 			case "max-age":
 				secs, err := strconv.Atoi(val)
@@ -121,7 +116,6 @@ func readSetCookies(h Header) []*Cookie {
 				continue
 			case "path":
 				c.Path = val
-				// TODO: Add path parsing
 				continue
 			}
 			c.Unparsed = append(c.Unparsed, parts[i])
@@ -300,12 +294,23 @@ func sanitizeCookieName(n string) string {
 //           ; US-ASCII characters excluding CTLs,
 //           ; whitespace DQUOTE, comma, semicolon,
 //           ; and backslash
+// We loosen this as spaces and commas are common in cookie values
+// but we produce a quoted cookie-value in when value starts or ends
+// with a comma or space.
+// See http://golang.org/issue/7243 for the discussion.
 func sanitizeCookieValue(v string) string {
-	return sanitizeOrWarn("Cookie.Value", validCookieValueByte, v)
+	v = sanitizeOrWarn("Cookie.Value", validCookieValueByte, v)
+	if len(v) == 0 {
+		return v
+	}
+	if v[0] == ' ' || v[0] == ',' || v[len(v)-1] == ' ' || v[len(v)-1] == ',' {
+		return `"` + v + `"`
+	}
+	return v
 }
 
 func validCookieValueByte(b byte) bool {
-	return 0x20 < b && b < 0x7f && b != '"' && b != ',' && b != ';' && b != '\\'
+	return 0x20 <= b && b < 0x7f && b != '"' && b != ';' && b != '\\'
 }
 
 // path-av           = "Path=" path-value
@@ -340,38 +345,13 @@ func sanitizeOrWarn(fieldName string, valid func(byte) bool, v string) string {
 	return string(buf)
 }
 
-func unquoteCookieValue(v string) string {
-	if len(v) > 1 && v[0] == '"' && v[len(v)-1] == '"' {
-		return v[1 : len(v)-1]
-	}
-	return v
-}
-
-func isCookieByte(c byte) bool {
-	switch {
-	case c == 0x21, 0x23 <= c && c <= 0x2b, 0x2d <= c && c <= 0x3a,
-		0x3c <= c && c <= 0x5b, 0x5d <= c && c <= 0x7e:
-		return true
-	}
-	return false
-}
-
-func isCookieExpiresByte(c byte) (ok bool) {
-	return isCookieByte(c) || c == ',' || c == ' '
-}
-
 func parseCookieValue(raw string) (string, bool) {
-	return parseCookieValueUsing(raw, isCookieByte)
-}
-
-func parseCookieExpiresValue(raw string) (string, bool) {
-	return parseCookieValueUsing(raw, isCookieExpiresByte)
-}
-
-func parseCookieValueUsing(raw string, validByte func(byte) bool) (string, bool) {
-	raw = unquoteCookieValue(raw)
+	// Strip the quotes, if present.
+	if len(raw) > 1 && raw[0] == '"' && raw[len(raw)-1] == '"' {
+		raw = raw[1 : len(raw)-1]
+	}
 	for i := 0; i < len(raw); i++ {
-		if !validByte(raw[i]) {
+		if !validCookieValueByte(raw[i]) {
 			return "", false
 		}
 	}
diff --git a/src/pkg/net/http/cookie_test.go b/src/pkg/net/http/cookie_test.go
index 11b01cc..f78f372 100644
--- a/src/pkg/net/http/cookie_test.go
+++ b/src/pkg/net/http/cookie_test.go
@@ -5,9 +5,13 @@
 package http
 
 import (
+	"bytes"
 	"encoding/json"
 	"fmt"
+	"log"
+	"os"
 	"reflect"
+	"strings"
 	"testing"
 	"time"
 )
@@ -48,15 +52,61 @@ var writeSetCookiesTests = []struct {
 		&Cookie{Name: "cookie-8", Value: "eight", Domain: "::1"},
 		"cookie-8=eight",
 	},
+	// The "special" cookies have values containing commas or spaces which
+	// are disallowed by RFC 6265 but are common in the wild.
+	{
+		&Cookie{Name: "special-1", Value: "a z"},
+		`special-1=a z`,
+	},
+	{
+		&Cookie{Name: "special-2", Value: " z"},
+		`special-2=" z"`,
+	},
+	{
+		&Cookie{Name: "special-3", Value: "a "},
+		`special-3="a "`,
+	},
+	{
+		&Cookie{Name: "special-4", Value: " "},
+		`special-4=" "`,
+	},
+	{
+		&Cookie{Name: "special-5", Value: "a,z"},
+		`special-5=a,z`,
+	},
+	{
+		&Cookie{Name: "special-6", Value: ",z"},
+		`special-6=",z"`,
+	},
+	{
+		&Cookie{Name: "special-7", Value: "a,"},
+		`special-7="a,"`,
+	},
+	{
+		&Cookie{Name: "special-8", Value: ","},
+		`special-8=","`,
+	},
+	{
+		&Cookie{Name: "empty-value", Value: ""},
+		`empty-value=`,
+	},
 }
 
 func TestWriteSetCookies(t *testing.T) {
+	defer log.SetOutput(os.Stderr)
+	var logbuf bytes.Buffer
+	log.SetOutput(&logbuf)
+
 	for i, tt := range writeSetCookiesTests {
 		if g, e := tt.Cookie.String(), tt.Raw; g != e {
 			t.Errorf("Test %d, expecting:\n%s\nGot:\n%s\n", i, e, g)
 			continue
 		}
 	}
+
+	if got, sub := logbuf.String(), "dropping domain attribute"; !strings.Contains(got, sub) {
+		t.Errorf("Expected substring %q in log output. Got:\n%s", sub, got)
+	}
 }
 
 type headerOnlyResponseWriter Header
@@ -166,6 +216,40 @@ var readSetCookiesTests = []struct {
 			Raw:      "ASP.NET_SessionId=foo; path=/; HttpOnly",
 		}},
 	},
+	// Make sure we can properly read back the Set-Cookie headers we create
+	// for values containing spaces or commas:
+	{
+		Header{"Set-Cookie": {`special-1=a z`}},
+		[]*Cookie{{Name: "special-1", Value: "a z", Raw: `special-1=a z`}},
+	},
+	{
+		Header{"Set-Cookie": {`special-2=" z"`}},
+		[]*Cookie{{Name: "special-2", Value: " z", Raw: `special-2=" z"`}},
+	},
+	{
+		Header{"Set-Cookie": {`special-3="a "`}},
+		[]*Cookie{{Name: "special-3", Value: "a ", Raw: `special-3="a "`}},
+	},
+	{
+		Header{"Set-Cookie": {`special-4=" "`}},
+		[]*Cookie{{Name: "special-4", Value: " ", Raw: `special-4=" "`}},
+	},
+	{
+		Header{"Set-Cookie": {`special-5=a,z`}},
+		[]*Cookie{{Name: "special-5", Value: "a,z", Raw: `special-5=a,z`}},
+	},
+	{
+		Header{"Set-Cookie": {`special-6=",z"`}},
+		[]*Cookie{{Name: "special-6", Value: ",z", Raw: `special-6=",z"`}},
+	},
+	{
+		Header{"Set-Cookie": {`special-7=a,`}},
+		[]*Cookie{{Name: "special-7", Value: "a,", Raw: `special-7=a,`}},
+	},
+	{
+		Header{"Set-Cookie": {`special-8=","`}},
+		[]*Cookie{{Name: "special-8", Value: ",", Raw: `special-8=","`}},
+	},
 
 	// TODO(bradfitz): users have reported seeing this in the
 	// wild, but do browsers handle it? RFC 6265 just says "don't
@@ -244,22 +328,39 @@ func TestReadCookies(t *testing.T) {
 }
 
 func TestCookieSanitizeValue(t *testing.T) {
+	defer log.SetOutput(os.Stderr)
+	var logbuf bytes.Buffer
+	log.SetOutput(&logbuf)
+
 	tests := []struct {
 		in, want string
 	}{
 		{"foo", "foo"},
-		{"foo bar", "foobar"},
+		{"foo;bar", "foobar"},
+		{"foo\\bar", "foobar"},
+		{"foo\"bar", "foobar"},
 		{"\x00\x7e\x7f\x80", "\x7e"},
 		{`"withquotes"`, "withquotes"},
+		{"a z", "a z"},
+		{" z", `" z"`},
+		{"a ", `"a "`},
 	}
 	for _, tt := range tests {
 		if got := sanitizeCookieValue(tt.in); got != tt.want {
 			t.Errorf("sanitizeCookieValue(%q) = %q; want %q", tt.in, got, tt.want)
 		}
 	}
+
+	if got, sub := logbuf.String(), "dropping invalid bytes"; !strings.Contains(got, sub) {
+		t.Errorf("Expected substring %q in log output. Got:\n%s", sub, got)
+	}
 }
 
 func TestCookieSanitizePath(t *testing.T) {
+	defer log.SetOutput(os.Stderr)
+	var logbuf bytes.Buffer
+	log.SetOutput(&logbuf)
+
 	tests := []struct {
 		in, want string
 	}{
@@ -272,4 +373,8 @@ func TestCookieSanitizePath(t *testing.T) {
 			t.Errorf("sanitizeCookiePath(%q) = %q; want %q", tt.in, got, tt.want)
 		}
 	}
+
+	if got, sub := logbuf.String(), "dropping invalid bytes"; !strings.Contains(got, sub) {
+		t.Errorf("Expected substring %q in log output. Got:\n%s", sub, got)
+	}
 }
diff --git a/src/pkg/net/http/export_test.go b/src/pkg/net/http/export_test.go
index 22b7f27..960563b 100644
--- a/src/pkg/net/http/export_test.go
+++ b/src/pkg/net/http/export_test.go
@@ -21,7 +21,7 @@ var ExportAppendTime = appendTime
 func (t *Transport) NumPendingRequestsForTesting() int {
 	t.reqMu.Lock()
 	defer t.reqMu.Unlock()
-	return len(t.reqConn)
+	return len(t.reqCanceler)
 }
 
 func (t *Transport) IdleConnKeysForTesting() (keys []string) {
@@ -32,7 +32,7 @@ func (t *Transport) IdleConnKeysForTesting() (keys []string) {
 		return
 	}
 	for key := range t.idleConn {
-		keys = append(keys, key)
+		keys = append(keys, key.String())
 	}
 	return
 }
@@ -43,11 +43,12 @@ func (t *Transport) IdleConnCountForTesting(cacheKey string) int {
 	if t.idleConn == nil {
 		return 0
 	}
-	conns, ok := t.idleConn[cacheKey]
-	if !ok {
-		return 0
+	for k, conns := range t.idleConn {
+		if k.String() == cacheKey {
+			return len(conns)
+		}
 	}
-	return len(conns)
+	return 0
 }
 
 func (t *Transport) IdleConnChMapSizeForTesting() int {
@@ -63,4 +64,9 @@ func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler {
 	return &timeoutHandler{handler, f, ""}
 }
 
+func ResetCachedEnvironment() {
+	httpProxyEnv.reset()
+	noProxyEnv.reset()
+}
+
 var DefaultUserAgent = defaultUserAgent
diff --git a/src/pkg/net/http/fcgi/child.go b/src/pkg/net/http/fcgi/child.go
index 60b794e..a3beaa3 100644
--- a/src/pkg/net/http/fcgi/child.go
+++ b/src/pkg/net/http/fcgi/child.go
@@ -16,6 +16,7 @@ import (
 	"net/http/cgi"
 	"os"
 	"strings"
+	"sync"
 	"time"
 )
 
@@ -126,8 +127,10 @@ func (r *response) Close() error {
 }
 
 type child struct {
-	conn     *conn
-	handler  http.Handler
+	conn    *conn
+	handler http.Handler
+
+	mu       sync.Mutex          // protects requests:
 	requests map[uint16]*request // keyed by request ID
 }
 
@@ -157,7 +160,9 @@ var errCloseConn = errors.New("fcgi: connection should be closed")
 var emptyBody = ioutil.NopCloser(strings.NewReader(""))
 
 func (c *child) handleRecord(rec *record) error {
+	c.mu.Lock()
 	req, ok := c.requests[rec.h.Id]
+	c.mu.Unlock()
 	if !ok && rec.h.Type != typeBeginRequest && rec.h.Type != typeGetValues {
 		// The spec says to ignore unknown request IDs.
 		return nil
@@ -179,7 +184,10 @@ func (c *child) handleRecord(rec *record) error {
 			c.conn.writeEndRequest(rec.h.Id, 0, statusUnknownRole)
 			return nil
 		}
-		c.requests[rec.h.Id] = newRequest(rec.h.Id, br.flags)
+		req = newRequest(rec.h.Id, br.flags)
+		c.mu.Lock()
+		c.requests[rec.h.Id] = req
+		c.mu.Unlock()
 		return nil
 	case typeParams:
 		// NOTE(eds): Technically a key-value pair can straddle the boundary
@@ -220,7 +228,9 @@ func (c *child) handleRecord(rec *record) error {
 		return nil
 	case typeAbortRequest:
 		println("abort")
+		c.mu.Lock()
 		delete(c.requests, rec.h.Id)
+		c.mu.Unlock()
 		c.conn.writeEndRequest(rec.h.Id, 0, statusRequestComplete)
 		if !req.keepConn {
 			// connection will close upon return
@@ -247,6 +257,9 @@ func (c *child) serveRequest(req *request, body io.ReadCloser) {
 		c.handler.ServeHTTP(r, httpReq)
 	}
 	r.Close()
+	c.mu.Lock()
+	delete(c.requests, req.reqId)
+	c.mu.Unlock()
 	c.conn.writeEndRequest(req.reqId, 0, statusRequestComplete)
 
 	// Consume the entire body, so the host isn't still writing to
diff --git a/src/pkg/net/http/fs.go b/src/pkg/net/http/fs.go
index 8b32ca1..8576cf8 100644
--- a/src/pkg/net/http/fs.go
+++ b/src/pkg/net/http/fs.go
@@ -13,6 +13,7 @@ import (
 	"mime"
 	"mime/multipart"
 	"net/textproto"
+	"net/url"
 	"os"
 	"path"
 	"path/filepath"
@@ -52,12 +53,14 @@ type FileSystem interface {
 
 // A File is returned by a FileSystem's Open method and can be
 // served by the FileServer implementation.
+//
+// The methods should behave the same as those on an *os.File.
 type File interface {
-	Close() error
-	Stat() (os.FileInfo, error)
+	io.Closer
+	io.Reader
 	Readdir(count int) ([]os.FileInfo, error)
-	Read([]byte) (int, error)
 	Seek(offset int64, whence int) (int64, error)
+	Stat() (os.FileInfo, error)
 }
 
 func dirList(w ResponseWriter, f File) {
@@ -73,8 +76,11 @@ func dirList(w ResponseWriter, f File) {
 			if d.IsDir() {
 				name += "/"
 			}
-			// TODO htmlescape
-			fmt.Fprintf(w, "<a href=\"%s\">%s</a>\n", name, name)
+			// name may contain '?' or '#', which must be escaped to remain
+			// part of the URL path, and not indicate the start of a query
+			// string or fragment.
+			url := url.URL{Path: name}
+			fmt.Fprintf(w, "<a href=\"%s\">%s</a>\n", url.String(), htmlReplacer.Replace(name))
 		}
 	}
 	fmt.Fprintf(w, "</pre>\n")
@@ -521,7 +527,7 @@ func (w *countingWriter) Write(p []byte) (n int, err error) {
 	return len(p), nil
 }
 
-// rangesMIMESize returns the nunber of bytes it takes to encode the
+// rangesMIMESize returns the number of bytes it takes to encode the
 // provided ranges as a multipart response.
 func rangesMIMESize(ranges []httpRange, contentType string, contentSize int64) (encSize int64) {
 	var w countingWriter
diff --git a/src/pkg/net/http/fs_test.go b/src/pkg/net/http/fs_test.go
index ae54edf..f968565 100644
--- a/src/pkg/net/http/fs_test.go
+++ b/src/pkg/net/http/fs_test.go
@@ -227,6 +227,54 @@ func TestFileServerCleans(t *testing.T) {
 	}
 }
 
+func TestFileServerEscapesNames(t *testing.T) {
+	defer afterTest(t)
+	const dirListPrefix = "<pre>\n"
+	const dirListSuffix = "\n</pre>\n"
+	tests := []struct {
+		name, escaped string
+	}{
+		{`simple_name`, `<a href="simple_name">simple_name</a>`},
+		{`"'<>&`, `<a href="%22%27%3C%3E&">"'<>&</a>`},
+		{`?foo=bar#baz`, `<a href="%3Ffoo=bar%23baz">?foo=bar#baz</a>`},
+		{`<combo>?foo`, `<a href="%3Ccombo%3E%3Ffoo"><combo>?foo</a>`},
+	}
+
+	// We put each test file in its own directory in the fakeFS so we can look at it in isolation.
+	fs := make(fakeFS)
+	for i, test := range tests {
+		testFile := &fakeFileInfo{basename: test.name}
+		fs[fmt.Sprintf("/%d", i)] = &fakeFileInfo{
+			dir:     true,
+			modtime: time.Unix(1000000000, 0).UTC(),
+			ents:    []*fakeFileInfo{testFile},
+		}
+		fs[fmt.Sprintf("/%d/%s", i, test.name)] = testFile
+	}
+
+	ts := httptest.NewServer(FileServer(&fs))
+	defer ts.Close()
+	for i, test := range tests {
+		url := fmt.Sprintf("%s/%d", ts.URL, i)
+		res, err := Get(url)
+		if err != nil {
+			t.Fatalf("test %q: Get: %v", test.name, err)
+		}
+		b, err := ioutil.ReadAll(res.Body)
+		if err != nil {
+			t.Fatalf("test %q: read Body: %v", test.name, err)
+		}
+		s := string(b)
+		if !strings.HasPrefix(s, dirListPrefix) || !strings.HasSuffix(s, dirListSuffix) {
+			t.Errorf("test %q: listing dir, full output is %q, want prefix %q and suffix %q", test.name, s, dirListPrefix, dirListSuffix)
+		}
+		if trimmed := strings.TrimSuffix(strings.TrimPrefix(s, dirListPrefix), dirListSuffix); trimmed != test.escaped {
+			t.Errorf("test %q: listing dir, filename escaped to %q, want %q", test.name, trimmed, test.escaped)
+		}
+		res.Body.Close()
+	}
+}
+
 func mustRemoveAll(dir string) {
 	err := os.RemoveAll(dir)
 	if err != nil {
@@ -457,8 +505,9 @@ func (f *fakeFileInfo) Mode() os.FileMode {
 
 type fakeFile struct {
 	io.ReadSeeker
-	fi   *fakeFileInfo
-	path string // as opened
+	fi     *fakeFileInfo
+	path   string // as opened
+	entpos int
 }
 
 func (f *fakeFile) Close() error               { return nil }
@@ -468,10 +517,20 @@ func (f *fakeFile) Readdir(count int) ([]os.FileInfo, error) {
 		return nil, os.ErrInvalid
 	}
 	var fis []os.FileInfo
-	for _, fi := range f.fi.ents {
-		fis = append(fis, fi)
+
+	limit := f.entpos + count
+	if count <= 0 || limit > len(f.fi.ents) {
+		limit = len(f.fi.ents)
+	}
+	for ; f.entpos < limit; f.entpos++ {
+		fis = append(fis, f.fi.ents[f.entpos])
+	}
+
+	if len(fis) == 0 && count > 0 {
+		return fis, io.EOF
+	} else {
+		return fis, nil
 	}
-	return fis, nil
 }
 
 type fakeFS map[string]*fakeFileInfo
@@ -480,7 +539,6 @@ func (fs fakeFS) Open(name string) (File, error) {
 	name = path.Clean(name)
 	f, ok := fs[name]
 	if !ok {
-		println("fake filesystem didn't find file", name)
 		return nil, os.ErrNotExist
 	}
 	return &fakeFile{ReadSeeker: strings.NewReader(f.contents), fi: f, path: name}, nil
diff --git a/src/pkg/net/http/header.go b/src/pkg/net/http/header.go
index ca1ae07..153b943 100644
--- a/src/pkg/net/http/header.go
+++ b/src/pkg/net/http/header.go
@@ -9,9 +9,12 @@ import (
 	"net/textproto"
 	"sort"
 	"strings"
+	"sync"
 	"time"
 )
 
+var raceEnabled = false // set by race.go
+
 // A Header represents the key-value pairs in an HTTP header.
 type Header map[string][]string
 
@@ -114,18 +117,15 @@ func (s *headerSorter) Len() int           { return len(s.kvs) }
 func (s *headerSorter) Swap(i, j int)      { s.kvs[i], s.kvs[j] = s.kvs[j], s.kvs[i] }
 func (s *headerSorter) Less(i, j int) bool { return s.kvs[i].key < s.kvs[j].key }
 
-// TODO: convert this to a sync.Cache (issue 4720)
-var headerSorterCache = make(chan *headerSorter, 8)
+var headerSorterPool = sync.Pool{
+	New: func() interface{} { return new(headerSorter) },
+}
 
 // sortedKeyValues returns h's keys sorted in the returned kvs
 // slice. The headerSorter used to sort is also returned, for possible
 // return to headerSorterCache.
 func (h Header) sortedKeyValues(exclude map[string]bool) (kvs []keyValues, hs *headerSorter) {
-	select {
-	case hs = <-headerSorterCache:
-	default:
-		hs = new(headerSorter)
-	}
+	hs = headerSorterPool.Get().(*headerSorter)
 	if cap(hs.kvs) < len(h) {
 		hs.kvs = make([]keyValues, 0, len(h))
 	}
@@ -159,10 +159,7 @@ func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error {
 			}
 		}
 	}
-	select {
-	case headerSorterCache <- sorter:
-	default:
-	}
+	headerSorterPool.Put(sorter)
 	return nil
 }
 
diff --git a/src/pkg/net/http/header_test.go b/src/pkg/net/http/header_test.go
index 9fd9837..9dcd591 100644
--- a/src/pkg/net/http/header_test.go
+++ b/src/pkg/net/http/header_test.go
@@ -192,9 +192,12 @@ func BenchmarkHeaderWriteSubset(b *testing.B) {
 	}
 }
 
-func TestHeaderWriteSubsetMallocs(t *testing.T) {
+func TestHeaderWriteSubsetAllocs(t *testing.T) {
 	if testing.Short() {
-		t.Skip("skipping malloc count in short mode")
+		t.Skip("skipping alloc test in short mode")
+	}
+	if raceEnabled {
+		t.Skip("skipping test under race detector")
 	}
 	if runtime.GOMAXPROCS(0) > 1 {
 		t.Skip("skipping; GOMAXPROCS>1")
@@ -204,6 +207,6 @@ func TestHeaderWriteSubsetMallocs(t *testing.T) {
 		testHeader.WriteSubset(&buf, nil)
 	})
 	if n > 0 {
-		t.Errorf("mallocs = %g; want 0", n)
+		t.Errorf("allocs = %g; want 0", n)
 	}
 }
diff --git a/src/pkg/net/http/httptest/server_test.go b/src/pkg/net/http/httptest/server_test.go
index 500a9f0..501cc8a 100644
--- a/src/pkg/net/http/httptest/server_test.go
+++ b/src/pkg/net/http/httptest/server_test.go
@@ -8,6 +8,7 @@ import (
 	"io/ioutil"
 	"net/http"
 	"testing"
+	"time"
 )
 
 func TestServer(t *testing.T) {
@@ -27,3 +28,25 @@ func TestServer(t *testing.T) {
 		t.Errorf("got %q, want hello", string(got))
 	}
 }
+
+func TestIssue7264(t *testing.T) {
+	for i := 0; i < 1000; i++ {
+		func() {
+			inHandler := make(chan bool, 1)
+			ts := NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+				inHandler <- true
+			}))
+			defer ts.Close()
+			tr := &http.Transport{
+				ResponseHeaderTimeout: time.Nanosecond,
+			}
+			defer tr.CloseIdleConnections()
+			c := &http.Client{Transport: tr}
+			res, err := c.Get(ts.URL)
+			<-inHandler
+			if err == nil {
+				res.Body.Close()
+			}
+		}()
+	}
+}
diff --git a/src/pkg/net/http/httputil/chunked.go b/src/pkg/net/http/httputil/chunked.go
index b66d409..9632bfd 100644
--- a/src/pkg/net/http/httputil/chunked.go
+++ b/src/pkg/net/http/httputil/chunked.go
@@ -4,15 +4,14 @@
 
 // The wire protocol for HTTP's "chunked" Transfer-Encoding.
 
-// This code is a duplicate of ../chunked.go with these edits:
-//	s/newChunked/NewChunked/g
-//	s/package http/package httputil/
+// This code is duplicated in net/http and net/http/httputil.
 // Please make any changes in both files.
 
 package httputil
 
 import (
 	"bufio"
+	"bytes"
 	"errors"
 	"fmt"
 	"io"
@@ -22,13 +21,13 @@ const maxLineLength = 4096 // assumed <= bufio.defaultBufSize
 
 var ErrLineTooLong = errors.New("header line too long")
 
-// NewChunkedReader returns a new chunkedReader that translates the data read from r
+// newChunkedReader returns a new chunkedReader that translates the data read from r
 // out of HTTP "chunked" format before returning it.
 // The chunkedReader returns io.EOF when the final 0-length chunk is read.
 //
-// NewChunkedReader is not needed by normal applications. The http package
+// newChunkedReader is not needed by normal applications. The http package
 // automatically decodes chunking when reading response bodies.
-func NewChunkedReader(r io.Reader) io.Reader {
+func newChunkedReader(r io.Reader) io.Reader {
 	br, ok := r.(*bufio.Reader)
 	if !ok {
 		br = bufio.NewReader(r)
@@ -59,26 +58,45 @@ func (cr *chunkedReader) beginChunk() {
 	}
 }
 
-func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
-	if cr.err != nil {
-		return 0, cr.err
+func (cr *chunkedReader) chunkHeaderAvailable() bool {
+	n := cr.r.Buffered()
+	if n > 0 {
+		peek, _ := cr.r.Peek(n)
+		return bytes.IndexByte(peek, '\n') >= 0
 	}
-	if cr.n == 0 {
-		cr.beginChunk()
-		if cr.err != nil {
-			return 0, cr.err
+	return false
+}
+
+func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
+	for cr.err == nil {
+		if cr.n == 0 {
+			if n > 0 && !cr.chunkHeaderAvailable() {
+				// We've read enough. Don't potentially block
+				// reading a new chunk header.
+				break
+			}
+			cr.beginChunk()
+			continue
 		}
-	}
-	if uint64(len(b)) > cr.n {
-		b = b[0:cr.n]
-	}
-	n, cr.err = cr.r.Read(b)
-	cr.n -= uint64(n)
-	if cr.n == 0 && cr.err == nil {
-		// end of chunk (CRLF)
-		if _, cr.err = io.ReadFull(cr.r, cr.buf[:]); cr.err == nil {
-			if cr.buf[0] != '\r' || cr.buf[1] != '\n' {
-				cr.err = errors.New("malformed chunked encoding")
+		if len(b) == 0 {
+			break
+		}
+		rbuf := b
+		if uint64(len(rbuf)) > cr.n {
+			rbuf = rbuf[:cr.n]
+		}
+		var n0 int
+		n0, cr.err = cr.r.Read(rbuf)
+		n += n0
+		b = b[n0:]
+		cr.n -= uint64(n0)
+		// If we're at the end of a chunk, read the next two
+		// bytes to verify they are "\r\n".
+		if cr.n == 0 && cr.err == nil {
+			if _, cr.err = io.ReadFull(cr.r, cr.buf[:2]); cr.err == nil {
+				if cr.buf[0] != '\r' || cr.buf[1] != '\n' {
+					cr.err = errors.New("malformed chunked encoding")
+				}
 			}
 		}
 	}
@@ -117,16 +135,16 @@ func isASCIISpace(b byte) bool {
 	return b == ' ' || b == '\t' || b == '\n' || b == '\r'
 }
 
-// NewChunkedWriter returns a new chunkedWriter that translates writes into HTTP
+// newChunkedWriter returns a new chunkedWriter that translates writes into HTTP
 // "chunked" format before writing them to w. Closing the returned chunkedWriter
 // sends the final 0-length chunk that marks the end of the stream.
 //
-// NewChunkedWriter is not needed by normal applications. The http
+// newChunkedWriter is not needed by normal applications. The http
 // package adds chunking automatically if handlers don't set a
-// Content-Length header. Using NewChunkedWriter inside a handler
+// Content-Length header. Using newChunkedWriter inside a handler
 // would result in double chunking or chunking with a Content-Length
 // length, both of which are wrong.
-func NewChunkedWriter(w io.Writer) io.WriteCloser {
+func newChunkedWriter(w io.Writer) io.WriteCloser {
 	return &chunkedWriter{w}
 }
 
diff --git a/src/pkg/net/http/httputil/chunked_test.go b/src/pkg/net/http/httputil/chunked_test.go
index a06bffa..a7a5774 100644
--- a/src/pkg/net/http/httputil/chunked_test.go
+++ b/src/pkg/net/http/httputil/chunked_test.go
@@ -2,26 +2,25 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// This code is a duplicate of ../chunked_test.go with these edits:
-//	s/newChunked/NewChunked/g
-//	s/package http/package httputil/
+// This code is duplicated in net/http and net/http/httputil.
 // Please make any changes in both files.
 
 package httputil
 
 import (
+	"bufio"
 	"bytes"
 	"fmt"
 	"io"
 	"io/ioutil"
-	"runtime"
+	"strings"
 	"testing"
 )
 
 func TestChunk(t *testing.T) {
 	var b bytes.Buffer
 
-	w := NewChunkedWriter(&b)
+	w := newChunkedWriter(&b)
 	const chunk1 = "hello, "
 	const chunk2 = "world! 0123456789abcdef"
 	w.Write([]byte(chunk1))
@@ -32,7 +31,7 @@ func TestChunk(t *testing.T) {
 		t.Fatalf("chunk writer wrote %q; want %q", g, e)
 	}
 
-	r := NewChunkedReader(&b)
+	r := newChunkedReader(&b)
 	data, err := ioutil.ReadAll(r)
 	if err != nil {
 		t.Logf(`data: "%s"`, data)
@@ -43,37 +42,102 @@ func TestChunk(t *testing.T) {
 	}
 }
 
+func TestChunkReadMultiple(t *testing.T) {
+	// Bunch of small chunks, all read together.
+	{
+		var b bytes.Buffer
+		w := newChunkedWriter(&b)
+		w.Write([]byte("foo"))
+		w.Write([]byte("bar"))
+		w.Close()
+
+		r := newChunkedReader(&b)
+		buf := make([]byte, 10)
+		n, err := r.Read(buf)
+		if n != 6 || err != io.EOF {
+			t.Errorf("Read = %d, %v; want 6, EOF", n, err)
+		}
+		buf = buf[:n]
+		if string(buf) != "foobar" {
+			t.Errorf("Read = %q; want %q", buf, "foobar")
+		}
+	}
+
+	// One big chunk followed by a little chunk, but the small bufio.Reader size
+	// should prevent the second chunk header from being read.
+	{
+		var b bytes.Buffer
+		w := newChunkedWriter(&b)
+		// fillBufChunk is 11 bytes + 3 bytes header + 2 bytes footer = 16 bytes,
+		// the same as the bufio ReaderSize below (the minimum), so even
+		// though we're going to try to Read with a buffer larger enough to also
+		// receive "foo", the second chunk header won't be read yet.
+		const fillBufChunk = "0123456789a"
+		const shortChunk = "foo"
+		w.Write([]byte(fillBufChunk))
+		w.Write([]byte(shortChunk))
+		w.Close()
+
+		r := newChunkedReader(bufio.NewReaderSize(&b, 16))
+		buf := make([]byte, len(fillBufChunk)+len(shortChunk))
+		n, err := r.Read(buf)
+		if n != len(fillBufChunk) || err != nil {
+			t.Errorf("Read = %d, %v; want %d, nil", n, err, len(fillBufChunk))
+		}
+		buf = buf[:n]
+		if string(buf) != fillBufChunk {
+			t.Errorf("Read = %q; want %q", buf, fillBufChunk)
+		}
+
+		n, err = r.Read(buf)
+		if n != len(shortChunk) || err != io.EOF {
+			t.Errorf("Read = %d, %v; want %d, EOF", n, err, len(shortChunk))
+		}
+	}
+
+	// And test that we see an EOF chunk, even though our buffer is already full:
+	{
+		r := newChunkedReader(bufio.NewReader(strings.NewReader("3\r\nfoo\r\n0\r\n")))
+		buf := make([]byte, 3)
+		n, err := r.Read(buf)
+		if n != 3 || err != io.EOF {
+			t.Errorf("Read = %d, %v; want 3, EOF", n, err)
+		}
+		if string(buf) != "foo" {
+			t.Errorf("buf = %q; want foo", buf)
+		}
+	}
+}
+
 func TestChunkReaderAllocs(t *testing.T) {
-	// temporarily set GOMAXPROCS to 1 as we are testing memory allocations
-	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+	if testing.Short() {
+		t.Skip("skipping in short mode")
+	}
 	var buf bytes.Buffer
-	w := NewChunkedWriter(&buf)
+	w := newChunkedWriter(&buf)
 	a, b, c := []byte("aaaaaa"), []byte("bbbbbbbbbbbb"), []byte("cccccccccccccccccccccccc")
 	w.Write(a)
 	w.Write(b)
 	w.Write(c)
 	w.Close()
 
-	r := NewChunkedReader(&buf)
 	readBuf := make([]byte, len(a)+len(b)+len(c)+1)
-
-	var ms runtime.MemStats
-	runtime.ReadMemStats(&ms)
-	m0 := ms.Mallocs
-
-	n, err := io.ReadFull(r, readBuf)
-
-	runtime.ReadMemStats(&ms)
-	mallocs := ms.Mallocs - m0
-	if mallocs > 1 {
-		t.Errorf("%d mallocs; want <= 1", mallocs)
-	}
-
-	if n != len(readBuf)-1 {
-		t.Errorf("read %d bytes; want %d", n, len(readBuf)-1)
-	}
-	if err != io.ErrUnexpectedEOF {
-		t.Errorf("read error = %v; want ErrUnexpectedEOF", err)
+	byter := bytes.NewReader(buf.Bytes())
+	bufr := bufio.NewReader(byter)
+	mallocs := testing.AllocsPerRun(100, func() {
+		byter.Seek(0, 0)
+		bufr.Reset(byter)
+		r := newChunkedReader(bufr)
+		n, err := io.ReadFull(r, readBuf)
+		if n != len(readBuf)-1 {
+			t.Fatalf("read %d bytes; want %d", n, len(readBuf)-1)
+		}
+		if err != io.ErrUnexpectedEOF {
+			t.Fatalf("read error = %v; want ErrUnexpectedEOF", err)
+		}
+	})
+	if mallocs > 1.5 {
+		t.Errorf("mallocs = %v; want 1", mallocs)
 	}
 }
 
diff --git a/src/pkg/net/http/httputil/dump.go b/src/pkg/net/http/httputil/dump.go
index 265499f..2a7a413 100644
--- a/src/pkg/net/http/httputil/dump.go
+++ b/src/pkg/net/http/httputil/dump.go
@@ -7,6 +7,7 @@ package httputil
 import (
 	"bufio"
 	"bytes"
+	"errors"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -29,7 +30,7 @@ func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err error) {
 	if err = b.Close(); err != nil {
 		return nil, nil, err
 	}
-	return ioutil.NopCloser(&buf), ioutil.NopCloser(bytes.NewBuffer(buf.Bytes())), nil
+	return ioutil.NopCloser(&buf), ioutil.NopCloser(bytes.NewReader(buf.Bytes())), nil
 }
 
 // dumpConn is a net.Conn which writes to Writer and reads from Reader
@@ -106,6 +107,7 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
 			return &dumpConn{io.MultiWriter(&buf, pw), dr}, nil
 		},
 	}
+	defer t.CloseIdleConnections()
 
 	_, err := t.RoundTrip(reqSend)
 
@@ -230,14 +232,31 @@ func DumpRequest(req *http.Request, body bool) (dump []byte, err error) {
 	return
 }
 
+// errNoBody is a sentinel error value used by failureToReadBody so we can detect
+// that the lack of body was intentional.
+var errNoBody = errors.New("sentinel error value")
+
+// failureToReadBody is a io.ReadCloser that just returns errNoBody on
+// Read.  It's swapped in when we don't actually want to consume the
+// body, but need a non-nil one, and want to distinguish the error
+// from reading the dummy body.
+type failureToReadBody struct{}
+
+func (failureToReadBody) Read([]byte) (int, error) { return 0, errNoBody }
+func (failureToReadBody) Close() error             { return nil }
+
+var emptyBody = ioutil.NopCloser(strings.NewReader(""))
+
 // DumpResponse is like DumpRequest but dumps a response.
 func DumpResponse(resp *http.Response, body bool) (dump []byte, err error) {
 	var b bytes.Buffer
 	save := resp.Body
 	savecl := resp.ContentLength
-	if !body || resp.Body == nil {
-		resp.Body = nil
-		resp.ContentLength = 0
+
+	if !body {
+		resp.Body = failureToReadBody{}
+	} else if resp.Body == nil {
+		resp.Body = emptyBody
 	} else {
 		save, resp.Body, err = drainBody(resp.Body)
 		if err != nil {
@@ -245,11 +264,13 @@ func DumpResponse(resp *http.Response, body bool) (dump []byte, err error) {
 		}
 	}
 	err = resp.Write(&b)
+	if err == errNoBody {
+		err = nil
+	}
 	resp.Body = save
 	resp.ContentLength = savecl
 	if err != nil {
-		return
+		return nil, err
 	}
-	dump = b.Bytes()
-	return
+	return b.Bytes(), nil
 }
diff --git a/src/pkg/net/http/httputil/dump_test.go b/src/pkg/net/http/httputil/dump_test.go
index 987a820..e1ffb39 100644
--- a/src/pkg/net/http/httputil/dump_test.go
+++ b/src/pkg/net/http/httputil/dump_test.go
@@ -11,6 +11,8 @@ import (
 	"io/ioutil"
 	"net/http"
 	"net/url"
+	"runtime"
+	"strings"
 	"testing"
 )
 
@@ -112,6 +114,7 @@ var dumpTests = []dumpTest{
 }
 
 func TestDumpRequest(t *testing.T) {
+	numg0 := runtime.NumGoroutine()
 	for i, tt := range dumpTests {
 		setBody := func() {
 			if tt.Body == nil {
@@ -119,7 +122,7 @@ func TestDumpRequest(t *testing.T) {
 			}
 			switch b := tt.Body.(type) {
 			case []byte:
-				tt.Req.Body = ioutil.NopCloser(bytes.NewBuffer(b))
+				tt.Req.Body = ioutil.NopCloser(bytes.NewReader(b))
 			case func() io.ReadCloser:
 				tt.Req.Body = b()
 			}
@@ -155,6 +158,9 @@ func TestDumpRequest(t *testing.T) {
 			}
 		}
 	}
+	if dg := runtime.NumGoroutine() - numg0; dg > 4 {
+		t.Errorf("Unexpectedly large number of new goroutines: %d new", dg)
+	}
 }
 
 func chunk(s string) string {
@@ -176,3 +182,82 @@ func mustNewRequest(method, url string, body io.Reader) *http.Request {
 	}
 	return req
 }
+
+var dumpResTests = []struct {
+	res  *http.Response
+	body bool
+	want string
+}{
+	{
+		res: &http.Response{
+			Status:        "200 OK",
+			StatusCode:    200,
+			Proto:         "HTTP/1.1",
+			ProtoMajor:    1,
+			ProtoMinor:    1,
+			ContentLength: 50,
+			Header: http.Header{
+				"Foo": []string{"Bar"},
+			},
+			Body: ioutil.NopCloser(strings.NewReader("foo")), // shouldn't be used
+		},
+		body: false, // to verify we see 50, not empty or 3.
+		want: `HTTP/1.1 200 OK
+Content-Length: 50
+Foo: Bar`,
+	},
+
+	{
+		res: &http.Response{
+			Status:        "200 OK",
+			StatusCode:    200,
+			Proto:         "HTTP/1.1",
+			ProtoMajor:    1,
+			ProtoMinor:    1,
+			ContentLength: 3,
+			Body:          ioutil.NopCloser(strings.NewReader("foo")),
+		},
+		body: true,
+		want: `HTTP/1.1 200 OK
+Content-Length: 3
+
+foo`,
+	},
+
+	{
+		res: &http.Response{
+			Status:           "200 OK",
+			StatusCode:       200,
+			Proto:            "HTTP/1.1",
+			ProtoMajor:       1,
+			ProtoMinor:       1,
+			ContentLength:    -1,
+			Body:             ioutil.NopCloser(strings.NewReader("foo")),
+			TransferEncoding: []string{"chunked"},
+		},
+		body: true,
+		want: `HTTP/1.1 200 OK
+Transfer-Encoding: chunked
+
+3
+foo
+0`,
+	},
+}
+
+func TestDumpResponse(t *testing.T) {
+	for i, tt := range dumpResTests {
+		gotb, err := DumpResponse(tt.res, tt.body)
+		if err != nil {
+			t.Errorf("%d. DumpResponse = %v", i, err)
+			continue
+		}
+		got := string(gotb)
+		got = strings.TrimSpace(got)
+		got = strings.Replace(got, "\r", "", -1)
+
+		if got != tt.want {
+			t.Errorf("%d.\nDumpResponse got:\n%s\n\nWant:\n%s\n", i, got, tt.want)
+		}
+	}
+}
diff --git a/src/pkg/net/http/httputil/httputil.go b/src/pkg/net/http/httputil/httputil.go
new file mode 100644
index 0000000..74fb6c6
--- /dev/null
+++ b/src/pkg/net/http/httputil/httputil.go
@@ -0,0 +1,32 @@
+// 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 httputil provides HTTP utility functions, complementing the
+// more common ones in the net/http package.
+package httputil
+
+import "io"
+
+// NewChunkedReader returns a new chunkedReader that translates the data read from r
+// out of HTTP "chunked" format before returning it.
+// The chunkedReader returns io.EOF when the final 0-length chunk is read.
+//
+// NewChunkedReader is not needed by normal applications. The http package
+// automatically decodes chunking when reading response bodies.
+func NewChunkedReader(r io.Reader) io.Reader {
+	return newChunkedReader(r)
+}
+
+// NewChunkedWriter returns a new chunkedWriter that translates writes into HTTP
+// "chunked" format before writing them to w. Closing the returned chunkedWriter
+// sends the final 0-length chunk that marks the end of the stream.
+//
+// NewChunkedWriter is not needed by normal applications. The http
+// package adds chunking automatically if handlers don't set a
+// Content-Length header. Using NewChunkedWriter inside a handler
+// would result in double chunking or chunking with a Content-Length
+// length, both of which are wrong.
+func NewChunkedWriter(w io.Writer) io.WriteCloser {
+	return newChunkedWriter(w)
+}
diff --git a/src/pkg/net/http/httputil/persist.go b/src/pkg/net/http/httputil/persist.go
index 507938a..987bcc9 100644
--- a/src/pkg/net/http/httputil/persist.go
+++ b/src/pkg/net/http/httputil/persist.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.
 
-// Package httputil provides HTTP utility functions, complementing the
-// more common ones in the net/http package.
 package httputil
 
 import (
@@ -33,8 +31,8 @@ var errClosed = errors.New("i/o operation on closed connection")
 // i.e. requests can be read out of sync (but in the same order) while the
 // respective responses are sent.
 //
-// ServerConn is low-level and should not be needed by most applications.
-// See Server.
+// ServerConn is low-level and old. Applications should instead use Server
+// in the net/http package.
 type ServerConn struct {
 	lk              sync.Mutex // read-write protects the following fields
 	c               net.Conn
@@ -47,8 +45,11 @@ type ServerConn struct {
 	pipe textproto.Pipeline
 }
 
-// NewServerConn returns a new ServerConn reading and writing c.  If r is not
+// NewServerConn returns a new ServerConn reading and writing c. If r is not
 // nil, it is the buffer to use when reading c.
+//
+// ServerConn is low-level and old. Applications should instead use Server
+// in the net/http package.
 func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn {
 	if r == nil {
 		r = bufio.NewReader(c)
@@ -223,8 +224,8 @@ func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error {
 // supports hijacking the connection calling Hijack to
 // regain control of the underlying net.Conn and deal with it as desired.
 //
-// ClientConn is low-level and should not be needed by most applications.
-// See Client.
+// ClientConn is low-level and old. Applications should instead use
+// Client or Transport in the net/http package.
 type ClientConn struct {
 	lk              sync.Mutex // read-write protects the following fields
 	c               net.Conn
@@ -240,6 +241,9 @@ type ClientConn struct {
 
 // NewClientConn returns a new ClientConn reading and writing c.  If r is not
 // nil, it is the buffer to use when reading c.
+//
+// ClientConn is low-level and old. Applications should use Client or
+// Transport in the net/http package.
 func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
 	if r == nil {
 		r = bufio.NewReader(c)
@@ -254,6 +258,9 @@ func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
 
 // NewProxyClientConn works like NewClientConn but writes Requests
 // using Request's WriteProxy method.
+//
+// New code should not use NewProxyClientConn. See Client or
+// Transport in the net/http package instead.
 func NewProxyClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
 	cc := NewClientConn(c, r)
 	cc.writeReq = (*http.Request).WriteProxy
diff --git a/src/pkg/net/http/httputil/reverseproxy.go b/src/pkg/net/http/httputil/reverseproxy.go
index 1990f64..48ada5f 100644
--- a/src/pkg/net/http/httputil/reverseproxy.go
+++ b/src/pkg/net/http/httputil/reverseproxy.go
@@ -144,6 +144,10 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 	}
 	defer res.Body.Close()
 
+	for _, h := range hopHeaders {
+		res.Header.Del(h)
+	}
+
 	copyHeader(rw.Header(), res.Header)
 
 	rw.WriteHeader(res.StatusCode)
diff --git a/src/pkg/net/http/httputil/reverseproxy_test.go b/src/pkg/net/http/httputil/reverseproxy_test.go
index 1c0444e..e9539b4 100644
--- a/src/pkg/net/http/httputil/reverseproxy_test.go
+++ b/src/pkg/net/http/httputil/reverseproxy_test.go
@@ -16,6 +16,12 @@ import (
 	"time"
 )
 
+const fakeHopHeader = "X-Fake-Hop-Header-For-Test"
+
+func init() {
+	hopHeaders = append(hopHeaders, fakeHopHeader)
+}
+
 func TestReverseProxy(t *testing.T) {
 	const backendResponse = "I am the backend"
 	const backendStatus = 404
@@ -36,6 +42,10 @@ func TestReverseProxy(t *testing.T) {
 			t.Errorf("backend got Host header %q, want %q", g, e)
 		}
 		w.Header().Set("X-Foo", "bar")
+		w.Header().Set("Upgrade", "foo")
+		w.Header().Set(fakeHopHeader, "foo")
+		w.Header().Add("X-Multi-Value", "foo")
+		w.Header().Add("X-Multi-Value", "bar")
 		http.SetCookie(w, &http.Cookie{Name: "flavor", Value: "chocolateChip"})
 		w.WriteHeader(backendStatus)
 		w.Write([]byte(backendResponse))
@@ -64,6 +74,12 @@ func TestReverseProxy(t *testing.T) {
 	if g, e := res.Header.Get("X-Foo"), "bar"; g != e {
 		t.Errorf("got X-Foo %q; expected %q", g, e)
 	}
+	if c := res.Header.Get(fakeHopHeader); c != "" {
+		t.Errorf("got %s header value %q", fakeHopHeader, c)
+	}
+	if g, e := len(res.Header["X-Multi-Value"]), 2; g != e {
+		t.Errorf("got %d X-Multi-Value header values; expected %d", g, e)
+	}
 	if g, e := len(res.Header["Set-Cookie"]), 1; g != e {
 		t.Fatalf("got %d SetCookies, want %d", g, e)
 	}
diff --git a/src/pkg/net/http/proxy_test.go b/src/pkg/net/http/proxy_test.go
index 449ccae..b6aed37 100644
--- a/src/pkg/net/http/proxy_test.go
+++ b/src/pkg/net/http/proxy_test.go
@@ -35,12 +35,8 @@ var UseProxyTests = []struct {
 }
 
 func TestUseProxy(t *testing.T) {
-	oldenv := os.Getenv("NO_PROXY")
-	defer os.Setenv("NO_PROXY", oldenv)
-
-	no_proxy := "foobar.com, .barbaz.net"
-	os.Setenv("NO_PROXY", no_proxy)
-
+	ResetProxyEnv()
+	os.Setenv("NO_PROXY", "foobar.com, .barbaz.net")
 	for _, test := range UseProxyTests {
 		if useProxy(test.host+":80") != test.match {
 			t.Errorf("useProxy(%v) = %v, want %v", test.host, !test.match, test.match)
@@ -71,8 +67,15 @@ func TestCacheKeys(t *testing.T) {
 			proxy = u
 		}
 		cm := connectMethod{proxy, tt.scheme, tt.addr}
-		if cm.String() != tt.key {
-			t.Fatalf("{%q, %q, %q} cache key %q; want %q", tt.proxy, tt.scheme, tt.addr, cm.String(), tt.key)
+		if got := cm.key().String(); got != tt.key {
+			t.Fatalf("{%q, %q, %q} cache key = %q; want %q", tt.proxy, tt.scheme, tt.addr, got, tt.key)
 		}
 	}
 }
+
+func ResetProxyEnv() {
+	for _, v := range []string{"HTTP_PROXY", "http_proxy", "NO_PROXY", "no_proxy"} {
+		os.Setenv(v, "")
+	}
+	ResetCachedEnvironment()
+}
diff --git a/src/pkg/net/http/race.go b/src/pkg/net/http/race.go
new file mode 100644
index 0000000..7665039
--- /dev/null
+++ b/src/pkg/net/http/race.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.
+
+// +build race
+
+package http
+
+func init() {
+	raceEnabled = true
+}
diff --git a/src/pkg/net/http/request.go b/src/pkg/net/http/request.go
index 57b5d09..a670920 100644
--- a/src/pkg/net/http/request.go
+++ b/src/pkg/net/http/request.go
@@ -20,6 +20,7 @@ import (
 	"net/url"
 	"strconv"
 	"strings"
+	"sync"
 )
 
 const (
@@ -68,18 +69,31 @@ var reqWriteExcludeHeader = map[string]bool{
 
 // A Request represents an HTTP request received by a server
 // or to be sent by a client.
+//
+// The field semantics differ slightly between client and server
+// usage. In addition to the notes on the fields below, see the
+// documentation for Request.Write and RoundTripper.
 type Request struct {
-	Method string // GET, POST, PUT, etc.
+	// Method specifies the HTTP method (GET, POST, PUT, etc.).
+	// For client requests an empty string means GET.
+	Method string
 
-	// URL is created from the URI supplied on the Request-Line
-	// as stored in RequestURI.
+	// URL specifies either the URI being requested (for server
+	// requests) or the URL to access (for client requests).
+	//
+	// For server requests the URL is parsed from the URI
+	// supplied on the Request-Line as stored in RequestURI.  For
+	// most requests, fields other than Path and RawQuery will be
+	// empty. (See RFC 2616, Section 5.1.2)
 	//
-	// For most requests, fields other than Path and RawQuery
-	// will be empty. (See RFC 2616, Section 5.1.2)
+	// For client requests, the URL's Host specifies the server to
+	// connect to, while the Request's Host field optionally
+	// specifies the Host header value to send in the HTTP
+	// request.
 	URL *url.URL
 
 	// The protocol version for incoming requests.
-	// Outgoing requests always use HTTP/1.1.
+	// Client requests always use HTTP/1.1.
 	Proto      string // "HTTP/1.0"
 	ProtoMajor int    // 1
 	ProtoMinor int    // 0
@@ -103,15 +117,20 @@ type Request struct {
 	// The request parser implements this by canonicalizing the
 	// name, making the first character and any characters
 	// following a hyphen uppercase and the rest lowercase.
+	//
+	// For client requests certain headers are automatically
+	// added and may override values in Header.
+	//
+	// See the documentation for the Request.Write method.
 	Header Header
 
 	// Body is the request's body.
 	//
-	// For client requests, a nil body means the request has no
+	// For client requests a nil body means the request has no
 	// body, such as a GET request. The HTTP Client's Transport
 	// is responsible for calling the Close method.
 	//
-	// For server requests, the Request Body is always non-nil
+	// For server requests the Request Body is always non-nil
 	// but will return EOF immediately when no body is present.
 	// The Server will close the request body. The ServeHTTP
 	// Handler does not need to.
@@ -121,7 +140,7 @@ type Request struct {
 	// The value -1 indicates that the length is unknown.
 	// Values >= 0 indicate that the given number of bytes may
 	// be read from Body.
-	// For outgoing requests, a value of 0 means unknown if Body is not nil.
+	// For client requests, a value of 0 means unknown if Body is not nil.
 	ContentLength int64
 
 	// TransferEncoding lists the transfer encodings from outermost to
@@ -132,13 +151,18 @@ type Request struct {
 	TransferEncoding []string
 
 	// Close indicates whether to close the connection after
-	// replying to this request.
+	// replying to this request (for servers) or after sending
+	// the request (for clients).
 	Close bool
 
-	// The host on which the URL is sought.
-	// Per RFC 2616, this is either the value of the Host: header
-	// or the host name given in the URL itself.
+	// For server requests Host specifies the host on which the
+	// URL is sought. Per RFC 2616, this is either the value of
+	// the "Host" header or the host name given in the URL itself.
 	// It may be of the form "host:port".
+	//
+	// For client requests Host optionally overrides the Host
+	// header to send. If empty, the Request.Write method uses
+	// the value of URL.Host.
 	Host string
 
 	// Form contains the parsed form data, including both the URL
@@ -158,12 +182,24 @@ type Request struct {
 	// The HTTP client ignores MultipartForm and uses Body instead.
 	MultipartForm *multipart.Form
 
-	// Trailer maps trailer keys to values.  Like for Header, if the
-	// response has multiple trailer lines with the same key, they will be
-	// concatenated, delimited by commas.
-	// For server requests, Trailer is only populated after Body has been
-	// closed or fully consumed.
-	// Trailer support is only partially complete.
+	// Trailer specifies additional headers that are sent after the request
+	// body.
+	//
+	// For server requests the Trailer map initially contains only the
+	// trailer keys, with nil values. (The client declares which trailers it
+	// will later send.)  While the handler is reading from Body, it must
+	// not reference Trailer. After reading from Body returns EOF, Trailer
+	// can be read again and will contain non-nil values, if they were sent
+	// by the client.
+	//
+	// For client requests Trailer must be initialized to a map containing
+	// the trailer keys to later send. The values may be nil or their final
+	// values. The ContentLength must be 0 or -1, to send a chunked request.
+	// After the HTTP request is sent the map values can be updated while
+	// the request body is read. Once the body returns EOF, the caller must
+	// not mutate Trailer.
+	//
+	// Few HTTP clients, servers, or proxies support HTTP trailers.
 	Trailer Header
 
 	// RemoteAddr allows HTTP servers and other software to record
@@ -381,7 +417,6 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err
 		return err
 	}
 
-	// TODO: split long values?  (If so, should share code with Conn.Write)
 	err = req.Header.WriteSubset(w, reqWriteExcludeHeader)
 	if err != nil {
 		return err
@@ -494,25 +529,20 @@ func parseRequestLine(line string) (method, requestURI, proto string, ok bool) {
 	return line[:s1], line[s1+1 : s2], line[s2+1:], true
 }
 
-// TODO(bradfitz): use a sync.Cache when available
-var textprotoReaderCache = make(chan *textproto.Reader, 4)
+var textprotoReaderPool sync.Pool
 
 func newTextprotoReader(br *bufio.Reader) *textproto.Reader {
-	select {
-	case r := <-textprotoReaderCache:
-		r.R = br
-		return r
-	default:
-		return textproto.NewReader(br)
+	if v := textprotoReaderPool.Get(); v != nil {
+		tr := v.(*textproto.Reader)
+		tr.R = br
+		return tr
 	}
+	return textproto.NewReader(br)
 }
 
 func putTextprotoReader(r *textproto.Reader) {
 	r.R = nil
-	select {
-	case textprotoReaderCache <- r:
-	default:
-	}
+	textprotoReaderPool.Put(r)
 }
 
 // ReadRequest reads and parses a request from b.
@@ -588,32 +618,6 @@ func ReadRequest(b *bufio.Reader) (req *Request, err error) {
 
 	fixPragmaCacheControl(req.Header)
 
-	// TODO: Parse specific header values:
-	//	Accept
-	//	Accept-Encoding
-	//	Accept-Language
-	//	Authorization
-	//	Cache-Control
-	//	Connection
-	//	Date
-	//	Expect
-	//	From
-	//	If-Match
-	//	If-Modified-Since
-	//	If-None-Match
-	//	If-Range
-	//	If-Unmodified-Since
-	//	Max-Forwards
-	//	Proxy-Authorization
-	//	Referer [sic]
-	//	TE (transfer-codings)
-	//	Trailer
-	//	Transfer-Encoding
-	//	Upgrade
-	//	User-Agent
-	//	Via
-	//	Warning
-
 	err = readTransfer(req, b)
 	if err != nil {
 		return nil, err
@@ -677,6 +681,11 @@ func parsePostForm(r *Request) (vs url.Values, err error) {
 		return
 	}
 	ct := r.Header.Get("Content-Type")
+	// RFC 2616, section 7.2.1 - empty type
+	//   SHOULD be treated as application/octet-stream
+	if ct == "" {
+		ct = "application/octet-stream"
+	}
 	ct, _, err = mime.ParseMediaType(ct)
 	switch {
 	case ct == "application/x-www-form-urlencoded":
@@ -707,7 +716,7 @@ func parsePostForm(r *Request) (vs url.Values, err error) {
 		// orders to call too many functions here.
 		// Clean this up and write more tests.
 		// request_test.go contains the start of this,
-		// in TestRequestMultipartCallOrder.
+		// in TestParseMultipartFormOrder and others.
 	}
 	return
 }
@@ -727,7 +736,7 @@ func parsePostForm(r *Request) (vs url.Values, err error) {
 func (r *Request) ParseForm() error {
 	var err error
 	if r.PostForm == nil {
-		if r.Method == "POST" || r.Method == "PUT" {
+		if r.Method == "POST" || r.Method == "PUT" || r.Method == "PATCH" {
 			r.PostForm, err = parsePostForm(r)
 		}
 		if r.PostForm == nil {
@@ -780,9 +789,7 @@ func (r *Request) ParseMultipartForm(maxMemory int64) error {
 	}
 
 	mr, err := r.multipartReader()
-	if err == ErrNotMultipart {
-		return nil
-	} else if err != nil {
+	if err != nil {
 		return err
 	}
 
@@ -860,3 +867,9 @@ func (r *Request) wantsHttp10KeepAlive() bool {
 func (r *Request) wantsClose() bool {
 	return hasToken(r.Header.get("Connection"), "close")
 }
+
+func (r *Request) closeBody() {
+	if r.Body != nil {
+		r.Body.Close()
+	}
+}
diff --git a/src/pkg/net/http/request_test.go b/src/pkg/net/http/request_test.go
index 89303c3..b9fa3c2 100644
--- a/src/pkg/net/http/request_test.go
+++ b/src/pkg/net/http/request_test.go
@@ -60,6 +60,37 @@ func TestPostQuery(t *testing.T) {
 	}
 }
 
+func TestPatchQuery(t *testing.T) {
+	req, _ := NewRequest("PATCH", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&empty=not",
+		strings.NewReader("z=post&both=y&prio=2&empty="))
+	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
+
+	if q := req.FormValue("q"); q != "foo" {
+		t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
+	}
+	if z := req.FormValue("z"); z != "post" {
+		t.Errorf(`req.FormValue("z") = %q, want "post"`, z)
+	}
+	if bq, found := req.PostForm["q"]; found {
+		t.Errorf(`req.PostForm["q"] = %q, want no entry in map`, bq)
+	}
+	if bz := req.PostFormValue("z"); bz != "post" {
+		t.Errorf(`req.PostFormValue("z") = %q, want "post"`, bz)
+	}
+	if qs := req.Form["q"]; !reflect.DeepEqual(qs, []string{"foo", "bar"}) {
+		t.Errorf(`req.Form["q"] = %q, want ["foo", "bar"]`, qs)
+	}
+	if both := req.Form["both"]; !reflect.DeepEqual(both, []string{"y", "x"}) {
+		t.Errorf(`req.Form["both"] = %q, want ["y", "x"]`, both)
+	}
+	if prio := req.FormValue("prio"); prio != "2" {
+		t.Errorf(`req.FormValue("prio") = %q, want "2" (from body)`, prio)
+	}
+	if empty := req.FormValue("empty"); empty != "" {
+		t.Errorf(`req.FormValue("empty") = %q, want "" (from body)`, empty)
+	}
+}
+
 type stringMap map[string][]string
 type parseContentTypeTest struct {
 	shouldError bool
@@ -68,8 +99,9 @@ type parseContentTypeTest struct {
 
 var parseContentTypeTests = []parseContentTypeTest{
 	{false, stringMap{"Content-Type": {"text/plain"}}},
-	// Non-existent keys are not placed. The value nil is illegal.
-	{true, stringMap{}},
+	// Empty content type is legal - shoult be treated as
+	// application/octet-stream (RFC 2616, section 7.2.1)
+	{false, stringMap{}},
 	{true, stringMap{"Content-Type": {"text/plain; boundary="}}},
 	{false, stringMap{"Content-Type": {"application/unknown"}}},
 }
@@ -79,7 +111,7 @@ func TestParseFormUnknownContentType(t *testing.T) {
 		req := &Request{
 			Method: "POST",
 			Header: Header(test.contentType),
-			Body:   ioutil.NopCloser(bytes.NewBufferString("body")),
+			Body:   ioutil.NopCloser(strings.NewReader("body")),
 		}
 		err := req.ParseForm()
 		switch {
@@ -122,7 +154,25 @@ func TestMultipartReader(t *testing.T) {
 	req.Header = Header{"Content-Type": {"text/plain"}}
 	multipart, err = req.MultipartReader()
 	if multipart != nil {
-		t.Errorf("unexpected multipart for text/plain")
+		t.Error("unexpected multipart for text/plain")
+	}
+}
+
+func TestParseMultipartForm(t *testing.T) {
+	req := &Request{
+		Method: "POST",
+		Header: Header{"Content-Type": {`multipart/form-data; boundary="foo123"`}},
+		Body:   ioutil.NopCloser(new(bytes.Buffer)),
+	}
+	err := req.ParseMultipartForm(25)
+	if err == nil {
+		t.Error("expected multipart EOF, got nil")
+	}
+
+	req.Header = Header{"Content-Type": {"text/plain"}}
+	err = req.ParseMultipartForm(25)
+	if err != ErrNotMultipart {
+		t.Error("expected ErrNotMultipart for text/plain")
 	}
 }
 
@@ -188,25 +238,72 @@ func TestMultipartRequestAuto(t *testing.T) {
 	validateTestMultipartContents(t, req, true)
 }
 
-func TestEmptyMultipartRequest(t *testing.T) {
-	// Test that FormValue and FormFile automatically invoke
-	// ParseMultipartForm and return the right values.
-	req, err := NewRequest("GET", "/", nil)
-	if err != nil {
-		t.Errorf("NewRequest err = %q", err)
-	}
+func TestMissingFileMultipartRequest(t *testing.T) {
+	// Test that FormFile returns an error if
+	// the named file is missing.
+	req := newTestMultipartRequest(t)
 	testMissingFile(t, req)
 }
 
-func TestRequestMultipartCallOrder(t *testing.T) {
+// Test that FormValue invokes ParseMultipartForm.
+func TestFormValueCallsParseMultipartForm(t *testing.T) {
+	req, _ := NewRequest("POST", "http://www.google.com/", strings.NewReader("z=post"))
+	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
+	if req.Form != nil {
+		t.Fatal("Unexpected request Form, want nil")
+	}
+	req.FormValue("z")
+	if req.Form == nil {
+		t.Fatal("ParseMultipartForm not called by FormValue")
+	}
+}
+
+// Test that FormFile invokes ParseMultipartForm.
+func TestFormFileCallsParseMultipartForm(t *testing.T) {
 	req := newTestMultipartRequest(t)
-	_, err := req.MultipartReader()
-	if err != nil {
+	if req.Form != nil {
+		t.Fatal("Unexpected request Form, want nil")
+	}
+	req.FormFile("")
+	if req.Form == nil {
+		t.Fatal("ParseMultipartForm not called by FormFile")
+	}
+}
+
+// Test that ParseMultipartForm errors if called
+// after MultipartReader on the same request.
+func TestParseMultipartFormOrder(t *testing.T) {
+	req := newTestMultipartRequest(t)
+	if _, err := req.MultipartReader(); err != nil {
 		t.Fatalf("MultipartReader: %v", err)
 	}
-	err = req.ParseMultipartForm(1024)
-	if err == nil {
-		t.Errorf("expected an error from ParseMultipartForm after call to MultipartReader")
+	if err := req.ParseMultipartForm(1024); err == nil {
+		t.Fatal("expected an error from ParseMultipartForm after call to MultipartReader")
+	}
+}
+
+// Test that MultipartReader errors if called
+// after ParseMultipartForm on the same request.
+func TestMultipartReaderOrder(t *testing.T) {
+	req := newTestMultipartRequest(t)
+	if err := req.ParseMultipartForm(25); err != nil {
+		t.Fatalf("ParseMultipartForm: %v", err)
+	}
+	defer req.MultipartForm.RemoveAll()
+	if _, err := req.MultipartReader(); err == nil {
+		t.Fatal("expected an error from MultipartReader after call to ParseMultipartForm")
+	}
+}
+
+// Test that FormFile errors if called after
+// MultipartReader on the same request.
+func TestFormFileOrder(t *testing.T) {
+	req := newTestMultipartRequest(t)
+	if _, err := req.MultipartReader(); err != nil {
+		t.Fatalf("MultipartReader: %v", err)
+	}
+	if _, _, err := req.FormFile(""); err == nil {
+		t.Fatal("expected an error from FormFile after call to MultipartReader")
 	}
 }
 
@@ -343,7 +440,7 @@ func testMissingFile(t *testing.T, req *Request) {
 }
 
 func newTestMultipartRequest(t *testing.T) *Request {
-	b := bytes.NewBufferString(strings.Replace(message, "\n", "\r\n", -1))
+	b := strings.NewReader(strings.Replace(message, "\n", "\r\n", -1))
 	req, err := NewRequest("POST", "/", b)
 	if err != nil {
 		t.Fatal("NewRequest:", err)
diff --git a/src/pkg/net/http/requestwrite_test.go b/src/pkg/net/http/requestwrite_test.go
index b27b1f7..dc0e204 100644
--- a/src/pkg/net/http/requestwrite_test.go
+++ b/src/pkg/net/http/requestwrite_test.go
@@ -310,6 +310,46 @@ var reqWriteTests = []reqWriteTest{
 		WantError: errors.New("http: Request.ContentLength=5 with nil Body"),
 	},
 
+	// Request with a 0 ContentLength and a body with 1 byte content and an error.
+	{
+		Req: Request{
+			Method:        "POST",
+			URL:           mustParseURL("/"),
+			Host:          "example.com",
+			ProtoMajor:    1,
+			ProtoMinor:    1,
+			ContentLength: 0, // as if unset by user
+		},
+
+		Body: func() io.ReadCloser {
+			err := errors.New("Custom reader error")
+			errReader := &errorReader{err}
+			return ioutil.NopCloser(io.MultiReader(strings.NewReader("x"), errReader))
+		},
+
+		WantError: errors.New("Custom reader error"),
+	},
+
+	// Request with a 0 ContentLength and a body without content and an error.
+	{
+		Req: Request{
+			Method:        "POST",
+			URL:           mustParseURL("/"),
+			Host:          "example.com",
+			ProtoMajor:    1,
+			ProtoMinor:    1,
+			ContentLength: 0, // as if unset by user
+		},
+
+		Body: func() io.ReadCloser {
+			err := errors.New("Custom reader error")
+			errReader := &errorReader{err}
+			return ioutil.NopCloser(errReader)
+		},
+
+		WantError: errors.New("Custom reader error"),
+	},
+
 	// Verify that DumpRequest preserves the HTTP version number, doesn't add a Host,
 	// and doesn't add a User-Agent.
 	{
@@ -427,7 +467,7 @@ func TestRequestWrite(t *testing.T) {
 			}
 			switch b := tt.Body.(type) {
 			case []byte:
-				tt.Req.Body = ioutil.NopCloser(bytes.NewBuffer(b))
+				tt.Req.Body = ioutil.NopCloser(bytes.NewReader(b))
 			case func() io.ReadCloser:
 				tt.Req.Body = b()
 			}
diff --git a/src/pkg/net/http/response.go b/src/pkg/net/http/response.go
index 35d0ba3..5d2c390 100644
--- a/src/pkg/net/http/response.go
+++ b/src/pkg/net/http/response.go
@@ -8,6 +8,8 @@ package http
 
 import (
 	"bufio"
+	"bytes"
+	"crypto/tls"
 	"errors"
 	"io"
 	"net/textproto"
@@ -45,7 +47,8 @@ type Response struct {
 	//
 	// The http Client and Transport guarantee that Body is always
 	// non-nil, even on responses without a body or responses with
-	// a zero-lengthed body.
+	// a zero-length body. It is the caller's responsibility to
+	// close Body.
 	//
 	// The Body is automatically dechunked if the server replied
 	// with a "chunked" Transfer-Encoding.
@@ -74,6 +77,12 @@ type Response struct {
 	// Request's Body is nil (having already been consumed).
 	// This is only populated for Client requests.
 	Request *Request
+
+	// TLS contains information about the TLS connection on which the
+	// response was received. It is nil for unencrypted responses.
+	// The pointer is shared between responses and should not be
+	// modified.
+	TLS *tls.ConnectionState
 }
 
 // Cookies parses and returns the cookies set in the Set-Cookie headers.
@@ -141,6 +150,9 @@ func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) {
 	// Parse the response headers.
 	mimeHeader, err := tp.ReadMIMEHeader()
 	if err != nil {
+		if err == io.EOF {
+			err = io.ErrUnexpectedEOF
+		}
 		return nil, err
 	}
 	resp.Header = Header(mimeHeader)
@@ -187,8 +199,8 @@ func (r *Response) ProtoAtLeast(major, minor int) bool {
 //  ContentLength
 //  Header, values for non-canonical keys will have unpredictable behavior
 //
+// Body is closed after it is sent.
 func (r *Response) Write(w io.Writer) error {
-
 	// Status line
 	text := r.Status
 	if text == "" {
@@ -201,10 +213,45 @@ func (r *Response) Write(w io.Writer) error {
 	protoMajor, protoMinor := strconv.Itoa(r.ProtoMajor), strconv.Itoa(r.ProtoMinor)
 	statusCode := strconv.Itoa(r.StatusCode) + " "
 	text = strings.TrimPrefix(text, statusCode)
-	io.WriteString(w, "HTTP/"+protoMajor+"."+protoMinor+" "+statusCode+text+"\r\n")
+	if _, err := io.WriteString(w, "HTTP/"+protoMajor+"."+protoMinor+" "+statusCode+text+"\r\n"); err != nil {
+		return err
+	}
+
+	// Clone it, so we can modify r1 as needed.
+	r1 := new(Response)
+	*r1 = *r
+	if r1.ContentLength == 0 && r1.Body != nil {
+		// Is it actually 0 length? Or just unknown?
+		var buf [1]byte
+		n, err := r1.Body.Read(buf[:])
+		if err != nil && err != io.EOF {
+			return err
+		}
+		if n == 0 {
+			// Reset it to a known zero reader, in case underlying one
+			// is unhappy being read repeatedly.
+			r1.Body = eofReader
+		} else {
+			r1.ContentLength = -1
+			r1.Body = struct {
+				io.Reader
+				io.Closer
+			}{
+				io.MultiReader(bytes.NewReader(buf[:1]), r.Body),
+				r.Body,
+			}
+		}
+	}
+	// If we're sending a non-chunked HTTP/1.1 response without a
+	// content-length, the only way to do that is the old HTTP/1.0
+	// way, by noting the EOF with a connection close, so we need
+	// to set Close.
+	if r1.ContentLength == -1 && !r1.Close && r1.ProtoAtLeast(1, 1) && !chunked(r1.TransferEncoding) {
+		r1.Close = true
+	}
 
 	// Process Body,ContentLength,Close,Trailer
-	tw, err := newTransferWriter(r)
+	tw, err := newTransferWriter(r1)
 	if err != nil {
 		return err
 	}
@@ -219,8 +266,19 @@ func (r *Response) Write(w io.Writer) error {
 		return err
 	}
 
+	// contentLengthAlreadySent may have been already sent for
+	// POST/PUT requests, even if zero length. See Issue 8180.
+	contentLengthAlreadySent := tw.shouldSendContentLength()
+	if r1.ContentLength == 0 && !chunked(r1.TransferEncoding) && !contentLengthAlreadySent {
+		if _, err := io.WriteString(w, "Content-Length: 0\r\n"); err != nil {
+			return err
+		}
+	}
+
 	// End-of-header
-	io.WriteString(w, "\r\n")
+	if _, err := io.WriteString(w, "\r\n"); err != nil {
+		return err
+	}
 
 	// Write body and trailer
 	err = tw.WriteBody(w)
diff --git a/src/pkg/net/http/response_test.go b/src/pkg/net/http/response_test.go
index 5044306..4b8946f 100644
--- a/src/pkg/net/http/response_test.go
+++ b/src/pkg/net/http/response_test.go
@@ -14,6 +14,7 @@ import (
 	"io/ioutil"
 	"net/url"
 	"reflect"
+	"regexp"
 	"strings"
 	"testing"
 )
@@ -28,6 +29,10 @@ func dummyReq(method string) *Request {
 	return &Request{Method: method}
 }
 
+func dummyReq11(method string) *Request {
+	return &Request{Method: method, Proto: "HTTP/1.1", ProtoMajor: 1, ProtoMinor: 1}
+}
+
 var respTests = []respTest{
 	// Unchunked response without Content-Length.
 	{
@@ -406,8 +411,7 @@ func TestWriteResponse(t *testing.T) {
 			t.Errorf("#%d: %v", i, err)
 			continue
 		}
-		bout := bytes.NewBuffer(nil)
-		err = resp.Write(bout)
+		err = resp.Write(ioutil.Discard)
 		if err != nil {
 			t.Errorf("#%d: %v", i, err)
 			continue
@@ -506,6 +510,9 @@ func TestReadResponseCloseInMiddle(t *testing.T) {
 		rest, err := ioutil.ReadAll(bufr)
 		checkErr(err, "ReadAll on remainder")
 		if e, g := "Next Request Here", string(rest); e != g {
+			g = regexp.MustCompile(`(xx+)`).ReplaceAllStringFunc(g, func(match string) string {
+				return fmt.Sprintf("x(repeated x%d)", len(match))
+			})
 			fatalf("remainder = %q, expected %q", g, e)
 		}
 	}
@@ -615,6 +622,15 @@ func TestResponseContentLengthShortBody(t *testing.T) {
 	}
 }
 
+func TestReadResponseUnexpectedEOF(t *testing.T) {
+	br := bufio.NewReader(strings.NewReader("HTTP/1.1 301 Moved Permanently\r\n" +
+		"Location: http://example.com"))
+	_, err := ReadResponse(br, nil)
+	if err != io.ErrUnexpectedEOF {
+		t.Errorf("ReadResponse = %v; want io.ErrUnexpectedEOF", err)
+	}
+}
+
 func TestNeedsSniff(t *testing.T) {
 	// needsSniff returns true with an empty response.
 	r := &response{}
diff --git a/src/pkg/net/http/responsewrite_test.go b/src/pkg/net/http/responsewrite_test.go
index 5c10e21..585b13b 100644
--- a/src/pkg/net/http/responsewrite_test.go
+++ b/src/pkg/net/http/responsewrite_test.go
@@ -7,6 +7,7 @@ package http
 import (
 	"bytes"
 	"io/ioutil"
+	"strings"
 	"testing"
 )
 
@@ -25,7 +26,7 @@ func TestResponseWrite(t *testing.T) {
 				ProtoMinor:    0,
 				Request:       dummyReq("GET"),
 				Header:        Header{},
-				Body:          ioutil.NopCloser(bytes.NewBufferString("abcdef")),
+				Body:          ioutil.NopCloser(strings.NewReader("abcdef")),
 				ContentLength: 6,
 			},
 
@@ -41,13 +42,113 @@ func TestResponseWrite(t *testing.T) {
 				ProtoMinor:    0,
 				Request:       dummyReq("GET"),
 				Header:        Header{},
-				Body:          ioutil.NopCloser(bytes.NewBufferString("abcdef")),
+				Body:          ioutil.NopCloser(strings.NewReader("abcdef")),
 				ContentLength: -1,
 			},
 			"HTTP/1.0 200 OK\r\n" +
 				"\r\n" +
 				"abcdef",
 		},
+		// HTTP/1.1 response with unknown length and Connection: close
+		{
+			Response{
+				StatusCode:    200,
+				ProtoMajor:    1,
+				ProtoMinor:    1,
+				Request:       dummyReq("GET"),
+				Header:        Header{},
+				Body:          ioutil.NopCloser(strings.NewReader("abcdef")),
+				ContentLength: -1,
+				Close:         true,
+			},
+			"HTTP/1.1 200 OK\r\n" +
+				"Connection: close\r\n" +
+				"\r\n" +
+				"abcdef",
+		},
+		// HTTP/1.1 response with unknown length and not setting connection: close
+		{
+			Response{
+				StatusCode:    200,
+				ProtoMajor:    1,
+				ProtoMinor:    1,
+				Request:       dummyReq11("GET"),
+				Header:        Header{},
+				Body:          ioutil.NopCloser(strings.NewReader("abcdef")),
+				ContentLength: -1,
+				Close:         false,
+			},
+			"HTTP/1.1 200 OK\r\n" +
+				"Connection: close\r\n" +
+				"\r\n" +
+				"abcdef",
+		},
+		// HTTP/1.1 response with unknown length and not setting connection: close, but
+		// setting chunked.
+		{
+			Response{
+				StatusCode:       200,
+				ProtoMajor:       1,
+				ProtoMinor:       1,
+				Request:          dummyReq11("GET"),
+				Header:           Header{},
+				Body:             ioutil.NopCloser(strings.NewReader("abcdef")),
+				ContentLength:    -1,
+				TransferEncoding: []string{"chunked"},
+				Close:            false,
+			},
+			"HTTP/1.1 200 OK\r\n" +
+				"Transfer-Encoding: chunked\r\n\r\n" +
+				"6\r\nabcdef\r\n0\r\n\r\n",
+		},
+		// HTTP/1.1 response 0 content-length, and nil body
+		{
+			Response{
+				StatusCode:    200,
+				ProtoMajor:    1,
+				ProtoMinor:    1,
+				Request:       dummyReq11("GET"),
+				Header:        Header{},
+				Body:          nil,
+				ContentLength: 0,
+				Close:         false,
+			},
+			"HTTP/1.1 200 OK\r\n" +
+				"Content-Length: 0\r\n" +
+				"\r\n",
+		},
+		// HTTP/1.1 response 0 content-length, and non-nil empty body
+		{
+			Response{
+				StatusCode:    200,
+				ProtoMajor:    1,
+				ProtoMinor:    1,
+				Request:       dummyReq11("GET"),
+				Header:        Header{},
+				Body:          ioutil.NopCloser(strings.NewReader("")),
+				ContentLength: 0,
+				Close:         false,
+			},
+			"HTTP/1.1 200 OK\r\n" +
+				"Content-Length: 0\r\n" +
+				"\r\n",
+		},
+		// HTTP/1.1 response 0 content-length, and non-nil non-empty body
+		{
+			Response{
+				StatusCode:    200,
+				ProtoMajor:    1,
+				ProtoMinor:    1,
+				Request:       dummyReq11("GET"),
+				Header:        Header{},
+				Body:          ioutil.NopCloser(strings.NewReader("foo")),
+				ContentLength: 0,
+				Close:         false,
+			},
+			"HTTP/1.1 200 OK\r\n" +
+				"Connection: close\r\n" +
+				"\r\nfoo",
+		},
 		// HTTP/1.1, chunked coding; empty trailer; close
 		{
 			Response{
@@ -56,7 +157,7 @@ func TestResponseWrite(t *testing.T) {
 				ProtoMinor:       1,
 				Request:          dummyReq("GET"),
 				Header:           Header{},
-				Body:             ioutil.NopCloser(bytes.NewBufferString("abcdef")),
+				Body:             ioutil.NopCloser(strings.NewReader("abcdef")),
 				ContentLength:    6,
 				TransferEncoding: []string{"chunked"},
 				Close:            true,
@@ -90,6 +191,22 @@ func TestResponseWrite(t *testing.T) {
 				"Foo: Bar Baz\r\n" +
 				"\r\n",
 		},
+
+		// Want a single Content-Length header. Fixing issue 8180 where
+		// there were two.
+		{
+			Response{
+				StatusCode:       StatusOK,
+				ProtoMajor:       1,
+				ProtoMinor:       1,
+				Request:          &Request{Method: "POST"},
+				Header:           Header{},
+				ContentLength:    0,
+				TransferEncoding: nil,
+				Body:             nil,
+			},
+			"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
+		},
 	}
 
 	for i := range respWriteTests {
diff --git a/src/pkg/net/http/serve_test.go b/src/pkg/net/http/serve_test.go
index 955112b..9e4d226 100644
--- a/src/pkg/net/http/serve_test.go
+++ b/src/pkg/net/http/serve_test.go
@@ -419,7 +419,7 @@ func TestServeMuxHandlerRedirects(t *testing.T) {
 func TestMuxRedirectLeadingSlashes(t *testing.T) {
 	paths := []string{"//foo.txt", "///foo.txt", "/../../foo.txt"}
 	for _, path := range paths {
-		req, err := ReadRequest(bufio.NewReader(bytes.NewBufferString("GET " + path + " HTTP/1.1\r\nHost: test\r\n\r\n")))
+		req, err := ReadRequest(bufio.NewReader(strings.NewReader("GET " + path + " HTTP/1.1\r\nHost: test\r\n\r\n")))
 		if err != nil {
 			t.Errorf("%s", err)
 		}
@@ -441,6 +441,9 @@ func TestMuxRedirectLeadingSlashes(t *testing.T) {
 }
 
 func TestServerTimeouts(t *testing.T) {
+	if runtime.GOOS == "plan9" {
+		t.Skip("skipping test; see http://golang.org/issue/7237")
+	}
 	defer afterTest(t)
 	reqNum := 0
 	ts := httptest.NewUnstartedServer(HandlerFunc(func(res ResponseWriter, req *Request) {
@@ -517,6 +520,9 @@ func TestServerTimeouts(t *testing.T) {
 // shouldn't cause a handler to block forever on reads (next HTTP
 // request) that will never happen.
 func TestOnlyWriteTimeout(t *testing.T) {
+	if runtime.GOOS == "plan9" {
+		t.Skip("skipping test; see http://golang.org/issue/7237")
+	}
 	defer afterTest(t)
 	var conn net.Conn
 	var afterTimeoutErrc = make(chan error, 1)
@@ -840,9 +846,14 @@ func TestHeadResponses(t *testing.T) {
 }
 
 func TestTLSHandshakeTimeout(t *testing.T) {
+	if runtime.GOOS == "plan9" {
+		t.Skip("skipping test; see http://golang.org/issue/7237")
+	}
 	defer afterTest(t)
 	ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
+	errc := make(chanWriter, 10) // but only expecting 1
 	ts.Config.ReadTimeout = 250 * time.Millisecond
+	ts.Config.ErrorLog = log.New(errc, "", 0)
 	ts.StartTLS()
 	defer ts.Close()
 	conn, err := net.Dial("tcp", ts.Listener.Addr().String())
@@ -857,6 +868,14 @@ func TestTLSHandshakeTimeout(t *testing.T) {
 			t.Errorf("Read = %d, %v; want an error and no bytes", n, err)
 		}
 	})
+	select {
+	case v := <-errc:
+		if !strings.Contains(v, "timeout") && !strings.Contains(v, "TLS handshake") {
+			t.Errorf("expected a TLS handshake timeout error; got %q", v)
+		}
+	case <-time.After(5 * time.Second):
+		t.Errorf("timeout waiting for logged error")
+	}
 }
 
 func TestTLSServer(t *testing.T) {
@@ -869,6 +888,7 @@ func TestTLSServer(t *testing.T) {
 			}
 		}
 	}))
+	ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0)
 	defer ts.Close()
 
 	// Connect an idle TCP connection to this server before we run
@@ -913,31 +933,50 @@ func TestTLSServer(t *testing.T) {
 }
 
 type serverExpectTest struct {
-	contentLength    int    // of request body
+	contentLength    int // of request body
+	chunked          bool
 	expectation      string // e.g. "100-continue"
 	readBody         bool   // whether handler should read the body (if false, sends StatusUnauthorized)
 	expectedResponse string // expected substring in first line of http response
 }
 
+func expectTest(contentLength int, expectation string, readBody bool, expectedResponse string) serverExpectTest {
+	return serverExpectTest{
+		contentLength:    contentLength,
+		expectation:      expectation,
+		readBody:         readBody,
+		expectedResponse: expectedResponse,
+	}
+}
+
 var serverExpectTests = []serverExpectTest{
 	// Normal 100-continues, case-insensitive.
-	{100, "100-continue", true, "100 Continue"},
-	{100, "100-cOntInUE", true, "100 Continue"},
+	expectTest(100, "100-continue", true, "100 Continue"),
+	expectTest(100, "100-cOntInUE", true, "100 Continue"),
 
 	// No 100-continue.
-	{100, "", true, "200 OK"},
+	expectTest(100, "", true, "200 OK"),
 
 	// 100-continue but requesting client to deny us,
 	// so it never reads the body.
-	{100, "100-continue", false, "401 Unauthorized"},
+	expectTest(100, "100-continue", false, "401 Unauthorized"),
 	// Likewise without 100-continue:
-	{100, "", false, "401 Unauthorized"},
+	expectTest(100, "", false, "401 Unauthorized"),
 
 	// Non-standard expectations are failures
-	{0, "a-pony", false, "417 Expectation Failed"},
+	expectTest(0, "a-pony", false, "417 Expectation Failed"),
 
-	// Expect-100 requested but no body
-	{0, "100-continue", true, "400 Bad Request"},
+	// Expect-100 requested but no body (is apparently okay: Issue 7625)
+	expectTest(0, "100-continue", true, "200 OK"),
+	// Expect-100 requested but handler doesn't read the body
+	expectTest(0, "100-continue", false, "401 Unauthorized"),
+	// Expect-100 continue with no body, but a chunked body.
+	{
+		expectation:      "100-continue",
+		readBody:         true,
+		chunked:          true,
+		expectedResponse: "100 Continue",
+	},
 }
 
 // Tests that the server responds to the "Expect" request header
@@ -966,21 +1005,38 @@ func TestServerExpect(t *testing.T) {
 
 		// Only send the body immediately if we're acting like an HTTP client
 		// that doesn't send 100-continue expectations.
-		writeBody := test.contentLength > 0 && strings.ToLower(test.expectation) != "100-continue"
+		writeBody := test.contentLength != 0 && strings.ToLower(test.expectation) != "100-continue"
 
 		go func() {
+			contentLen := fmt.Sprintf("Content-Length: %d", test.contentLength)
+			if test.chunked {
+				contentLen = "Transfer-Encoding: chunked"
+			}
 			_, err := fmt.Fprintf(conn, "POST /?readbody=%v HTTP/1.1\r\n"+
 				"Connection: close\r\n"+
-				"Content-Length: %d\r\n"+
+				"%s\r\n"+
 				"Expect: %s\r\nHost: foo\r\n\r\n",
-				test.readBody, test.contentLength, test.expectation)
+				test.readBody, contentLen, test.expectation)
 			if err != nil {
 				t.Errorf("On test %#v, error writing request headers: %v", test, err)
 				return
 			}
 			if writeBody {
+				var targ io.WriteCloser = struct {
+					io.Writer
+					io.Closer
+				}{
+					conn,
+					ioutil.NopCloser(nil),
+				}
+				if test.chunked {
+					targ = httputil.NewChunkedWriter(conn)
+				}
 				body := strings.Repeat("A", test.contentLength)
-				_, err = fmt.Fprint(conn, body)
+				_, err = fmt.Fprint(targ, body)
+				if err == nil {
+					err = targ.Close()
+				}
 				if err != nil {
 					if !test.readBody {
 						// Server likely already hung up on us.
@@ -1414,6 +1470,9 @@ func TestRequestBodyLimit(t *testing.T) {
 // TestClientWriteShutdown tests that if the client shuts down the write
 // side of their TCP connection, the server doesn't send a 400 Bad Request.
 func TestClientWriteShutdown(t *testing.T) {
+	if runtime.GOOS == "plan9" {
+		t.Skip("skipping test; see http://golang.org/issue/7237")
+	}
 	defer afterTest(t)
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
 	defer ts.Close()
@@ -1934,6 +1993,31 @@ func TestWriteAfterHijack(t *testing.T) {
 	}
 }
 
+func TestDoubleHijack(t *testing.T) {
+	req := reqBytes("GET / HTTP/1.1\nHost: golang.org")
+	var buf bytes.Buffer
+	conn := &rwTestConn{
+		Reader: bytes.NewReader(req),
+		Writer: &buf,
+		closec: make(chan bool, 1),
+	}
+	handler := HandlerFunc(func(rw ResponseWriter, r *Request) {
+		conn, _, err := rw.(Hijacker).Hijack()
+		if err != nil {
+			t.Error(err)
+			return
+		}
+		_, _, err = rw.(Hijacker).Hijack()
+		if err == nil {
+			t.Errorf("got err = nil;  want err != nil")
+		}
+		conn.Close()
+	})
+	ln := &oneConnListener{conn: conn}
+	go Serve(ln, handler)
+	<-conn.closec
+}
+
 // http://code.google.com/p/go/issues/detail?id=5955
 // Note that this does not test the "request too large"
 // exit path from the http server. This is intentional;
@@ -2037,31 +2121,160 @@ func TestServerReaderFromOrder(t *testing.T) {
 	}
 }
 
-// Issue 6157
-func TestNoContentTypeOnNotModified(t *testing.T) {
+// Issue 6157, Issue 6685
+func TestCodesPreventingContentTypeAndBody(t *testing.T) {
+	for _, code := range []int{StatusNotModified, StatusNoContent, StatusContinue} {
+		ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
+			if r.URL.Path == "/header" {
+				w.Header().Set("Content-Length", "123")
+			}
+			w.WriteHeader(code)
+			if r.URL.Path == "/more" {
+				w.Write([]byte("stuff"))
+			}
+		}))
+		for _, req := range []string{
+			"GET / HTTP/1.0",
+			"GET /header HTTP/1.0",
+			"GET /more HTTP/1.0",
+			"GET / HTTP/1.1",
+			"GET /header HTTP/1.1",
+			"GET /more HTTP/1.1",
+		} {
+			got := ht.rawResponse(req)
+			wantStatus := fmt.Sprintf("%d %s", code, StatusText(code))
+			if !strings.Contains(got, wantStatus) {
+				t.Errorf("Code %d: Wanted %q Modified for %q: %s", code, wantStatus, req, got)
+			} else if strings.Contains(got, "Content-Length") {
+				t.Errorf("Code %d: Got a Content-Length from %q: %s", code, req, got)
+			} else if strings.Contains(got, "stuff") {
+				t.Errorf("Code %d: Response contains a body from %q: %s", code, req, got)
+			}
+		}
+	}
+}
+
+func TestContentTypeOkayOn204(t *testing.T) {
 	ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
-		if r.URL.Path == "/header" {
-			w.Header().Set("Content-Length", "123")
+		w.Header().Set("Content-Length", "123") // suppressed
+		w.Header().Set("Content-Type", "foo/bar")
+		w.WriteHeader(204)
+	}))
+	got := ht.rawResponse("GET / HTTP/1.1")
+	if !strings.Contains(got, "Content-Type: foo/bar") {
+		t.Errorf("Response = %q; want Content-Type: foo/bar", got)
+	}
+	if strings.Contains(got, "Content-Length: 123") {
+		t.Errorf("Response = %q; don't want a Content-Length", got)
+	}
+}
+
+// Issue 6995
+// A server Handler can receive a Request, and then turn around and
+// give a copy of that Request.Body out to the Transport (e.g. any
+// proxy).  So then two people own that Request.Body (both the server
+// and the http client), and both think they can close it on failure.
+// Therefore, all incoming server requests Bodies need to be thread-safe.
+func TestTransportAndServerSharedBodyRace(t *testing.T) {
+	defer afterTest(t)
+
+	const bodySize = 1 << 20
+
+	unblockBackend := make(chan bool)
+	backend := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+		io.CopyN(rw, req.Body, bodySize/2)
+		<-unblockBackend
+	}))
+	defer backend.Close()
+
+	backendRespc := make(chan *Response, 1)
+	proxy := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+		if req.RequestURI == "/foo" {
+			rw.Write([]byte("bar"))
+			return
 		}
-		w.WriteHeader(StatusNotModified)
-		if r.URL.Path == "/more" {
-			w.Write([]byte("stuff"))
+		req2, _ := NewRequest("POST", backend.URL, req.Body)
+		req2.ContentLength = bodySize
+
+		bresp, err := DefaultClient.Do(req2)
+		if err != nil {
+			t.Errorf("Proxy outbound request: %v", err)
+			return
+		}
+		_, err = io.CopyN(ioutil.Discard, bresp.Body, bodySize/4)
+		if err != nil {
+			t.Errorf("Proxy copy error: %v", err)
+			return
 		}
+		backendRespc <- bresp // to close later
+
+		// Try to cause a race: Both the DefaultTransport and the proxy handler's Server
+		// will try to read/close req.Body (aka req2.Body)
+		DefaultTransport.(*Transport).CancelRequest(req2)
+		rw.Write([]byte("OK"))
+	}))
+	defer proxy.Close()
+
+	req, _ := NewRequest("POST", proxy.URL, io.LimitReader(neverEnding('a'), bodySize))
+	res, err := DefaultClient.Do(req)
+	if err != nil {
+		t.Fatalf("Original request: %v", err)
+	}
+
+	// Cleanup, so we don't leak goroutines.
+	res.Body.Close()
+	close(unblockBackend)
+	(<-backendRespc).Body.Close()
+}
+
+// Test that a hanging Request.Body.Read from another goroutine can't
+// cause the Handler goroutine's Request.Body.Close to block.
+func TestRequestBodyCloseDoesntBlock(t *testing.T) {
+	t.Skipf("Skipping known issue; see golang.org/issue/7121")
+	if testing.Short() {
+		t.Skip("skipping in -short mode")
+	}
+	defer afterTest(t)
+
+	readErrCh := make(chan error, 1)
+	errCh := make(chan error, 2)
+
+	server := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+		go func(body io.Reader) {
+			_, err := body.Read(make([]byte, 100))
+			readErrCh <- err
+		}(req.Body)
+		time.Sleep(500 * time.Millisecond)
 	}))
-	for _, req := range []string{
-		"GET / HTTP/1.0",
-		"GET /header HTTP/1.0",
-		"GET /more HTTP/1.0",
-		"GET / HTTP/1.1",
-		"GET /header HTTP/1.1",
-		"GET /more HTTP/1.1",
-	} {
-		got := ht.rawResponse(req)
-		if !strings.Contains(got, "304 Not Modified") {
-			t.Errorf("Non-304 Not Modified for %q: %s", req, got)
-		} else if strings.Contains(got, "Content-Length") {
-			t.Errorf("Got a Content-Length from %q: %s", req, got)
+	defer server.Close()
+
+	closeConn := make(chan bool)
+	defer close(closeConn)
+	go func() {
+		conn, err := net.Dial("tcp", server.Listener.Addr().String())
+		if err != nil {
+			errCh <- err
+			return
+		}
+		defer conn.Close()
+		_, err = conn.Write([]byte("POST / HTTP/1.1\r\nConnection: close\r\nHost: foo\r\nContent-Length: 100000\r\n\r\n"))
+		if err != nil {
+			errCh <- err
+			return
 		}
+		// And now just block, making the server block on our
+		// 100000 bytes of body that will never arrive.
+		<-closeConn
+	}()
+	select {
+	case err := <-readErrCh:
+		if err == nil {
+			t.Error("Read was nil. Expected error.")
+		}
+	case err := <-errCh:
+		t.Error(err)
+	case <-time.After(5 * time.Second):
+		t.Error("timeout")
 	}
 }
 
@@ -2073,8 +2286,8 @@ func TestResponseWriterWriteStringAllocs(t *testing.T) {
 			w.Write([]byte("Hello world"))
 		}
 	}))
-	before := testing.AllocsPerRun(25, func() { ht.rawResponse("GET / HTTP/1.0") })
-	after := testing.AllocsPerRun(25, func() { ht.rawResponse("GET /s HTTP/1.0") })
+	before := testing.AllocsPerRun(50, func() { ht.rawResponse("GET / HTTP/1.0") })
+	after := testing.AllocsPerRun(50, func() { ht.rawResponse("GET /s HTTP/1.0") })
 	if int(after) >= int(before) {
 		t.Errorf("WriteString allocs of %v >= Write allocs of %v", after, before)
 	}
@@ -2093,6 +2306,230 @@ func TestAppendTime(t *testing.T) {
 	}
 }
 
+func TestServerConnState(t *testing.T) {
+	defer afterTest(t)
+	handler := map[string]func(w ResponseWriter, r *Request){
+		"/": func(w ResponseWriter, r *Request) {
+			fmt.Fprintf(w, "Hello.")
+		},
+		"/close": func(w ResponseWriter, r *Request) {
+			w.Header().Set("Connection", "close")
+			fmt.Fprintf(w, "Hello.")
+		},
+		"/hijack": func(w ResponseWriter, r *Request) {
+			c, _, _ := w.(Hijacker).Hijack()
+			c.Write([]byte("HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nHello."))
+			c.Close()
+		},
+		"/hijack-panic": func(w ResponseWriter, r *Request) {
+			c, _, _ := w.(Hijacker).Hijack()
+			c.Write([]byte("HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nHello."))
+			c.Close()
+			panic("intentional panic")
+		},
+	}
+	ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		handler[r.URL.Path](w, r)
+	}))
+	defer ts.Close()
+
+	var mu sync.Mutex // guard stateLog and connID
+	var stateLog = map[int][]ConnState{}
+	var connID = map[net.Conn]int{}
+
+	ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0)
+	ts.Config.ConnState = func(c net.Conn, state ConnState) {
+		if c == nil {
+			t.Errorf("nil conn seen in state %s", state)
+			return
+		}
+		mu.Lock()
+		defer mu.Unlock()
+		id, ok := connID[c]
+		if !ok {
+			id = len(connID) + 1
+			connID[c] = id
+		}
+		stateLog[id] = append(stateLog[id], state)
+	}
+	ts.Start()
+
+	mustGet(t, ts.URL+"/")
+	mustGet(t, ts.URL+"/close")
+
+	mustGet(t, ts.URL+"/")
+	mustGet(t, ts.URL+"/", "Connection", "close")
+
+	mustGet(t, ts.URL+"/hijack")
+	mustGet(t, ts.URL+"/hijack-panic")
+
+	// New->Closed
+	{
+		c, err := net.Dial("tcp", ts.Listener.Addr().String())
+		if err != nil {
+			t.Fatal(err)
+		}
+		c.Close()
+	}
+
+	// New->Active->Closed
+	{
+		c, err := net.Dial("tcp", ts.Listener.Addr().String())
+		if err != nil {
+			t.Fatal(err)
+		}
+		if _, err := io.WriteString(c, "BOGUS REQUEST\r\n\r\n"); err != nil {
+			t.Fatal(err)
+		}
+		c.Close()
+	}
+
+	// New->Idle->Closed
+	{
+		c, err := net.Dial("tcp", ts.Listener.Addr().String())
+		if err != nil {
+			t.Fatal(err)
+		}
+		if _, err := io.WriteString(c, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n"); err != nil {
+			t.Fatal(err)
+		}
+		res, err := ReadResponse(bufio.NewReader(c), nil)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if _, err := io.Copy(ioutil.Discard, res.Body); err != nil {
+			t.Fatal(err)
+		}
+		c.Close()
+	}
+
+	want := map[int][]ConnState{
+		1: []ConnState{StateNew, StateActive, StateIdle, StateActive, StateClosed},
+		2: []ConnState{StateNew, StateActive, StateIdle, StateActive, StateClosed},
+		3: []ConnState{StateNew, StateActive, StateHijacked},
+		4: []ConnState{StateNew, StateActive, StateHijacked},
+		5: []ConnState{StateNew, StateClosed},
+		6: []ConnState{StateNew, StateActive, StateClosed},
+		7: []ConnState{StateNew, StateActive, StateIdle, StateClosed},
+	}
+	logString := func(m map[int][]ConnState) string {
+		var b bytes.Buffer
+		for id, l := range m {
+			fmt.Fprintf(&b, "Conn %d: ", id)
+			for _, s := range l {
+				fmt.Fprintf(&b, "%s ", s)
+			}
+			b.WriteString("\n")
+		}
+		return b.String()
+	}
+
+	for i := 0; i < 5; i++ {
+		time.Sleep(time.Duration(i) * 50 * time.Millisecond)
+		mu.Lock()
+		match := reflect.DeepEqual(stateLog, want)
+		mu.Unlock()
+		if match {
+			return
+		}
+	}
+
+	mu.Lock()
+	t.Errorf("Unexpected events.\nGot log: %s\n   Want: %s\n", logString(stateLog), logString(want))
+	mu.Unlock()
+}
+
+func mustGet(t *testing.T, url string, headers ...string) {
+	req, err := NewRequest("GET", url, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	for len(headers) > 0 {
+		req.Header.Add(headers[0], headers[1])
+		headers = headers[2:]
+	}
+	res, err := DefaultClient.Do(req)
+	if err != nil {
+		t.Errorf("Error fetching %s: %v", url, err)
+		return
+	}
+	_, err = ioutil.ReadAll(res.Body)
+	defer res.Body.Close()
+	if err != nil {
+		t.Errorf("Error reading %s: %v", url, err)
+	}
+}
+
+func TestServerKeepAlivesEnabled(t *testing.T) {
+	defer afterTest(t)
+	ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
+	ts.Config.SetKeepAlivesEnabled(false)
+	ts.Start()
+	defer ts.Close()
+	res, err := Get(ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer res.Body.Close()
+	if !res.Close {
+		t.Errorf("Body.Close == false; want true")
+	}
+}
+
+// golang.org/issue/7856
+func TestServerEmptyBodyRace(t *testing.T) {
+	defer afterTest(t)
+	var n int32
+	ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+		atomic.AddInt32(&n, 1)
+	}))
+	defer ts.Close()
+	var wg sync.WaitGroup
+	const reqs = 20
+	for i := 0; i < reqs; i++ {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			res, err := Get(ts.URL)
+			if err != nil {
+				t.Error(err)
+				return
+			}
+			defer res.Body.Close()
+			_, err = io.Copy(ioutil.Discard, res.Body)
+			if err != nil {
+				t.Error(err)
+				return
+			}
+		}()
+	}
+	wg.Wait()
+	if got := atomic.LoadInt32(&n); got != reqs {
+		t.Errorf("handler ran %d times; want %d", got, reqs)
+	}
+}
+
+func TestServerConnStateNew(t *testing.T) {
+	sawNew := false // if the test is buggy, we'll race on this variable.
+	srv := &Server{
+		ConnState: func(c net.Conn, state ConnState) {
+			if state == StateNew {
+				sawNew = true // testing that this write isn't racy
+			}
+		},
+		Handler: HandlerFunc(func(w ResponseWriter, r *Request) {}), // irrelevant
+	}
+	srv.Serve(&oneConnListener{
+		conn: &rwTestConn{
+			Reader: strings.NewReader("GET / HTTP/1.1\r\nHost: foo\r\n\r\n"),
+			Writer: ioutil.Discard,
+		},
+	})
+	if !sawNew { // testing that this read isn't racy
+		t.Error("StateNew not seen")
+	}
+}
+
 func BenchmarkClientServer(b *testing.B) {
 	b.ReportAllocs()
 	b.StopTimer()
@@ -2108,6 +2545,7 @@ func BenchmarkClientServer(b *testing.B) {
 			b.Fatal("Get:", err)
 		}
 		all, err := ioutil.ReadAll(res.Body)
+		res.Body.Close()
 		if err != nil {
 			b.Fatal("ReadAll:", err)
 		}
@@ -2128,41 +2566,33 @@ func BenchmarkClientServerParallel64(b *testing.B) {
 	benchmarkClientServerParallel(b, 64)
 }
 
-func benchmarkClientServerParallel(b *testing.B, conc int) {
+func benchmarkClientServerParallel(b *testing.B, parallelism int) {
 	b.ReportAllocs()
-	b.StopTimer()
 	ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) {
 		fmt.Fprintf(rw, "Hello world.\n")
 	}))
 	defer ts.Close()
-	b.StartTimer()
-
-	numProcs := runtime.GOMAXPROCS(-1) * conc
-	var wg sync.WaitGroup
-	wg.Add(numProcs)
-	n := int32(b.N)
-	for p := 0; p < numProcs; p++ {
-		go func() {
-			for atomic.AddInt32(&n, -1) >= 0 {
-				res, err := Get(ts.URL)
-				if err != nil {
-					b.Logf("Get: %v", err)
-					continue
-				}
-				all, err := ioutil.ReadAll(res.Body)
-				if err != nil {
-					b.Logf("ReadAll: %v", err)
-					continue
-				}
-				body := string(all)
-				if body != "Hello world.\n" {
-					panic("Got body: " + body)
-				}
+	b.ResetTimer()
+	b.SetParallelism(parallelism)
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			res, err := Get(ts.URL)
+			if err != nil {
+				b.Logf("Get: %v", err)
+				continue
 			}
-			wg.Done()
-		}()
-	}
-	wg.Wait()
+			all, err := ioutil.ReadAll(res.Body)
+			res.Body.Close()
+			if err != nil {
+				b.Logf("ReadAll: %v", err)
+				continue
+			}
+			body := string(all)
+			if body != "Hello world.\n" {
+				panic("Got body: " + body)
+			}
+		}
+	})
 }
 
 // A benchmark for profiling the server without the HTTP client code.
@@ -2187,6 +2617,7 @@ func BenchmarkServer(b *testing.B) {
 				log.Panicf("Get: %v", err)
 			}
 			all, err := ioutil.ReadAll(res.Body)
+			res.Body.Close()
 			if err != nil {
 				log.Panicf("ReadAll: %v", err)
 			}
@@ -2390,3 +2821,28 @@ Host: golang.org
 		b.Errorf("b.N=%d but handled %d", b.N, handled)
 	}
 }
+
+func BenchmarkServerHijack(b *testing.B) {
+	b.ReportAllocs()
+	req := reqBytes(`GET / HTTP/1.1
+Host: golang.org
+`)
+	h := HandlerFunc(func(w ResponseWriter, r *Request) {
+		conn, _, err := w.(Hijacker).Hijack()
+		if err != nil {
+			panic(err)
+		}
+		conn.Close()
+	})
+	conn := &rwTestConn{
+		Writer: ioutil.Discard,
+		closec: make(chan bool, 1),
+	}
+	ln := &oneConnListener{conn: conn}
+	for i := 0; i < b.N; i++ {
+		conn.Reader = bytes.NewReader(req)
+		ln.conn = conn
+		Serve(ln, h)
+		<-conn.closec
+	}
+}
diff --git a/src/pkg/net/http/server.go b/src/pkg/net/http/server.go
index 0e46863..eae097e 100644
--- a/src/pkg/net/http/server.go
+++ b/src/pkg/net/http/server.go
@@ -22,6 +22,7 @@ import (
 	"strconv"
 	"strings"
 	"sync"
+	"sync/atomic"
 	"time"
 )
 
@@ -138,6 +139,7 @@ func (c *conn) hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
 	buf = c.buf
 	c.rwc = nil
 	c.buf = nil
+	c.setState(rwc, StateHijacked)
 	return
 }
 
@@ -435,56 +437,52 @@ func (srv *Server) newConn(rwc net.Conn) (c *conn, err error) {
 	return c, nil
 }
 
-// TODO: use a sync.Cache instead
 var (
-	bufioReaderCache   = make(chan *bufio.Reader, 4)
-	bufioWriterCache2k = make(chan *bufio.Writer, 4)
-	bufioWriterCache4k = make(chan *bufio.Writer, 4)
+	bufioReaderPool   sync.Pool
+	bufioWriter2kPool sync.Pool
+	bufioWriter4kPool sync.Pool
 )
 
-func bufioWriterCache(size int) chan *bufio.Writer {
+func bufioWriterPool(size int) *sync.Pool {
 	switch size {
 	case 2 << 10:
-		return bufioWriterCache2k
+		return &bufioWriter2kPool
 	case 4 << 10:
-		return bufioWriterCache4k
+		return &bufioWriter4kPool
 	}
 	return nil
 }
 
 func newBufioReader(r io.Reader) *bufio.Reader {
-	select {
-	case p := <-bufioReaderCache:
-		p.Reset(r)
-		return p
-	default:
-		return bufio.NewReader(r)
+	if v := bufioReaderPool.Get(); v != nil {
+		br := v.(*bufio.Reader)
+		br.Reset(r)
+		return br
 	}
+	return bufio.NewReader(r)
 }
 
 func putBufioReader(br *bufio.Reader) {
 	br.Reset(nil)
-	select {
-	case bufioReaderCache <- br:
-	default:
-	}
+	bufioReaderPool.Put(br)
 }
 
 func newBufioWriterSize(w io.Writer, size int) *bufio.Writer {
-	select {
-	case p := <-bufioWriterCache(size):
-		p.Reset(w)
-		return p
-	default:
-		return bufio.NewWriterSize(w, size)
+	pool := bufioWriterPool(size)
+	if pool != nil {
+		if v := pool.Get(); v != nil {
+			bw := v.(*bufio.Writer)
+			bw.Reset(w)
+			return bw
+		}
 	}
+	return bufio.NewWriterSize(w, size)
 }
 
 func putBufioWriter(bw *bufio.Writer) {
 	bw.Reset(nil)
-	select {
-	case bufioWriterCache(bw.Available()) <- bw:
-	default:
+	if pool := bufioWriterPool(bw.Available()); pool != nil {
+		pool.Put(bw)
 	}
 }
 
@@ -500,6 +498,10 @@ func (srv *Server) maxHeaderBytes() int {
 	return DefaultMaxHeaderBytes
 }
 
+func (srv *Server) initialLimitedReaderSize() int64 {
+	return int64(srv.maxHeaderBytes()) + 4096 // bufio slop
+}
+
 // wrapper around io.ReaderCloser which on first read, sends an
 // HTTP/1.1 100 Continue header
 type expectContinueReader struct {
@@ -570,7 +572,7 @@ func (c *conn) readRequest() (w *response, err error) {
 		}()
 	}
 
-	c.lr.N = int64(c.server.maxHeaderBytes()) + 4096 /* bufio slop */
+	c.lr.N = c.server.initialLimitedReaderSize()
 	var req *Request
 	if req, err = ReadRequest(c.buf.Reader); err != nil {
 		if c.lr.N == 0 {
@@ -618,11 +620,11 @@ const maxPostHandlerReadBytes = 256 << 10
 
 func (w *response) WriteHeader(code int) {
 	if w.conn.hijacked() {
-		log.Print("http: response.WriteHeader on hijacked connection")
+		w.conn.server.logf("http: response.WriteHeader on hijacked connection")
 		return
 	}
 	if w.wroteHeader {
-		log.Print("http: multiple response.WriteHeader calls")
+		w.conn.server.logf("http: multiple response.WriteHeader calls")
 		return
 	}
 	w.wroteHeader = true
@@ -637,7 +639,7 @@ func (w *response) WriteHeader(code int) {
 		if err == nil && v >= 0 {
 			w.contentLength = v
 		} else {
-			log.Printf("http: invalid Content-Length of %q", cl)
+			w.conn.server.logf("http: invalid Content-Length of %q", cl)
 			w.handlerHeader.Del("Content-Length")
 		}
 	}
@@ -707,6 +709,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 	cw.wroteHeader = true
 
 	w := cw.res
+	keepAlivesEnabled := w.conn.server.doKeepAlives()
 	isHEAD := w.req.Method == "HEAD"
 
 	// header is written out to w.conn.buf below. Depending on the
@@ -739,7 +742,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 	// response header and this is our first (and last) write, set
 	// it, even to zero. This helps HTTP/1.0 clients keep their
 	// "keep-alive" connections alive.
-	// Exceptions: 304 responses never get Content-Length, and if
+	// Exceptions: 304/204/1xx responses never get Content-Length, and if
 	// it was a HEAD request, we don't know the difference between
 	// 0 actual bytes and 0 bytes because the handler noticed it
 	// was a HEAD request and chose not to write anything.  So for
@@ -747,14 +750,14 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 	// write non-zero bytes.  If it's actually 0 bytes and the
 	// handler never looked at the Request.Method, we just don't
 	// send a Content-Length header.
-	if w.handlerDone && w.status != StatusNotModified && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) {
+	if w.handlerDone && bodyAllowedForStatus(w.status) && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) {
 		w.contentLength = int64(len(p))
 		setHeader.contentLength = strconv.AppendInt(cw.res.clenBuf[:0], int64(len(p)), 10)
 	}
 
 	// If this was an HTTP/1.0 request with keep-alive and we sent a
 	// Content-Length back, we can make this a keep-alive response ...
-	if w.req.wantsHttp10KeepAlive() {
+	if w.req.wantsHttp10KeepAlive() && keepAlivesEnabled {
 		sentLength := header.get("Content-Length") != ""
 		if sentLength && header.get("Connection") == "keep-alive" {
 			w.closeAfterReply = false
@@ -773,7 +776,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 		w.closeAfterReply = true
 	}
 
-	if header.get("Connection") == "close" {
+	if header.get("Connection") == "close" || !keepAlivesEnabled {
 		w.closeAfterReply = true
 	}
 
@@ -796,18 +799,16 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 	}
 
 	code := w.status
-	if code == StatusNotModified {
-		// Must not have body.
-		// RFC 2616 section 10.3.5: "the response MUST NOT include other entity-headers"
-		for _, k := range []string{"Content-Type", "Content-Length", "Transfer-Encoding"} {
-			delHeader(k)
-		}
-	} else {
+	if bodyAllowedForStatus(code) {
 		// If no content type, apply sniffing algorithm to body.
 		_, haveType := header["Content-Type"]
 		if !haveType {
 			setHeader.contentType = DetectContentType(p)
 		}
+	} else {
+		for _, k := range suppressedHeaders(code) {
+			delHeader(k)
+		}
 	}
 
 	if _, ok := header["Date"]; !ok {
@@ -819,13 +820,13 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 	if hasCL && hasTE && te != "identity" {
 		// TODO: return an error if WriteHeader gets a return parameter
 		// For now just ignore the Content-Length.
-		log.Printf("http: WriteHeader called with both Transfer-Encoding of %q and a Content-Length of %d",
+		w.conn.server.logf("http: WriteHeader called with both Transfer-Encoding of %q and a Content-Length of %d",
 			te, w.contentLength)
 		delHeader("Content-Length")
 		hasCL = false
 	}
 
-	if w.req.Method == "HEAD" || code == StatusNotModified {
+	if w.req.Method == "HEAD" || !bodyAllowedForStatus(code) {
 		// do nothing
 	} else if code == StatusNoContent {
 		delHeader("Transfer-Encoding")
@@ -855,7 +856,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 		return
 	}
 
-	if w.closeAfterReply && !hasToken(cw.header.get("Connection"), "close") {
+	if w.closeAfterReply && (!keepAlivesEnabled || !hasToken(cw.header.get("Connection"), "close")) {
 		delHeader("Connection")
 		if w.req.ProtoAtLeast(1, 1) {
 			setHeader.connection = "close"
@@ -919,7 +920,7 @@ func (w *response) bodyAllowed() bool {
 	if !w.wroteHeader {
 		panic("")
 	}
-	return w.status != StatusNotModified
+	return bodyAllowedForStatus(w.status)
 }
 
 // The Life Of A Write is like this:
@@ -965,7 +966,7 @@ func (w *response) WriteString(data string) (n int, err error) {
 // either dataB or dataS is non-zero.
 func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err error) {
 	if w.conn.hijacked() {
-		log.Print("http: response.Write on hijacked connection")
+		w.conn.server.logf("http: response.Write on hijacked connection")
 		return 0, ErrHijacked
 	}
 	if !w.wroteHeader {
@@ -1001,11 +1002,10 @@ func (w *response) finishRequest() {
 	w.cw.close()
 	w.conn.buf.Flush()
 
-	// Close the body, unless we're about to close the whole TCP connection
-	// anyway.
-	if !w.closeAfterReply {
-		w.req.Body.Close()
-	}
+	// Close the body (regardless of w.closeAfterReply) so we can
+	// re-use its bufio.Reader later safely.
+	w.req.Body.Close()
+
 	if w.req.MultipartForm != nil {
 		w.req.MultipartForm.RemoveAll()
 	}
@@ -1084,17 +1084,25 @@ func validNPN(proto string) bool {
 	return true
 }
 
+func (c *conn) setState(nc net.Conn, state ConnState) {
+	if hook := c.server.ConnState; hook != nil {
+		hook(nc, state)
+	}
+}
+
 // Serve a new connection.
 func (c *conn) serve() {
+	origConn := c.rwc // copy it before it's set nil on Close or Hijack
 	defer func() {
 		if err := recover(); err != nil {
-			const size = 4096
+			const size = 64 << 10
 			buf := make([]byte, size)
 			buf = buf[:runtime.Stack(buf, false)]
-			log.Printf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf)
+			c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf)
 		}
 		if !c.hijacked() {
 			c.close()
+			c.setState(origConn, StateClosed)
 		}
 	}()
 
@@ -1106,6 +1114,7 @@ func (c *conn) serve() {
 			c.rwc.SetWriteDeadline(time.Now().Add(d))
 		}
 		if err := tlsConn.Handshake(); err != nil {
+			c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err)
 			return
 		}
 		c.tlsState = new(tls.ConnectionState)
@@ -1121,6 +1130,10 @@ func (c *conn) serve() {
 
 	for {
 		w, err := c.readRequest()
+		if c.lr.N != c.server.initialLimitedReaderSize() {
+			// If we read any bytes off the wire, we're active.
+			c.setState(c.rwc, StateActive)
+		}
 		if err != nil {
 			if err == errTooLarge {
 				// Their HTTP client may or may not be
@@ -1143,16 +1156,10 @@ func (c *conn) serve() {
 		// Expect 100 Continue support
 		req := w.req
 		if req.expectsContinue() {
-			if req.ProtoAtLeast(1, 1) {
+			if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 {
 				// Wrap the Body reader with one that replies on the connection
 				req.Body = &expectContinueReader{readCloser: req.Body, resp: w}
 			}
-			if req.ContentLength == 0 {
-				w.Header().Set("Connection", "close")
-				w.WriteHeader(StatusBadRequest)
-				w.finishRequest()
-				break
-			}
 			req.Header.Del("Expect")
 		} else if req.Header.get("Expect") != "" {
 			w.sendExpectationFailed()
@@ -1175,6 +1182,7 @@ func (c *conn) serve() {
 			}
 			break
 		}
+		c.setState(c.rwc, StateIdle)
 	}
 }
 
@@ -1202,7 +1210,14 @@ func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
 	if w.wroteHeader {
 		w.cw.flush()
 	}
-	return w.conn.hijack()
+	// Release the bufioWriter that writes to the chunk writer, it is not
+	// used after a connection has been hijacked.
+	rwc, buf, err = w.conn.hijack()
+	if err == nil {
+		putBufioWriter(w.w)
+		w.w = nil
+	}
+	return rwc, buf, err
 }
 
 func (w *response) CloseNotify() <-chan bool {
@@ -1562,6 +1577,7 @@ func Serve(l net.Listener, handler Handler) error {
 }
 
 // A Server defines parameters for running an HTTP server.
+// The zero value for Server is a valid configuration.
 type Server struct {
 	Addr           string        // TCP address to listen on, ":http" if empty
 	Handler        Handler       // handler to invoke, http.DefaultServeMux if nil
@@ -1578,6 +1594,66 @@ type Server struct {
 	// and RemoteAddr if not already set.  The connection is
 	// automatically closed when the function returns.
 	TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
+
+	// ConnState specifies an optional callback function that is
+	// called when a client connection changes state. See the
+	// ConnState type and associated constants for details.
+	ConnState func(net.Conn, ConnState)
+
+	// ErrorLog specifies an optional logger for errors accepting
+	// connections and unexpected behavior from handlers.
+	// If nil, logging goes to os.Stderr via the log package's
+	// standard logger.
+	ErrorLog *log.Logger
+
+	disableKeepAlives int32 // accessed atomically.
+}
+
+// A ConnState represents the state of a client connection to a server.
+// It's used by the optional Server.ConnState hook.
+type ConnState int
+
+const (
+	// StateNew represents a new connection that is expected to
+	// send a request immediately. Connections begin at this
+	// state and then transition to either StateActive or
+	// StateClosed.
+	StateNew ConnState = iota
+
+	// StateActive represents a connection that has read 1 or more
+	// bytes of a request. The Server.ConnState hook for
+	// StateActive fires before the request has entered a handler
+	// and doesn't fire again until the request has been
+	// handled. After the request is handled, the state
+	// transitions to StateClosed, StateHijacked, or StateIdle.
+	StateActive
+
+	// StateIdle represents a connection that has finished
+	// handling a request and is in the keep-alive state, waiting
+	// for a new request. Connections transition from StateIdle
+	// to either StateActive or StateClosed.
+	StateIdle
+
+	// StateHijacked represents a hijacked connection.
+	// This is a terminal state. It does not transition to StateClosed.
+	StateHijacked
+
+	// StateClosed represents a closed connection.
+	// This is a terminal state. Hijacked connections do not
+	// transition to StateClosed.
+	StateClosed
+)
+
+var stateName = map[ConnState]string{
+	StateNew:      "new",
+	StateActive:   "active",
+	StateIdle:     "idle",
+	StateHijacked: "hijacked",
+	StateClosed:   "closed",
+}
+
+func (c ConnState) String() string {
+	return stateName[c]
 }
 
 // serverHandler delegates to either the server's Handler or
@@ -1605,11 +1681,11 @@ func (srv *Server) ListenAndServe() error {
 	if addr == "" {
 		addr = ":http"
 	}
-	l, e := net.Listen("tcp", addr)
-	if e != nil {
-		return e
+	ln, err := net.Listen("tcp", addr)
+	if err != nil {
+		return err
 	}
-	return srv.Serve(l)
+	return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
 }
 
 // Serve accepts incoming connections on the Listener l, creating a
@@ -1630,7 +1706,7 @@ func (srv *Server) Serve(l net.Listener) error {
 				if max := 1 * time.Second; tempDelay > max {
 					tempDelay = max
 				}
-				log.Printf("http: Accept error: %v; retrying in %v", e, tempDelay)
+				srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
 				time.Sleep(tempDelay)
 				continue
 			}
@@ -1641,10 +1717,35 @@ func (srv *Server) Serve(l net.Listener) error {
 		if err != nil {
 			continue
 		}
+		c.setState(c.rwc, StateNew) // before Serve can return
 		go c.serve()
 	}
 }
 
+func (s *Server) doKeepAlives() bool {
+	return atomic.LoadInt32(&s.disableKeepAlives) == 0
+}
+
+// SetKeepAlivesEnabled controls whether HTTP keep-alives are enabled.
+// By default, keep-alives are always enabled. Only very
+// resource-constrained environments or servers in the process of
+// shutting down should disable them.
+func (s *Server) SetKeepAlivesEnabled(v bool) {
+	if v {
+		atomic.StoreInt32(&s.disableKeepAlives, 0)
+	} else {
+		atomic.StoreInt32(&s.disableKeepAlives, 1)
+	}
+}
+
+func (s *Server) logf(format string, args ...interface{}) {
+	if s.ErrorLog != nil {
+		s.ErrorLog.Printf(format, args...)
+	} else {
+		log.Printf(format, args...)
+	}
+}
+
 // ListenAndServe listens on the TCP network address addr
 // and then calls Serve with handler to handle requests
 // on incoming connections.  Handler is typically nil,
@@ -1739,12 +1840,12 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
 		return err
 	}
 
-	conn, err := net.Listen("tcp", addr)
+	ln, err := net.Listen("tcp", addr)
 	if err != nil {
 		return err
 	}
 
-	tlsListener := tls.NewListener(conn, config)
+	tlsListener := tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, config)
 	return srv.Serve(tlsListener)
 }
 
@@ -1834,6 +1935,24 @@ func (tw *timeoutWriter) WriteHeader(code int) {
 	tw.w.WriteHeader(code)
 }
 
+// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
+// connections. It's used by ListenAndServe and ListenAndServeTLS so
+// dead TCP connections (e.g. closing laptop mid-download) eventually
+// go away.
+type tcpKeepAliveListener struct {
+	*net.TCPListener
+}
+
+func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
+	tc, err := ln.AcceptTCP()
+	if err != nil {
+		return
+	}
+	tc.SetKeepAlive(true)
+	tc.SetKeepAlivePeriod(3 * time.Minute)
+	return tc, nil
+}
+
 // globalOptionsHandler responds to "OPTIONS *" requests.
 type globalOptionsHandler struct{}
 
@@ -1850,17 +1969,24 @@ func (globalOptionsHandler) ServeHTTP(w ResponseWriter, r *Request) {
 	}
 }
 
+type eofReaderWithWriteTo struct{}
+
+func (eofReaderWithWriteTo) WriteTo(io.Writer) (int64, error) { return 0, nil }
+func (eofReaderWithWriteTo) Read([]byte) (int, error)         { return 0, io.EOF }
+
 // eofReader is a non-nil io.ReadCloser that always returns EOF.
-// It embeds a *strings.Reader so it still has a WriteTo method
-// and io.Copy won't need a buffer.
+// It has a WriteTo method so io.Copy won't need a buffer.
 var eofReader = &struct {
-	*strings.Reader
+	eofReaderWithWriteTo
 	io.Closer
 }{
-	strings.NewReader(""),
+	eofReaderWithWriteTo{},
 	ioutil.NopCloser(nil),
 }
 
+// Verify that an io.Copy from an eofReader won't require a buffer.
+var _ io.WriterTo = eofReader
+
 // initNPNRequest is an HTTP handler that initializes certain
 // uninitialized fields in its *Request. Such partially-initialized
 // Requests come from NPN protocol handlers.
diff --git a/src/pkg/net/http/transfer.go b/src/pkg/net/http/transfer.go
index bacd837..7f63686 100644
--- a/src/pkg/net/http/transfer.go
+++ b/src/pkg/net/http/transfer.go
@@ -12,10 +12,20 @@ import (
 	"io"
 	"io/ioutil"
 	"net/textproto"
+	"sort"
 	"strconv"
 	"strings"
+	"sync"
 )
 
+type errorReader struct {
+	err error
+}
+
+func (r *errorReader) Read(p []byte) (n int, err error) {
+	return 0, r.err
+}
+
 // transferWriter inspects the fields of a user-supplied Request or Response,
 // sanitizes them without changing the user object and provides methods for
 // writing the respective header, body and trailer in wire format.
@@ -52,14 +62,17 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) {
 			if t.ContentLength == 0 {
 				// Test to see if it's actually zero or just unset.
 				var buf [1]byte
-				n, _ := io.ReadFull(t.Body, buf[:])
-				if n == 1 {
+				n, rerr := io.ReadFull(t.Body, buf[:])
+				if rerr != nil && rerr != io.EOF {
+					t.ContentLength = -1
+					t.Body = &errorReader{rerr}
+				} else if n == 1 {
 					// Oh, guess there is data in this Body Reader after all.
 					// The ContentLength field just wasn't set.
 					// Stich the Body back together again, re-attaching our
 					// consumed byte.
 					t.ContentLength = -1
-					t.Body = io.MultiReader(bytes.NewBuffer(buf[:]), t.Body)
+					t.Body = io.MultiReader(bytes.NewReader(buf[:]), t.Body)
 				} else {
 					// Body is actually empty.
 					t.Body = nil
@@ -131,11 +144,10 @@ func (t *transferWriter) shouldSendContentLength() bool {
 	return false
 }
 
-func (t *transferWriter) WriteHeader(w io.Writer) (err error) {
+func (t *transferWriter) WriteHeader(w io.Writer) error {
 	if t.Close {
-		_, err = io.WriteString(w, "Connection: close\r\n")
-		if err != nil {
-			return
+		if _, err := io.WriteString(w, "Connection: close\r\n"); err != nil {
+			return err
 		}
 	}
 
@@ -143,43 +155,44 @@ func (t *transferWriter) WriteHeader(w io.Writer) (err error) {
 	// function of the sanitized field triple (Body, ContentLength,
 	// TransferEncoding)
 	if t.shouldSendContentLength() {
-		io.WriteString(w, "Content-Length: ")
-		_, err = io.WriteString(w, strconv.FormatInt(t.ContentLength, 10)+"\r\n")
-		if err != nil {
-			return
+		if _, err := io.WriteString(w, "Content-Length: "); err != nil {
+			return err
+		}
+		if _, err := io.WriteString(w, strconv.FormatInt(t.ContentLength, 10)+"\r\n"); err != nil {
+			return err
 		}
 	} else if chunked(t.TransferEncoding) {
-		_, err = io.WriteString(w, "Transfer-Encoding: chunked\r\n")
-		if err != nil {
-			return
+		if _, err := io.WriteString(w, "Transfer-Encoding: chunked\r\n"); err != nil {
+			return err
 		}
 	}
 
 	// Write Trailer header
 	if t.Trailer != nil {
-		// TODO: At some point, there should be a generic mechanism for
-		// writing long headers, using HTTP line splitting
-		io.WriteString(w, "Trailer: ")
-		needComma := false
+		keys := make([]string, 0, len(t.Trailer))
 		for k := range t.Trailer {
 			k = CanonicalHeaderKey(k)
 			switch k {
 			case "Transfer-Encoding", "Trailer", "Content-Length":
 				return &badStringError{"invalid Trailer key", k}
 			}
-			if needComma {
-				io.WriteString(w, ",")
+			keys = append(keys, k)
+		}
+		if len(keys) > 0 {
+			sort.Strings(keys)
+			// TODO: could do better allocation-wise here, but trailers are rare,
+			// so being lazy for now.
+			if _, err := io.WriteString(w, "Trailer: "+strings.Join(keys, ",")+"\r\n"); err != nil {
+				return err
 			}
-			io.WriteString(w, k)
-			needComma = true
 		}
-		_, err = io.WriteString(w, "\r\n")
 	}
 
-	return
+	return nil
 }
 
-func (t *transferWriter) WriteBody(w io.Writer) (err error) {
+func (t *transferWriter) WriteBody(w io.Writer) error {
+	var err error
 	var ncopy int64
 
 	// Write body
@@ -216,11 +229,16 @@ func (t *transferWriter) WriteBody(w io.Writer) (err error) {
 
 	// TODO(petar): Place trailer writer code here.
 	if chunked(t.TransferEncoding) {
+		// Write Trailer header
+		if t.Trailer != nil {
+			if err := t.Trailer.Write(w); err != nil {
+				return err
+			}
+		}
 		// Last chunk, empty trailer
 		_, err = io.WriteString(w, "\r\n")
 	}
-
-	return
+	return err
 }
 
 type transferReader struct {
@@ -252,6 +270,22 @@ func bodyAllowedForStatus(status int) bool {
 	return true
 }
 
+var (
+	suppressedHeaders304    = []string{"Content-Type", "Content-Length", "Transfer-Encoding"}
+	suppressedHeadersNoBody = []string{"Content-Length", "Transfer-Encoding"}
+)
+
+func suppressedHeaders(status int) []string {
+	switch {
+	case status == 304:
+		// RFC 2616 section 10.3.5: "the response MUST NOT include other entity-headers"
+		return suppressedHeaders304
+	case !bodyAllowedForStatus(status):
+		return suppressedHeadersNoBody
+	}
+	return nil
+}
+
 // msg is *Request or *Response.
 func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
 	t := &transferReader{RequestMethod: "GET"}
@@ -331,17 +365,17 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
 		if noBodyExpected(t.RequestMethod) {
 			t.Body = eofReader
 		} else {
-			t.Body = &body{Reader: newChunkedReader(r), hdr: msg, r: r, closing: t.Close}
+			t.Body = &body{src: newChunkedReader(r), hdr: msg, r: r, closing: t.Close}
 		}
 	case realLength == 0:
 		t.Body = eofReader
 	case realLength > 0:
-		t.Body = &body{Reader: io.LimitReader(r, realLength), closing: t.Close}
+		t.Body = &body{src: io.LimitReader(r, realLength), closing: t.Close}
 	default:
 		// realLength < 0, i.e. "Content-Length" not mentioned in header
 		if t.Close {
 			// Close semantics (i.e. HTTP/1.0)
-			t.Body = &body{Reader: r, closing: t.Close}
+			t.Body = &body{src: r, closing: t.Close}
 		} else {
 			// Persistent connection (i.e. HTTP/1.1)
 			t.Body = eofReader
@@ -498,7 +532,7 @@ func fixTrailer(header Header, te []string) (Header, error) {
 		case "Transfer-Encoding", "Trailer", "Content-Length":
 			return nil, &badStringError{"bad trailer key", key}
 		}
-		trailer.Del(key)
+		trailer[key] = nil
 	}
 	if len(trailer) == 0 {
 		return nil, nil
@@ -514,11 +548,13 @@ func fixTrailer(header Header, te []string) (Header, error) {
 // Close ensures that the body has been fully read
 // and then reads the trailer if necessary.
 type body struct {
-	io.Reader
+	src     io.Reader
 	hdr     interface{}   // non-nil (Response or Request) value means read trailer
 	r       *bufio.Reader // underlying wire-format reader for the trailer
 	closing bool          // is the connection to be closed after reading body?
-	closed  bool
+
+	mu     sync.Mutex // guards closed, and calls to Read and Close
+	closed bool
 }
 
 // ErrBodyReadAfterClose is returned when reading a Request or Response
@@ -528,10 +564,17 @@ type body struct {
 var ErrBodyReadAfterClose = errors.New("http: invalid Read on closed Body")
 
 func (b *body) Read(p []byte) (n int, err error) {
+	b.mu.Lock()
+	defer b.mu.Unlock()
 	if b.closed {
 		return 0, ErrBodyReadAfterClose
 	}
-	n, err = b.Reader.Read(p)
+	return b.readLocked(p)
+}
+
+// Must hold b.mu.
+func (b *body) readLocked(p []byte) (n int, err error) {
+	n, err = b.src.Read(p)
 
 	if err == io.EOF {
 		// Chunked case. Read the trailer.
@@ -543,12 +586,23 @@ func (b *body) Read(p []byte) (n int, err error) {
 		} else {
 			// If the server declared the Content-Length, our body is a LimitedReader
 			// and we need to check whether this EOF arrived early.
-			if lr, ok := b.Reader.(*io.LimitedReader); ok && lr.N > 0 {
+			if lr, ok := b.src.(*io.LimitedReader); ok && lr.N > 0 {
 				err = io.ErrUnexpectedEOF
 			}
 		}
 	}
 
+	// If we can return an EOF here along with the read data, do
+	// so. This is optional per the io.Reader contract, but doing
+	// so helps the HTTP transport code recycle its connection
+	// earlier (since it will see this EOF itself), even if the
+	// client doesn't do future reads or Close.
+	if err == nil && n > 0 {
+		if lr, ok := b.src.(*io.LimitedReader); ok && lr.N == 0 {
+			err = io.EOF
+		}
+	}
+
 	return n, err
 }
 
@@ -610,14 +664,26 @@ func (b *body) readTrailer() error {
 	}
 	switch rr := b.hdr.(type) {
 	case *Request:
-		rr.Trailer = Header(hdr)
+		mergeSetHeader(&rr.Trailer, Header(hdr))
 	case *Response:
-		rr.Trailer = Header(hdr)
+		mergeSetHeader(&rr.Trailer, Header(hdr))
 	}
 	return nil
 }
 
+func mergeSetHeader(dst *Header, src Header) {
+	if *dst == nil {
+		*dst = src
+		return
+	}
+	for k, vv := range src {
+		(*dst)[k] = vv
+	}
+}
+
 func (b *body) Close() error {
+	b.mu.Lock()
+	defer b.mu.Unlock()
 	if b.closed {
 		return nil
 	}
@@ -629,12 +695,25 @@ func (b *body) Close() error {
 	default:
 		// Fully consume the body, which will also lead to us reading
 		// the trailer headers after the body, if present.
-		_, err = io.Copy(ioutil.Discard, b)
+		_, err = io.Copy(ioutil.Discard, bodyLocked{b})
 	}
 	b.closed = true
 	return err
 }
 
+// bodyLocked is a io.Reader reading from a *body when its mutex is
+// already held.
+type bodyLocked struct {
+	b *body
+}
+
+func (bl bodyLocked) Read(p []byte) (n int, err error) {
+	if bl.b.closed {
+		return 0, ErrBodyReadAfterClose
+	}
+	return bl.b.readLocked(p)
+}
+
 // parseContentLength trims whitespace from s and returns -1 if no value
 // is set, or the value if it's >= 0.
 func parseContentLength(cl string) (int64, error) {
diff --git a/src/pkg/net/http/transfer_test.go b/src/pkg/net/http/transfer_test.go
index 8627a37..48cd540 100644
--- a/src/pkg/net/http/transfer_test.go
+++ b/src/pkg/net/http/transfer_test.go
@@ -6,15 +6,16 @@ package http
 
 import (
 	"bufio"
+	"io"
 	"strings"
 	"testing"
 )
 
 func TestBodyReadBadTrailer(t *testing.T) {
 	b := &body{
-		Reader: strings.NewReader("foobar"),
-		hdr:    true, // force reading the trailer
-		r:      bufio.NewReader(strings.NewReader("")),
+		src: strings.NewReader("foobar"),
+		hdr: true, // force reading the trailer
+		r:   bufio.NewReader(strings.NewReader("")),
 	}
 	buf := make([]byte, 7)
 	n, err := b.Read(buf[:3])
@@ -35,3 +36,29 @@ func TestBodyReadBadTrailer(t *testing.T) {
 		t.Errorf("final Read was successful (%q), expected error from trailer read", got)
 	}
 }
+
+func TestFinalChunkedBodyReadEOF(t *testing.T) {
+	res, err := ReadResponse(bufio.NewReader(strings.NewReader(
+		"HTTP/1.1 200 OK\r\n"+
+			"Transfer-Encoding: chunked\r\n"+
+			"\r\n"+
+			"0a\r\n"+
+			"Body here\n\r\n"+
+			"09\r\n"+
+			"continued\r\n"+
+			"0\r\n"+
+			"\r\n")), nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	want := "Body here\ncontinued"
+	buf := make([]byte, len(want))
+	n, err := res.Body.Read(buf)
+	if n != len(want) || err != io.EOF {
+		t.Logf("body = %#v", res.Body)
+		t.Errorf("Read = %v, %v; want %d, EOF", n, err, len(want))
+	}
+	if string(buf) != want {
+		t.Errorf("buf = %q; want %q", buf, want)
+	}
+}
diff --git a/src/pkg/net/http/transport.go b/src/pkg/net/http/transport.go
index f6871af..b1cc632 100644
--- a/src/pkg/net/http/transport.go
+++ b/src/pkg/net/http/transport.go
@@ -30,7 +30,14 @@ import (
 // and caches them for reuse by subsequent calls. It uses HTTP proxies
 // as directed by the $HTTP_PROXY and $NO_PROXY (or $http_proxy and
 // $no_proxy) environment variables.
-var DefaultTransport RoundTripper = &Transport{Proxy: ProxyFromEnvironment}
+var DefaultTransport RoundTripper = &Transport{
+	Proxy: ProxyFromEnvironment,
+	Dial: (&net.Dialer{
+		Timeout:   30 * time.Second,
+		KeepAlive: 30 * time.Second,
+	}).Dial,
+	TLSHandshakeTimeout: 10 * time.Second,
+}
 
 // DefaultMaxIdleConnsPerHost is the default value of Transport's
 // MaxIdleConnsPerHost.
@@ -40,13 +47,13 @@ const DefaultMaxIdleConnsPerHost = 2
 // https, and http proxies (for either http or https with CONNECT).
 // Transport can also cache connections for future re-use.
 type Transport struct {
-	idleMu     sync.Mutex
-	idleConn   map[string][]*persistConn
-	idleConnCh map[string]chan *persistConn
-	reqMu      sync.Mutex
-	reqConn    map[*Request]*persistConn
-	altMu      sync.RWMutex
-	altProto   map[string]RoundTripper // nil or map of URI scheme => RoundTripper
+	idleMu      sync.Mutex
+	idleConn    map[connectMethodKey][]*persistConn
+	idleConnCh  map[connectMethodKey]chan *persistConn
+	reqMu       sync.Mutex
+	reqCanceler map[*Request]func()
+	altMu       sync.RWMutex
+	altProto    map[string]RoundTripper // nil or map of URI scheme => RoundTripper
 
 	// Proxy specifies a function to return a proxy for a given
 	// Request. If the function returns a non-nil error, the
@@ -63,6 +70,10 @@ type Transport struct {
 	// tls.Client. If nil, the default configuration is used.
 	TLSClientConfig *tls.Config
 
+	// TLSHandshakeTimeout specifies the maximum amount of time waiting to
+	// wait for a TLS handshake. Zero means no timeout.
+	TLSHandshakeTimeout time.Duration
+
 	// DisableKeepAlives, if true, prevents re-use of TCP connections
 	// between different HTTP requests.
 	DisableKeepAlives bool
@@ -98,8 +109,11 @@ type Transport struct {
 // An error is returned if the proxy environment is invalid.
 // A nil URL and nil error are returned if no proxy is defined in the
 // environment, or a proxy should not be used for the given request.
+//
+// As a special case, if req.URL.Host is "localhost" (with or without
+// a port number), then a nil URL and nil error will be returned.
 func ProxyFromEnvironment(req *Request) (*url.URL, error) {
-	proxy := getenvEitherCase("HTTP_PROXY")
+	proxy := httpProxyEnv.Get()
 	if proxy == "" {
 		return nil, nil
 	}
@@ -149,9 +163,11 @@ func (tr *transportRequest) extraHeaders() Header {
 // and redirects), see Get, Post, and the Client type.
 func (t *Transport) RoundTrip(req *Request) (resp *Response, err error) {
 	if req.URL == nil {
+		req.closeBody()
 		return nil, errors.New("http: nil Request.URL")
 	}
 	if req.Header == nil {
+		req.closeBody()
 		return nil, errors.New("http: nil Request.Header")
 	}
 	if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
@@ -162,16 +178,19 @@ func (t *Transport) RoundTrip(req *Request) (resp *Response, err error) {
 		}
 		t.altMu.RUnlock()
 		if rt == nil {
+			req.closeBody()
 			return nil, &badStringError{"unsupported protocol scheme", req.URL.Scheme}
 		}
 		return rt.RoundTrip(req)
 	}
 	if req.URL.Host == "" {
+		req.closeBody()
 		return nil, errors.New("http: no Host in request URL")
 	}
 	treq := &transportRequest{Request: req}
 	cm, err := t.connectMethodForRequest(treq)
 	if err != nil {
+		req.closeBody()
 		return nil, err
 	}
 
@@ -179,8 +198,10 @@ func (t *Transport) RoundTrip(req *Request) (resp *Response, err error) {
 	// host (for http or https), the http proxy, or the http proxy
 	// pre-CONNECTed to https server.  In any case, we'll be ready
 	// to send it requests.
-	pconn, err := t.getConn(cm)
+	pconn, err := t.getConn(req, cm)
 	if err != nil {
+		t.setReqCanceler(req, nil)
+		req.closeBody()
 		return nil, err
 	}
 
@@ -218,9 +239,6 @@ func (t *Transport) CloseIdleConnections() {
 	t.idleConn = nil
 	t.idleConnCh = nil
 	t.idleMu.Unlock()
-	if m == nil {
-		return
-	}
 	for _, conns := range m {
 		for _, pconn := range conns {
 			pconn.close()
@@ -232,10 +250,10 @@ func (t *Transport) CloseIdleConnections() {
 // connection.
 func (t *Transport) CancelRequest(req *Request) {
 	t.reqMu.Lock()
-	pc := t.reqConn[req]
+	cancel := t.reqCanceler[req]
 	t.reqMu.Unlock()
-	if pc != nil {
-		pc.conn.Close()
+	if cancel != nil {
+		cancel()
 	}
 }
 
@@ -243,24 +261,49 @@ func (t *Transport) CancelRequest(req *Request) {
 // Private implementation past this point.
 //
 
-func getenvEitherCase(k string) string {
-	if v := os.Getenv(strings.ToUpper(k)); v != "" {
-		return v
+var (
+	httpProxyEnv = &envOnce{
+		names: []string{"HTTP_PROXY", "http_proxy"},
 	}
-	return os.Getenv(strings.ToLower(k))
+	noProxyEnv = &envOnce{
+		names: []string{"NO_PROXY", "no_proxy"},
+	}
+)
+
+// envOnce looks up an environment variable (optionally by multiple
+// names) once. It mitigates expensive lookups on some platforms
+// (e.g. Windows).
+type envOnce struct {
+	names []string
+	once  sync.Once
+	val   string
+}
+
+func (e *envOnce) Get() string {
+	e.once.Do(e.init)
+	return e.val
 }
 
-func (t *Transport) connectMethodForRequest(treq *transportRequest) (*connectMethod, error) {
-	cm := &connectMethod{
-		targetScheme: treq.URL.Scheme,
-		targetAddr:   canonicalAddr(treq.URL),
+func (e *envOnce) init() {
+	for _, n := range e.names {
+		e.val = os.Getenv(n)
+		if e.val != "" {
+			return
+		}
 	}
+}
+
+// reset is used by tests
+func (e *envOnce) reset() {
+	e.once = sync.Once{}
+	e.val = ""
+}
+
+func (t *Transport) connectMethodForRequest(treq *transportRequest) (cm connectMethod, err error) {
+	cm.targetScheme = treq.URL.Scheme
+	cm.targetAddr = canonicalAddr(treq.URL)
 	if t.Proxy != nil {
-		var err error
 		cm.proxyURL, err = t.Proxy(treq.Request)
-		if err != nil {
-			return nil, err
-		}
 	}
 	return cm, nil
 }
@@ -316,7 +359,7 @@ func (t *Transport) putIdleConn(pconn *persistConn) bool {
 		}
 	}
 	if t.idleConn == nil {
-		t.idleConn = make(map[string][]*persistConn)
+		t.idleConn = make(map[connectMethodKey][]*persistConn)
 	}
 	if len(t.idleConn[key]) >= max {
 		t.idleMu.Unlock()
@@ -336,7 +379,7 @@ func (t *Transport) putIdleConn(pconn *persistConn) bool {
 // getIdleConnCh returns a channel to receive and return idle
 // persistent connection for the given connectMethod.
 // It may return nil, if persistent connections are not being used.
-func (t *Transport) getIdleConnCh(cm *connectMethod) chan *persistConn {
+func (t *Transport) getIdleConnCh(cm connectMethod) chan *persistConn {
 	if t.DisableKeepAlives {
 		return nil
 	}
@@ -344,7 +387,7 @@ func (t *Transport) getIdleConnCh(cm *connectMethod) chan *persistConn {
 	t.idleMu.Lock()
 	defer t.idleMu.Unlock()
 	if t.idleConnCh == nil {
-		t.idleConnCh = make(map[string]chan *persistConn)
+		t.idleConnCh = make(map[connectMethodKey]chan *persistConn)
 	}
 	ch, ok := t.idleConnCh[key]
 	if !ok {
@@ -354,7 +397,7 @@ func (t *Transport) getIdleConnCh(cm *connectMethod) chan *persistConn {
 	return ch
 }
 
-func (t *Transport) getIdleConn(cm *connectMethod) (pconn *persistConn) {
+func (t *Transport) getIdleConn(cm connectMethod) (pconn *persistConn) {
 	key := cm.key()
 	t.idleMu.Lock()
 	defer t.idleMu.Unlock()
@@ -373,7 +416,7 @@ func (t *Transport) getIdleConn(cm *connectMethod) (pconn *persistConn) {
 			// 2 or more cached connections; pop last
 			// TODO: queue?
 			pconn = pconns[len(pconns)-1]
-			t.idleConn[key] = pconns[0 : len(pconns)-1]
+			t.idleConn[key] = pconns[:len(pconns)-1]
 		}
 		if !pconn.isBroken() {
 			return
@@ -381,16 +424,16 @@ func (t *Transport) getIdleConn(cm *connectMethod) (pconn *persistConn) {
 	}
 }
 
-func (t *Transport) setReqConn(r *Request, pc *persistConn) {
+func (t *Transport) setReqCanceler(r *Request, fn func()) {
 	t.reqMu.Lock()
 	defer t.reqMu.Unlock()
-	if t.reqConn == nil {
-		t.reqConn = make(map[*Request]*persistConn)
+	if t.reqCanceler == nil {
+		t.reqCanceler = make(map[*Request]func())
 	}
-	if pc != nil {
-		t.reqConn[r] = pc
+	if fn != nil {
+		t.reqCanceler[r] = fn
 	} else {
-		delete(t.reqConn, r)
+		delete(t.reqCanceler, r)
 	}
 }
 
@@ -405,7 +448,7 @@ func (t *Transport) dial(network, addr string) (c net.Conn, err error) {
 // specified in the connectMethod.  This includes doing a proxy CONNECT
 // and/or setting up TLS.  If this doesn't return an error, the persistConn
 // is ready to write requests to.
-func (t *Transport) getConn(cm *connectMethod) (*persistConn, error) {
+func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error) {
 	if pc := t.getIdleConn(cm); pc != nil {
 		return pc, nil
 	}
@@ -415,6 +458,16 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, error) {
 		err error
 	}
 	dialc := make(chan dialRes)
+
+	handlePendingDial := func() {
+		if v := <-dialc; v.err == nil {
+			t.putIdleConn(v.pc)
+		}
+	}
+
+	cancelc := make(chan struct{})
+	t.setReqCanceler(req, func() { close(cancelc) })
+
 	go func() {
 		pc, err := t.dialConn(cm)
 		dialc <- dialRes{pc, err}
@@ -431,16 +484,15 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, error) {
 		// else's dial that they didn't use.
 		// But our dial is still going, so give it away
 		// when it finishes:
-		go func() {
-			if v := <-dialc; v.err == nil {
-				t.putIdleConn(v.pc)
-			}
-		}()
+		go handlePendingDial()
 		return pc, nil
+	case <-cancelc:
+		go handlePendingDial()
+		return nil, errors.New("net/http: request canceled while waiting for connection")
 	}
 }
 
-func (t *Transport) dialConn(cm *connectMethod) (*persistConn, error) {
+func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
 	conn, err := t.dial("tcp", cm.addr())
 	if err != nil {
 		if cm.proxyURL != nil {
@@ -452,12 +504,13 @@ func (t *Transport) dialConn(cm *connectMethod) (*persistConn, error) {
 	pa := cm.proxyAuth()
 
 	pconn := &persistConn{
-		t:        t,
-		cacheKey: cm.key(),
-		conn:     conn,
-		reqch:    make(chan requestAndChan, 50),
-		writech:  make(chan writeRequest, 50),
-		closech:  make(chan struct{}),
+		t:          t,
+		cacheKey:   cm.key(),
+		conn:       conn,
+		reqch:      make(chan requestAndChan, 1),
+		writech:    make(chan writeRequest, 1),
+		closech:    make(chan struct{}),
+		writeErrCh: make(chan error, 1),
 	}
 
 	switch {
@@ -511,19 +564,38 @@ func (t *Transport) dialConn(cm *connectMethod) (*persistConn, error) {
 				cfg = &clone
 			}
 		}
-		conn = tls.Client(conn, cfg)
-		if err = conn.(*tls.Conn).Handshake(); err != nil {
+		plainConn := conn
+		tlsConn := tls.Client(plainConn, cfg)
+		errc := make(chan error, 2)
+		var timer *time.Timer // for canceling TLS handshake
+		if d := t.TLSHandshakeTimeout; d != 0 {
+			timer = time.AfterFunc(d, func() {
+				errc <- tlsHandshakeTimeoutError{}
+			})
+		}
+		go func() {
+			err := tlsConn.Handshake()
+			if timer != nil {
+				timer.Stop()
+			}
+			errc <- err
+		}()
+		if err := <-errc; err != nil {
+			plainConn.Close()
 			return nil, err
 		}
 		if !cfg.InsecureSkipVerify {
-			if err = conn.(*tls.Conn).VerifyHostname(cfg.ServerName); err != nil {
+			if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil {
+				plainConn.Close()
 				return nil, err
 			}
 		}
-		pconn.conn = conn
+		cs := tlsConn.ConnectionState()
+		pconn.tlsState = &cs
+		pconn.conn = tlsConn
 	}
 
-	pconn.br = bufio.NewReader(pconn.conn)
+	pconn.br = bufio.NewReader(noteEOFReader{pconn.conn, &pconn.sawEOF})
 	pconn.bw = bufio.NewWriter(pconn.conn)
 	go pconn.readLoop()
 	go pconn.writeLoop()
@@ -550,7 +622,7 @@ func useProxy(addr string) bool {
 		}
 	}
 
-	no_proxy := getenvEitherCase("NO_PROXY")
+	no_proxy := noProxyEnv.Get()
 	if no_proxy == "*" {
 		return false
 	}
@@ -590,8 +662,8 @@ func useProxy(addr string) bool {
 //
 // Cache key form                Description
 // -----------------             -------------------------
-// ||http|foo.com                http directly to server, no proxy
-// ||https|foo.com               https directly to server, no proxy
+// |http|foo.com                 http directly to server, no proxy
+// |https|foo.com                https directly to server, no proxy
 // http://proxy.com|https|foo.com  http to proxy, then CONNECT to foo.com
 // http://proxy.com|http           http to proxy, http to anywhere after that
 //
@@ -603,20 +675,20 @@ type connectMethod struct {
 	targetAddr   string   // Not used if proxy + http targetScheme (4th example in table)
 }
 
-func (ck *connectMethod) key() string {
-	return ck.String() // TODO: use a struct type instead
-}
-
-func (ck *connectMethod) String() string {
+func (cm *connectMethod) key() connectMethodKey {
 	proxyStr := ""
-	targetAddr := ck.targetAddr
-	if ck.proxyURL != nil {
-		proxyStr = ck.proxyURL.String()
-		if ck.targetScheme == "http" {
+	targetAddr := cm.targetAddr
+	if cm.proxyURL != nil {
+		proxyStr = cm.proxyURL.String()
+		if cm.targetScheme == "http" {
 			targetAddr = ""
 		}
 	}
-	return strings.Join([]string{proxyStr, ck.targetScheme, targetAddr}, "|")
+	return connectMethodKey{
+		proxy:  proxyStr,
+		scheme: cm.targetScheme,
+		addr:   targetAddr,
+	}
 }
 
 // addr returns the first hop "host:port" to which we need to TCP connect.
@@ -637,22 +709,41 @@ func (cm *connectMethod) tlsHost() string {
 	return h
 }
 
+// connectMethodKey is the map key version of connectMethod, with a
+// stringified proxy URL (or the empty string) instead of a pointer to
+// a URL.
+type connectMethodKey struct {
+	proxy, scheme, addr string
+}
+
+func (k connectMethodKey) String() string {
+	// Only used by tests.
+	return fmt.Sprintf("%s|%s|%s", k.proxy, k.scheme, k.addr)
+}
+
 // persistConn wraps a connection, usually a persistent one
 // (but may be used for non-keep-alive requests as well)
 type persistConn struct {
 	t        *Transport
-	cacheKey string // its connectMethod.String()
+	cacheKey connectMethodKey
 	conn     net.Conn
-	closed   bool                // whether conn has been closed
+	tlsState *tls.ConnectionState
 	br       *bufio.Reader       // from conn
+	sawEOF   bool                // whether we've seen EOF from conn; owned by readLoop
 	bw       *bufio.Writer       // to conn
 	reqch    chan requestAndChan // written by roundTrip; read by readLoop
 	writech  chan writeRequest   // written by roundTrip; read by writeLoop
-	closech  chan struct{}       // broadcast close when readLoop (TCP connection) closes
+	closech  chan struct{}       // closed when conn closed
 	isProxy  bool
+	// writeErrCh passes the request write error (usually nil)
+	// from the writeLoop goroutine to the readLoop which passes
+	// it off to the res.Body reader, which then uses it to decide
+	// whether or not a connection can be reused. Issue 7569.
+	writeErrCh chan error
 
-	lk                   sync.Mutex // guards following 3 fields
+	lk                   sync.Mutex // guards following fields
 	numExpectedResponses int
+	closed               bool // whether conn has been closed
 	broken               bool // an error has happened on this connection; marked broken so it's not reused.
 	// mutateHeaderFunc is an optional func to modify extra
 	// headers on each outbound request before it's written. (the
@@ -660,6 +751,7 @@ type persistConn struct {
 	mutateHeaderFunc func(Header)
 }
 
+// isBroken reports whether this connection is in a known broken state.
 func (pc *persistConn) isBroken() bool {
 	pc.lk.Lock()
 	b := pc.broken
@@ -667,6 +759,10 @@ func (pc *persistConn) isBroken() bool {
 	return b
 }
 
+func (pc *persistConn) cancelRequest() {
+	pc.conn.Close()
+}
+
 var remoteSideClosedFunc func(error) bool // or nil to use default
 
 func remoteSideClosed(err error) bool {
@@ -680,7 +776,6 @@ func remoteSideClosed(err error) bool {
 }
 
 func (pc *persistConn) readLoop() {
-	defer close(pc.closech)
 	alive := true
 
 	for alive {
@@ -688,12 +783,14 @@ func (pc *persistConn) readLoop() {
 
 		pc.lk.Lock()
 		if pc.numExpectedResponses == 0 {
-			pc.closeLocked()
-			pc.lk.Unlock()
-			if len(pb) > 0 {
-				log.Printf("Unsolicited response received on idle HTTP channel starting with %q; err=%v",
-					string(pb), err)
+			if !pc.closed {
+				pc.closeLocked()
+				if len(pb) > 0 {
+					log.Printf("Unsolicited response received on idle HTTP channel starting with %q; err=%v",
+						string(pb), err)
+				}
 			}
+			pc.lk.Unlock()
 			return
 		}
 		pc.lk.Unlock()
@@ -712,6 +809,11 @@ func (pc *persistConn) readLoop() {
 				resp, err = ReadResponse(pc.br, rc.req)
 			}
 		}
+
+		if resp != nil {
+			resp.TLS = pc.tlsState
+		}
+
 		hasBody := resp != nil && rc.req.Method != "HEAD" && resp.ContentLength != 0
 
 		if err != nil {
@@ -721,13 +823,7 @@ func (pc *persistConn) readLoop() {
 				resp.Header.Del("Content-Encoding")
 				resp.Header.Del("Content-Length")
 				resp.ContentLength = -1
-				gzReader, zerr := gzip.NewReader(resp.Body)
-				if zerr != nil {
-					pc.close()
-					err = zerr
-				} else {
-					resp.Body = &readerAndCloser{gzReader, resp.Body}
-				}
+				resp.Body = &gzipReader{body: resp.Body}
 			}
 			resp.Body = &bodyEOFSignal{body: resp.Body}
 		}
@@ -750,24 +846,18 @@ func (pc *persistConn) readLoop() {
 				return nil
 			}
 			resp.Body.(*bodyEOFSignal).fn = func(err error) {
-				alive1 := alive
-				if err != nil {
-					alive1 = false
-				}
-				if alive1 && !pc.t.putIdleConn(pc) {
-					alive1 = false
-				}
-				if !alive1 || pc.isBroken() {
-					pc.close()
-				}
-				waitForBodyRead <- alive1
+				waitForBodyRead <- alive &&
+					err == nil &&
+					!pc.sawEOF &&
+					pc.wroteRequest() &&
+					pc.t.putIdleConn(pc)
 			}
 		}
 
 		if alive && !hasBody {
-			if !pc.t.putIdleConn(pc) {
-				alive = false
-			}
+			alive = !pc.sawEOF &&
+				pc.wroteRequest() &&
+				pc.t.putIdleConn(pc)
 		}
 
 		rc.ch <- responseAndError{resp, err}
@@ -775,10 +865,14 @@ func (pc *persistConn) readLoop() {
 		// Wait for the just-returned response body to be fully consumed
 		// before we race and peek on the underlying bufio reader.
 		if waitForBodyRead != nil {
-			alive = <-waitForBodyRead
+			select {
+			case alive = <-waitForBodyRead:
+			case <-pc.closech:
+				alive = false
+			}
 		}
 
-		pc.t.setReqConn(rc.req, nil)
+		pc.t.setReqCanceler(rc.req, nil)
 
 		if !alive {
 			pc.close()
@@ -800,14 +894,44 @@ func (pc *persistConn) writeLoop() {
 			}
 			if err != nil {
 				pc.markBroken()
+				wr.req.Request.closeBody()
 			}
-			wr.ch <- err
+			pc.writeErrCh <- err // to the body reader, which might recycle us
+			wr.ch <- err         // to the roundTrip function
 		case <-pc.closech:
 			return
 		}
 	}
 }
 
+// wroteRequest is a check before recycling a connection that the previous write
+// (from writeLoop above) happened and was successful.
+func (pc *persistConn) wroteRequest() bool {
+	select {
+	case err := <-pc.writeErrCh:
+		// Common case: the write happened well before the response, so
+		// avoid creating a timer.
+		return err == nil
+	default:
+		// Rare case: the request was written in writeLoop above but
+		// before it could send to pc.writeErrCh, the reader read it
+		// all, processed it, and called us here. In this case, give the
+		// write goroutine a bit of time to finish its send.
+		//
+		// Less rare case: We also get here in the legitimate case of
+		// Issue 7569, where the writer is still writing (or stalled),
+		// but the server has already replied. In this case, we don't
+		// want to wait too long, and we want to return false so this
+		// connection isn't re-used.
+		select {
+		case err := <-pc.writeErrCh:
+			return err == nil
+		case <-time.After(50 * time.Millisecond):
+			return false
+		}
+	}
+}
+
 type responseAndError struct {
 	res *Response
 	err error
@@ -832,8 +956,20 @@ type writeRequest struct {
 	ch  chan<- error
 }
 
+type httpError struct {
+	err     string
+	timeout bool
+}
+
+func (e *httpError) Error() string   { return e.err }
+func (e *httpError) Timeout() bool   { return e.timeout }
+func (e *httpError) Temporary() bool { return true }
+
+var errTimeout error = &httpError{err: "net/http: timeout awaiting response headers", timeout: true}
+var errClosed error = &httpError{err: "net/http: transport closed before response was received"}
+
 func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err error) {
-	pc.t.setReqConn(req.Request, pc)
+	pc.t.setReqCanceler(req.Request, pc.cancelRequest)
 	pc.lk.Lock()
 	pc.numExpectedResponses++
 	headerFn := pc.mutateHeaderFunc
@@ -902,11 +1038,11 @@ WaitResponse:
 			pconnDeadCh = nil                               // avoid spinning
 			failTicker = time.After(100 * time.Millisecond) // arbitrary time to wait for resc
 		case <-failTicker:
-			re = responseAndError{err: errors.New("net/http: transport closed before response was received")}
+			re = responseAndError{err: errClosed}
 			break WaitResponse
 		case <-respHeaderTimer:
 			pc.close()
-			re = responseAndError{err: errors.New("net/http: timeout awaiting response headers")}
+			re = responseAndError{err: errTimeout}
 			break WaitResponse
 		case re = <-resc:
 			break WaitResponse
@@ -918,7 +1054,7 @@ WaitResponse:
 	pc.lk.Unlock()
 
 	if re.err != nil {
-		pc.t.setReqConn(req.Request, nil)
+		pc.t.setReqCanceler(req.Request, nil)
 	}
 	return re.res, re.err
 }
@@ -943,6 +1079,7 @@ func (pc *persistConn) closeLocked() {
 	if !pc.closed {
 		pc.conn.Close()
 		pc.closed = true
+		close(pc.closech)
 	}
 	pc.mutateHeaderFunc = nil
 }
@@ -1025,7 +1162,47 @@ func (es *bodyEOFSignal) condfn(err error) {
 	es.fn = nil
 }
 
+// gzipReader wraps a response body so it can lazily
+// call gzip.NewReader on the first call to Read
+type gzipReader struct {
+	body io.ReadCloser // underlying Response.Body
+	zr   io.Reader     // lazily-initialized gzip reader
+}
+
+func (gz *gzipReader) Read(p []byte) (n int, err error) {
+	if gz.zr == nil {
+		gz.zr, err = gzip.NewReader(gz.body)
+		if err != nil {
+			return 0, err
+		}
+	}
+	return gz.zr.Read(p)
+}
+
+func (gz *gzipReader) Close() error {
+	return gz.body.Close()
+}
+
 type readerAndCloser struct {
 	io.Reader
 	io.Closer
 }
+
+type tlsHandshakeTimeoutError struct{}
+
+func (tlsHandshakeTimeoutError) Timeout() bool   { return true }
+func (tlsHandshakeTimeoutError) Temporary() bool { return true }
+func (tlsHandshakeTimeoutError) Error() string   { return "net/http: TLS handshake timeout" }
+
+type noteEOFReader struct {
+	r      io.Reader
+	sawEOF *bool
+}
+
+func (nr noteEOFReader) Read(p []byte) (n int, err error) {
+	n, err = nr.r.Read(p)
+	if err == io.EOF {
+		*nr.sawEOF = true
+	}
+	return
+}
diff --git a/src/pkg/net/http/transport_test.go b/src/pkg/net/http/transport_test.go
index e4df30a..964ca0f 100644
--- a/src/pkg/net/http/transport_test.go
+++ b/src/pkg/net/http/transport_test.go
@@ -11,9 +11,12 @@ import (
 	"bytes"
 	"compress/gzip"
 	"crypto/rand"
+	"crypto/tls"
+	"errors"
 	"fmt"
 	"io"
 	"io/ioutil"
+	"log"
 	"net"
 	"net/http"
 	. "net/http"
@@ -54,21 +57,21 @@ func (c *testCloseConn) Close() error {
 // been closed.
 type testConnSet struct {
 	t      *testing.T
+	mu     sync.Mutex // guards closed and list
 	closed map[net.Conn]bool
 	list   []net.Conn // in order created
-	mutex  sync.Mutex
 }
 
 func (tcs *testConnSet) insert(c net.Conn) {
-	tcs.mutex.Lock()
-	defer tcs.mutex.Unlock()
+	tcs.mu.Lock()
+	defer tcs.mu.Unlock()
 	tcs.closed[c] = false
 	tcs.list = append(tcs.list, c)
 }
 
 func (tcs *testConnSet) remove(c net.Conn) {
-	tcs.mutex.Lock()
-	defer tcs.mutex.Unlock()
+	tcs.mu.Lock()
+	defer tcs.mu.Unlock()
 	tcs.closed[c] = true
 }
 
@@ -91,11 +94,19 @@ func makeTestDial(t *testing.T) (*testConnSet, func(n, addr string) (net.Conn, e
 }
 
 func (tcs *testConnSet) check(t *testing.T) {
-	tcs.mutex.Lock()
-	defer tcs.mutex.Unlock()
-
-	for i, c := range tcs.list {
-		if !tcs.closed[c] {
+	tcs.mu.Lock()
+	defer tcs.mu.Unlock()
+	for i := 4; i >= 0; i-- {
+		for i, c := range tcs.list {
+			if tcs.closed[c] {
+				continue
+			}
+			if i != 0 {
+				tcs.mu.Unlock()
+				time.Sleep(50 * time.Millisecond)
+				tcs.mu.Lock()
+				continue
+			}
 			t.Errorf("TCP connection #%d, %p (of %d total) was not closed", i+1, c, len(tcs.list))
 		}
 	}
@@ -271,6 +282,58 @@ func TestTransportIdleCacheKeys(t *testing.T) {
 	}
 }
 
+// Tests that the HTTP transport re-uses connections when a client
+// reads to the end of a response Body without closing it.
+func TestTransportReadToEndReusesConn(t *testing.T) {
+	defer afterTest(t)
+	const msg = "foobar"
+
+	var addrSeen map[string]int
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		addrSeen[r.RemoteAddr]++
+		if r.URL.Path == "/chunked/" {
+			w.WriteHeader(200)
+			w.(http.Flusher).Flush()
+		} else {
+			w.Header().Set("Content-Type", strconv.Itoa(len(msg)))
+			w.WriteHeader(200)
+		}
+		w.Write([]byte(msg))
+	}))
+	defer ts.Close()
+
+	buf := make([]byte, len(msg))
+
+	for pi, path := range []string{"/content-length/", "/chunked/"} {
+		wantLen := []int{len(msg), -1}[pi]
+		addrSeen = make(map[string]int)
+		for i := 0; i < 3; i++ {
+			res, err := http.Get(ts.URL + path)
+			if err != nil {
+				t.Errorf("Get %s: %v", path, err)
+				continue
+			}
+			// We want to close this body eventually (before the
+			// defer afterTest at top runs), but not before the
+			// len(addrSeen) check at the bottom of this test,
+			// since Closing this early in the loop would risk
+			// making connections be re-used for the wrong reason.
+			defer res.Body.Close()
+
+			if res.ContentLength != int64(wantLen) {
+				t.Errorf("%s res.ContentLength = %d; want %d", path, res.ContentLength, wantLen)
+			}
+			n, err := res.Body.Read(buf)
+			if n != len(msg) || err != io.EOF {
+				t.Errorf("%s Read = %v, %v; want %d, EOF", path, n, err, len(msg))
+			}
+		}
+		if len(addrSeen) != 1 {
+			t.Errorf("for %s, server saw %d distinct client addresses; want 1", path, len(addrSeen))
+		}
+	}
+}
+
 func TestTransportMaxPerHostIdleConns(t *testing.T) {
 	defer afterTest(t)
 	resch := make(chan string)
@@ -295,10 +358,11 @@ func TestTransportMaxPerHostIdleConns(t *testing.T) {
 		resp, err := c.Get(ts.URL)
 		if err != nil {
 			t.Error(err)
+			return
 		}
-		_, err = ioutil.ReadAll(resp.Body)
-		if err != nil {
-			t.Fatalf("ReadAll: %v", err)
+		if _, err := ioutil.ReadAll(resp.Body); err != nil {
+			t.Errorf("ReadAll: %v", err)
+			return
 		}
 		donech <- true
 	}
@@ -739,8 +803,38 @@ func TestTransportGzipRecursive(t *testing.T) {
 	}
 }
 
+// golang.org/issue/7750: request fails when server replies with
+// a short gzip body
+func TestTransportGzipShort(t *testing.T) {
+	defer afterTest(t)
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		w.Header().Set("Content-Encoding", "gzip")
+		w.Write([]byte{0x1f, 0x8b})
+	}))
+	defer ts.Close()
+
+	tr := &Transport{}
+	defer tr.CloseIdleConnections()
+	c := &Client{Transport: tr}
+	res, err := c.Get(ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer res.Body.Close()
+	_, err = ioutil.ReadAll(res.Body)
+	if err == nil {
+		t.Fatal("Expect an error from reading a body.")
+	}
+	if err != io.ErrUnexpectedEOF {
+		t.Errorf("ReadAll error = %v; want io.ErrUnexpectedEOF", err)
+	}
+}
+
 // tests that persistent goroutine connections shut down when no longer desired.
 func TestTransportPersistConnLeak(t *testing.T) {
+	if runtime.GOOS == "plan9" {
+		t.Skip("skipping test; see http://golang.org/issue/7237")
+	}
 	defer afterTest(t)
 	gotReqCh := make(chan bool)
 	unblockCh := make(chan bool)
@@ -798,8 +892,8 @@ func TestTransportPersistConnLeak(t *testing.T) {
 
 	// We expect 0 or 1 extra goroutine, empirically.  Allow up to 5.
 	// Previously we were leaking one per numReq.
-	t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth)
 	if int(growth) > 5 {
+		t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth)
 		t.Error("too many new goroutines")
 	}
 }
@@ -807,6 +901,9 @@ func TestTransportPersistConnLeak(t *testing.T) {
 // golang.org/issue/4531: Transport leaks goroutines when
 // request.ContentLength is explicitly short
 func TestTransportPersistConnLeakShortBody(t *testing.T) {
+	if runtime.GOOS == "plan9" {
+		t.Skip("skipping test; see http://golang.org/issue/7237")
+	}
 	defer afterTest(t)
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
 	}))
@@ -1014,6 +1111,9 @@ func TestTransportConcurrency(t *testing.T) {
 }
 
 func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
+	if runtime.GOOS == "plan9" {
+		t.Skip("skipping test; see http://golang.org/issue/7237")
+	}
 	defer afterTest(t)
 	const debug = false
 	mux := NewServeMux()
@@ -1075,6 +1175,9 @@ func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
 }
 
 func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) {
+	if runtime.GOOS == "plan9" {
+		t.Skip("skipping test; see http://golang.org/issue/7237")
+	}
 	defer afterTest(t)
 	const debug = false
 	mux := NewServeMux()
@@ -1147,9 +1250,13 @@ func TestTransportResponseHeaderTimeout(t *testing.T) {
 	if testing.Short() {
 		t.Skip("skipping timeout test in -short mode")
 	}
+	inHandler := make(chan bool, 1)
 	mux := NewServeMux()
-	mux.HandleFunc("/fast", func(w ResponseWriter, r *Request) {})
+	mux.HandleFunc("/fast", func(w ResponseWriter, r *Request) {
+		inHandler <- true
+	})
 	mux.HandleFunc("/slow", func(w ResponseWriter, r *Request) {
+		inHandler <- true
 		time.Sleep(2 * time.Second)
 	})
 	ts := httptest.NewServer(mux)
@@ -1172,7 +1279,27 @@ func TestTransportResponseHeaderTimeout(t *testing.T) {
 	}
 	for i, tt := range tests {
 		res, err := c.Get(ts.URL + tt.path)
+		select {
+		case <-inHandler:
+		case <-time.After(5 * time.Second):
+			t.Errorf("never entered handler for test index %d, %s", i, tt.path)
+			continue
+		}
 		if err != nil {
+			uerr, ok := err.(*url.Error)
+			if !ok {
+				t.Errorf("error is not an url.Error; got: %#v", err)
+				continue
+			}
+			nerr, ok := uerr.Err.(net.Error)
+			if !ok {
+				t.Errorf("error does not satisfy net.Error interface; got: %#v", err)
+				continue
+			}
+			if !nerr.Timeout() {
+				t.Errorf("want timeout error; got: %q", nerr)
+				continue
+			}
 			if strings.Contains(err.Error(), tt.wantErr) {
 				continue
 			}
@@ -1243,6 +1370,60 @@ func TestTransportCancelRequest(t *testing.T) {
 	}
 }
 
+func TestTransportCancelRequestInDial(t *testing.T) {
+	defer afterTest(t)
+	if testing.Short() {
+		t.Skip("skipping test in -short mode")
+	}
+	var logbuf bytes.Buffer
+	eventLog := log.New(&logbuf, "", 0)
+
+	unblockDial := make(chan bool)
+	defer close(unblockDial)
+
+	inDial := make(chan bool)
+	tr := &Transport{
+		Dial: func(network, addr string) (net.Conn, error) {
+			eventLog.Println("dial: blocking")
+			inDial <- true
+			<-unblockDial
+			return nil, errors.New("nope")
+		},
+	}
+	cl := &Client{Transport: tr}
+	gotres := make(chan bool)
+	req, _ := NewRequest("GET", "http://something.no-network.tld/", nil)
+	go func() {
+		_, err := cl.Do(req)
+		eventLog.Printf("Get = %v", err)
+		gotres <- true
+	}()
+
+	select {
+	case <-inDial:
+	case <-time.After(5 * time.Second):
+		t.Fatal("timeout; never saw blocking dial")
+	}
+
+	eventLog.Printf("canceling")
+	tr.CancelRequest(req)
+
+	select {
+	case <-gotres:
+	case <-time.After(5 * time.Second):
+		panic("hang. events are: " + logbuf.String())
+	}
+
+	got := logbuf.String()
+	want := `dial: blocking
+canceling
+Get = Get http://something.no-network.tld/: net/http: request canceled while waiting for connection
+`
+	if got != want {
+		t.Errorf("Got events:\n%s\nWant:\n%s", got, want)
+	}
+}
+
 // golang.org/issue/3672 -- Client can't close HTTP stream
 // Calling Close on a Response.Body used to just read until EOF.
 // Now it actually closes the TCP connection.
@@ -1283,7 +1464,7 @@ func TestTransportCloseResponseBody(t *testing.T) {
 		t.Fatal(err)
 	}
 	if !bytes.Equal(buf, want) {
-		t.Errorf("read %q; want %q", buf, want)
+		t.Fatalf("read %q; want %q", buf, want)
 	}
 	didClose := make(chan error, 1)
 	go func() {
@@ -1372,8 +1553,10 @@ func TestTransportSocketLateBinding(t *testing.T) {
 	dialGate := make(chan bool, 1)
 	tr := &Transport{
 		Dial: func(n, addr string) (net.Conn, error) {
-			<-dialGate
-			return net.Dial(n, addr)
+			if <-dialGate {
+				return net.Dial(n, addr)
+			}
+			return nil, errors.New("manually closed")
 		},
 		DisableKeepAlives: false,
 	}
@@ -1408,7 +1591,7 @@ func TestTransportSocketLateBinding(t *testing.T) {
 		t.Fatalf("/foo came from conn %q; /bar came from %q instead", fooAddr, barAddr)
 	}
 	barRes.Body.Close()
-	dialGate <- true
+	dialGate <- false
 }
 
 // Issue 2184
@@ -1559,13 +1742,11 @@ var proxyFromEnvTests = []proxyFromEnvTest{
 }
 
 func TestProxyFromEnvironment(t *testing.T) {
-	os.Setenv("HTTP_PROXY", "")
-	os.Setenv("http_proxy", "")
-	os.Setenv("NO_PROXY", "")
-	os.Setenv("no_proxy", "")
+	ResetProxyEnv()
 	for _, tt := range proxyFromEnvTests {
 		os.Setenv("HTTP_PROXY", tt.env)
 		os.Setenv("NO_PROXY", tt.noenv)
+		ResetCachedEnvironment()
 		reqURL := tt.req
 		if reqURL == "" {
 			reqURL = "http://example.com"
@@ -1643,6 +1824,308 @@ func TestTransportClosesRequestBody(t *testing.T) {
 	}
 }
 
+func TestTransportTLSHandshakeTimeout(t *testing.T) {
+	defer afterTest(t)
+	if testing.Short() {
+		t.Skip("skipping in short mode")
+	}
+	ln := newLocalListener(t)
+	defer ln.Close()
+	testdonec := make(chan struct{})
+	defer close(testdonec)
+
+	go func() {
+		c, err := ln.Accept()
+		if err != nil {
+			t.Error(err)
+			return
+		}
+		<-testdonec
+		c.Close()
+	}()
+
+	getdonec := make(chan struct{})
+	go func() {
+		defer close(getdonec)
+		tr := &Transport{
+			Dial: func(_, _ string) (net.Conn, error) {
+				return net.Dial("tcp", ln.Addr().String())
+			},
+			TLSHandshakeTimeout: 250 * time.Millisecond,
+		}
+		cl := &Client{Transport: tr}
+		_, err := cl.Get("https://dummy.tld/")
+		if err == nil {
+			t.Error("expected error")
+			return
+		}
+		ue, ok := err.(*url.Error)
+		if !ok {
+			t.Errorf("expected url.Error; got %#v", err)
+			return
+		}
+		ne, ok := ue.Err.(net.Error)
+		if !ok {
+			t.Errorf("expected net.Error; got %#v", err)
+			return
+		}
+		if !ne.Timeout() {
+			t.Errorf("expected timeout error; got %v", err)
+		}
+		if !strings.Contains(err.Error(), "handshake timeout") {
+			t.Errorf("expected 'handshake timeout' in error; got %v", err)
+		}
+	}()
+	select {
+	case <-getdonec:
+	case <-time.After(5 * time.Second):
+		t.Error("test timeout; TLS handshake hung?")
+	}
+}
+
+// Trying to repro golang.org/issue/3514
+func TestTLSServerClosesConnection(t *testing.T) {
+	defer afterTest(t)
+	if runtime.GOOS == "windows" {
+		t.Skip("skipping flaky test on Windows; golang.org/issue/7634")
+	}
+	closedc := make(chan bool, 1)
+	ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		if strings.Contains(r.URL.Path, "/keep-alive-then-die") {
+			conn, _, _ := w.(Hijacker).Hijack()
+			conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo"))
+			conn.Close()
+			closedc <- true
+			return
+		}
+		fmt.Fprintf(w, "hello")
+	}))
+	defer ts.Close()
+	tr := &Transport{
+		TLSClientConfig: &tls.Config{
+			InsecureSkipVerify: true,
+		},
+	}
+	defer tr.CloseIdleConnections()
+	client := &Client{Transport: tr}
+
+	var nSuccess = 0
+	var errs []error
+	const trials = 20
+	for i := 0; i < trials; i++ {
+		tr.CloseIdleConnections()
+		res, err := client.Get(ts.URL + "/keep-alive-then-die")
+		if err != nil {
+			t.Fatal(err)
+		}
+		<-closedc
+		slurp, err := ioutil.ReadAll(res.Body)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if string(slurp) != "foo" {
+			t.Errorf("Got %q, want foo", slurp)
+		}
+
+		// Now try again and see if we successfully
+		// pick a new connection.
+		res, err = client.Get(ts.URL + "/")
+		if err != nil {
+			errs = append(errs, err)
+			continue
+		}
+		slurp, err = ioutil.ReadAll(res.Body)
+		if err != nil {
+			errs = append(errs, err)
+			continue
+		}
+		nSuccess++
+	}
+	if nSuccess > 0 {
+		t.Logf("successes = %d of %d", nSuccess, trials)
+	} else {
+		t.Errorf("All runs failed:")
+	}
+	for _, err := range errs {
+		t.Logf("  err: %v", err)
+	}
+}
+
+// byteFromChanReader is an io.Reader that reads a single byte at a
+// time from the channel.  When the channel is closed, the reader
+// returns io.EOF.
+type byteFromChanReader chan byte
+
+func (c byteFromChanReader) Read(p []byte) (n int, err error) {
+	if len(p) == 0 {
+		return
+	}
+	b, ok := <-c
+	if !ok {
+		return 0, io.EOF
+	}
+	p[0] = b
+	return 1, nil
+}
+
+// Verifies that the Transport doesn't reuse a connection in the case
+// where the server replies before the request has been fully
+// written. We still honor that reply (see TestIssue3595), but don't
+// send future requests on the connection because it's then in a
+// questionable state.
+// golang.org/issue/7569
+func TestTransportNoReuseAfterEarlyResponse(t *testing.T) {
+	defer afterTest(t)
+	var sconn struct {
+		sync.Mutex
+		c net.Conn
+	}
+	var getOkay bool
+	closeConn := func() {
+		sconn.Lock()
+		defer sconn.Unlock()
+		if sconn.c != nil {
+			sconn.c.Close()
+			sconn.c = nil
+			if !getOkay {
+				t.Logf("Closed server connection")
+			}
+		}
+	}
+	defer closeConn()
+
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		if r.Method == "GET" {
+			io.WriteString(w, "bar")
+			return
+		}
+		conn, _, _ := w.(Hijacker).Hijack()
+		sconn.Lock()
+		sconn.c = conn
+		sconn.Unlock()
+		conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo")) // keep-alive
+		go io.Copy(ioutil.Discard, conn)
+	}))
+	defer ts.Close()
+	tr := &Transport{}
+	defer tr.CloseIdleConnections()
+	client := &Client{Transport: tr}
+
+	const bodySize = 256 << 10
+	finalBit := make(byteFromChanReader, 1)
+	req, _ := NewRequest("POST", ts.URL, io.MultiReader(io.LimitReader(neverEnding('x'), bodySize-1), finalBit))
+	req.ContentLength = bodySize
+	res, err := client.Do(req)
+	if err := wantBody(res, err, "foo"); err != nil {
+		t.Errorf("POST response: %v", err)
+	}
+	donec := make(chan bool)
+	go func() {
+		defer close(donec)
+		res, err = client.Get(ts.URL)
+		if err := wantBody(res, err, "bar"); err != nil {
+			t.Errorf("GET response: %v", err)
+			return
+		}
+		getOkay = true // suppress test noise
+	}()
+	time.AfterFunc(5*time.Second, closeConn)
+	select {
+	case <-donec:
+		finalBit <- 'x' // unblock the writeloop of the first Post
+		close(finalBit)
+	case <-time.After(7 * time.Second):
+		t.Fatal("timeout waiting for GET request to finish")
+	}
+}
+
+type errorReader struct {
+	err error
+}
+
+func (e errorReader) Read(p []byte) (int, error) { return 0, e.err }
+
+type closerFunc func() error
+
+func (f closerFunc) Close() error { return f() }
+
+// Issue 6981
+func TestTransportClosesBodyOnError(t *testing.T) {
+	if runtime.GOOS == "plan9" {
+		t.Skip("skipping test; see http://golang.org/issue/7782")
+	}
+	defer afterTest(t)
+	readBody := make(chan error, 1)
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		_, err := ioutil.ReadAll(r.Body)
+		readBody <- err
+	}))
+	defer ts.Close()
+	fakeErr := errors.New("fake error")
+	didClose := make(chan bool, 1)
+	req, _ := NewRequest("POST", ts.URL, struct {
+		io.Reader
+		io.Closer
+	}{
+		io.MultiReader(io.LimitReader(neverEnding('x'), 1<<20), errorReader{fakeErr}),
+		closerFunc(func() error {
+			select {
+			case didClose <- true:
+			default:
+			}
+			return nil
+		}),
+	})
+	res, err := DefaultClient.Do(req)
+	if res != nil {
+		defer res.Body.Close()
+	}
+	if err == nil || !strings.Contains(err.Error(), fakeErr.Error()) {
+		t.Fatalf("Do error = %v; want something containing %q", err, fakeErr.Error())
+	}
+	select {
+	case err := <-readBody:
+		if err == nil {
+			t.Errorf("Unexpected success reading request body from handler; want 'unexpected EOF reading trailer'")
+		}
+	case <-time.After(5 * time.Second):
+		t.Error("timeout waiting for server handler to complete")
+	}
+	select {
+	case <-didClose:
+	default:
+		t.Errorf("didn't see Body.Close")
+	}
+}
+
+func wantBody(res *http.Response, err error, want string) error {
+	if err != nil {
+		return err
+	}
+	slurp, err := ioutil.ReadAll(res.Body)
+	if err != nil {
+		return fmt.Errorf("error reading body: %v", err)
+	}
+	if string(slurp) != want {
+		return fmt.Errorf("body = %q; want %q", slurp, want)
+	}
+	if err := res.Body.Close(); err != nil {
+		return fmt.Errorf("body Close = %v", err)
+	}
+	return nil
+}
+
+func newLocalListener(t *testing.T) net.Listener {
+	ln, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		ln, err = net.Listen("tcp6", "[::1]:0")
+	}
+	if err != nil {
+		t.Fatal(err)
+	}
+	return ln
+}
+
 type countCloseReader struct {
 	n *int
 	io.Reader
diff --git a/src/pkg/net/interface.go b/src/pkg/net/interface.go
index 0713e9c..2e9f1eb 100644
--- a/src/pkg/net/interface.go
+++ b/src/pkg/net/interface.go
@@ -7,11 +7,11 @@ package net
 import "errors"
 
 var (
-	errInvalidInterface         = errors.New("net: invalid interface")
-	errInvalidInterfaceIndex    = errors.New("net: invalid interface index")
-	errInvalidInterfaceName     = errors.New("net: invalid interface name")
-	errNoSuchInterface          = errors.New("net: no such interface")
-	errNoSuchMulticastInterface = errors.New("net: no such multicast interface")
+	errInvalidInterface         = errors.New("invalid network interface")
+	errInvalidInterfaceIndex    = errors.New("invalid network interface index")
+	errInvalidInterfaceName     = errors.New("invalid network interface name")
+	errNoSuchInterface          = errors.New("no such network interface")
+	errNoSuchMulticastInterface = errors.New("no such multicast network interface")
 )
 
 // Interface represents a mapping between network interface name
diff --git a/src/pkg/net/interface_linux.go b/src/pkg/net/interface_linux.go
index 1207c0f..1115d0f 100644
--- a/src/pkg/net/interface_linux.go
+++ b/src/pkg/net/interface_linux.go
@@ -45,15 +45,41 @@ loop:
 	return ift, nil
 }
 
+const (
+	// See linux/if_arp.h.
+	// Note that Linux doesn't support IPv4 over IPv6 tunneling.
+	sysARPHardwareIPv4IPv4 = 768 // IPv4 over IPv4 tunneling
+	sysARPHardwareIPv6IPv6 = 769 // IPv6 over IPv6 tunneling
+	sysARPHardwareIPv6IPv4 = 776 // IPv6 over IPv4 tunneling
+	sysARPHardwareGREIPv4  = 778 // any over GRE over IPv4 tunneling
+	sysARPHardwareGREIPv6  = 823 // any over GRE over IPv6 tunneling
+)
+
 func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) *Interface {
 	ifi := &Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)}
 	for _, a := range attrs {
 		switch a.Attr.Type {
 		case syscall.IFLA_ADDRESS:
+			// We never return any /32 or /128 IP address
+			// prefix on any IP tunnel interface as the
+			// hardware address.
+			switch len(a.Value) {
+			case IPv4len:
+				switch ifim.Type {
+				case sysARPHardwareIPv4IPv4, sysARPHardwareGREIPv4, sysARPHardwareIPv6IPv4:
+					continue
+				}
+			case IPv6len:
+				switch ifim.Type {
+				case sysARPHardwareIPv6IPv6, sysARPHardwareGREIPv6:
+					continue
+				}
+			}
 			var nonzero bool
 			for _, b := range a.Value {
 				if b != 0 {
 					nonzero = true
+					break
 				}
 			}
 			if nonzero {
@@ -147,19 +173,31 @@ loop:
 }
 
 func newAddr(ifi *Interface, ifam *syscall.IfAddrmsg, attrs []syscall.NetlinkRouteAttr) Addr {
-	for _, a := range attrs {
-		if ifi.Flags&FlagPointToPoint != 0 && a.Attr.Type == syscall.IFA_LOCAL ||
-			ifi.Flags&FlagPointToPoint == 0 && a.Attr.Type == syscall.IFA_ADDRESS {
-			switch ifam.Family {
-			case syscall.AF_INET:
-				return &IPNet{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3]), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv4len)}
-			case syscall.AF_INET6:
-				ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv6len)}
-				copy(ifa.IP, a.Value[:])
-				return ifa
+	var ipPointToPoint bool
+	// Seems like we need to make sure whether the IP interface
+	// stack consists of IP point-to-point numbered or unnumbered
+	// addressing over point-to-point link encapsulation.
+	if ifi.Flags&FlagPointToPoint != 0 {
+		for _, a := range attrs {
+			if a.Attr.Type == syscall.IFA_LOCAL {
+				ipPointToPoint = true
+				break
 			}
 		}
 	}
+	for _, a := range attrs {
+		if ipPointToPoint && a.Attr.Type == syscall.IFA_ADDRESS || !ipPointToPoint && a.Attr.Type == syscall.IFA_LOCAL {
+			continue
+		}
+		switch ifam.Family {
+		case syscall.AF_INET:
+			return &IPNet{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3]), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv4len)}
+		case syscall.AF_INET6:
+			ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv6len)}
+			copy(ifa.IP, a.Value[:])
+			return ifa
+		}
+	}
 	return nil
 }
 
diff --git a/src/pkg/net/interface_stub.go b/src/pkg/net/interface_stub.go
index a4eb731..c38fb7f 100644
--- a/src/pkg/net/interface_stub.go
+++ b/src/pkg/net/interface_stub.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 plan9
+// +build nacl plan9 solaris
 
 package net
 
diff --git a/src/pkg/net/ip.go b/src/pkg/net/ip.go
index fd6a7d4..0582009 100644
--- a/src/pkg/net/ip.go
+++ b/src/pkg/net/ip.go
@@ -623,6 +623,9 @@ func parseIPv6(s string, zoneAllowed bool) (ip IP, zone string) {
 		for k := ellipsis + n - 1; k >= ellipsis; k-- {
 			ip[k] = 0
 		}
+	} else if ellipsis >= 0 {
+		// Ellipsis must represent at least one 0 group.
+		return nil, zone
 	}
 	return ip, zone
 }
diff --git a/src/pkg/net/ip_test.go b/src/pkg/net/ip_test.go
index 26b5372..ffeb9d3 100644
--- a/src/pkg/net/ip_test.go
+++ b/src/pkg/net/ip_test.go
@@ -25,6 +25,7 @@ var parseIPTests = []struct {
 	{"fe80::1%lo0", nil},
 	{"fe80::1%911", nil},
 	{"", nil},
+	{"a1:a2:a3:a4::b1:b2:b3:b4", nil}, // Issue 6628
 }
 
 func TestParseIP(t *testing.T) {
diff --git a/src/pkg/net/ipraw_test.go b/src/pkg/net/ipraw_test.go
index ea183f1..0632daf 100644
--- a/src/pkg/net/ipraw_test.go
+++ b/src/pkg/net/ipraw_test.go
@@ -247,7 +247,7 @@ var ipConnLocalNameTests = []struct {
 
 func TestIPConnLocalName(t *testing.T) {
 	switch runtime.GOOS {
-	case "plan9", "windows":
+	case "nacl", "plan9", "windows":
 		t.Skipf("skipping test on %q", runtime.GOOS)
 	default:
 		if os.Getuid() != 0 {
@@ -277,7 +277,7 @@ func TestIPConnRemoteName(t *testing.T) {
 		}
 	}
 
-	raddr := &IPAddr{IP: IPv4(127, 0, 0, 10).To4()}
+	raddr := &IPAddr{IP: IPv4(127, 0, 0, 1).To4()}
 	c, err := DialIP("ip:tcp", &IPAddr{IP: IPv4(127, 0, 0, 1)}, raddr)
 	if err != nil {
 		t.Fatalf("DialIP failed: %v", err)
diff --git a/src/pkg/net/iprawsock_posix.go b/src/pkg/net/iprawsock_posix.go
index 7228532..bbb3f3e 100644
--- a/src/pkg/net/iprawsock_posix.go
+++ b/src/pkg/net/iprawsock_posix.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 windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
@@ -19,7 +19,7 @@ import (
 // that you do not uses these methods if it is important to receive a
 // full packet.
 //
-// The Go 1 compatibliity guidelines make it impossible for us to
+// The Go 1 compatibility guidelines make it impossible for us to
 // change the behavior of these methods; use Read or ReadMsgIP
 // instead.
 
@@ -79,7 +79,7 @@ func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
 	// TODO(cw,rsc): consider using readv if we know the family
 	// type to avoid the header trim/copy
 	var addr *IPAddr
-	n, sa, err := c.fd.ReadFrom(b)
+	n, sa, err := c.fd.readFrom(b)
 	switch sa := sa.(type) {
 	case *syscall.SockaddrInet4:
 		addr = &IPAddr{IP: sa.Addr[0:]}
@@ -112,7 +112,7 @@ func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err
 		return 0, 0, 0, nil, syscall.EINVAL
 	}
 	var sa syscall.Sockaddr
-	n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob)
+	n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
 	switch sa := sa.(type) {
 	case *syscall.SockaddrInet4:
 		addr = &IPAddr{IP: sa.Addr[0:]}
@@ -133,6 +133,9 @@ func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
 	if !c.ok() {
 		return 0, syscall.EINVAL
 	}
+	if c.fd.isConnected {
+		return 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected}
+	}
 	if addr == nil {
 		return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
 	}
@@ -140,7 +143,7 @@ func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
 	if err != nil {
 		return 0, &OpError{"write", c.fd.net, addr, err}
 	}
-	return c.fd.WriteTo(b, sa)
+	return c.fd.writeTo(b, sa)
 }
 
 // WriteTo implements the PacketConn WriteTo method.
@@ -162,6 +165,9 @@ func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error
 	if !c.ok() {
 		return 0, 0, syscall.EINVAL
 	}
+	if c.fd.isConnected {
+		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected}
+	}
 	if addr == nil {
 		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
 	}
@@ -169,7 +175,7 @@ func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error
 	if err != nil {
 		return 0, 0, &OpError{"write", c.fd.net, addr, err}
 	}
-	return c.fd.WriteMsg(b, oob, sa)
+	return c.fd.writeMsg(b, oob, sa)
 }
 
 // DialIP connects to the remote address raddr on the network protocol
diff --git a/src/pkg/net/ipsock.go b/src/pkg/net/ipsock.go
index 8b586ef..dda8578 100644
--- a/src/pkg/net/ipsock.go
+++ b/src/pkg/net/ipsock.go
@@ -16,7 +16,7 @@ var (
 	// networking functionality.
 	supportsIPv4 bool
 
-	// supportsIPv6 reports whether the platfrom supports IPv6
+	// supportsIPv6 reports whether the platform supports IPv6
 	// networking functionality.
 	supportsIPv6 bool
 
@@ -207,7 +207,7 @@ missingBrackets:
 }
 
 func splitHostZone(s string) (host, zone string) {
-	// The IPv6 scoped addressing zone identifer starts after the
+	// The IPv6 scoped addressing zone identifier starts after the
 	// last percent sign.
 	if i := last(s, '%'); i > 0 {
 		host, zone = s[:i], s[i+1:]
@@ -232,7 +232,7 @@ func JoinHostPort(host, port string) string {
 // address or a DNS name and returns an internet protocol family
 // address. It returns a list that contains a pair of different
 // address family addresses when addr is a DNS name and the name has
-// mutiple address family records. The result contains at least one
+// multiple address family records. The result contains at least one
 // address when error is nil.
 func resolveInternetAddr(net, addr string, deadline time.Time) (netaddr, error) {
 	var (
diff --git a/src/pkg/net/ipsock_plan9.go b/src/pkg/net/ipsock_plan9.go
index fcec416..94ceea3 100644
--- a/src/pkg/net/ipsock_plan9.go
+++ b/src/pkg/net/ipsock_plan9.go
@@ -12,19 +12,45 @@ import (
 	"syscall"
 )
 
+func probe(filename, query string) bool {
+	var file *file
+	var err error
+	if file, err = open(filename); err != nil {
+		return false
+	}
+
+	r := false
+	for line, ok := file.readLine(); ok && !r; line, ok = file.readLine() {
+		f := getFields(line)
+		if len(f) < 3 {
+			continue
+		}
+		for i := 0; i < len(f); i++ {
+			if query == f[i] {
+				r = true
+				break
+			}
+		}
+	}
+	file.close()
+	return r
+}
+
 func probeIPv4Stack() bool {
-	// TODO(mikio): implement this when Plan 9 supports IPv6-only
-	// kernel.
-	return true
+	return probe(netdir+"/iproute", "4i")
 }
 
 // probeIPv6Stack returns two boolean values.  If the first boolean
 // value is true, kernel supports basic IPv6 functionality.  If the
 // second boolean value is true, kernel supports IPv6 IPv4-mapping.
 func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
-	// TODO(mikio): implement this once Plan 9 gets an IPv6
-	// protocol stack implementation.
-	return false, false
+	// Plan 9 uses IPv6 natively, see ip(3).
+	r := probe(netdir+"/iproute", "6i")
+	v := false
+	if r {
+		v = probe(netdir+"/iproute", "4i")
+	}
+	return r, v
 }
 
 // parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
@@ -34,12 +60,12 @@ func parsePlan9Addr(s string) (ip IP, iport int, err error) {
 	if i >= 0 {
 		addr = ParseIP(s[:i])
 		if addr == nil {
-			return nil, 0, errors.New("net: parsing IP failed")
+			return nil, 0, errors.New("parsing IP failed")
 		}
 	}
 	p, _, ok := dtoi(s[i+1:], 0)
 	if !ok {
-		return nil, 0, errors.New("net: parsing port failed")
+		return nil, 0, errors.New("parsing port failed")
 	}
 	if p < 0 || p > 0xFFFF {
 		return nil, 0, &AddrError{"invalid port", string(p)}
@@ -133,18 +159,18 @@ func dialPlan9(net string, laddr, raddr Addr) (fd *netFD, err error) {
 		f.Close()
 		return nil, &OpError{"dial", f.Name(), raddr, err}
 	}
-	data, err := os.OpenFile("/net/"+proto+"/"+name+"/data", os.O_RDWR, 0)
+	data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
 	if err != nil {
 		f.Close()
 		return nil, &OpError{"dial", net, raddr, err}
 	}
-	laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local")
+	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
 	if err != nil {
 		data.Close()
 		f.Close()
 		return nil, &OpError{"dial", proto, raddr, err}
 	}
-	return newFD(proto, name, f, data, laddr, raddr), nil
+	return newFD(proto, name, f, data, laddr, raddr)
 }
 
 func listenPlan9(net string, laddr Addr) (fd *netFD, err error) {
@@ -158,20 +184,24 @@ func listenPlan9(net string, laddr Addr) (fd *netFD, err error) {
 		f.Close()
 		return nil, &OpError{"announce", proto, laddr, err}
 	}
-	laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local")
+	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
 	if err != nil {
 		f.Close()
 		return nil, &OpError{Op: "listen", Net: net, Err: err}
 	}
-	return newFD(proto, name, f, nil, laddr, nil), nil
+	return newFD(proto, name, f, nil, laddr, nil)
 }
 
-func (l *netFD) netFD() *netFD {
-	return newFD(l.proto, l.name, l.ctl, l.data, l.laddr, l.raddr)
+func (l *netFD) netFD() (*netFD, error) {
+	return newFD(l.proto, l.n, l.ctl, l.data, l.laddr, l.raddr)
 }
 
 func (l *netFD) acceptPlan9() (fd *netFD, err error) {
 	defer func() { netErr(err) }()
+	if err := l.readLock(); err != nil {
+		return nil, err
+	}
+	defer l.readUnlock()
 	f, err := os.Open(l.dir + "/listen")
 	if err != nil {
 		return nil, &OpError{"accept", l.dir + "/listen", l.laddr, err}
@@ -183,16 +213,16 @@ func (l *netFD) acceptPlan9() (fd *netFD, err error) {
 		return nil, &OpError{"accept", l.dir + "/listen", l.laddr, err}
 	}
 	name := string(buf[:n])
-	data, err := os.OpenFile("/net/"+l.proto+"/"+name+"/data", os.O_RDWR, 0)
+	data, err := os.OpenFile(netdir+"/"+l.proto+"/"+name+"/data", os.O_RDWR, 0)
 	if err != nil {
 		f.Close()
 		return nil, &OpError{"accept", l.proto, l.laddr, err}
 	}
-	raddr, err := readPlan9Addr(l.proto, "/net/"+l.proto+"/"+name+"/remote")
+	raddr, err := readPlan9Addr(l.proto, netdir+"/"+l.proto+"/"+name+"/remote")
 	if err != nil {
 		data.Close()
 		f.Close()
 		return nil, &OpError{"accept", l.proto, l.laddr, err}
 	}
-	return newFD(l.proto, name, f, data, l.laddr, raddr), nil
+	return newFD(l.proto, name, f, data, l.laddr, raddr)
 }
diff --git a/src/pkg/net/ipsock_posix.go b/src/pkg/net/ipsock_posix.go
index a83e525..2ba4c8e 100644
--- a/src/pkg/net/ipsock_posix.go
+++ b/src/pkg/net/ipsock_posix.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 windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 // Internet protocol family sockets for POSIX
 
@@ -40,12 +40,13 @@ func probeIPv4Stack() bool {
 func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 	var probes = []struct {
 		laddr TCPAddr
+		value int
 		ok    bool
 	}{
 		// IPv6 communication capability
-		{TCPAddr{IP: ParseIP("::1")}, false},
+		{laddr: TCPAddr{IP: ParseIP("::1")}, value: 1},
 		// IPv6 IPv4-mapped address communication capability
-		{TCPAddr{IP: IPv4(127, 0, 0, 1)}, false},
+		{laddr: TCPAddr{IP: IPv4(127, 0, 0, 1)}, value: 0},
 	}
 
 	for i := range probes {
@@ -54,7 +55,7 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 			continue
 		}
 		defer closesocket(s)
-		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, probes[i].value)
 		sa, err := probes[i].laddr.sockaddr(syscall.AF_INET6)
 		if err != nil {
 			continue
diff --git a/src/pkg/net/lookup_plan9.go b/src/pkg/net/lookup_plan9.go
index f1204a9..b80ac10 100644
--- a/src/pkg/net/lookup_plan9.go
+++ b/src/pkg/net/lookup_plan9.go
@@ -16,6 +16,10 @@ func query(filename, query string, bufSize int) (res []string, err error) {
 	}
 	defer file.Close()
 
+	_, err = file.Seek(0, 0)
+	if err != nil {
+		return
+	}
 	_, err = file.WriteString(query)
 	if err != nil {
 		return
@@ -45,7 +49,7 @@ func queryCS(net, host, service string) (res []string, err error) {
 	if host == "" {
 		host = "*"
 	}
-	return query("/net/cs", net+"!"+host+"!"+service, 128)
+	return query(netdir+"/cs", net+"!"+host+"!"+service, 128)
 }
 
 func queryCS1(net string, ip IP, port int) (clone, dest string, err error) {
@@ -59,20 +63,41 @@ func queryCS1(net string, ip IP, port int) (clone, dest string, err error) {
 	}
 	f := getFields(lines[0])
 	if len(f) < 2 {
-		return "", "", errors.New("net: bad response from ndb/cs")
+		return "", "", errors.New("bad response from ndb/cs")
 	}
 	clone, dest = f[0], f[1]
 	return
 }
 
 func queryDNS(addr string, typ string) (res []string, err error) {
-	return query("/net/dns", addr+" "+typ, 1024)
+	return query(netdir+"/dns", addr+" "+typ, 1024)
+}
+
+// toLower returns a lower-case version of in. Restricting us to
+// ASCII is sufficient to handle the IP protocol names and allow
+// us to not depend on the strings and unicode packages.
+func toLower(in string) string {
+	for _, c := range in {
+		if 'A' <= c && c <= 'Z' {
+			// Has upper case; need to fix.
+			out := []byte(in)
+			for i := 0; i < len(in); i++ {
+				c := in[i]
+				if 'A' <= c && c <= 'Z' {
+					c += 'a' - 'A'
+				}
+				out[i] = c
+			}
+			return string(out)
+		}
+	}
+	return in
 }
 
 // lookupProtocol looks up IP protocol name and returns
 // the corresponding protocol number.
 func lookupProtocol(name string) (proto int, err error) {
-	lines, err := query("/net/cs", "!protocol="+name, 128)
+	lines, err := query(netdir+"/cs", "!protocol="+toLower(name), 128)
 	if err != nil {
 		return 0, err
 	}
@@ -92,12 +117,13 @@ func lookupProtocol(name string) (proto int, err error) {
 }
 
 func lookupHost(host string) (addrs []string, err error) {
-	// Use /net/cs instead of /net/dns because cs knows about
+	// Use netdir/cs instead of netdir/dns because cs knows about
 	// host names in local network (e.g. from /lib/ndb/local)
-	lines, err := queryCS("tcp", host, "1")
+	lines, err := queryCS("net", host, "1")
 	if err != nil {
 		return
 	}
+loop:
 	for _, line := range lines {
 		f := getFields(line)
 		if len(f) < 2 {
@@ -110,6 +136,12 @@ func lookupHost(host string) (addrs []string, err error) {
 		if ParseIP(addr) == nil {
 			continue
 		}
+		// only return unique addresses
+		for _, a := range addrs {
+			if a == addr {
+				continue loop
+			}
+		}
 		addrs = append(addrs, addr)
 	}
 	return
@@ -167,7 +199,7 @@ func lookupCNAME(name string) (cname string, err error) {
 			return f[2] + ".", nil
 		}
 	}
-	return "", errors.New("net: bad response from ndb/dns")
+	return "", errors.New("bad response from ndb/dns")
 }
 
 func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
diff --git a/src/pkg/net/lookup_unix.go b/src/pkg/net/lookup_unix.go
index 59e9f63..b1d2f8f 100644
--- a/src/pkg/net/lookup_unix.go
+++ b/src/pkg/net/lookup_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 net
 
diff --git a/src/pkg/net/mail/message.go b/src/pkg/net/mail/message.go
index dc2ab44..ba0778c 100644
--- a/src/pkg/net/mail/message.go
+++ b/src/pkg/net/mail/message.go
@@ -159,7 +159,9 @@ func (a *Address) String() string {
 	// If every character is printable ASCII, quoting is simple.
 	allPrintable := true
 	for i := 0; i < len(a.Name); i++ {
-		if !isVchar(a.Name[i]) {
+		// isWSP here should actually be isFWS,
+		// but we don't support folding yet.
+		if !isVchar(a.Name[i]) && !isWSP(a.Name[i]) {
 			allPrintable = false
 			break
 		}
@@ -167,7 +169,7 @@ func (a *Address) String() string {
 	if allPrintable {
 		b := bytes.NewBufferString(`"`)
 		for i := 0; i < len(a.Name); i++ {
-			if !isQtext(a.Name[i]) {
+			if !isQtext(a.Name[i]) && !isWSP(a.Name[i]) {
 				b.WriteByte('\\')
 			}
 			b.WriteByte(a.Name[i])
@@ -361,7 +363,7 @@ func (p *addrParser) consumePhrase() (phrase string, err error) {
 	// Ignore any error if we got at least one word.
 	if err != nil && len(words) == 0 {
 		debug.Printf("consumePhrase: hit err: %v", err)
-		return "", errors.New("mail: missing word in phrase")
+		return "", fmt.Errorf("mail: missing word in phrase: %v", err)
 	}
 	phrase = strings.Join(words, " ")
 	return phrase, nil
@@ -440,11 +442,11 @@ func (p *addrParser) len() int {
 func decodeRFC2047Word(s string) (string, error) {
 	fields := strings.Split(s, "?")
 	if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" {
-		return "", errors.New("mail: address not RFC 2047 encoded")
+		return "", errors.New("address not RFC 2047 encoded")
 	}
 	charset, enc := strings.ToLower(fields[1]), strings.ToLower(fields[2])
 	if charset != "iso-8859-1" && charset != "utf-8" {
-		return "", fmt.Errorf("mail: charset not supported: %q", charset)
+		return "", fmt.Errorf("charset not supported: %q", charset)
 	}
 
 	in := bytes.NewBufferString(fields[3])
@@ -455,7 +457,7 @@ func decodeRFC2047Word(s string) (string, error) {
 	case "q":
 		r = qDecoder{r: in}
 	default:
-		return "", fmt.Errorf("mail: RFC 2047 encoding not supported: %q", enc)
+		return "", fmt.Errorf("RFC 2047 encoding not supported: %q", enc)
 	}
 
 	dec, err := ioutil.ReadAll(r)
@@ -535,3 +537,9 @@ func isVchar(c byte) bool {
 	// Visible (printing) characters.
 	return '!' <= c && c <= '~'
 }
+
+// isWSP returns true if c is a WSP (white space).
+// WSP is a space or horizontal tab (RFC5234 Appendix B).
+func isWSP(c byte) bool {
+	return c == ' ' || c == '\t'
+}
diff --git a/src/pkg/net/mail/message_test.go b/src/pkg/net/mail/message_test.go
index 3c037f3..eb9c8cb 100644
--- a/src/pkg/net/mail/message_test.go
+++ b/src/pkg/net/mail/message_test.go
@@ -8,6 +8,7 @@ import (
 	"bytes"
 	"io/ioutil"
 	"reflect"
+	"strings"
 	"testing"
 	"time"
 )
@@ -116,6 +117,14 @@ func TestDateParsing(t *testing.T) {
 	}
 }
 
+func TestAddressParsingError(t *testing.T) {
+	const txt = "=?iso-8859-2?Q?Bogl=E1rka_Tak=E1cs?= <unknown at gmail.com>"
+	_, err := ParseAddress(txt)
+	if err == nil || !strings.Contains(err.Error(), "charset not supported") {
+		t.Errorf(`mail.ParseAddress(%q) err: %q, want ".*charset not supported.*"`, txt, err)
+	}
+}
+
 func TestAddressParsing(t *testing.T) {
 	tests := []struct {
 		addrsStr string
@@ -277,6 +286,14 @@ func TestAddressFormatting(t *testing.T) {
 			&Address{Name: "Böb", Address: "bob at example.com"},
 			`=?utf-8?q?B=C3=B6b?= <bob at example.com>`,
 		},
+		{
+			&Address{Name: "Bob Jane", Address: "bob at example.com"},
+			`"Bob Jane" <bob at example.com>`,
+		},
+		{
+			&Address{Name: "Böb Jacöb", Address: "bob at example.com"},
+			`=?utf-8?q?B=C3=B6b_Jac=C3=B6b?= <bob at example.com>`,
+		},
 	}
 	for _, test := range tests {
 		s := test.addr.String()
diff --git a/src/pkg/net/multicast_test.go b/src/pkg/net/multicast_test.go
index 5660fd4..63dbce8 100644
--- a/src/pkg/net/multicast_test.go
+++ b/src/pkg/net/multicast_test.go
@@ -25,8 +25,10 @@ var ipv4MulticastListenerTests = []struct {
 // port.
 func TestIPv4MulticastListener(t *testing.T) {
 	switch runtime.GOOS {
-	case "plan9":
+	case "nacl", "plan9":
 		t.Skipf("skipping test on %q", runtime.GOOS)
+	case "solaris":
+		t.Skipf("skipping test on solaris, see issue 7399")
 	}
 
 	closer := func(cs []*UDPConn) {
@@ -93,8 +95,10 @@ var ipv6MulticastListenerTests = []struct {
 // port.
 func TestIPv6MulticastListener(t *testing.T) {
 	switch runtime.GOOS {
-	case "plan9", "solaris":
+	case "plan9":
 		t.Skipf("skipping test on %q", runtime.GOOS)
+	case "solaris":
+		t.Skipf("skipping test on solaris, see issue 7399")
 	}
 	if !supportsIPv6 {
 		t.Skip("ipv6 is not supported")
diff --git a/src/pkg/net/net.go b/src/pkg/net/net.go
index 2e6db55..ca56af5 100644
--- a/src/pkg/net/net.go
+++ b/src/pkg/net/net.go
@@ -275,7 +275,16 @@ type Listener interface {
 	Addr() Addr
 }
 
-var errMissingAddress = errors.New("missing address")
+// Various errors contained in OpError.
+var (
+	// For connection setup and write operations.
+	errMissingAddress = errors.New("missing address")
+
+	// For both read and write operations.
+	errTimeout          error = &timeoutError{}
+	errClosing                = errors.New("use of closed network connection")
+	ErrWriteToConnected       = errors.New("use of WriteTo with pre-connected connection")
+)
 
 // OpError is the error type usually returned by functions in the net
 // package. It describes the operation, network type, and address of
@@ -337,10 +346,6 @@ func (e *timeoutError) Error() string   { return "i/o timeout" }
 func (e *timeoutError) Timeout() bool   { return true }
 func (e *timeoutError) Temporary() bool { return true }
 
-var errTimeout error = &timeoutError{}
-
-var errClosing = errors.New("use of closed network connection")
-
 type AddrError struct {
 	Err  string
 	Addr string
diff --git a/src/pkg/net/net_test.go b/src/pkg/net/net_test.go
index 1320096..bfed4d6 100644
--- a/src/pkg/net/net_test.go
+++ b/src/pkg/net/net_test.go
@@ -28,12 +28,14 @@ func TestShutdown(t *testing.T) {
 		defer ln.Close()
 		c, err := ln.Accept()
 		if err != nil {
-			t.Fatalf("Accept: %v", err)
+			t.Errorf("Accept: %v", err)
+			return
 		}
 		var buf [10]byte
 		n, err := c.Read(buf[:])
 		if n != 0 || err != io.EOF {
-			t.Fatalf("server Read = %d, %v; want 0, io.EOF", n, err)
+			t.Errorf("server Read = %d, %v; want 0, io.EOF", n, err)
+			return
 		}
 		c.Write([]byte("response"))
 		c.Close()
@@ -62,7 +64,7 @@ func TestShutdown(t *testing.T) {
 
 func TestShutdownUnix(t *testing.T) {
 	switch runtime.GOOS {
-	case "windows", "plan9":
+	case "nacl", "plan9", "windows":
 		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 	f, err := ioutil.TempFile("", "go_net_unixtest")
@@ -84,12 +86,14 @@ func TestShutdownUnix(t *testing.T) {
 	go func() {
 		c, err := ln.Accept()
 		if err != nil {
-			t.Fatalf("Accept: %v", err)
+			t.Errorf("Accept: %v", err)
+			return
 		}
 		var buf [10]byte
 		n, err := c.Read(buf[:])
 		if n != 0 || err != io.EOF {
-			t.Fatalf("server Read = %d, %v; want 0, io.EOF", n, err)
+			t.Errorf("server Read = %d, %v; want 0, io.EOF", n, err)
+			return
 		}
 		c.Write([]byte("response"))
 		c.Close()
@@ -196,7 +200,8 @@ func TestTCPClose(t *testing.T) {
 	go func() {
 		c, err := Dial("tcp", l.Addr().String())
 		if err != nil {
-			t.Fatal(err)
+			t.Errorf("Dial: %v", err)
+			return
 		}
 
 		go read(c)
@@ -231,12 +236,12 @@ func TestErrorNil(t *testing.T) {
 	// Make Listen fail by relistening on the same address.
 	l, err := Listen("tcp", "127.0.0.1:0")
 	if err != nil {
-		t.Fatal("Listen 127.0.0.1:0: %v", err)
+		t.Fatalf("Listen 127.0.0.1:0: %v", err)
 	}
 	defer l.Close()
 	l1, err := Listen("tcp", l.Addr().String())
 	if err == nil {
-		t.Fatal("second Listen %v: %v", l.Addr(), err)
+		t.Fatalf("second Listen %v: %v", l.Addr(), err)
 	}
 	if l1 != nil {
 		t.Fatalf("Listen returned non-nil interface %T(%v) with err != nil", l1, l1)
@@ -245,12 +250,12 @@ func TestErrorNil(t *testing.T) {
 	// Make ListenPacket fail by relistening on the same address.
 	lp, err := ListenPacket("udp", "127.0.0.1:0")
 	if err != nil {
-		t.Fatal("Listen 127.0.0.1:0: %v", err)
+		t.Fatalf("Listen 127.0.0.1:0: %v", err)
 	}
 	defer lp.Close()
 	lp1, err := ListenPacket("udp", lp.LocalAddr().String())
 	if err == nil {
-		t.Fatal("second Listen %v: %v", lp.LocalAddr(), err)
+		t.Fatalf("second Listen %v: %v", lp.LocalAddr(), err)
 	}
 	if lp1 != nil {
 		t.Fatalf("ListenPacket returned non-nil interface %T(%v) with err != nil", lp1, lp1)
diff --git a/src/pkg/net/net_windows_test.go b/src/pkg/net/net_windows_test.go
index 8b1c9cd..2f57745 100644
--- a/src/pkg/net/net_windows_test.go
+++ b/src/pkg/net/net_windows_test.go
@@ -84,7 +84,7 @@ func TestAcceptIgnoreSomeErrors(t *testing.T) {
 	}
 	err = cmd.Start()
 	if err != nil {
-		t.Fatalf("cmd.Start failed: %v\n%s\n", err)
+		t.Fatalf("cmd.Start failed: %v\n", err)
 	}
 	outReader := bufio.NewReader(stdout)
 	for {
@@ -107,7 +107,7 @@ func TestAcceptIgnoreSomeErrors(t *testing.T) {
 	result := make(chan error)
 	go func() {
 		time.Sleep(alittle)
-		err = send(ln.Addr().String(), "abc")
+		err := send(ln.Addr().String(), "abc")
 		if err != nil {
 			result <- err
 		}
diff --git a/src/pkg/net/netgo_unix_test.go b/src/pkg/net/netgo_unix_test.go
new file mode 100644
index 0000000..9fb2a56
--- /dev/null
+++ b/src/pkg/net/netgo_unix_test.go
@@ -0,0 +1,24 @@
+// 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 !cgo netgo
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package net
+
+import "testing"
+
+func TestGoLookupIP(t *testing.T) {
+	host := "localhost"
+	_, err, ok := cgoLookupIP(host)
+	if ok {
+		t.Errorf("cgoLookupIP must be a placeholder")
+	}
+	if err != nil {
+		t.Errorf("cgoLookupIP failed: %v", err)
+	}
+	if _, err := goLookupIP(host); err != nil {
+		t.Errorf("goLookupIP failed: %v", err)
+	}
+}
diff --git a/src/pkg/net/packetconn_test.go b/src/pkg/net/packetconn_test.go
index 945003f..b6e4e76 100644
--- a/src/pkg/net/packetconn_test.go
+++ b/src/pkg/net/packetconn_test.go
@@ -15,12 +15,6 @@ import (
 	"time"
 )
 
-func strfunc(s string) func() string {
-	return func() string {
-		return s
-	}
-}
-
 func packetConnTestData(t *testing.T, net string, i int) ([]byte, func()) {
 	switch net {
 	case "udp":
@@ -46,7 +40,7 @@ func packetConnTestData(t *testing.T, net string, i int) ([]byte, func()) {
 		return b, nil
 	case "unixgram":
 		switch runtime.GOOS {
-		case "plan9", "windows":
+		case "nacl", "plan9", "windows":
 			return nil, func() {
 				t.Logf("skipping %q test on %q", net, runtime.GOOS)
 			}
@@ -62,12 +56,12 @@ func packetConnTestData(t *testing.T, net string, i int) ([]byte, func()) {
 
 var packetConnTests = []struct {
 	net   string
-	addr1 func() string
-	addr2 func() string
+	addr1 string
+	addr2 string
 }{
-	{"udp", strfunc("127.0.0.1:0"), strfunc("127.0.0.1:0")},
-	{"ip:icmp", strfunc("127.0.0.1"), strfunc("127.0.0.1")},
-	{"unixgram", testUnixAddr, testUnixAddr},
+	{"udp", "127.0.0.1:0", "127.0.0.1:0"},
+	{"ip:icmp", "127.0.0.1", "127.0.0.1"},
+	{"unixgram", testUnixAddr(), testUnixAddr()},
 }
 
 func TestPacketConn(t *testing.T) {
@@ -88,22 +82,21 @@ func TestPacketConn(t *testing.T) {
 			continue
 		}
 
-		addr1, addr2 := tt.addr1(), tt.addr2()
-		c1, err := ListenPacket(tt.net, addr1)
+		c1, err := ListenPacket(tt.net, tt.addr1)
 		if err != nil {
 			t.Fatalf("ListenPacket failed: %v", err)
 		}
-		defer closer(c1, netstr[0], addr1, addr2)
+		defer closer(c1, netstr[0], tt.addr1, tt.addr2)
 		c1.LocalAddr()
 		c1.SetDeadline(time.Now().Add(100 * time.Millisecond))
 		c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
 		c1.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
 
-		c2, err := ListenPacket(tt.net, addr2)
+		c2, err := ListenPacket(tt.net, tt.addr2)
 		if err != nil {
 			t.Fatalf("ListenPacket failed: %v", err)
 		}
-		defer closer(c2, netstr[0], addr1, addr2)
+		defer closer(c2, netstr[0], tt.addr1, tt.addr2)
 		c2.LocalAddr()
 		c2.SetDeadline(time.Now().Add(100 * time.Millisecond))
 		c2.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
@@ -145,12 +138,11 @@ func TestConnAndPacketConn(t *testing.T) {
 			continue
 		}
 
-		addr1, addr2 := tt.addr1(), tt.addr2()
-		c1, err := ListenPacket(tt.net, addr1)
+		c1, err := ListenPacket(tt.net, tt.addr1)
 		if err != nil {
 			t.Fatalf("ListenPacket failed: %v", err)
 		}
-		defer closer(c1, netstr[0], addr1, addr2)
+		defer closer(c1, netstr[0], tt.addr1, tt.addr2)
 		c1.LocalAddr()
 		c1.SetDeadline(time.Now().Add(100 * time.Millisecond))
 		c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
diff --git a/src/pkg/net/parse.go b/src/pkg/net/parse.go
index 6056de2..ee6e7e9 100644
--- a/src/pkg/net/parse.go
+++ b/src/pkg/net/parse.go
@@ -67,7 +67,7 @@ func open(name string) (*file, error) {
 	if err != nil {
 		return nil, err
 	}
-	return &file{fd, make([]byte, os.Getpagesize())[0:0], false}, nil
+	return &file{fd, make([]byte, 0, os.Getpagesize()), false}, nil
 }
 
 func byteIndex(s string, c byte) int {
diff --git a/src/pkg/net/port_unix.go b/src/pkg/net/port_unix.go
index 3cd9ca2..89558c1 100644
--- a/src/pkg/net/port_unix.go
+++ b/src/pkg/net/port_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
 
 // Read system port mappings from /etc/services
 
@@ -10,12 +10,16 @@ package net
 
 import "sync"
 
-var services map[string]map[string]int
+// services contains minimal mappings between services names and port
+// numbers for platforms that don't have a complete list of port numbers
+// (some Solaris distros).
+var services = map[string]map[string]int{
+	"tcp": {"http": 80},
+}
 var servicesError error
 var onceReadServices sync.Once
 
 func readServices() {
-	services = make(map[string]map[string]int)
 	var file *file
 	if file, servicesError = open("/etc/services"); servicesError != nil {
 		return
@@ -29,7 +33,7 @@ func readServices() {
 		if len(f) < 2 {
 			continue
 		}
-		portnet := f[1] // "tcp/80"
+		portnet := f[1] // "80/tcp"
 		port, j, ok := dtoi(portnet, 0)
 		if !ok || port <= 0 || j >= len(portnet) || portnet[j] != '/' {
 			continue
diff --git a/src/pkg/net/protoconn_test.go b/src/pkg/net/protoconn_test.go
index 5a8958b..12856b6 100644
--- a/src/pkg/net/protoconn_test.go
+++ b/src/pkg/net/protoconn_test.go
@@ -19,7 +19,7 @@ import (
 // also uses /tmp directory in case it is prohibited to create UNIX
 // sockets in TMPDIR.
 func testUnixAddr() string {
-	f, err := ioutil.TempFile("/tmp", "nettest")
+	f, err := ioutil.TempFile("", "nettest")
 	if err != nil {
 		panic(err)
 	}
@@ -236,7 +236,7 @@ func TestIPConnSpecificMethods(t *testing.T) {
 
 func TestUnixListenerSpecificMethods(t *testing.T) {
 	switch runtime.GOOS {
-	case "plan9", "windows":
+	case "nacl", "plan9", "windows":
 		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
@@ -278,7 +278,7 @@ func TestUnixListenerSpecificMethods(t *testing.T) {
 
 func TestUnixConnSpecificMethods(t *testing.T) {
 	switch runtime.GOOS {
-	case "plan9", "windows":
+	case "nacl", "plan9", "windows":
 		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
diff --git a/src/pkg/net/rpc/client.go b/src/pkg/net/rpc/client.go
index c524d0a..21f79b0 100644
--- a/src/pkg/net/rpc/client.go
+++ b/src/pkg/net/rpc/client.go
@@ -39,14 +39,16 @@ type Call struct {
 // with a single Client, and a Client may be used by
 // multiple goroutines simultaneously.
 type Client struct {
-	mutex    sync.Mutex // protects pending, seq, request
-	sending  sync.Mutex
+	codec ClientCodec
+
+	sending sync.Mutex
+
+	mutex    sync.Mutex // protects following
 	request  Request
 	seq      uint64
-	codec    ClientCodec
 	pending  map[uint64]*Call
-	closing  bool
-	shutdown bool
+	closing  bool // user has called Close
+	shutdown bool // server has told us to stop
 }
 
 // A ClientCodec implements writing of RPC requests and
@@ -274,7 +276,7 @@ func Dial(network, address string) (*Client, error) {
 
 func (client *Client) Close() error {
 	client.mutex.Lock()
-	if client.shutdown || client.closing {
+	if client.closing {
 		client.mutex.Unlock()
 		return ErrShutdown
 	}
diff --git a/src/pkg/net/rpc/client_test.go b/src/pkg/net/rpc/client_test.go
new file mode 100644
index 0000000..bbfc1ec
--- /dev/null
+++ b/src/pkg/net/rpc/client_test.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 rpc
+
+import (
+	"errors"
+	"testing"
+)
+
+type shutdownCodec struct {
+	responded chan int
+	closed    bool
+}
+
+func (c *shutdownCodec) WriteRequest(*Request, interface{}) error { return nil }
+func (c *shutdownCodec) ReadResponseBody(interface{}) error       { return nil }
+func (c *shutdownCodec) ReadResponseHeader(*Response) error {
+	c.responded <- 1
+	return errors.New("shutdownCodec ReadResponseHeader")
+}
+func (c *shutdownCodec) Close() error {
+	c.closed = true
+	return nil
+}
+
+func TestCloseCodec(t *testing.T) {
+	codec := &shutdownCodec{responded: make(chan int)}
+	client := NewClientWithCodec(codec)
+	<-codec.responded
+	client.Close()
+	if !codec.closed {
+		t.Error("client.Close did not close codec")
+	}
+}
diff --git a/src/pkg/net/rpc/jsonrpc/all_test.go b/src/pkg/net/rpc/jsonrpc/all_test.go
index 40d4b82..a433a36 100644
--- a/src/pkg/net/rpc/jsonrpc/all_test.go
+++ b/src/pkg/net/rpc/jsonrpc/all_test.go
@@ -5,6 +5,7 @@
 package jsonrpc
 
 import (
+	"bytes"
 	"encoding/json"
 	"errors"
 	"fmt"
@@ -12,6 +13,7 @@ import (
 	"io/ioutil"
 	"net"
 	"net/rpc"
+	"strings"
 	"testing"
 )
 
@@ -202,6 +204,39 @@ func TestMalformedOutput(t *testing.T) {
 	}
 }
 
+func TestServerErrorHasNullResult(t *testing.T) {
+	var out bytes.Buffer
+	sc := NewServerCodec(struct {
+		io.Reader
+		io.Writer
+		io.Closer
+	}{
+		Reader: strings.NewReader(`{"method": "Arith.Add", "id": "123", "params": []}`),
+		Writer: &out,
+		Closer: ioutil.NopCloser(nil),
+	})
+	r := new(rpc.Request)
+	if err := sc.ReadRequestHeader(r); err != nil {
+		t.Fatal(err)
+	}
+	const valueText = "the value we don't want to see"
+	const errorText = "some error"
+	err := sc.WriteResponse(&rpc.Response{
+		ServiceMethod: "Method",
+		Seq:           1,
+		Error:         errorText,
+	}, valueText)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !strings.Contains(out.String(), errorText) {
+		t.Fatalf("Response didn't contain expected error %q: %s", errorText, &out)
+	}
+	if strings.Contains(out.String(), valueText) {
+		t.Errorf("Response contains both an error and value: %s", &out)
+	}
+}
+
 func TestUnexpectedError(t *testing.T) {
 	cli, srv := myPipe()
 	go cli.PipeWriter.CloseWithError(errors.New("unexpected error!")) // reader will get this error
diff --git a/src/pkg/net/rpc/jsonrpc/server.go b/src/pkg/net/rpc/jsonrpc/server.go
index 16ec0fe..e6d37cf 100644
--- a/src/pkg/net/rpc/jsonrpc/server.go
+++ b/src/pkg/net/rpc/jsonrpc/server.go
@@ -100,7 +100,6 @@ func (c *serverCodec) ReadRequestBody(x interface{}) error {
 var null = json.RawMessage([]byte("null"))
 
 func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) error {
-	var resp serverResponse
 	c.mutex.Lock()
 	b, ok := c.pending[r.Seq]
 	if !ok {
@@ -114,10 +113,9 @@ func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) error {
 		// Invalid request so no id.  Use JSON null.
 		b = &null
 	}
-	resp.Id = b
-	resp.Result = x
+	resp := serverResponse{Id: b}
 	if r.Error == "" {
-		resp.Error = nil
+		resp.Result = x
 	} else {
 		resp.Error = r.Error
 	}
diff --git a/src/pkg/net/rpc/server.go b/src/pkg/net/rpc/server.go
index 7eb2dcf..6b264b4 100644
--- a/src/pkg/net/rpc/server.go
+++ b/src/pkg/net/rpc/server.go
@@ -217,10 +217,11 @@ func isExportedOrBuiltinType(t reflect.Type) bool {
 // Register publishes in the server the set of methods of the
 // receiver value that satisfy the following conditions:
 //	- exported method
-//	- two arguments, both pointers to exported structs
+//	- two arguments, both of exported type
+//	- the second argument is a pointer
 //	- one return value, of type error
 // It returns an error if the receiver is not an exported type or has
-// no methods or unsuitable methods. It also logs the error using package log.
+// no suitable methods. It also logs the error using package log.
 // The client accesses each method using a string of the form "Type.Method",
 // where Type is the receiver's concrete type.
 func (server *Server) Register(rcvr interface{}) error {
diff --git a/src/pkg/net/rpc/server_test.go b/src/pkg/net/rpc/server_test.go
index 3b9a883..0dc4ddc 100644
--- a/src/pkg/net/rpc/server_test.go
+++ b/src/pkg/net/rpc/server_test.go
@@ -594,7 +594,6 @@ func TestErrorAfterClientClose(t *testing.T) {
 }
 
 func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) {
-	b.StopTimer()
 	once.Do(startServer)
 	client, err := dial()
 	if err != nil {
@@ -604,33 +603,24 @@ func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) {
 
 	// Synchronous calls
 	args := &Args{7, 8}
-	procs := runtime.GOMAXPROCS(-1)
-	N := int32(b.N)
-	var wg sync.WaitGroup
-	wg.Add(procs)
-	b.StartTimer()
-
-	for p := 0; p < procs; p++ {
-		go func() {
-			reply := new(Reply)
-			for atomic.AddInt32(&N, -1) >= 0 {
-				err := client.Call("Arith.Add", args, reply)
-				if err != nil {
-					b.Fatalf("rpc error: Add: expected no error but got string %q", err.Error())
-				}
-				if reply.C != args.A+args.B {
-					b.Fatalf("rpc error: Add: expected %d got %d", reply.C, args.A+args.B)
-				}
+	b.ResetTimer()
+
+	b.RunParallel(func(pb *testing.PB) {
+		reply := new(Reply)
+		for pb.Next() {
+			err := client.Call("Arith.Add", args, reply)
+			if err != nil {
+				b.Fatalf("rpc error: Add: expected no error but got string %q", err.Error())
 			}
-			wg.Done()
-		}()
-	}
-	wg.Wait()
+			if reply.C != args.A+args.B {
+				b.Fatalf("rpc error: Add: expected %d got %d", reply.C, args.A+args.B)
+			}
+		}
+	})
 }
 
 func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) {
 	const MaxConcurrentCalls = 100
-	b.StopTimer()
 	once.Do(startServer)
 	client, err := dial()
 	if err != nil {
@@ -647,7 +637,7 @@ func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) {
 	wg.Add(procs)
 	gate := make(chan bool, MaxConcurrentCalls)
 	res := make(chan *Call, MaxConcurrentCalls)
-	b.StartTimer()
+	b.ResetTimer()
 
 	for p := 0; p < procs; p++ {
 		go func() {
diff --git a/src/pkg/net/sendfile_dragonfly.go b/src/pkg/net/sendfile_dragonfly.go
index a2219c1..bc88fd3 100644
--- a/src/pkg/net/sendfile_dragonfly.go
+++ b/src/pkg/net/sendfile_dragonfly.go
@@ -23,7 +23,7 @@ const maxSendfileSize int = 4 << 20
 // if handled == false, sendFile performed no work.
 func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
 	// DragonFly uses 0 as the "until EOF" value. If you pass in more bytes than the
-	// file contains, it will loop back to the beginning ad nauseum until it's sent
+	// file contains, it will loop back to the beginning ad nauseam until it's sent
 	// exactly the number of bytes told to. As such, we need to know exactly how many
 	// bytes to send.
 	var remain int64 = 0
diff --git a/src/pkg/net/sendfile_freebsd.go b/src/pkg/net/sendfile_freebsd.go
index 42fe799..ffc1472 100644
--- a/src/pkg/net/sendfile_freebsd.go
+++ b/src/pkg/net/sendfile_freebsd.go
@@ -23,7 +23,7 @@ const maxSendfileSize int = 4 << 20
 // if handled == false, sendFile performed no work.
 func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
 	// FreeBSD uses 0 as the "until EOF" value. If you pass in more bytes than the
-	// file contains, it will loop back to the beginning ad nauseum until it's sent
+	// file contains, it will loop back to the beginning ad nauseam until it's sent
 	// exactly the number of bytes told to. As such, we need to know exactly how many
 	// bytes to send.
 	var remain int64 = 0
diff --git a/src/pkg/net/sendfile_stub.go b/src/pkg/net/sendfile_stub.go
index 3660849..03426ef 100644
--- a/src/pkg/net/sendfile_stub.go
+++ b/src/pkg/net/sendfile_stub.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 netbsd openbsd
+// +build darwin nacl netbsd openbsd solaris
 
 package net
 
diff --git a/src/pkg/net/server_test.go b/src/pkg/net/server_test.go
index 9194a8e..6a2bb92 100644
--- a/src/pkg/net/server_test.go
+++ b/src/pkg/net/server_test.go
@@ -9,21 +9,20 @@ import (
 	"io"
 	"os"
 	"runtime"
-	"strconv"
 	"testing"
 	"time"
 )
 
-func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxonly bool) bool {
+func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxOnly bool) bool {
 	switch runtime.GOOS {
 	case "linux":
-	case "plan9", "windows":
+	case "nacl", "plan9", "windows":
 		// "unix" sockets are not supported on Windows and Plan 9.
 		if net == unixsotype {
 			return true
 		}
 	default:
-		if net == unixsotype && linuxonly {
+		if net == unixsotype && linuxOnly {
 			return true
 		}
 	}
@@ -42,21 +41,15 @@ func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxonly bool)
 	return false
 }
 
-func tempfile(filename string) string {
-	// use /tmp in case it is prohibited to create
-	// UNIX sockets in TMPDIR
-	return "/tmp/" + filename + "." + strconv.Itoa(os.Getpid())
-}
-
 var streamConnServerTests = []struct {
-	snet    string // server side
-	saddr   string
-	cnet    string // client side
-	caddr   string
-	ipv6    bool // test with underlying AF_INET6 socket
-	ipv4map bool // test with IPv6 IPv4-mapping functionality
-	empty   bool // test with empty data
-	linux   bool // test with abstract unix domain socket, a Linux-ism
+	snet      string // server side
+	saddr     string
+	cnet      string // client side
+	caddr     string
+	ipv6      bool // test with underlying AF_INET6 socket
+	ipv4map   bool // test with IPv6 IPv4-mapping functionality
+	empty     bool // test with empty data
+	linuxOnly bool // test with abstract unix domain socket, a Linux-ism
 }{
 	{snet: "tcp", saddr: "", cnet: "tcp", caddr: "127.0.0.1"},
 	{snet: "tcp", saddr: "0.0.0.0", cnet: "tcp", caddr: "127.0.0.1"},
@@ -93,13 +86,13 @@ var streamConnServerTests = []struct {
 
 	{snet: "tcp6", saddr: "[::1]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
 
-	{snet: "unix", saddr: tempfile("gotest1.net"), cnet: "unix", caddr: tempfile("gotest1.net.local")},
-	{snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local", linux: true},
+	{snet: "unix", saddr: testUnixAddr(), cnet: "unix", caddr: testUnixAddr()},
+	{snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local", linuxOnly: true},
 }
 
 func TestStreamConnServer(t *testing.T) {
 	for _, tt := range streamConnServerTests {
-		if skipServerTest(tt.snet, "unix", tt.saddr, tt.ipv6, tt.ipv4map, tt.linux) {
+		if skipServerTest(tt.snet, "unix", tt.saddr, tt.ipv6, tt.ipv4map, tt.linuxOnly) {
 			continue
 		}
 
@@ -137,21 +130,28 @@ func TestStreamConnServer(t *testing.T) {
 }
 
 var seqpacketConnServerTests = []struct {
-	net   string
-	saddr string // server address
-	caddr string // client address
-	empty bool   // test with empty data
+	net       string
+	saddr     string // server address
+	caddr     string // client address
+	empty     bool   // test with empty data
+	linuxOnly bool   // test with abstract unix domain socket, a Linux-ism
 }{
-	{net: "unixpacket", saddr: tempfile("/gotest3.net"), caddr: tempfile("gotest3.net.local")},
-	{net: "unixpacket", saddr: "@gotest4/net", caddr: "@gotest4/net.local"},
+	{net: "unixpacket", saddr: testUnixAddr(), caddr: testUnixAddr()},
+	{net: "unixpacket", saddr: "@gotest4/net", caddr: "@gotest4/net.local", linuxOnly: true},
 }
 
 func TestSeqpacketConnServer(t *testing.T) {
-	if runtime.GOOS != "linux" {
+	switch runtime.GOOS {
+	case "darwin", "nacl", "openbsd", "plan9", "windows":
+		fallthrough
+	case "freebsd": // FreeBSD 8 doesn't support unixpacket
 		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
 	for _, tt := range seqpacketConnServerTests {
+		if runtime.GOOS != "linux" && tt.linuxOnly {
+			continue
+		}
 		listening := make(chan string)
 		done := make(chan int)
 		switch tt.net {
@@ -248,15 +248,15 @@ func runStreamConnClient(t *testing.T, net, taddr string, isEmpty bool) {
 var testDatagram = flag.Bool("datagram", false, "whether to test udp and unixgram")
 
 var datagramPacketConnServerTests = []struct {
-	snet    string // server side
-	saddr   string
-	cnet    string // client side
-	caddr   string
-	ipv6    bool // test with underlying AF_INET6 socket
-	ipv4map bool // test with IPv6 IPv4-mapping functionality
-	dial    bool // test with Dial or DialUnix
-	empty   bool // test with empty data
-	linux   bool // test with abstract unix domain socket, a Linux-ism
+	snet      string // server side
+	saddr     string
+	cnet      string // client side
+	caddr     string
+	ipv6      bool // test with underlying AF_INET6 socket
+	ipv4map   bool // test with IPv6 IPv4-mapping functionality
+	dial      bool // test with Dial or DialUnix
+	empty     bool // test with empty data
+	linuxOnly bool // test with abstract unix domain socket, a Linux-ism
 }{
 	{snet: "udp", saddr: "", cnet: "udp", caddr: "127.0.0.1"},
 	{snet: "udp", saddr: "0.0.0.0", cnet: "udp", caddr: "127.0.0.1"},
@@ -301,12 +301,12 @@ var datagramPacketConnServerTests = []struct {
 	{snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, empty: true},
 	{snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, dial: true, empty: true},
 
-	{snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local")},
-	{snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), dial: true},
-	{snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), empty: true},
-	{snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), dial: true, empty: true},
+	{snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr()},
+	{snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), dial: true},
+	{snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), empty: true},
+	{snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), dial: true, empty: true},
 
-	{snet: "unixgram", saddr: "@gotest6/net", cnet: "unixgram", caddr: "@gotest6/net.local", linux: true},
+	{snet: "unixgram", saddr: "@gotest6/net", cnet: "unixgram", caddr: "@gotest6/net.local", linuxOnly: true},
 }
 
 func TestDatagramPacketConnServer(t *testing.T) {
@@ -315,7 +315,7 @@ func TestDatagramPacketConnServer(t *testing.T) {
 	}
 
 	for _, tt := range datagramPacketConnServerTests {
-		if skipServerTest(tt.snet, "unixgram", tt.saddr, tt.ipv6, tt.ipv4map, tt.linux) {
+		if skipServerTest(tt.snet, "unixgram", tt.saddr, tt.ipv6, tt.ipv4map, tt.linuxOnly) {
 			continue
 		}
 
diff --git a/src/pkg/net/smtp/example_test.go b/src/pkg/net/smtp/example_test.go
new file mode 100644
index 0000000..d551e36
--- /dev/null
+++ b/src/pkg/net/smtp/example_test.go
@@ -0,0 +1,61 @@
+// 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 smtp_test
+
+import (
+	"fmt"
+	"log"
+	"net/smtp"
+)
+
+func Example() {
+	// Connect to the remote SMTP server.
+	c, err := smtp.Dial("mail.example.com:25")
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// Set the sender and recipient first
+	if err := c.Mail("sender at example.org"); err != nil {
+		log.Fatal(err)
+	}
+	if err := c.Rcpt("recipient at example.net"); err != nil {
+		log.Fatal(err)
+	}
+
+	// Send the email body.
+	wc, err := c.Data()
+	if err != nil {
+		log.Fatal(err)
+	}
+	_, err = fmt.Fprintf(wc, "This is the email body")
+	if err != nil {
+		log.Fatal(err)
+	}
+	err = wc.Close()
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// Send the QUIT command and close the connection.
+	err = c.Quit()
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
+func ExamplePlainAuth() {
+	// Set up authentication information.
+	auth := smtp.PlainAuth("", "user at example.com", "password", "mail.example.com")
+
+	// Connect to the server, authenticate, set the sender and recipient,
+	// and send the email all in one step.
+	to := []string{"recipient at example.net"}
+	msg := []byte("This is the email body.")
+	err := smtp.SendMail("mail.example.com:25", auth, "sender at example.org", to, msg)
+	if err != nil {
+		log.Fatal(err)
+	}
+}
diff --git a/src/pkg/net/smtp/smtp.go b/src/pkg/net/smtp/smtp.go
index a0a478a..87dea44 100644
--- a/src/pkg/net/smtp/smtp.go
+++ b/src/pkg/net/smtp/smtp.go
@@ -264,6 +264,8 @@ func (c *Client) Data() (io.WriteCloser, error) {
 	return &dataCloser{c, c.Text.DotWriter()}, nil
 }
 
+var testHookStartTLS func(*tls.Config) // nil, except for tests
+
 // SendMail connects to the server at addr, switches to TLS if
 // possible, authenticates with the optional mechanism a if possible,
 // and then sends an email from address from, to addresses to, with
@@ -278,7 +280,11 @@ func SendMail(addr string, a Auth, from string, to []string, msg []byte) error {
 		return err
 	}
 	if ok, _ := c.Extension("STARTTLS"); ok {
-		if err = c.StartTLS(nil); err != nil {
+		config := &tls.Config{ServerName: c.serverName}
+		if testHookStartTLS != nil {
+			testHookStartTLS(config)
+		}
+		if err = c.StartTLS(config); err != nil {
 			return err
 		}
 	}
diff --git a/src/pkg/net/smtp/smtp_test.go b/src/pkg/net/smtp/smtp_test.go
index 2133dc7..3fba1ea 100644
--- a/src/pkg/net/smtp/smtp_test.go
+++ b/src/pkg/net/smtp/smtp_test.go
@@ -7,6 +7,8 @@ package smtp
 import (
 	"bufio"
 	"bytes"
+	"crypto/tls"
+	"crypto/x509"
 	"io"
 	"net"
 	"net/textproto"
@@ -548,3 +550,145 @@ AUTH PLAIN AHVzZXIAcGFzcw==
 *
 QUIT
 `
+
+func TestTLSClient(t *testing.T) {
+	ln := newLocalListener(t)
+	defer ln.Close()
+	errc := make(chan error)
+	go func() {
+		errc <- sendMail(ln.Addr().String())
+	}()
+	conn, err := ln.Accept()
+	if err != nil {
+		t.Fatalf("failed to accept connection: %v", err)
+	}
+	defer conn.Close()
+	if err := serverHandle(conn, t); err != nil {
+		t.Fatalf("failed to handle connection: %v", err)
+	}
+	if err := <-errc; err != nil {
+		t.Fatalf("client error: %v", err)
+	}
+}
+
+func newLocalListener(t *testing.T) net.Listener {
+	ln, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		ln, err = net.Listen("tcp6", "[::1]:0")
+	}
+	if err != nil {
+		t.Fatal(err)
+	}
+	return ln
+}
+
+type smtpSender struct {
+	w io.Writer
+}
+
+func (s smtpSender) send(f string) {
+	s.w.Write([]byte(f + "\r\n"))
+}
+
+// smtp server, finely tailored to deal with our own client only!
+func serverHandle(c net.Conn, t *testing.T) error {
+	send := smtpSender{c}.send
+	send("220 127.0.0.1 ESMTP service ready")
+	s := bufio.NewScanner(c)
+	for s.Scan() {
+		switch s.Text() {
+		case "EHLO localhost":
+			send("250-127.0.0.1 ESMTP offers a warm hug of welcome")
+			send("250-STARTTLS")
+			send("250 Ok")
+		case "STARTTLS":
+			send("220 Go ahead")
+			keypair, err := tls.X509KeyPair(localhostCert, localhostKey)
+			if err != nil {
+				return err
+			}
+			config := &tls.Config{Certificates: []tls.Certificate{keypair}}
+			c = tls.Server(c, config)
+			defer c.Close()
+			return serverHandleTLS(c, t)
+		default:
+			t.Fatalf("unrecognized command: %q", s.Text())
+		}
+	}
+	return s.Err()
+}
+
+func serverHandleTLS(c net.Conn, t *testing.T) error {
+	send := smtpSender{c}.send
+	s := bufio.NewScanner(c)
+	for s.Scan() {
+		switch s.Text() {
+		case "EHLO localhost":
+			send("250 Ok")
+		case "MAIL FROM:<joe1 at example.com>":
+			send("250 Ok")
+		case "RCPT TO:<joe2 at example.com>":
+			send("250 Ok")
+		case "DATA":
+			send("354 send the mail data, end with .")
+			send("250 Ok")
+		case "Subject: test":
+		case "":
+		case "howdy!":
+		case ".":
+		case "QUIT":
+			send("221 127.0.0.1 Service closing transmission channel")
+			return nil
+		default:
+			t.Fatalf("unrecognized command during TLS: %q", s.Text())
+		}
+	}
+	return s.Err()
+}
+
+func init() {
+	testRootCAs := x509.NewCertPool()
+	testRootCAs.AppendCertsFromPEM(localhostCert)
+	testHookStartTLS = func(config *tls.Config) {
+		config.RootCAs = testRootCAs
+	}
+}
+
+func sendMail(hostPort string) error {
+	host, _, err := net.SplitHostPort(hostPort)
+	if err != nil {
+		return err
+	}
+	auth := PlainAuth("", "", "", host)
+	from := "joe1 at example.com"
+	to := []string{"joe2 at example.com"}
+	return SendMail(hostPort, auth, from, to, []byte("Subject: test\n\nhowdy!"))
+}
+
+// (copied from net/http/httptest)
+// localhostCert is a PEM-encoded TLS cert with SAN IPs
+// "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end
+// of ASN.1 time).
+// generated from src/pkg/crypto/tls:
+// go run generate_cert.go  --rsa-bits 512 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
+var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
+MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD
+bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj
+bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa
+IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA
+AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud
+EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA
+AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk
+Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA==
+-----END CERTIFICATE-----`)
+
+// localhostKey is the private key for localhostCert.
+var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
+MIIBPAIBAAJBAN55NcYKZeInyTuhcCwFMhDHCmwaIUSdtXdcbItRB/yfXGBhiex0
+0IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEAAQJBAQdUx66rfh8sYsgfdcvV
+NoafYpnEcB5s4m/vSVe6SU7dCK6eYec9f9wpT353ljhDUHq3EbmE4foNzJngh35d
+AekCIQDhRQG5Li0Wj8TM4obOnnXUXf1jRv0UkzE9AHWLG5q3AwIhAPzSjpYUDjVW
+MCUXgckTpKCuGwbJk7424Nb8bLzf3kllAiA5mUBgjfr/WtFSJdWcPQ4Zt9KTMNKD
+EUO0ukpTwEIl6wIhAMbGqZK3zAAFdq8DD2jPx+UJXnh0rnOkZBzDtJ6/iN69AiEA
+1Aq8MJgTaYsDQWyU/hDq5YkDJc9e9DSCvUIzqxQWMQE=
+-----END RSA PRIVATE KEY-----`)
diff --git a/src/pkg/net/sock_bsd.go b/src/pkg/net/sock_bsd.go
index 6c37109..48fb785 100644
--- a/src/pkg/net/sock_bsd.go
+++ b/src/pkg/net/sock_bsd.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 netbsd openbsd
+// +build darwin dragonfly freebsd nacl netbsd openbsd
 
 package net
 
diff --git a/src/pkg/net/sock_cloexec.go b/src/pkg/net/sock_cloexec.go
index 3f22cd8..dec8185 100644
--- a/src/pkg/net/sock_cloexec.go
+++ b/src/pkg/net/sock_cloexec.go
@@ -5,7 +5,7 @@
 // This file implements sysSocket and accept for platforms that
 // provide a fast path for setting SetNonblock and CloseOnExec.
 
-// +build linux
+// +build freebsd linux
 
 package net
 
@@ -13,18 +13,20 @@ import "syscall"
 
 // Wrapper around the socket system call that marks the returned file
 // descriptor as nonblocking and close-on-exec.
-func sysSocket(f, t, p int) (int, error) {
-	s, err := syscall.Socket(f, t|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, p)
-	// The SOCK_NONBLOCK and SOCK_CLOEXEC flags were introduced in
-	// Linux 2.6.27.  If we get an EINVAL error, fall back to
-	// using socket without them.
-	if err == nil || err != syscall.EINVAL {
+func sysSocket(family, sotype, proto int) (int, error) {
+	s, err := syscall.Socket(family, sotype|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, proto)
+	// On Linux the SOCK_NONBLOCK and SOCK_CLOEXEC flags were
+	// introduced in 2.6.27 kernel and on FreeBSD both flags were
+	// introduced in 10 kernel. If we get an EINVAL error on Linux
+	// or EPROTONOSUPPORT error on FreeBSD, fall back to using
+	// socket without them.
+	if err == nil || (err != syscall.EPROTONOSUPPORT && err != syscall.EINVAL) {
 		return s, err
 	}
 
 	// See ../syscall/exec_unix.go for description of ForkLock.
 	syscall.ForkLock.RLock()
-	s, err = syscall.Socket(f, t, p)
+	s, err = syscall.Socket(family, sotype, proto)
 	if err == nil {
 		syscall.CloseOnExec(s)
 	}
@@ -41,12 +43,19 @@ func sysSocket(f, t, p int) (int, error) {
 
 // Wrapper around the accept system call that marks the returned file
 // descriptor as nonblocking and close-on-exec.
-func accept(fd int) (int, syscall.Sockaddr, error) {
-	nfd, sa, err := syscall.Accept4(fd, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
-	// The accept4 system call was introduced in Linux 2.6.28.  If
-	// we get an ENOSYS or EINVAL error, fall back to using accept.
-	if err == nil || (err != syscall.ENOSYS && err != syscall.EINVAL) {
-		return nfd, sa, err
+func accept(s int) (int, syscall.Sockaddr, error) {
+	ns, sa, err := syscall.Accept4(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
+	// On Linux the accept4 system call was introduced in 2.6.28
+	// kernel and on FreeBSD it was introduced in 10 kernel. If we
+	// get an ENOSYS error on both Linux and FreeBSD, or EINVAL
+	// error on Linux, fall back to using accept.
+	switch err {
+	default: // nil and errors other than the ones listed
+		return ns, sa, err
+	case syscall.ENOSYS: // syscall missing
+	case syscall.EINVAL: // some Linux use this instead of ENOSYS
+	case syscall.EACCES: // some Linux use this instead of ENOSYS
+	case syscall.EFAULT: // some Linux use this instead of ENOSYS
 	}
 
 	// See ../syscall/exec_unix.go for description of ForkLock.
@@ -54,16 +63,16 @@ func accept(fd int) (int, syscall.Sockaddr, error) {
 	// because we have put fd.sysfd into non-blocking mode.
 	// However, a call to the File method will put it back into
 	// blocking mode. We can't take that risk, so no use of ForkLock here.
-	nfd, sa, err = syscall.Accept(fd)
+	ns, sa, err = syscall.Accept(s)
 	if err == nil {
-		syscall.CloseOnExec(nfd)
+		syscall.CloseOnExec(ns)
 	}
 	if err != nil {
 		return -1, nil, err
 	}
-	if err = syscall.SetNonblock(nfd, true); err != nil {
-		syscall.Close(nfd)
+	if err = syscall.SetNonblock(ns, true); err != nil {
+		syscall.Close(ns)
 		return -1, nil, err
 	}
-	return nfd, sa, nil
+	return ns, sa, nil
 }
diff --git a/src/pkg/net/sock_posix.go b/src/pkg/net/sock_posix.go
index c2d343c..a6ef874 100644
--- a/src/pkg/net/sock_posix.go
+++ b/src/pkg/net/sock_posix.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 windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
diff --git a/src/pkg/net/sock_solaris.go b/src/pkg/net/sock_solaris.go
new file mode 100644
index 0000000..90fe9de
--- /dev/null
+++ b/src/pkg/net/sock_solaris.go
@@ -0,0 +1,13 @@
+// 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.
+
+package net
+
+import "syscall"
+
+func maxListenerBacklog() int {
+	// TODO: Implement this
+	// NOTE: Never return a number bigger than 1<<16 - 1. See issue 5030.
+	return syscall.SOMAXCONN
+}
diff --git a/src/pkg/net/sockopt_bsd.go b/src/pkg/net/sockopt_bsd.go
index ef6eb85..77d51d7 100644
--- a/src/pkg/net/sockopt_bsd.go
+++ b/src/pkg/net/sockopt_bsd.go
@@ -2,16 +2,29 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly freebsd nacl netbsd openbsd
 
 package net
 
 import (
 	"os"
+	"runtime"
 	"syscall"
 )
 
 func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
+	if runtime.GOOS == "dragonfly" && sotype != syscall.SOCK_RAW {
+		// On DragonFly BSD, we adjust the ephemeral port
+		// range because unlike other BSD systems its default
+		// port range doesn't conform to IANA recommendation
+		// as described in RFC 6355 and is pretty narrow.
+		switch family {
+		case syscall.AF_INET:
+			syscall.SetsockoptInt(s, syscall.IPPROTO_IP, syscall.IP_PORTRANGE, syscall.IP_PORTRANGE_HIGH)
+		case syscall.AF_INET6:
+			syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_PORTRANGE, syscall.IPV6_PORTRANGE_HIGH)
+		}
+	}
 	if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
 		// Allow both IP versions even if the OS default
 		// is otherwise.  Note that some operating systems
diff --git a/src/pkg/net/sockopt_plan9.go b/src/pkg/net/sockopt_plan9.go
new file mode 100644
index 0000000..8bc689b
--- /dev/null
+++ b/src/pkg/net/sockopt_plan9.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.
+
+package net
+
+func setKeepAlive(fd *netFD, keepalive bool) error {
+	if keepalive {
+		_, e := fd.ctl.WriteAt([]byte("keepalive"), 0)
+		return e
+	}
+	return nil
+}
diff --git a/src/pkg/net/sockopt_posix.go b/src/pkg/net/sockopt_posix.go
index ff3bc68..921918c 100644
--- a/src/pkg/net/sockopt_posix.go
+++ b/src/pkg/net/sockopt_posix.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 windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
diff --git a/src/pkg/net/sockopt_linux.go b/src/pkg/net/sockopt_solaris.go
similarity index 100%
copy from src/pkg/net/sockopt_linux.go
copy to src/pkg/net/sockopt_solaris.go
diff --git a/src/pkg/net/sockoptip_bsd.go b/src/pkg/net/sockoptip_bsd.go
index 2199e48..87132f0 100644
--- a/src/pkg/net/sockoptip_bsd.go
+++ b/src/pkg/net/sockoptip_bsd.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 netbsd openbsd
+// +build darwin dragonfly freebsd nacl netbsd openbsd
 
 package net
 
diff --git a/src/pkg/net/sockoptip_posix.go b/src/pkg/net/sockoptip_posix.go
index c2579be..b5c80e4 100644
--- a/src/pkg/net/sockoptip_posix.go
+++ b/src/pkg/net/sockoptip_posix.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 windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd windows
 
 package net
 
diff --git a/src/pkg/net/sockoptip_stub.go b/src/pkg/net/sockoptip_stub.go
new file mode 100644
index 0000000..dcd3a22
--- /dev/null
+++ b/src/pkg/net/sockoptip_stub.go
@@ -0,0 +1,39 @@
+// 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.
+
+// +build solaris
+
+package net
+
+import "syscall"
+
+func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
+	// See golang.org/issue/7399.
+	return syscall.EINVAL
+}
+
+func setIPv4MulticastLoopback(fd *netFD, v bool) error {
+	// See golang.org/issue/7399.
+	return syscall.EINVAL
+}
+
+func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error {
+	// See golang.org/issue/7399.
+	return syscall.EINVAL
+}
+
+func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error {
+	// See golang.org/issue/7399.
+	return syscall.EINVAL
+}
+
+func setIPv6MulticastLoopback(fd *netFD, v bool) error {
+	// See golang.org/issue/7399.
+	return syscall.EINVAL
+}
+
+func joinIPv6Group(fd *netFD, ifi *Interface, ip IP) error {
+	// See golang.org/issue/7399.
+	return syscall.EINVAL
+}
diff --git a/src/pkg/net/sys_cloexec.go b/src/pkg/net/sys_cloexec.go
index bbfcc1a..898fb7c 100644
--- a/src/pkg/net/sys_cloexec.go
+++ b/src/pkg/net/sys_cloexec.go
@@ -5,7 +5,7 @@
 // This file implements sysSocket and accept for platforms that do not
 // provide a fast path for setting SetNonblock and CloseOnExec.
 
-// +build darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly nacl netbsd openbsd solaris
 
 package net
 
@@ -13,10 +13,10 @@ import "syscall"
 
 // Wrapper around the socket system call that marks the returned file
 // descriptor as nonblocking and close-on-exec.
-func sysSocket(f, t, p int) (int, error) {
+func sysSocket(family, sotype, proto int) (int, error) {
 	// See ../syscall/exec_unix.go for description of ForkLock.
 	syscall.ForkLock.RLock()
-	s, err := syscall.Socket(f, t, p)
+	s, err := syscall.Socket(family, sotype, proto)
 	if err == nil {
 		syscall.CloseOnExec(s)
 	}
@@ -33,22 +33,22 @@ func sysSocket(f, t, p int) (int, error) {
 
 // Wrapper around the accept system call that marks the returned file
 // descriptor as nonblocking and close-on-exec.
-func accept(fd int) (int, syscall.Sockaddr, error) {
+func accept(s int) (int, syscall.Sockaddr, error) {
 	// See ../syscall/exec_unix.go for description of ForkLock.
 	// It is probably okay to hold the lock across syscall.Accept
 	// because we have put fd.sysfd into non-blocking mode.
 	// However, a call to the File method will put it back into
 	// blocking mode. We can't take that risk, so no use of ForkLock here.
-	nfd, sa, err := syscall.Accept(fd)
+	ns, sa, err := syscall.Accept(s)
 	if err == nil {
-		syscall.CloseOnExec(nfd)
+		syscall.CloseOnExec(ns)
 	}
 	if err != nil {
 		return -1, nil, err
 	}
-	if err = syscall.SetNonblock(nfd, true); err != nil {
-		syscall.Close(nfd)
+	if err = syscall.SetNonblock(ns, true); err != nil {
+		syscall.Close(ns)
 		return -1, nil, err
 	}
-	return nfd, sa, nil
+	return ns, sa, nil
 }
diff --git a/src/pkg/net/tcp_test.go b/src/pkg/net/tcp_test.go
index 62fd99f..c04198e 100644
--- a/src/pkg/net/tcp_test.go
+++ b/src/pkg/net/tcp_test.go
@@ -97,6 +97,7 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
 		b.Fatalf("Listen failed: %v", err)
 	}
 	defer ln.Close()
+	serverSem := make(chan bool, numConcurrent)
 	// Acceptor.
 	go func() {
 		for {
@@ -104,9 +105,13 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
 			if err != nil {
 				break
 			}
+			serverSem <- true
 			// Server connection.
 			go func(c Conn) {
-				defer c.Close()
+				defer func() {
+					c.Close()
+					<-serverSem
+				}()
 				if timeout {
 					c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire.
 				}
@@ -119,13 +124,13 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
 			}(c)
 		}
 	}()
-	sem := make(chan bool, numConcurrent)
+	clientSem := make(chan bool, numConcurrent)
 	for i := 0; i < conns; i++ {
-		sem <- true
+		clientSem <- true
 		// Client connection.
 		go func() {
 			defer func() {
-				<-sem
+				<-clientSem
 			}()
 			c, err := Dial("tcp", ln.Addr().String())
 			if err != nil {
@@ -144,8 +149,9 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
 			}
 		}()
 	}
-	for i := 0; i < cap(sem); i++ {
-		sem <- true
+	for i := 0; i < numConcurrent; i++ {
+		clientSem <- true
+		serverSem <- true
 	}
 }
 
@@ -185,7 +191,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 		for p := 0; p < P; p++ {
 			s, err := ln.Accept()
 			if err != nil {
-				b.Fatalf("Accept failed: %v", err)
+				b.Errorf("Accept failed: %v", err)
+				return
 			}
 			servers[p] = s
 		}
@@ -217,7 +224,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 				buf[0] = v
 				_, err := c.Write(buf[:])
 				if err != nil {
-					b.Fatalf("Write failed: %v", err)
+					b.Errorf("Write failed: %v", err)
+					return
 				}
 			}
 		}(clients[p])
@@ -232,7 +240,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 			for i := 0; i < N; i++ {
 				_, err := s.Read(buf[:])
 				if err != nil {
-					b.Fatalf("Read failed: %v", err)
+					b.Errorf("Read failed: %v", err)
+					return
 				}
 				pipe <- buf[0]
 			}
@@ -250,7 +259,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 				buf[0] = v
 				_, err := s.Write(buf[:])
 				if err != nil {
-					b.Fatalf("Write failed: %v", err)
+					b.Errorf("Write failed: %v", err)
+					return
 				}
 			}
 			s.Close()
@@ -263,7 +273,8 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 			for i := 0; i < N; i++ {
 				_, err := c.Read(buf[:])
 				if err != nil {
-					b.Fatalf("Read failed: %v", err)
+					b.Errorf("Read failed: %v", err)
+					return
 				}
 			}
 			c.Close()
@@ -388,7 +399,7 @@ func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
 		{"tcp6", "[" + laddr + "%" + ifi.Name + "]:0", false},
 	}
 	switch runtime.GOOS {
-	case "darwin", "freebsd", "opensbd", "netbsd":
+	case "darwin", "freebsd", "openbsd", "netbsd":
 		tests = append(tests, []test{
 			{"tcp", "[localhost%" + ifi.Name + "]:0", true},
 			{"tcp6", "[localhost%" + ifi.Name + "]:0", true},
@@ -460,15 +471,25 @@ func TestTCPConcurrentAccept(t *testing.T) {
 			wg.Done()
 		}()
 	}
-	for i := 0; i < 10*N; i++ {
-		c, err := Dial("tcp", ln.Addr().String())
+	attempts := 10 * N
+	fails := 0
+	d := &Dialer{Timeout: 200 * time.Millisecond}
+	for i := 0; i < attempts; i++ {
+		c, err := d.Dial("tcp", ln.Addr().String())
 		if err != nil {
-			t.Fatalf("Dial failed: %v", err)
+			fails++
+		} else {
+			c.Close()
 		}
-		c.Close()
 	}
 	ln.Close()
 	wg.Wait()
+	if fails > attempts/9 { // see issues 7400 and 7541
+		t.Fatalf("too many Dial failed: %v", fails)
+	}
+	if fails > 0 {
+		t.Logf("# of failed Dials: %v", fails)
+	}
 }
 
 func TestTCPReadWriteMallocs(t *testing.T) {
diff --git a/src/pkg/net/tcpsock_plan9.go b/src/pkg/net/tcpsock_plan9.go
index cf9c0f8..52019d7 100644
--- a/src/pkg/net/tcpsock_plan9.go
+++ b/src/pkg/net/tcpsock_plan9.go
@@ -32,7 +32,7 @@ func (c *TCPConn) CloseRead() error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.CloseRead()
+	return c.fd.closeRead()
 }
 
 // CloseWrite shuts down the writing side of the TCP connection.
@@ -41,20 +41,21 @@ func (c *TCPConn) CloseWrite() error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.CloseWrite()
+	return c.fd.closeWrite()
 }
 
-// SetLinger sets the behavior of Close() on a connection which still
+// SetLinger sets the behavior of Close on a connection which still
 // has data waiting to be sent or to be acknowledged.
 //
-// If sec < 0 (the default), Close returns immediately and the
-// operating system finishes sending the data in the background.
+// If sec < 0 (the default), the operating system finishes sending the
+// data in the background.
 //
-// If sec == 0, Close returns immediately and the operating system
-// discards any unsent or unacknowledged data.
+// If sec == 0, the operating system discards any unsent or
+// unacknowledged data.
 //
-// If sec > 0, Close blocks for at most sec seconds waiting for data
-// to be sent and acknowledged.
+// If sec > 0, the data is sent in the background as with sec < 0. On
+// some operating systems after sec seconds have elapsed any remaining
+// unsent data may be discarded.
 func (c *TCPConn) SetLinger(sec int) error {
 	return syscall.EPLAN9
 }
@@ -62,12 +63,18 @@ func (c *TCPConn) SetLinger(sec int) error {
 // SetKeepAlive sets whether the operating system should send
 // keepalive messages on the connection.
 func (c *TCPConn) SetKeepAlive(keepalive bool) error {
-	return syscall.EPLAN9
+	if !c.ok() {
+		return syscall.EPLAN9
+	}
+	return setKeepAlive(c.fd, keepalive)
 }
 
 // SetKeepAlivePeriod sets period between keep alives.
 func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error {
-	return syscall.EPLAN9
+	if !c.ok() {
+		return syscall.EPLAN9
+	}
+	return setKeepAlivePeriod(c.fd, d)
 }
 
 // SetNoDelay controls whether the operating system should delay
diff --git a/src/pkg/net/tcpsock_posix.go b/src/pkg/net/tcpsock_posix.go
index 00c692e..b79b115 100644
--- a/src/pkg/net/tcpsock_posix.go
+++ b/src/pkg/net/tcpsock_posix.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 windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
@@ -78,7 +78,7 @@ func (c *TCPConn) CloseRead() error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.CloseRead()
+	return c.fd.closeRead()
 }
 
 // CloseWrite shuts down the writing side of the TCP connection.
@@ -87,20 +87,21 @@ func (c *TCPConn) CloseWrite() error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.CloseWrite()
+	return c.fd.closeWrite()
 }
 
-// SetLinger sets the behavior of Close() on a connection which still
+// SetLinger sets the behavior of Close on a connection which still
 // has data waiting to be sent or to be acknowledged.
 //
-// If sec < 0 (the default), Close returns immediately and the
-// operating system finishes sending the data in the background.
+// If sec < 0 (the default), the operating system finishes sending the
+// data in the background.
 //
-// If sec == 0, Close returns immediately and the operating system
-// discards any unsent or unacknowledged data.
+// If sec == 0, the operating system discards any unsent or
+// unacknowledged data.
 //
-// If sec > 0, Close blocks for at most sec seconds waiting for data
-// to be sent and acknowledged.
+// If sec > 0, the data is sent in the background as with sec < 0. On
+// some operating systems after sec seconds have elapsed any remaining
+// unsent data may be discarded.
 func (c *TCPConn) SetLinger(sec int) error {
 	if !c.ok() {
 		return syscall.EINVAL
diff --git a/src/pkg/net/tcpsockopt_dragonfly.go b/src/pkg/net/tcpsockopt_dragonfly.go
new file mode 100644
index 0000000..d10a777
--- /dev/null
+++ b/src/pkg/net/tcpsockopt_dragonfly.go
@@ -0,0 +1,29 @@
+// 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.
+
+package net
+
+import (
+	"os"
+	"syscall"
+	"time"
+)
+
+// Set keep alive period.
+func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+
+	// The kernel expects milliseconds so round to next highest millisecond.
+	d += (time.Millisecond - time.Nanosecond)
+	msecs := int(time.Duration(d.Nanoseconds()) / time.Millisecond)
+
+	err := os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, msecs))
+	if err != nil {
+		return err
+	}
+	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, msecs))
+}
diff --git a/src/pkg/net/tcpsockopt_plan9.go b/src/pkg/net/tcpsockopt_plan9.go
new file mode 100644
index 0000000..0e7a664
--- /dev/null
+++ b/src/pkg/net/tcpsockopt_plan9.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.
+
+// TCP socket options for plan9
+
+package net
+
+import (
+	"time"
+)
+
+// Set keep alive period.
+func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
+	cmd := "keepalive " + string(int64(d/time.Millisecond))
+	_, e := fd.ctl.WriteAt([]byte(cmd), 0)
+	return e
+}
diff --git a/src/pkg/net/tcpsockopt_posix.go b/src/pkg/net/tcpsockopt_posix.go
index e03476a..6484bad 100644
--- a/src/pkg/net/tcpsockopt_posix.go
+++ b/src/pkg/net/tcpsockopt_posix.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 windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
diff --git a/src/pkg/net/tcpsockopt_solaris.go b/src/pkg/net/tcpsockopt_solaris.go
new file mode 100644
index 0000000..eaab6b6
--- /dev/null
+++ b/src/pkg/net/tcpsockopt_solaris.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.
+
+// TCP socket options for solaris
+
+package net
+
+import (
+	"os"
+	"syscall"
+	"time"
+)
+
+// Set keep alive period.
+func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+
+	// The kernel expects seconds so round to next highest second.
+	d += (time.Second - time.Nanosecond)
+	secs := int(d.Seconds())
+
+	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.SO_KEEPALIVE, secs))
+}
diff --git a/src/pkg/net/tcpsockopt_unix.go b/src/pkg/net/tcpsockopt_unix.go
index 89d9143..2693a54 100644
--- a/src/pkg/net/tcpsockopt_unix.go
+++ b/src/pkg/net/tcpsockopt_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 dragonfly freebsd linux netbsd
+// +build freebsd linux nacl netbsd
 
 package net
 
diff --git a/src/pkg/net/tcpsockopt_windows.go b/src/pkg/net/tcpsockopt_windows.go
index 0bf4312..8ef1407 100644
--- a/src/pkg/net/tcpsockopt_windows.go
+++ b/src/pkg/net/tcpsockopt_windows.go
@@ -7,7 +7,10 @@
 package net
 
 import (
+	"os"
+	"syscall"
 	"time"
+	"unsafe"
 )
 
 func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
@@ -16,6 +19,16 @@ func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
 	}
 	defer fd.decref()
 
-	// We can't actually set this per connection.  Act as a noop rather than an error.
-	return nil
+	// Windows expects milliseconds so round to next highest millisecond.
+	d += (time.Millisecond - time.Nanosecond)
+	millis := uint32(d / time.Millisecond)
+	ka := syscall.TCPKeepalive{
+		OnOff:    1,
+		Time:     millis,
+		Interval: millis,
+	}
+	ret := uint32(0)
+	size := uint32(unsafe.Sizeof(ka))
+	err := syscall.WSAIoctl(fd.sysfd, syscall.SIO_KEEPALIVE_VALS, (*byte)(unsafe.Pointer(&ka)), size, nil, 0, &ret, nil, 0)
+	return os.NewSyscallError("WSAIoctl", err)
 }
diff --git a/src/pkg/net/testdata/resolv.conf b/src/pkg/net/testdata/resolv.conf
new file mode 100644
index 0000000..b5972e0
--- /dev/null
+++ b/src/pkg/net/testdata/resolv.conf
@@ -0,0 +1,5 @@
+# /etc/resolv.conf
+
+domain Home
+nameserver 192.168.1.1
+options ndots:5 timeout:10 attempts:3 rotate
diff --git a/src/pkg/net/textproto/reader.go b/src/pkg/net/textproto/reader.go
index b0c0741..eea9207 100644
--- a/src/pkg/net/textproto/reader.go
+++ b/src/pkg/net/textproto/reader.go
@@ -562,19 +562,12 @@ const toLower = 'a' - 'A'
 // allowed to mutate the provided byte slice before returning the
 // string.
 func canonicalMIMEHeaderKey(a []byte) string {
-	// Look for it in commonHeaders , so that we can avoid an
-	// allocation by sharing the strings among all users
-	// of textproto. If we don't find it, a has been canonicalized
-	// so just return string(a).
 	upper := true
-	lo := 0
-	hi := len(commonHeaders)
-	for i := 0; i < len(a); i++ {
+	for i, c := range a {
 		// Canonicalize: first letter upper case
 		// and upper case after each dash.
 		// (Host, User-Agent, If-Modified-Since).
 		// MIME headers are ASCII only, so no Unicode issues.
-		c := a[i]
 		if c == ' ' {
 			c = '-'
 		} else if upper && 'a' <= c && c <= 'z' {
@@ -584,60 +577,61 @@ func canonicalMIMEHeaderKey(a []byte) string {
 		}
 		a[i] = c
 		upper = c == '-' // for next time
-
-		if lo < hi {
-			for lo < hi && (len(commonHeaders[lo]) <= i || commonHeaders[lo][i] < c) {
-				lo++
-			}
-			for hi > lo && commonHeaders[hi-1][i] > c {
-				hi--
-			}
-		}
 	}
-	if lo < hi && len(commonHeaders[lo]) == len(a) {
-		return commonHeaders[lo]
+	// The compiler recognizes m[string(byteSlice)] as a special
+	// case, so a copy of a's bytes into a new string does not
+	// happen in this map lookup:
+	if v := commonHeader[string(a)]; v != "" {
+		return v
 	}
 	return string(a)
 }
 
-var commonHeaders = []string{
-	"Accept",
-	"Accept-Charset",
-	"Accept-Encoding",
-	"Accept-Language",
-	"Accept-Ranges",
-	"Cache-Control",
-	"Cc",
-	"Connection",
-	"Content-Id",
-	"Content-Language",
-	"Content-Length",
-	"Content-Transfer-Encoding",
-	"Content-Type",
-	"Cookie",
-	"Date",
-	"Dkim-Signature",
-	"Etag",
-	"Expires",
-	"From",
-	"Host",
-	"If-Modified-Since",
-	"If-None-Match",
-	"In-Reply-To",
-	"Last-Modified",
-	"Location",
-	"Message-Id",
-	"Mime-Version",
-	"Pragma",
-	"Received",
-	"Return-Path",
-	"Server",
-	"Set-Cookie",
-	"Subject",
-	"To",
-	"User-Agent",
-	"Via",
-	"X-Forwarded-For",
-	"X-Imforwards",
-	"X-Powered-By",
+// commonHeader interns common header strings.
+var commonHeader = make(map[string]string)
+
+func init() {
+	for _, v := range []string{
+		"Accept",
+		"Accept-Charset",
+		"Accept-Encoding",
+		"Accept-Language",
+		"Accept-Ranges",
+		"Cache-Control",
+		"Cc",
+		"Connection",
+		"Content-Id",
+		"Content-Language",
+		"Content-Length",
+		"Content-Transfer-Encoding",
+		"Content-Type",
+		"Cookie",
+		"Date",
+		"Dkim-Signature",
+		"Etag",
+		"Expires",
+		"From",
+		"Host",
+		"If-Modified-Since",
+		"If-None-Match",
+		"In-Reply-To",
+		"Last-Modified",
+		"Location",
+		"Message-Id",
+		"Mime-Version",
+		"Pragma",
+		"Received",
+		"Return-Path",
+		"Server",
+		"Set-Cookie",
+		"Subject",
+		"To",
+		"User-Agent",
+		"Via",
+		"X-Forwarded-For",
+		"X-Imforwards",
+		"X-Powered-By",
+	} {
+		commonHeader[v] = v
+	}
 }
diff --git a/src/pkg/net/textproto/reader_test.go b/src/pkg/net/textproto/reader_test.go
index cc12912..cbc0ed1 100644
--- a/src/pkg/net/textproto/reader_test.go
+++ b/src/pkg/net/textproto/reader_test.go
@@ -247,24 +247,20 @@ func TestRFC959Lines(t *testing.T) {
 }
 
 func TestCommonHeaders(t *testing.T) {
-	// need to disable the commonHeaders-based optimization
-	// during this check, or we'd not be testing anything
-	oldch := commonHeaders
-	commonHeaders = []string{}
-	defer func() { commonHeaders = oldch }()
-
-	last := ""
-	for _, h := range oldch {
-		if last > h {
-			t.Errorf("%v is out of order", h)
-		}
-		if last == h {
-			t.Errorf("%v is duplicated", h)
+	for h := range commonHeader {
+		if h != CanonicalMIMEHeaderKey(h) {
+			t.Errorf("Non-canonical header %q in commonHeader", h)
 		}
-		if canon := CanonicalMIMEHeaderKey(h); h != canon {
-			t.Errorf("%v is not canonical", h)
+	}
+	b := []byte("content-Length")
+	want := "Content-Length"
+	n := testing.AllocsPerRun(200, func() {
+		if x := canonicalMIMEHeaderKey(b); x != want {
+			t.Fatalf("canonicalMIMEHeaderKey(%q) = %q; want %q", b, x, want)
 		}
-		last = h
+	})
+	if n > 0 {
+		t.Errorf("canonicalMIMEHeaderKey allocs = %v; want 0", n)
 	}
 }
 
diff --git a/src/pkg/net/timeout_test.go b/src/pkg/net/timeout_test.go
index 35d427a..9ef0c4d 100644
--- a/src/pkg/net/timeout_test.go
+++ b/src/pkg/net/timeout_test.go
@@ -120,6 +120,9 @@ func TestReadTimeout(t *testing.T) {
 			t.Fatalf("Read: expected err %v, got %v", errClosing, err)
 		}
 	default:
+		if err == io.EOF && runtime.GOOS == "nacl" { // close enough; golang.org/issue/8044
+			break
+		}
 		if err != errClosing {
 			t.Fatalf("Read: expected err %v, got %v", errClosing, err)
 		}
@@ -348,7 +351,8 @@ func TestReadWriteDeadline(t *testing.T) {
 	go func() {
 		c, err := ln.Accept()
 		if err != nil {
-			t.Fatalf("Accept: %v", err)
+			t.Errorf("Accept: %v", err)
+			return
 		}
 		defer c.Close()
 		lnquit <- true
@@ -493,10 +497,7 @@ func testVariousDeadlines(t *testing.T, maxProcs int) {
 				clientc <- copyRes{n, err, d}
 			}()
 
-			tooLong := 2 * time.Second
-			if runtime.GOOS == "windows" {
-				tooLong = 5 * time.Second
-			}
+			tooLong := 5 * time.Second
 			select {
 			case res := <-clientc:
 				if isTimeout(res.err) {
@@ -536,7 +537,8 @@ func TestReadDeadlineDataAvailable(t *testing.T) {
 	go func() {
 		c, err := ln.Accept()
 		if err != nil {
-			t.Fatalf("Accept: %v", err)
+			t.Errorf("Accept: %v", err)
+			return
 		}
 		defer c.Close()
 		n, err := c.Write([]byte(msg))
@@ -574,7 +576,8 @@ func TestWriteDeadlineBufferAvailable(t *testing.T) {
 	go func() {
 		c, err := ln.Accept()
 		if err != nil {
-			t.Fatalf("Accept: %v", err)
+			t.Errorf("Accept: %v", err)
+			return
 		}
 		defer c.Close()
 		c.SetWriteDeadline(time.Now().Add(-5 * time.Second)) // in the past
@@ -610,7 +613,8 @@ func TestAcceptDeadlineConnectionAvailable(t *testing.T) {
 	go func() {
 		c, err := Dial("tcp", ln.Addr().String())
 		if err != nil {
-			t.Fatalf("Dial: %v", err)
+			t.Errorf("Dial: %v", err)
+			return
 		}
 		defer c.Close()
 		var buf [1]byte
@@ -669,7 +673,8 @@ func TestProlongTimeout(t *testing.T) {
 		s, err := ln.Accept()
 		connected <- true
 		if err != nil {
-			t.Fatalf("ln.Accept: %v", err)
+			t.Errorf("ln.Accept: %v", err)
+			return
 		}
 		defer s.Close()
 		s.SetDeadline(time.Now().Add(time.Hour))
@@ -706,7 +711,7 @@ func TestProlongTimeout(t *testing.T) {
 
 func TestDeadlineRace(t *testing.T) {
 	switch runtime.GOOS {
-	case "plan9":
+	case "nacl", "plan9":
 		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
diff --git a/src/pkg/net/udp_test.go b/src/pkg/net/udp_test.go
index 6f4d215..e177877 100644
--- a/src/pkg/net/udp_test.go
+++ b/src/pkg/net/udp_test.go
@@ -201,6 +201,10 @@ func TestIPv6LinkLocalUnicastUDP(t *testing.T) {
 		{"udp", "[" + laddr + "%" + ifi.Name + "]:0", false},
 		{"udp6", "[" + laddr + "%" + ifi.Name + "]:0", false},
 	}
+	// The first udp test fails on DragonFly - see issue 7473.
+	if runtime.GOOS == "dragonfly" {
+		tests = tests[1:]
+	}
 	switch runtime.GOOS {
 	case "darwin", "dragonfly", "freebsd", "openbsd", "netbsd":
 		tests = append(tests, []test{
diff --git a/src/pkg/net/udpsock.go b/src/pkg/net/udpsock.go
index 0dd0dbd..4c99ae4 100644
--- a/src/pkg/net/udpsock.go
+++ b/src/pkg/net/udpsock.go
@@ -4,10 +4,6 @@
 
 package net
 
-import "errors"
-
-var ErrWriteToConnected = errors.New("use of WriteTo with pre-connected UDP")
-
 // UDPAddr represents the address of a UDP end point.
 type UDPAddr struct {
 	IP   IP
diff --git a/src/pkg/net/udpsock_plan9.go b/src/pkg/net/udpsock_plan9.go
index 7362170..510ac5e 100644
--- a/src/pkg/net/udpsock_plan9.go
+++ b/src/pkg/net/udpsock_plan9.go
@@ -190,7 +190,8 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
 	if err != nil {
 		return nil, err
 	}
-	return newUDPConn(l.netFD()), nil
+	fd, err := l.netFD()
+	return newUDPConn(fd), err
 }
 
 // ListenMulticastUDP listens for incoming multicast UDP packets
diff --git a/src/pkg/net/udpsock_posix.go b/src/pkg/net/udpsock_posix.go
index 142da81..5dfba94 100644
--- a/src/pkg/net/udpsock_posix.go
+++ b/src/pkg/net/udpsock_posix.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 windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
@@ -64,7 +64,7 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
 	if !c.ok() {
 		return 0, nil, syscall.EINVAL
 	}
-	n, sa, err := c.fd.ReadFrom(b)
+	n, sa, err := c.fd.readFrom(b)
 	switch sa := sa.(type) {
 	case *syscall.SockaddrInet4:
 		addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
@@ -93,7 +93,7 @@ func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr,
 		return 0, 0, 0, nil, syscall.EINVAL
 	}
 	var sa syscall.Sockaddr
-	n, oobn, flags, sa, err = c.fd.ReadMsg(b, oob)
+	n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
 	switch sa := sa.(type) {
 	case *syscall.SockaddrInet4:
 		addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port}
@@ -124,7 +124,7 @@ func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
 	if err != nil {
 		return 0, &OpError{"write", c.fd.net, addr, err}
 	}
-	return c.fd.WriteTo(b, sa)
+	return c.fd.writeTo(b, sa)
 }
 
 // WriteTo implements the PacketConn WriteTo method.
@@ -156,7 +156,7 @@ func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err er
 	if err != nil {
 		return 0, 0, &OpError{"write", c.fd.net, addr, err}
 	}
-	return c.fd.WriteMsg(b, oob, sa)
+	return c.fd.writeMsg(b, oob, sa)
 }
 
 // DialUDP connects to the remote address raddr on the network net,
diff --git a/src/pkg/net/unicast_posix_test.go b/src/pkg/net/unicast_posix_test.go
index 5deb8f4..452ac92 100644
--- a/src/pkg/net/unicast_posix_test.go
+++ b/src/pkg/net/unicast_posix_test.go
@@ -166,9 +166,12 @@ var dualStackListenerTests = []struct {
 }
 
 // TestDualStackTCPListener tests both single and double listen
-// to a test listener with various address families, differnet
+// to a test listener with various address families, different
 // listening address and same port.
 func TestDualStackTCPListener(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping in -short mode, see issue 5001")
+	}
 	switch runtime.GOOS {
 	case "plan9":
 		t.Skipf("skipping test on %q", runtime.GOOS)
@@ -178,7 +181,7 @@ func TestDualStackTCPListener(t *testing.T) {
 	}
 
 	for _, tt := range dualStackListenerTests {
-		if tt.wildcard && (testing.Short() || !*testExternal) {
+		if tt.wildcard && !*testExternal {
 			continue
 		}
 		switch runtime.GOOS {
diff --git a/src/pkg/net/unix_test.go b/src/pkg/net/unix_test.go
index 91df3ff..05643dd 100644
--- a/src/pkg/net/unix_test.go
+++ b/src/pkg/net/unix_test.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 !plan9,!windows
+// +build !nacl,!plan9,!windows
 
 package net
 
@@ -151,6 +151,73 @@ func TestUnixAutobindClose(t *testing.T) {
 	ln.Close()
 }
 
+func TestUnixgramWrite(t *testing.T) {
+	addr := testUnixAddr()
+	laddr, err := ResolveUnixAddr("unixgram", addr)
+	if err != nil {
+		t.Fatalf("ResolveUnixAddr failed: %v", err)
+	}
+	c, err := ListenPacket("unixgram", addr)
+	if err != nil {
+		t.Fatalf("ListenPacket failed: %v", err)
+	}
+	defer os.Remove(addr)
+	defer c.Close()
+
+	testUnixgramWriteConn(t, laddr)
+	testUnixgramWritePacketConn(t, laddr)
+}
+
+func testUnixgramWriteConn(t *testing.T, raddr *UnixAddr) {
+	c, err := Dial("unixgram", raddr.String())
+	if err != nil {
+		t.Fatalf("Dial failed: %v", err)
+	}
+	defer c.Close()
+
+	if _, err := c.(*UnixConn).WriteToUnix([]byte("Connection-oriented mode socket"), raddr); err == nil {
+		t.Fatal("WriteToUnix should fail")
+	} else if err.(*OpError).Err != ErrWriteToConnected {
+		t.Fatalf("WriteToUnix should fail as ErrWriteToConnected: %v", err)
+	}
+	if _, err = c.(*UnixConn).WriteTo([]byte("Connection-oriented mode socket"), raddr); err == nil {
+		t.Fatal("WriteTo should fail")
+	} else if err.(*OpError).Err != ErrWriteToConnected {
+		t.Fatalf("WriteTo should fail as ErrWriteToConnected: %v", err)
+	}
+	if _, _, err = c.(*UnixConn).WriteMsgUnix([]byte("Connection-oriented mode socket"), nil, raddr); err == nil {
+		t.Fatal("WriteTo should fail")
+	} else if err.(*OpError).Err != ErrWriteToConnected {
+		t.Fatalf("WriteMsgUnix should fail as ErrWriteToConnected: %v", err)
+	}
+	if _, err := c.Write([]byte("Connection-oriented mode socket")); err != nil {
+		t.Fatalf("Write failed: %v", err)
+	}
+}
+
+func testUnixgramWritePacketConn(t *testing.T, raddr *UnixAddr) {
+	addr := testUnixAddr()
+	c, err := ListenPacket("unixgram", addr)
+	if err != nil {
+		t.Fatalf("ListenPacket failed: %v", err)
+	}
+	defer os.Remove(addr)
+	defer c.Close()
+
+	if _, err := c.(*UnixConn).WriteToUnix([]byte("Connectionless mode socket"), raddr); err != nil {
+		t.Fatalf("WriteToUnix failed: %v", err)
+	}
+	if _, err := c.WriteTo([]byte("Connectionless mode socket"), raddr); err != nil {
+		t.Fatalf("WriteTo failed: %v", err)
+	}
+	if _, _, err := c.(*UnixConn).WriteMsgUnix([]byte("Connectionless mode socket"), nil, raddr); err != nil {
+		t.Fatalf("WriteMsgUnix failed: %v", err)
+	}
+	if _, err := c.(*UnixConn).Write([]byte("Connectionless mode socket")); err == nil {
+		t.Fatal("Write should fail")
+	}
+}
+
 func TestUnixConnLocalAndRemoteNames(t *testing.T) {
 	for _, laddr := range []string{"", testUnixAddr()} {
 		laddr := laddr
diff --git a/src/pkg/net/unixsock_posix.go b/src/pkg/net/unixsock_posix.go
index b82f3ce..2610779 100644
--- a/src/pkg/net/unixsock_posix.go
+++ b/src/pkg/net/unixsock_posix.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 windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
@@ -124,7 +124,7 @@ func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) {
 	if !c.ok() {
 		return 0, nil, syscall.EINVAL
 	}
-	n, sa, err := c.fd.ReadFrom(b)
+	n, sa, err := c.fd.readFrom(b)
 	switch sa := sa.(type) {
 	case *syscall.SockaddrUnix:
 		if sa.Name != "" {
@@ -151,7 +151,7 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd
 	if !c.ok() {
 		return 0, 0, 0, nil, syscall.EINVAL
 	}
-	n, oobn, flags, sa, err := c.fd.ReadMsg(b, oob)
+	n, oobn, flags, sa, err := c.fd.readMsg(b, oob)
 	switch sa := sa.(type) {
 	case *syscall.SockaddrUnix:
 		if sa.Name != "" {
@@ -171,6 +171,9 @@ func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err error) {
 	if !c.ok() {
 		return 0, syscall.EINVAL
 	}
+	if c.fd.isConnected {
+		return 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected}
+	}
 	if addr == nil {
 		return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
 	}
@@ -178,7 +181,7 @@ func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err error) {
 		return 0, syscall.EAFNOSUPPORT
 	}
 	sa := &syscall.SockaddrUnix{Name: addr.Name}
-	return c.fd.WriteTo(b, sa)
+	return c.fd.writeTo(b, sa)
 }
 
 // WriteTo implements the PacketConn WriteTo method.
@@ -200,14 +203,17 @@ func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err
 	if !c.ok() {
 		return 0, 0, syscall.EINVAL
 	}
+	if c.fd.sotype == syscall.SOCK_DGRAM && c.fd.isConnected {
+		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected}
+	}
 	if addr != nil {
 		if addr.Net != sotypeToNet(c.fd.sotype) {
 			return 0, 0, syscall.EAFNOSUPPORT
 		}
 		sa := &syscall.SockaddrUnix{Name: addr.Name}
-		return c.fd.WriteMsg(b, oob, sa)
+		return c.fd.writeMsg(b, oob, sa)
 	}
-	return c.fd.WriteMsg(b, oob, nil)
+	return c.fd.writeMsg(b, oob, nil)
 }
 
 // CloseRead shuts down the reading side of the Unix domain connection.
@@ -216,7 +222,7 @@ func (c *UnixConn) CloseRead() error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.CloseRead()
+	return c.fd.closeRead()
 }
 
 // CloseWrite shuts down the writing side of the Unix domain connection.
@@ -225,7 +231,7 @@ func (c *UnixConn) CloseWrite() error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.CloseWrite()
+	return c.fd.closeWrite()
 }
 
 // DialUnix connects to the remote address raddr on the network net,
@@ -280,7 +286,11 @@ func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
 	if l == nil || l.fd == nil {
 		return nil, syscall.EINVAL
 	}
-	fd, err := l.fd.accept(sockaddrToUnix)
+	toAddr := sockaddrToUnix
+	if l.fd.sotype == syscall.SOCK_SEQPACKET {
+		toAddr = sockaddrToUnixpacket
+	}
+	fd, err := l.fd.accept(toAddr)
 	if err != nil {
 		return nil, err
 	}
diff --git a/src/pkg/net/url/url.go b/src/pkg/net/url/url.go
index 3b37872..75f650a 100644
--- a/src/pkg/net/url/url.go
+++ b/src/pkg/net/url/url.go
@@ -502,7 +502,7 @@ func (v Values) Set(key, value string) {
 	v[key] = []string{value}
 }
 
-// Add adds the key to value. It appends to any existing
+// Add adds the value to key. It appends to any existing
 // values associated with key.
 func (v Values) Add(key, value string) {
 	v[key] = append(v[key], value)
diff --git a/src/pkg/net/url/url_test.go b/src/pkg/net/url/url_test.go
index 7578eb1..cad758f 100644
--- a/src/pkg/net/url/url_test.go
+++ b/src/pkg/net/url/url_test.go
@@ -251,6 +251,17 @@ var urltests = []URLTest{
 		},
 		"file:///home/adg/rabbits",
 	},
+	// "Windows" paths are no exception to the rule.
+	// See golang.org/issue/6027, especially comment #9.
+	{
+		"file:///C:/FooBar/Baz.txt",
+		&URL{
+			Scheme: "file",
+			Host:   "",
+			Path:   "/C:/FooBar/Baz.txt",
+		},
+		"file:///C:/FooBar/Baz.txt",
+	},
 	// case-insensitive scheme
 	{
 		"MaIlTo:webmaster at golang.org",
diff --git a/src/pkg/net/z_last_test.go b/src/pkg/net/z_last_test.go
new file mode 100644
index 0000000..4f6a54a
--- /dev/null
+++ b/src/pkg/net/z_last_test.go
@@ -0,0 +1,37 @@
+// 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.
+
+package net
+
+import (
+	"flag"
+	"fmt"
+	"testing"
+)
+
+var testDNSFlood = flag.Bool("dnsflood", false, "whether to test dns query flooding")
+
+func TestDNSThreadLimit(t *testing.T) {
+	if !*testDNSFlood {
+		t.Skip("test disabled; use -dnsflood to enable")
+	}
+
+	const N = 10000
+	c := make(chan int, N)
+	for i := 0; i < N; i++ {
+		go func(i int) {
+			LookupIP(fmt.Sprintf("%d.net-test.golang.org", i))
+			c <- 1
+		}(i)
+	}
+	// Don't bother waiting for the stragglers; stop at 0.9 N.
+	for i := 0; i < N*9/10; i++ {
+		if i%100 == 0 {
+			//println("TestDNSThreadLimit:", i)
+		}
+		<-c
+	}
+
+	// If we're still here, it worked.
+}
diff --git a/src/pkg/os/dir_unix.go b/src/pkg/os/dir_unix.go
index 9fa7ad6..d353e40 100644
--- a/src/pkg/os/dir_unix.go
+++ b/src/pkg/os/dir_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 os
 
diff --git a/src/pkg/os/doc.go b/src/pkg/os/doc.go
index a954e31..389a8eb 100644
--- a/src/pkg/os/doc.go
+++ b/src/pkg/os/doc.go
@@ -39,11 +39,14 @@ func (p *Process) Kill() error {
 // Wait waits for the Process to exit, and then returns a
 // ProcessState describing its status and an error, if any.
 // Wait releases any resources associated with the Process.
+// On most operating systems, the Process must be a child
+// of the current process or an error will be returned.
 func (p *Process) Wait() (*ProcessState, error) {
 	return p.wait()
 }
 
 // Signal sends a signal to the Process.
+// Sending Interrupt on Windows is not implemented.
 func (p *Process) Signal(sig Signal) error {
 	return p.signal(sig)
 }
diff --git a/src/pkg/os/env_unix_test.go b/src/pkg/os/env_unix_test.go
index e16d71a..5ec07ee 100644
--- a/src/pkg/os/env_unix_test.go
+++ b/src/pkg/os/env_unix_test.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 netbsd openbsd solaris
 
 package os_test
 
diff --git a/src/pkg/os/error_unix.go b/src/pkg/os/error_unix.go
index 6250349..f2aabbb 100644
--- a/src/pkg/os/error_unix.go
+++ b/src/pkg/os/error_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 os
 
diff --git a/src/pkg/os/exec/exec.go b/src/pkg/os/exec/exec.go
index 491cc24..a70ed0d 100644
--- a/src/pkg/os/exec/exec.go
+++ b/src/pkg/os/exec/exec.go
@@ -12,7 +12,10 @@ import (
 	"errors"
 	"io"
 	"os"
+	"path/filepath"
+	"runtime"
 	"strconv"
+	"strings"
 	"sync"
 	"syscall"
 )
@@ -33,7 +36,8 @@ type Cmd struct {
 	// Path is the path of the command to run.
 	//
 	// This is the only field that must be set to a non-zero
-	// value.
+	// value. If Path is relative, it is evaluated relative
+	// to Dir.
 	Path string
 
 	// Args holds command line arguments, including the command as Args[0].
@@ -84,7 +88,7 @@ type Cmd struct {
 	// available after a call to Wait or Run.
 	ProcessState *os.ProcessState
 
-	err             error // last error (from LookPath, stdin, stdout, stderr)
+	lookPathErr     error // LookPath error, if any.
 	finished        bool  // when Wait was called
 	childFiles      []*os.File
 	closeAfterStart []io.Closer
@@ -96,8 +100,7 @@ type Cmd struct {
 // Command returns the Cmd struct to execute the named program with
 // the given arguments.
 //
-// It sets Path and Args in the returned structure and zeroes the
-// other fields.
+// It sets only the Path and Args in the returned structure.
 //
 // If name contains no path separators, Command uses LookPath to
 // resolve the path to a complete name if possible. Otherwise it uses
@@ -107,19 +110,22 @@ type Cmd struct {
 // followed by the elements of arg, so arg should not include the
 // command name itself. For example, Command("echo", "hello")
 func Command(name string, arg ...string) *Cmd {
-	aname, err := LookPath(name)
-	if err != nil {
-		aname = name
-	}
-	return &Cmd{
-		Path: aname,
+	cmd := &Cmd{
+		Path: name,
 		Args: append([]string{name}, arg...),
-		err:  err,
 	}
+	if filepath.Base(name) == name {
+		if lp, err := LookPath(name); err != nil {
+			cmd.lookPathErr = err
+		} else {
+			cmd.Path = lp
+		}
+	}
+	return cmd
 }
 
 // interfaceEqual protects against panics from doing equality tests on
-// two interfaces with non-comparable underlying types
+// two interfaces with non-comparable underlying types.
 func interfaceEqual(a, b interface{}) bool {
 	defer func() {
 		recover()
@@ -233,12 +239,50 @@ func (c *Cmd) Run() error {
 	return c.Wait()
 }
 
+// lookExtensions finds windows executable by its dir and path.
+// It uses LookPath to try appropriate extensions.
+// lookExtensions does not search PATH, instead it converts `prog` into `.\prog`.
+func lookExtensions(path, dir string) (string, error) {
+	if filepath.Base(path) == path {
+		path = filepath.Join(".", path)
+	}
+	if dir == "" {
+		return LookPath(path)
+	}
+	if filepath.VolumeName(path) != "" {
+		return LookPath(path)
+	}
+	if len(path) > 1 && os.IsPathSeparator(path[0]) {
+		return LookPath(path)
+	}
+	dirandpath := filepath.Join(dir, path)
+	// We assume that LookPath will only add file extension.
+	lp, err := LookPath(dirandpath)
+	if err != nil {
+		return "", err
+	}
+	ext := strings.TrimPrefix(lp, dirandpath)
+	return path + ext, nil
+}
+
 // Start starts the specified command but does not wait for it to complete.
+//
+// The Wait method will return the exit code and release associated resources
+// once the command exits.
 func (c *Cmd) Start() error {
-	if c.err != nil {
+	if c.lookPathErr != nil {
 		c.closeDescriptors(c.closeAfterStart)
 		c.closeDescriptors(c.closeAfterWait)
-		return c.err
+		return c.lookPathErr
+	}
+	if runtime.GOOS == "windows" {
+		lp, err := lookExtensions(c.Path, c.Dir)
+		if err != nil {
+			c.closeDescriptors(c.closeAfterStart)
+			c.closeDescriptors(c.closeAfterWait)
+			return err
+		}
+		c.Path = lp
 	}
 	if c.Process != nil {
 		return errors.New("exec: already started")
@@ -300,6 +344,8 @@ func (e *ExitError) Error() string {
 // If the command fails to run or doesn't complete successfully, the
 // error is of type *ExitError. Other error types may be
 // returned for I/O problems.
+//
+// Wait releases any resources associated with the Cmd.
 func (c *Cmd) Wait() error {
 	if c.Process == nil {
 		return errors.New("exec: not started")
@@ -383,15 +429,17 @@ func (c *Cmd) StdinPipe() (io.WriteCloser, error) {
 type closeOnce struct {
 	*os.File
 
-	close    sync.Once
-	closeErr error
+	once sync.Once
+	err  error
 }
 
 func (c *closeOnce) Close() error {
-	c.close.Do(func() {
-		c.closeErr = c.File.Close()
-	})
-	return c.closeErr
+	c.once.Do(c.close)
+	return c.err
+}
+
+func (c *closeOnce) close() {
+	c.err = c.File.Close()
 }
 
 // StdoutPipe returns a pipe that will be connected to the command's
diff --git a/src/pkg/os/exec/exec_test.go b/src/pkg/os/exec/exec_test.go
index c380d65..6f77ac3 100644
--- a/src/pkg/os/exec/exec_test.go
+++ b/src/pkg/os/exec/exec_test.go
@@ -2,7 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package exec
+// Use an external test to avoid os/exec -> net/http -> crypto/x509 -> os/exec
+// circular dependency on non-cgo darwin.
+
+package exec_test
 
 import (
 	"bufio"
@@ -10,10 +13,12 @@ import (
 	"fmt"
 	"io"
 	"io/ioutil"
+	"log"
 	"net"
 	"net/http"
 	"net/http/httptest"
 	"os"
+	"os/exec"
 	"path/filepath"
 	"runtime"
 	"strconv"
@@ -22,16 +27,19 @@ import (
 	"time"
 )
 
-func helperCommand(s ...string) *Cmd {
+func helperCommand(t *testing.T, s ...string) *exec.Cmd {
+	if runtime.GOOS == "nacl" {
+		t.Skip("skipping on nacl")
+	}
 	cs := []string{"-test.run=TestHelperProcess", "--"}
 	cs = append(cs, s...)
-	cmd := Command(os.Args[0], cs...)
+	cmd := exec.Command(os.Args[0], cs...)
 	cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
 	return cmd
 }
 
 func TestEcho(t *testing.T) {
-	bs, err := helperCommand("echo", "foo bar", "baz").Output()
+	bs, err := helperCommand(t, "echo", "foo bar", "baz").Output()
 	if err != nil {
 		t.Errorf("echo: %v", err)
 	}
@@ -40,10 +48,37 @@ func TestEcho(t *testing.T) {
 	}
 }
 
+func TestCommandRelativeName(t *testing.T) {
+	// Run our own binary as a relative path
+	// (e.g. "_test/exec.test") our parent directory.
+	base := filepath.Base(os.Args[0]) // "exec.test"
+	dir := filepath.Dir(os.Args[0])   // "/tmp/go-buildNNNN/os/exec/_test"
+	if dir == "." {
+		t.Skip("skipping; running test at root somehow")
+	}
+	parentDir := filepath.Dir(dir) // "/tmp/go-buildNNNN/os/exec"
+	dirBase := filepath.Base(dir)  // "_test"
+	if dirBase == "." {
+		t.Skipf("skipping; unexpected shallow dir of %q", dir)
+	}
+
+	cmd := exec.Command(filepath.Join(dirBase, base), "-test.run=TestHelperProcess", "--", "echo", "foo")
+	cmd.Dir = parentDir
+	cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+
+	out, err := cmd.Output()
+	if err != nil {
+		t.Errorf("echo: %v", err)
+	}
+	if g, e := string(out), "foo\n"; g != e {
+		t.Errorf("echo: want %q, got %q", e, g)
+	}
+}
+
 func TestCatStdin(t *testing.T) {
 	// Cat, testing stdin and stdout.
 	input := "Input string\nLine 2"
-	p := helperCommand("cat")
+	p := helperCommand(t, "cat")
 	p.Stdin = strings.NewReader(input)
 	bs, err := p.Output()
 	if err != nil {
@@ -57,9 +92,9 @@ func TestCatStdin(t *testing.T) {
 
 func TestCatGoodAndBadFile(t *testing.T) {
 	// Testing combined output and error values.
-	bs, err := helperCommand("cat", "/bogus/file.foo", "exec_test.go").CombinedOutput()
-	if _, ok := err.(*ExitError); !ok {
-		t.Errorf("expected *ExitError from cat combined; got %T: %v", err, err)
+	bs, err := helperCommand(t, "cat", "/bogus/file.foo", "exec_test.go").CombinedOutput()
+	if _, ok := err.(*exec.ExitError); !ok {
+		t.Errorf("expected *exec.ExitError from cat combined; got %T: %v", err, err)
 	}
 	s := string(bs)
 	sp := strings.SplitN(s, "\n", 2)
@@ -77,7 +112,7 @@ func TestCatGoodAndBadFile(t *testing.T) {
 
 func TestNoExistBinary(t *testing.T) {
 	// Can't run a non-existent binary
-	err := Command("/no-exist-binary").Run()
+	err := exec.Command("/no-exist-binary").Run()
 	if err == nil {
 		t.Error("expected error from /no-exist-binary")
 	}
@@ -85,19 +120,19 @@ func TestNoExistBinary(t *testing.T) {
 
 func TestExitStatus(t *testing.T) {
 	// Test that exit values are returned correctly
-	cmd := helperCommand("exit", "42")
+	cmd := helperCommand(t, "exit", "42")
 	err := cmd.Run()
 	want := "exit status 42"
 	switch runtime.GOOS {
 	case "plan9":
 		want = fmt.Sprintf("exit status: '%s %d: 42'", filepath.Base(cmd.Path), cmd.ProcessState.Pid())
 	}
-	if werr, ok := err.(*ExitError); ok {
+	if werr, ok := err.(*exec.ExitError); ok {
 		if s := werr.Error(); s != want {
 			t.Errorf("from exit 42 got exit %q, want %q", s, want)
 		}
 	} else {
-		t.Fatalf("expected *ExitError from exit 42; got %T: %v", err, err)
+		t.Fatalf("expected *exec.ExitError from exit 42; got %T: %v", err, err)
 	}
 }
 
@@ -108,7 +143,7 @@ func TestPipes(t *testing.T) {
 		}
 	}
 	// Cat, testing stdin and stdout.
-	c := helperCommand("pipetest")
+	c := helperCommand(t, "pipetest")
 	stdin, err := c.StdinPipe()
 	check("StdinPipe", err)
 	stdout, err := c.StdoutPipe()
@@ -161,7 +196,7 @@ func TestStdinClose(t *testing.T) {
 			t.Fatalf("%s: %v", what, err)
 		}
 	}
-	cmd := helperCommand("stdinClose")
+	cmd := helperCommand(t, "stdinClose")
 	stdin, err := cmd.StdinPipe()
 	check("StdinPipe", err)
 	// Check that we can access methods of the underlying os.File.`
@@ -182,9 +217,9 @@ func TestStdinClose(t *testing.T) {
 
 // Issue 5071
 func TestPipeLookPathLeak(t *testing.T) {
-	fd0 := numOpenFDS(t)
+	fd0, lsof0 := numOpenFDS(t)
 	for i := 0; i < 4; i++ {
-		cmd := Command("something-that-does-not-exist-binary")
+		cmd := exec.Command("something-that-does-not-exist-binary")
 		cmd.StdoutPipe()
 		cmd.StderrPipe()
 		cmd.StdinPipe()
@@ -192,19 +227,30 @@ func TestPipeLookPathLeak(t *testing.T) {
 			t.Fatal("unexpected success")
 		}
 	}
-	fdGrowth := numOpenFDS(t) - fd0
-	if fdGrowth > 2 {
-		t.Errorf("leaked %d fds; want ~0", fdGrowth)
+	for triesLeft := 3; triesLeft >= 0; triesLeft-- {
+		open, lsof := numOpenFDS(t)
+		fdGrowth := open - fd0
+		if fdGrowth > 2 {
+			if triesLeft > 0 {
+				// Work around what appears to be a race with Linux's
+				// proc filesystem (as used by lsof). It seems to only
+				// be eventually consistent. Give it awhile to settle.
+				// See golang.org/issue/7808
+				time.Sleep(100 * time.Millisecond)
+				continue
+			}
+			t.Errorf("leaked %d fds; want ~0; have:\n%s\noriginally:\n%s", fdGrowth, lsof, lsof0)
+		}
+		break
 	}
 }
 
-func numOpenFDS(t *testing.T) int {
-	lsof, err := Command("lsof", "-n", "-p", strconv.Itoa(os.Getpid())).Output()
+func numOpenFDS(t *testing.T) (n int, lsof []byte) {
+	lsof, err := exec.Command("lsof", "-n", "-p", strconv.Itoa(os.Getpid())).Output()
 	if err != nil {
 		t.Skip("skipping test; error finding or running lsof")
-		return 0
 	}
-	return bytes.Count(lsof, []byte("\n"))
+	return bytes.Count(lsof, []byte("\n")), lsof
 }
 
 var testedAlreadyLeaked = false
@@ -270,7 +316,7 @@ func TestExtraFilesFDShuffle(t *testing.T) {
 	// Moving this test case around within the overall tests may
 	// affect the FDs obtained and hence the checks to catch these cases.
 	npipes := 2
-	c := helperCommand("extraFilesAndPipes", strconv.Itoa(npipes+1))
+	c := helperCommand(t, "extraFilesAndPipes", strconv.Itoa(npipes+1))
 	rd, wr, _ := os.Pipe()
 	defer rd.Close()
 	if rd.Fd() != 3 {
@@ -370,11 +416,15 @@ func TestExtraFiles(t *testing.T) {
 
 	// Force TLS root certs to be loaded (which might involve
 	// cgo), to make sure none of that potential C code leaks fds.
-	ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		w.Write([]byte("Hello"))
-	}))
+	ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
+	// quiet expected TLS handshake error "remote error: bad certificate"
+	ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0)
+	ts.StartTLS()
 	defer ts.Close()
-	http.Get(ts.URL) // ignore result; just calling to force root cert loading
+	_, err = http.Get(ts.URL)
+	if err == nil {
+		t.Errorf("success trying to fetch %s; want an error", ts.URL)
+	}
 
 	tf, err := ioutil.TempFile("", "")
 	if err != nil {
@@ -393,7 +443,7 @@ func TestExtraFiles(t *testing.T) {
 		t.Fatalf("Seek: %v", err)
 	}
 
-	c := helperCommand("read3")
+	c := helperCommand(t, "read3")
 	var stdout, stderr bytes.Buffer
 	c.Stdout = &stdout
 	c.Stderr = &stderr
@@ -425,7 +475,7 @@ func TestExtraFilesRace(t *testing.T) {
 		}
 		return f
 	}
-	runCommand := func(c *Cmd, out chan<- string) {
+	runCommand := func(c *exec.Cmd, out chan<- string) {
 		bout, err := c.CombinedOutput()
 		if err != nil {
 			out <- "ERROR:" + err.Error()
@@ -436,10 +486,10 @@ func TestExtraFilesRace(t *testing.T) {
 
 	for i := 0; i < 10; i++ {
 		la := listen()
-		ca := helperCommand("describefiles")
+		ca := helperCommand(t, "describefiles")
 		ca.ExtraFiles = []*os.File{listenerFile(la)}
 		lb := listen()
-		cb := helperCommand("describefiles")
+		cb := helperCommand(t, "describefiles")
 		cb.ExtraFiles = []*os.File{listenerFile(lb)}
 		ares := make(chan string)
 		bres := make(chan string)
@@ -476,6 +526,8 @@ func TestHelperProcess(*testing.T) {
 	switch runtime.GOOS {
 	case "dragonfly", "freebsd", "netbsd", "openbsd":
 		ofcmd = "fstat"
+	case "plan9":
+		ofcmd = "/bin/cat"
 	}
 
 	args := os.Args
@@ -566,6 +618,14 @@ func TestHelperProcess(*testing.T) {
 			// the cloned file descriptors that result from opening
 			// /dev/urandom.
 			// http://golang.org/issue/3955
+		case "plan9":
+			// TODO(0intro): Determine why Plan 9 is leaking
+			// file descriptors.
+			// http://golang.org/issue/7118
+		case "solaris":
+			// TODO(aram): This fails on Solaris because libc opens
+			// its own files, as it sees fit. Darwin does the same,
+			// see: http://golang.org/issue/2603
 		default:
 			// Now verify that there are no other open fds.
 			var files []*os.File
@@ -577,7 +637,14 @@ func TestHelperProcess(*testing.T) {
 				}
 				if got := f.Fd(); got != wantfd {
 					fmt.Printf("leaked parent file. fd = %d; want %d\n", got, wantfd)
-					out, _ := Command(ofcmd, "-p", fmt.Sprint(os.Getpid())).CombinedOutput()
+					var args []string
+					switch runtime.GOOS {
+					case "plan9":
+						args = []string{fmt.Sprintf("/proc/%d/fd", os.Getpid())}
+					default:
+						args = []string{"-p", fmt.Sprint(os.Getpid())}
+					}
+					out, _ := exec.Command(ofcmd, args...).CombinedOutput()
 					fmt.Print(string(out))
 					os.Exit(1)
 				}
@@ -634,6 +701,24 @@ func TestHelperProcess(*testing.T) {
 		}
 		fmt.Fprintf(os.Stderr, "child: %s", response)
 		os.Exit(0)
+	case "exec":
+		cmd := exec.Command(args[1])
+		cmd.Dir = args[0]
+		output, err := cmd.CombinedOutput()
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "Child: %s %s", err, string(output))
+			os.Exit(1)
+		}
+		fmt.Printf("%s", string(output))
+		os.Exit(0)
+	case "lookpath":
+		p, err := exec.LookPath(args[0])
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "LookPath failed: %v\n", err)
+			os.Exit(1)
+		}
+		fmt.Print(p)
+		os.Exit(0)
 	default:
 		fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmd)
 		os.Exit(2)
diff --git a/src/pkg/os/exec/lp_unix.go b/src/pkg/os/exec/lp_unix.go
index 7ff2d20..3f895d5 100644
--- a/src/pkg/os/exec/lp_unix.go
+++ b/src/pkg/os/exec/lp_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 exec
 
diff --git a/src/pkg/os/exec/lp_unix_test.go b/src/pkg/os/exec/lp_unix_test.go
index f1ab6de..051db66 100644
--- a/src/pkg/os/exec/lp_unix_test.go
+++ b/src/pkg/os/exec/lp_unix_test.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 netbsd openbsd solaris
 
 package exec
 
diff --git a/src/pkg/os/exec/lp_windows_test.go b/src/pkg/os/exec/lp_windows_test.go
index 385dd33..72df03e 100644
--- a/src/pkg/os/exec/lp_windows_test.go
+++ b/src/pkg/os/exec/lp_windows_test.go
@@ -13,10 +13,48 @@ import (
 	"strconv"
 	"strings"
 	"testing"
-	"text/template"
 )
 
+func installExe(t *testing.T, dest, src string) {
+	fsrc, err := os.Open(src)
+	if err != nil {
+		t.Fatal("os.Open failed: ", err)
+	}
+	defer fsrc.Close()
+	fdest, err := os.Create(dest)
+	if err != nil {
+		t.Fatal("os.Create failed: ", err)
+	}
+	defer fdest.Close()
+	_, err = io.Copy(fdest, fsrc)
+	if err != nil {
+		t.Fatal("io.Copy failed: ", err)
+	}
+}
+
+func installBat(t *testing.T, dest string) {
+	f, err := os.Create(dest)
+	if err != nil {
+		t.Fatalf("failed to create batch file: %v", err)
+	}
+	defer f.Close()
+	fmt.Fprintf(f, "@echo %s\n", dest)
+}
+
+func installProg(t *testing.T, dest, srcExe string) {
+	err := os.MkdirAll(filepath.Dir(dest), 0700)
+	if err != nil {
+		t.Fatal("os.MkdirAll failed: ", err)
+	}
+	if strings.ToLower(filepath.Ext(dest)) == ".bat" {
+		installBat(t, dest)
+		return
+	}
+	installExe(t, dest, srcExe)
+}
+
 type lookPathTest struct {
+	rootDir   string
 	PATH      string
 	PATHEXT   string
 	files     []string
@@ -24,13 +62,97 @@ type lookPathTest struct {
 	fails     bool // test is expected to fail
 }
 
-// PrefixPATH returns p.PATH with every element prefixed by prefix.
-func (t lookPathTest) PrefixPATH(prefix string) string {
-	a := strings.SplitN(t.PATH, ";", -1)
-	for i := range a {
-		a[i] = filepath.Join(prefix, a[i])
+func (test lookPathTest) runProg(t *testing.T, env []string, args ...string) (string, error) {
+	cmd := Command(args[0], args[1:]...)
+	cmd.Env = env
+	cmd.Dir = test.rootDir
+	args[0] = filepath.Base(args[0])
+	cmdText := fmt.Sprintf("%q command", strings.Join(args, " "))
+	out, err := cmd.CombinedOutput()
+	if (err != nil) != test.fails {
+		if test.fails {
+			t.Fatalf("test=%+v: %s succeeded, but expected to fail", test, cmdText)
+		}
+		t.Fatalf("test=%+v: %s failed, but expected to succeed: %v - %v", test, cmdText, err, string(out))
+	}
+	if err != nil {
+		return "", fmt.Errorf("test=%+v: %s failed: %v - %v", test, cmdText, err, string(out))
+	}
+	// normalise program output
+	p := string(out)
+	// trim terminating \r and \n that batch file outputs
+	for len(p) > 0 && (p[len(p)-1] == '\n' || p[len(p)-1] == '\r') {
+		p = p[:len(p)-1]
+	}
+	if !filepath.IsAbs(p) {
+		return p, nil
+	}
+	if p[:len(test.rootDir)] != test.rootDir {
+		t.Fatalf("test=%+v: %s output is wrong: %q must have %q prefix", test, cmdText, p, test.rootDir)
+	}
+	return p[len(test.rootDir)+1:], nil
+}
+
+func updateEnv(env []string, name, value string) []string {
+	for i, e := range env {
+		if strings.HasPrefix(strings.ToUpper(e), name+"=") {
+			env[i] = name + "=" + value
+			return env
+		}
+	}
+	return append(env, name+"="+value)
+}
+
+func createEnv(dir, PATH, PATHEXT string) []string {
+	env := os.Environ()
+	env = updateEnv(env, "PATHEXT", PATHEXT)
+	// Add dir in front of every directory in the PATH.
+	dirs := splitList(PATH)
+	for i := range dirs {
+		dirs[i] = filepath.Join(dir, dirs[i])
+	}
+	path := strings.Join(dirs, ";")
+	env = updateEnv(env, "PATH", path)
+	return env
+}
+
+// createFiles copies srcPath file into multiply files.
+// It uses dir as preifx for all destination files.
+func createFiles(t *testing.T, dir string, files []string, srcPath string) {
+	for _, f := range files {
+		installProg(t, filepath.Join(dir, f), srcPath)
+	}
+}
+
+func (test lookPathTest) run(t *testing.T, tmpdir, printpathExe string) {
+	test.rootDir = tmpdir
+	createFiles(t, test.rootDir, test.files, printpathExe)
+	env := createEnv(test.rootDir, test.PATH, test.PATHEXT)
+	// Run "cmd.exe /c test.searchFor" with new environment and
+	// work directory set. All candidates are copies of printpath.exe.
+	// These will output their program paths when run.
+	should, errCmd := test.runProg(t, env, "cmd", "/c", test.searchFor)
+	// Run the lookpath program with new environment and work directory set.
+	env = append(env, "GO_WANT_HELPER_PROCESS=1")
+	have, errLP := test.runProg(t, env, os.Args[0], "-test.run=TestHelperProcess", "--", "lookpath", test.searchFor)
+	// Compare results.
+	if errCmd == nil && errLP == nil {
+		// both succeeded
+		if should != have {
+			t.Fatalf("test=%+v failed: expected to find %q, but found %q", test, should, have)
+		}
+		return
+	}
+	if errCmd != nil && errLP != nil {
+		// both failed -> continue
+		return
+	}
+	if errCmd != nil {
+		t.Fatal(errCmd)
+	}
+	if errLP != nil {
+		t.Fatal(errLP)
 	}
-	return strings.Join(a, ";")
 }
 
 var lookPathTests = []lookPathTest{
@@ -179,190 +301,250 @@ var lookPathTests = []lookPathTest{
 	},
 }
 
-func updateEnv(env []string, name, value string) []string {
-	for i, e := range env {
-		if strings.HasPrefix(strings.ToUpper(e), name+"=") {
-			env[i] = name + "=" + value
-			return env
-		}
-	}
-	return append(env, name+"="+value)
-}
-
-func installExe(t *testing.T, dest, src string) {
-	fsrc, err := os.Open(src)
-	if err != nil {
-		t.Fatal("os.Open failed: ", err)
-	}
-	defer fsrc.Close()
-	fdest, err := os.Create(dest)
+func TestLookPath(t *testing.T) {
+	tmp, err := ioutil.TempDir("", "TestLookPath")
 	if err != nil {
-		t.Fatal("os.Create failed: ", err)
+		t.Fatal("TempDir failed: ", err)
 	}
-	defer fdest.Close()
-	_, err = io.Copy(fdest, fsrc)
-	if err != nil {
-		t.Fatal("io.Copy failed: ", err)
+	defer os.RemoveAll(tmp)
+
+	printpathExe := buildPrintPathExe(t, tmp)
+
+	// Run all tests.
+	for i, test := range lookPathTests {
+		dir := filepath.Join(tmp, "d"+strconv.Itoa(i))
+		err := os.Mkdir(dir, 0700)
+		if err != nil {
+			t.Fatal("Mkdir failed: ", err)
+		}
+		test.run(t, dir, printpathExe)
 	}
 }
 
-func installBat(t *testing.T, dest string) {
-	f, err := os.Create(dest)
-	if err != nil {
-		t.Fatalf("failed to create batch file: %v", err)
-	}
-	defer f.Close()
-	fmt.Fprintf(f, "@echo %s\n", dest)
+type commandTest struct {
+	PATH  string
+	files []string
+	dir   string
+	arg0  string
+	want  string
+	fails bool // test is expected to fail
 }
 
-func installProg(t *testing.T, dest, srcExe string) {
-	err := os.MkdirAll(filepath.Dir(dest), 0700)
+func (test commandTest) isSuccess(rootDir, output string, err error) error {
 	if err != nil {
-		t.Fatal("os.MkdirAll failed: ", err)
+		return fmt.Errorf("test=%+v: exec: %v %v", test, err, output)
 	}
-	if strings.ToLower(filepath.Ext(dest)) == ".bat" {
-		installBat(t, dest)
-		return
+	path := output
+	if path[:len(rootDir)] != rootDir {
+		return fmt.Errorf("test=%+v: %q must have %q prefix", test, path, rootDir)
 	}
-	installExe(t, dest, srcExe)
+	path = path[len(rootDir)+1:]
+	if path != test.want {
+		return fmt.Errorf("test=%+v: want %q, got %q", test, test.want, path)
+	}
+	return nil
 }
 
-func runProg(t *testing.T, test lookPathTest, env []string, dir string, args ...string) (string, error) {
-	cmd := Command(args[0], args[1:]...)
+func (test commandTest) runOne(rootDir string, env []string, dir, arg0 string) error {
+	cmd := Command(os.Args[0], "-test.run=TestHelperProcess", "--", "exec", dir, arg0)
+	cmd.Dir = rootDir
 	cmd.Env = env
-	cmd.Dir = dir
-	args[0] = filepath.Base(args[0])
-	cmdText := fmt.Sprintf("%q command", strings.Join(args, " "))
-	out, err := cmd.CombinedOutput()
+	output, err := cmd.CombinedOutput()
+	err = test.isSuccess(rootDir, string(output), err)
 	if (err != nil) != test.fails {
 		if test.fails {
-			t.Fatalf("test=%+v: %s succeeded, but expected to fail", test, cmdText)
+			return fmt.Errorf("test=%+v: succeeded, but expected to fail", test)
 		}
-		t.Fatalf("test=%+v: %s failed, but expected to succeed: %v - %v", test, cmdText, err, string(out))
-	}
-	if err != nil {
-		return "", fmt.Errorf("test=%+v: %s failed: %v - %v", test, cmdText, err, string(out))
-	}
-	// normalise program output
-	p := string(out)
-	// trim terminating \r and \n that batch file outputs
-	for len(p) > 0 && (p[len(p)-1] == '\n' || p[len(p)-1] == '\r') {
-		p = p[:len(p)-1]
-	}
-	if !filepath.IsAbs(p) {
-		return p, nil
-	}
-	if p[:len(dir)] != dir {
-		t.Fatalf("test=%+v: %s output is wrong: %q must have %q prefix", test, cmdText, p, dir)
+		return err
 	}
-	return p[len(dir)+1:], nil
+	return nil
 }
 
-func testLookPath(t *testing.T, test lookPathTest, tmpdir, lookpathExe, printpathExe string) {
-	// Create files listed in test.files in tmp directory.
-	for i := range test.files {
-		installProg(t, filepath.Join(tmpdir, test.files[i]), printpathExe)
-	}
-	// Create environment with test.PATH and test.PATHEXT set.
-	env := os.Environ()
-	env = updateEnv(env, "PATH", test.PrefixPATH(tmpdir))
-	env = updateEnv(env, "PATHEXT", test.PATHEXT)
-	// Run "cmd.exe /c test.searchFor" with new environment and
-	// work directory set. All candidates are copies of printpath.exe.
-	// These will output their program paths when run.
-	should, errCmd := runProg(t, test, env, tmpdir, "cmd", "/c", test.searchFor)
-	// Run the lookpath program with new environment and work directory set.
-	have, errLP := runProg(t, test, env, tmpdir, lookpathExe, test.searchFor)
-	// Compare results.
-	if errCmd == nil && errLP == nil {
-		// both succeeded
-		if should != have {
-			//			t.Fatalf("test=%+v failed: expected to find %v, but found %v", test, should, have)
-			t.Fatalf("test=%+v failed: expected to find %q, but found %q", test, should, have)
-		}
-		return
-	}
-	if errCmd != nil && errLP != nil {
-		// both failed -> continue
-		return
-	}
-	if errCmd != nil {
-		t.Fatal(errCmd)
-	}
-	if errLP != nil {
-		t.Fatal(errLP)
+func (test commandTest) run(t *testing.T, rootDir, printpathExe string) {
+	createFiles(t, rootDir, test.files, printpathExe)
+	PATHEXT := `.COM;.EXE;.BAT`
+	env := createEnv(rootDir, test.PATH, PATHEXT)
+	env = append(env, "GO_WANT_HELPER_PROCESS=1")
+	err := test.runOne(rootDir, env, test.dir, test.arg0)
+	if err != nil {
+		t.Error(err)
 	}
 }
 
-func buildExe(t *testing.T, templ, dir, name string) string {
-	srcname := name + ".go"
-	f, err := os.Create(filepath.Join(dir, srcname))
-	if err != nil {
-		t.Fatalf("failed to create source: %v", err)
-	}
-	err = template.Must(template.New("template").Parse(templ)).Execute(f, nil)
-	f.Close()
-	if err != nil {
-		t.Fatalf("failed to execute template: %v", err)
-	}
-	outname := name + ".exe"
-	cmd := Command("go", "build", "-o", outname, srcname)
-	cmd.Dir = dir
-	out, err := cmd.CombinedOutput()
-	if err != nil {
-		t.Fatalf("failed to build executable: %v - %v", err, string(out))
-	}
-	return filepath.Join(dir, outname)
+var commandTests = []commandTest{
+	// testing commands with no slash, like `a.exe`
+	{
+		// should find a.exe in current directory
+		files: []string{`a.exe`},
+		arg0:  `a.exe`,
+		want:  `a.exe`,
+	},
+	{
+		// like above, but add PATH in attempt to break the test
+		PATH:  `p2;p`,
+		files: []string{`a.exe`, `p\a.exe`, `p2\a.exe`},
+		arg0:  `a.exe`,
+		want:  `a.exe`,
+	},
+	{
+		// like above, but use "a" instead of "a.exe" for command
+		PATH:  `p2;p`,
+		files: []string{`a.exe`, `p\a.exe`, `p2\a.exe`},
+		arg0:  `a`,
+		want:  `a.exe`,
+	},
+	// testing commands with slash, like `.\a.exe`
+	{
+		// should find p\a.exe
+		files: []string{`p\a.exe`},
+		arg0:  `p\a.exe`,
+		want:  `p\a.exe`,
+	},
+	{
+		// like above, but adding `.` in front of executable should still be OK
+		files: []string{`p\a.exe`},
+		arg0:  `.\p\a.exe`,
+		want:  `p\a.exe`,
+	},
+	{
+		// like above, but with PATH added in attempt to break it
+		PATH:  `p2`,
+		files: []string{`p\a.exe`, `p2\a.exe`},
+		arg0:  `p\a.exe`,
+		want:  `p\a.exe`,
+	},
+	{
+		// like above, but make sure .exe is tried even for commands with slash
+		PATH:  `p2`,
+		files: []string{`p\a.exe`, `p2\a.exe`},
+		arg0:  `p\a`,
+		want:  `p\a.exe`,
+	},
+	// tests commands, like `a.exe`, with c.Dir set
+	{
+		// should not find a.exe in p, becasue LookPath(`a.exe`) will fail
+		files: []string{`p\a.exe`},
+		dir:   `p`,
+		arg0:  `a.exe`,
+		want:  `p\a.exe`,
+		fails: true,
+	},
+	{
+		// LookPath(`a.exe`) will find `.\a.exe`, but prefixing that with
+		// dir `p\a.exe` will refer to not existant file
+		files: []string{`a.exe`, `p\not_important_file`},
+		dir:   `p`,
+		arg0:  `a.exe`,
+		want:  `a.exe`,
+		fails: true,
+	},
+	{
+		// like above, but making test succeed by installing file
+		// in refered destination (so LookPath(`a.exe`) will still
+		// find `.\a.exe`, but we successfully execute `p\a.exe`)
+		files: []string{`a.exe`, `p\a.exe`},
+		dir:   `p`,
+		arg0:  `a.exe`,
+		want:  `p\a.exe`,
+	},
+	{
+		// like above, but add PATH in attempt to break the test
+		PATH:  `p2;p`,
+		files: []string{`a.exe`, `p\a.exe`, `p2\a.exe`},
+		dir:   `p`,
+		arg0:  `a.exe`,
+		want:  `p\a.exe`,
+	},
+	{
+		// like above, but use "a" instead of "a.exe" for command
+		PATH:  `p2;p`,
+		files: []string{`a.exe`, `p\a.exe`, `p2\a.exe`},
+		dir:   `p`,
+		arg0:  `a`,
+		want:  `p\a.exe`,
+	},
+	{
+		// finds `a.exe` in the PATH regardless of dir set
+		// because LookPath returns full path in that case
+		PATH:  `p2;p`,
+		files: []string{`p\a.exe`, `p2\a.exe`},
+		dir:   `p`,
+		arg0:  `a.exe`,
+		want:  `p2\a.exe`,
+	},
+	// tests commands, like `.\a.exe`, with c.Dir set
+	{
+		// should use dir when command is path, like ".\a.exe"
+		files: []string{`p\a.exe`},
+		dir:   `p`,
+		arg0:  `.\a.exe`,
+		want:  `p\a.exe`,
+	},
+	{
+		// like above, but with PATH added in attempt to break it
+		PATH:  `p2`,
+		files: []string{`p\a.exe`, `p2\a.exe`},
+		dir:   `p`,
+		arg0:  `.\a.exe`,
+		want:  `p\a.exe`,
+	},
+	{
+		// like above, but make sure .exe is tried even for commands with slash
+		PATH:  `p2`,
+		files: []string{`p\a.exe`, `p2\a.exe`},
+		dir:   `p`,
+		arg0:  `.\a`,
+		want:  `p\a.exe`,
+	},
 }
 
-func TestLookPath(t *testing.T) {
-	tmp, err := ioutil.TempDir("", "TestLookPath")
+func TestCommand(t *testing.T) {
+	tmp, err := ioutil.TempDir("", "TestCommand")
 	if err != nil {
 		t.Fatal("TempDir failed: ", err)
 	}
 	defer os.RemoveAll(tmp)
 
-	// Create a Go program that uses LookPath to find executable passed as command line parameter.
-	lookpathExe := buildExe(t, lookpathSrc, tmp, "lookpath")
-
-	// Create a Go program that prints its own path.
-	printpathExe := buildExe(t, printpathSrc, tmp, "printpath")
+	printpathExe := buildPrintPathExe(t, tmp)
 
 	// Run all tests.
-	for i, test := range lookPathTests {
+	for i, test := range commandTests {
 		dir := filepath.Join(tmp, "d"+strconv.Itoa(i))
 		err := os.Mkdir(dir, 0700)
 		if err != nil {
 			t.Fatal("Mkdir failed: ", err)
 		}
-		testLookPath(t, test, dir, lookpathExe, printpathExe)
+		test.run(t, dir, printpathExe)
 	}
 }
 
-const lookpathSrc = `
-package main
-
-import (
-	"fmt"
-	"os"
-	"os/exec"
-)
-
-func main() {
-	p, err := exec.LookPath(os.Args[1])
+// buildPrintPathExe creates a Go program that prints its own path.
+// dir is a temp directory where executable will be created.
+// The function returns full path to the created program.
+func buildPrintPathExe(t *testing.T, dir string) string {
+	const name = "printpath"
+	srcname := name + ".go"
+	err := ioutil.WriteFile(filepath.Join(dir, srcname), []byte(printpathSrc), 0644)
 	if err != nil {
-		fmt.Printf("LookPath failed: %v\n", err)
-		os.Exit(1)
+		t.Fatalf("failed to create source: %v", err)
+	}
+	if err != nil {
+		t.Fatalf("failed to execute template: %v", err)
+	}
+	outname := name + ".exe"
+	cmd := Command("go", "build", "-o", outname, srcname)
+	cmd.Dir = dir
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("failed to build executable: %v - %v", err, string(out))
 	}
-	fmt.Print(p)
+	return filepath.Join(dir, outname)
 }
-`
 
 const printpathSrc = `
 package main
 
 import (
-	"fmt"
 	"os"
 	"syscall"
 	"unicode/utf16"
@@ -383,9 +565,9 @@ func getMyName() (string, error) {
 func main() {
 	path, err := getMyName()
 	if err != nil {
-		fmt.Printf("getMyName failed: %v\n", err)
+		os.Stderr.Write([]byte("getMyName failed: " + err.Error() + "\n"))
 		os.Exit(1)
 	}
-	fmt.Print(path)
+	os.Stdout.Write([]byte(path))
 }
 `
diff --git a/src/pkg/os/exec_plan9.go b/src/pkg/os/exec_plan9.go
index 2bd5b68..676be36 100644
--- a/src/pkg/os/exec_plan9.go
+++ b/src/pkg/os/exec_plan9.go
@@ -52,10 +52,6 @@ func (p *Process) signal(sig Signal) error {
 	if p.done() {
 		return errors.New("os: process already finished")
 	}
-	if sig == Kill {
-		// Special-case the kill signal since it doesn't use /proc/$pid/note.
-		return p.Kill()
-	}
 	if e := p.writeProcFile("note", sig.String()); e != nil {
 		return NewSyscallError("signal", e)
 	}
@@ -63,10 +59,7 @@ func (p *Process) signal(sig Signal) error {
 }
 
 func (p *Process) kill() error {
-	if e := p.writeProcFile("ctl", "kill"); e != nil {
-		return NewSyscallError("kill", e)
-	}
-	return nil
+	return p.signal(Kill)
 }
 
 func (p *Process) wait() (ps *ProcessState, err error) {
diff --git a/src/pkg/os/exec_posix.go b/src/pkg/os/exec_posix.go
index fb123ae..fb9d291 100644
--- a/src/pkg/os/exec_posix.go
+++ b/src/pkg/os/exec_posix.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 windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package os
 
diff --git a/src/pkg/os/exec_unix.go b/src/pkg/os/exec_unix.go
index 5572e62..1b1e335 100644
--- a/src/pkg/os/exec_unix.go
+++ b/src/pkg/os/exec_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 os
 
@@ -38,6 +38,9 @@ func (p *Process) signal(sig Signal) error {
 	if p.done() {
 		return errors.New("os: process already finished")
 	}
+	if p.Pid == -1 {
+		return errors.New("os: process already released")
+	}
 	s, ok := sig.(syscall.Signal)
 	if !ok {
 		return errors.New("os: unsupported signal type")
diff --git a/src/pkg/os/file.go b/src/pkg/os/file.go
index 2dd1fcf..b4a7458 100644
--- a/src/pkg/os/file.go
+++ b/src/pkg/os/file.go
@@ -140,6 +140,9 @@ func (f *File) Write(b []byte) (n int, err error) {
 	if n < 0 {
 		n = 0
 	}
+	if n != len(b) {
+		err = io.ErrShortWrite
+	}
 
 	epipecheck(f, e)
 
@@ -247,3 +250,8 @@ func Create(name string) (file *File, err error) {
 
 // lstat is overridden in tests.
 var lstat = Lstat
+
+// Rename renames (moves) a file. OS-specific restrictions might apply.
+func Rename(oldpath, newpath string) error {
+	return rename(oldpath, newpath)
+}
diff --git a/src/pkg/os/file_plan9.go b/src/pkg/os/file_plan9.go
index 708163e..a804b81 100644
--- a/src/pkg/os/file_plan9.go
+++ b/src/pkg/os/file_plan9.go
@@ -313,8 +313,33 @@ func Remove(name string) error {
 	return nil
 }
 
-// Rename renames a file.
-func Rename(oldname, newname string) error {
+// HasPrefix from the strings package.
+func hasPrefix(s, prefix string) bool {
+	return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
+}
+
+// Variant of LastIndex from the strings package.
+func lastIndex(s string, sep byte) int {
+	for i := len(s) - 1; i >= 0; i-- {
+		if s[i] == sep {
+			return i
+		}
+	}
+	return -1
+}
+
+func rename(oldname, newname string) error {
+	dirname := oldname[:lastIndex(oldname, '/')+1]
+	if hasPrefix(newname, dirname) {
+		newname = newname[len(dirname):]
+	} else {
+		return &LinkError{"rename", oldname, newname, ErrInvalid}
+	}
+
+	// If newname still contains slashes after removing the oldname
+	// prefix, the rename is cross-directory and must be rejected.
+	// This case is caught by d.Marshal below.
+
 	var d syscall.Dir
 
 	d.Null()
@@ -323,10 +348,10 @@ func Rename(oldname, newname string) error {
 	buf := make([]byte, syscall.STATFIXLEN+len(d.Name))
 	n, err := d.Marshal(buf[:])
 	if err != nil {
-		return &PathError{"rename", oldname, err}
+		return &LinkError{"rename", oldname, newname, err}
 	}
 	if err = syscall.Wstat(oldname, buf[:n]); err != nil {
-		return &PathError{"rename", oldname, err}
+		return &LinkError{"rename", oldname, newname, err}
 	}
 	return nil
 }
diff --git a/src/pkg/os/file_posix.go b/src/pkg/os/file_posix.go
index a8bef35..b3466b1 100644
--- a/src/pkg/os/file_posix.go
+++ b/src/pkg/os/file_posix.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 windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package os
 
@@ -48,8 +48,7 @@ func Readlink(name string) (string, error) {
 	}
 }
 
-// Rename renames a file.
-func Rename(oldname, newname string) error {
+func rename(oldname, newname string) error {
 	e := syscall.Rename(oldname, newname)
 	if e != nil {
 		return &LinkError{"rename", oldname, newname, e}
@@ -145,7 +144,7 @@ func (f *File) Truncate(size int64) error {
 // of recently written data to disk.
 func (f *File) Sync() (err error) {
 	if f == nil {
-		return syscall.EINVAL
+		return ErrInvalid
 	}
 	if e := syscall.Fsync(f.fd); e != nil {
 		return NewSyscallError("fsync", e)
diff --git a/src/pkg/os/file_unix.go b/src/pkg/os/file_unix.go
index ff1a597..7616833 100644
--- a/src/pkg/os/file_unix.go
+++ b/src/pkg/os/file_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 os
 
@@ -81,12 +81,7 @@ func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
 
 	// There's a race here with fork/exec, which we are
 	// content to live with.  See ../syscall/exec_unix.go.
-	// On OS X 10.6, the O_CLOEXEC flag is not respected.
-	// On OS X 10.7, the O_CLOEXEC flag works.
-	// Without a cheap & reliable way to detect 10.6 vs 10.7 at
-	// runtime, we just always call syscall.CloseOnExec on Darwin.
-	// Once >=10.7 is prevalent, this extra call can removed.
-	if syscall.O_CLOEXEC == 0 || runtime.GOOS == "darwin" { // O_CLOEXEC not supported
+	if !supportsCloseOnExec {
 		syscall.CloseOnExec(r)
 	}
 
@@ -160,30 +155,48 @@ func (f *File) readdir(n int) (fi []FileInfo, err error) {
 	if dirname == "" {
 		dirname = "."
 	}
-	dirname += "/"
 	names, err := f.Readdirnames(n)
-	fi = make([]FileInfo, len(names))
-	for i, filename := range names {
-		fip, lerr := lstat(dirname + filename)
-		if lerr != nil {
-			fi[i] = &fileStat{name: filename}
+	fi = make([]FileInfo, 0, len(names))
+	for _, filename := range names {
+		fip, lerr := lstat(dirname + "/" + filename)
+		if IsNotExist(lerr) {
+			// File disappeared between readdir + stat.
+			// Just treat it as if it didn't exist.
 			continue
 		}
-		fi[i] = fip
+		if lerr != nil {
+			return fi, lerr
+		}
+		fi = append(fi, fip)
 	}
 	return fi, err
 }
 
+// Darwin and FreeBSD can't read or write 2GB+ at a time,
+// even on 64-bit systems. See golang.org/issue/7812.
+// Use 1GB instead of, say, 2GB-1, to keep subsequent
+// reads aligned.
+const (
+	needsMaxRW = runtime.GOOS == "darwin" || runtime.GOOS == "freebsd"
+	maxRW      = 1 << 30
+)
+
 // read reads up to len(b) bytes from the File.
 // It returns the number of bytes read and an error, if any.
 func (f *File) read(b []byte) (n int, err error) {
+	if needsMaxRW && len(b) > maxRW {
+		b = b[:maxRW]
+	}
 	return syscall.Read(f.fd, b)
 }
 
 // pread reads len(b) bytes from the File starting at byte offset off.
 // It returns the number of bytes read and the error, if any.
-// EOF is signaled by a zero count with err set to 0.
+// EOF is signaled by a zero count with err set to nil.
 func (f *File) pread(b []byte, off int64) (n int, err error) {
+	if needsMaxRW && len(b) > maxRW {
+		b = b[:maxRW]
+	}
 	return syscall.Pread(f.fd, b, off)
 }
 
@@ -191,13 +204,22 @@ func (f *File) pread(b []byte, off int64) (n int, err error) {
 // It returns the number of bytes written and an error, if any.
 func (f *File) write(b []byte) (n int, err error) {
 	for {
-		m, err := syscall.Write(f.fd, b)
+		bcap := b
+		if needsMaxRW && len(bcap) > maxRW {
+			bcap = bcap[:maxRW]
+		}
+		m, err := syscall.Write(f.fd, bcap)
 		n += m
 
 		// If the syscall wrote some data but not all (short write)
 		// or it returned EINTR, then assume it stopped early for
 		// reasons that are uninteresting to the caller, and try again.
-		if 0 < m && m < len(b) || err == syscall.EINTR {
+		if 0 < m && m < len(bcap) || err == syscall.EINTR {
+			b = b[m:]
+			continue
+		}
+
+		if needsMaxRW && len(bcap) != len(b) && err == nil {
 			b = b[m:]
 			continue
 		}
@@ -209,6 +231,9 @@ func (f *File) write(b []byte) (n int, err error) {
 // pwrite writes len(b) bytes to the File starting at byte offset off.
 // It returns the number of bytes written and an error, if any.
 func (f *File) pwrite(b []byte, off int64) (n int, err error) {
+	if needsMaxRW && len(b) > maxRW {
+		b = b[:maxRW]
+	}
 	return syscall.Pwrite(f.fd, b, off)
 }
 
diff --git a/src/pkg/os/file_windows.go b/src/pkg/os/file_windows.go
index fab7de3..efe8bc0 100644
--- a/src/pkg/os/file_windows.go
+++ b/src/pkg/os/file_windows.go
@@ -134,20 +134,19 @@ func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
 	if name == "" {
 		return nil, &PathError{"open", name, syscall.ENOENT}
 	}
-	// TODO(brainman): not sure about my logic of assuming it is dir first, then fall back to file
-	r, e := openDir(name)
-	if e == nil {
+	r, errf := openFile(name, flag, perm)
+	if errf == nil {
+		return r, nil
+	}
+	r, errd := openDir(name)
+	if errd == nil {
 		if flag&O_WRONLY != 0 || flag&O_RDWR != 0 {
 			r.Close()
 			return nil, &PathError{"open", name, syscall.EISDIR}
 		}
 		return r, nil
 	}
-	r, e = openFile(name, flag, perm)
-	if e == nil {
-		return r, nil
-	}
-	return nil, &PathError{"open", name, e}
+	return nil, &PathError{"open", name, errf}
 }
 
 // Close closes the File, rendering it unusable for I/O.
diff --git a/src/pkg/os/getwd.go b/src/pkg/os/getwd.go
index 8c5ff7f..a72edea 100644
--- a/src/pkg/os/getwd.go
+++ b/src/pkg/os/getwd.go
@@ -22,7 +22,7 @@ var useSyscallwd = func(error) bool { return true }
 // current directory.  If the current directory can be
 // reached via multiple paths (due to symbolic links),
 // Getwd may return any one of them.
-func Getwd() (pwd string, err error) {
+func Getwd() (dir string, err error) {
 	// If the operating system provides a Getwd call, use it.
 	if syscall.ImplementsGetwd {
 		s, e := syscall.Getwd()
@@ -39,22 +39,22 @@ func Getwd() (pwd string, err error) {
 
 	// Clumsy but widespread kludge:
 	// if $PWD is set and matches ".", use it.
-	pwd = Getenv("PWD")
-	if len(pwd) > 0 && pwd[0] == '/' {
-		d, err := Stat(pwd)
+	dir = Getenv("PWD")
+	if len(dir) > 0 && dir[0] == '/' {
+		d, err := Stat(dir)
 		if err == nil && SameFile(dot, d) {
-			return pwd, nil
+			return dir, nil
 		}
 	}
 
 	// Apply same kludge but to cached dir instead of $PWD.
 	getwdCache.Lock()
-	pwd = getwdCache.dir
+	dir = getwdCache.dir
 	getwdCache.Unlock()
-	if len(pwd) > 0 {
-		d, err := Stat(pwd)
+	if len(dir) > 0 {
+		d, err := Stat(dir)
 		if err == nil && SameFile(dot, d) {
-			return pwd, nil
+			return dir, nil
 		}
 	}
 
@@ -71,8 +71,8 @@ func Getwd() (pwd string, err error) {
 
 	// General algorithm: find name in parent
 	// and then find name of parent.  Each iteration
-	// adds /name to the beginning of pwd.
-	pwd = ""
+	// adds /name to the beginning of dir.
+	dir = ""
 	for parent := ".."; ; parent = "../" + parent {
 		if len(parent) >= 1024 { // Sanity check
 			return "", syscall.ENAMETOOLONG
@@ -91,7 +91,7 @@ func Getwd() (pwd string, err error) {
 			for _, name := range names {
 				d, _ := Lstat(parent + "/" + name)
 				if SameFile(d, dot) {
-					pwd = "/" + name + pwd
+					dir = "/" + name + dir
 					goto Found
 				}
 			}
@@ -112,8 +112,8 @@ func Getwd() (pwd string, err error) {
 
 	// Save answer as hint to avoid the expensive path next time.
 	getwdCache.Lock()
-	getwdCache.dir = pwd
+	getwdCache.dir = dir
 	getwdCache.Unlock()
 
-	return pwd, nil
+	return dir, nil
 }
diff --git a/src/pkg/os/os_test.go b/src/pkg/os/os_test.go
index 9462ebd..16d5984 100644
--- a/src/pkg/os/os_test.go
+++ b/src/pkg/os/os_test.go
@@ -6,6 +6,7 @@ package os_test
 
 import (
 	"bytes"
+	"errors"
 	"flag"
 	"fmt"
 	"io"
@@ -13,7 +14,9 @@ import (
 	. "os"
 	osexec "os/exec"
 	"path/filepath"
+	"reflect"
 	"runtime"
+	"sort"
 	"strings"
 	"syscall"
 	"testing"
@@ -382,6 +385,84 @@ func TestReaddirNValues(t *testing.T) {
 	}
 }
 
+func touch(t *testing.T, name string) {
+	f, err := Create(name)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := f.Close(); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestReaddirStatFailures(t *testing.T) {
+	switch runtime.GOOS {
+	case "windows", "plan9":
+		// Windows and Plan 9 already do this correctly,
+		// but are structured with different syscalls such
+		// that they don't use Lstat, so the hook below for
+		// testing it wouldn't work.
+		t.Skipf("skipping test on %v", runtime.GOOS)
+	}
+	dir, err := ioutil.TempDir("", "")
+	if err != nil {
+		t.Fatalf("TempDir: %v", err)
+	}
+	defer RemoveAll(dir)
+	touch(t, filepath.Join(dir, "good1"))
+	touch(t, filepath.Join(dir, "x")) // will disappear or have an error
+	touch(t, filepath.Join(dir, "good2"))
+	defer func() {
+		*LstatP = Lstat
+	}()
+	var xerr error // error to return for x
+	*LstatP = func(path string) (FileInfo, error) {
+		if xerr != nil && strings.HasSuffix(path, "x") {
+			return nil, xerr
+		}
+		return Lstat(path)
+	}
+	readDir := func() ([]FileInfo, error) {
+		d, err := Open(dir)
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer d.Close()
+		return d.Readdir(-1)
+	}
+	mustReadDir := func(testName string) []FileInfo {
+		fis, err := readDir()
+		if err != nil {
+			t.Fatalf("%s: Readdir: %v", testName, err)
+		}
+		return fis
+	}
+	names := func(fis []FileInfo) []string {
+		s := make([]string, len(fis))
+		for i, fi := range fis {
+			s[i] = fi.Name()
+		}
+		sort.Strings(s)
+		return s
+	}
+
+	if got, want := names(mustReadDir("inital readdir")),
+		[]string{"good1", "good2", "x"}; !reflect.DeepEqual(got, want) {
+		t.Errorf("initial readdir got %q; want %q", got, want)
+	}
+
+	xerr = ErrNotExist
+	if got, want := names(mustReadDir("with x disappearing")),
+		[]string{"good1", "good2"}; !reflect.DeepEqual(got, want) {
+		t.Errorf("with x disappearing, got %q; want %q", got, want)
+	}
+
+	xerr = errors.New("some real error")
+	if _, err := readDir(); err != xerr {
+		t.Errorf("with a non-ErrNotExist error, got error %v; want %v", err, xerr)
+	}
+}
+
 func TestHardLink(t *testing.T) {
 	// Hardlinks are not supported under windows or Plan 9.
 	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
@@ -415,10 +496,10 @@ func TestHardLink(t *testing.T) {
 	}
 }
 
-func TestSymLink(t *testing.T) {
-	// Symlinks are not supported under windows or Plan 9.
-	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
-		return
+func TestSymlink(t *testing.T) {
+	switch runtime.GOOS {
+	case "windows", "plan9", "nacl":
+		t.Skipf("skipping on %s", runtime.GOOS)
 	}
 	from, to := "symlinktestfrom", "symlinktestto"
 	Remove(from) // Just in case.
@@ -478,9 +559,9 @@ func TestSymLink(t *testing.T) {
 }
 
 func TestLongSymlink(t *testing.T) {
-	// Symlinks are not supported under windows or Plan 9.
-	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
-		return
+	switch runtime.GOOS {
+	case "windows", "plan9", "nacl":
+		t.Skipf("skipping on %s", runtime.GOOS)
 	}
 	s := "0123456789abcdef"
 	// Long, but not too long: a common limit is 255.
@@ -549,6 +630,10 @@ func exec(t *testing.T, dir, cmd string, args []string, expect string) {
 }
 
 func TestStartProcess(t *testing.T) {
+	if runtime.GOOS == "nacl" {
+		t.Skip("skipping on nacl")
+	}
+
 	var dir, cmd string
 	var args []string
 	if runtime.GOOS == "windows" {
@@ -622,8 +707,10 @@ func TestFTruncate(t *testing.T) {
 	checkSize(t, f, 1024)
 	f.Truncate(0)
 	checkSize(t, f, 0)
-	f.Write([]byte("surprise!"))
-	checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
+	_, err := f.Write([]byte("surprise!"))
+	if err == nil {
+		checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
+	}
 }
 
 func TestTruncate(t *testing.T) {
@@ -640,8 +727,10 @@ func TestTruncate(t *testing.T) {
 	checkSize(t, f, 1024)
 	Truncate(f.Name(), 0)
 	checkSize(t, f, 0)
-	f.Write([]byte("surprise!"))
-	checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
+	_, err := f.Write([]byte("surprise!"))
+	if err == nil {
+		checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
+	}
 }
 
 // Use TempDir() to make sure we're on a local file system,
@@ -676,13 +765,13 @@ func TestChtimes(t *testing.T) {
 	}
 	postStat := st
 
-	/* Plan 9:
+	/* Plan 9, NaCl:
 		Mtime is the time of the last change of content.  Similarly, atime is set whenever the
 	    contents are accessed; also, it is set whenever mtime is set.
 	*/
 	pat := Atime(postStat)
 	pmt := postStat.ModTime()
-	if !pat.Before(at) && runtime.GOOS != "plan9" {
+	if !pat.Before(at) && runtime.GOOS != "plan9" && runtime.GOOS != "nacl" {
 		t.Errorf("AccessTime didn't go backwards; was=%d, after=%d", at, pat)
 	}
 
@@ -884,8 +973,9 @@ func run(t *testing.T, cmd []string) string {
 func TestHostname(t *testing.T) {
 	// There is no other way to fetch hostname on windows, but via winapi.
 	// On Plan 9 it is can be taken from #c/sysname as Hostname() does.
-	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
-		return
+	switch runtime.GOOS {
+	case "windows", "plan9", "nacl":
+		t.Skipf("skipping on %s", runtime.GOOS)
 	}
 
 	// Check internal Hostname() against the output of /bin/hostname.
@@ -1144,6 +1234,10 @@ func TestReadAtEOF(t *testing.T) {
 }
 
 func testKillProcess(t *testing.T, processKiller func(p *Process)) {
+	if runtime.GOOS == "nacl" {
+		t.Skip("skipping on nacl")
+	}
+
 	dir, err := ioutil.TempDir("", "go-build")
 	if err != nil {
 		t.Fatalf("Failed to create temp directory: %v", err)
@@ -1211,3 +1305,35 @@ func TestKillFindProcess(t *testing.T) {
 		}
 	})
 }
+
+var nilFileMethodTests = []struct {
+	name string
+	f    func(*File) error
+}{
+	{"Chdir", func(f *File) error { return f.Chdir() }},
+	{"Close", func(f *File) error { return f.Close() }},
+	{"Chmod", func(f *File) error { return f.Chmod(0) }},
+	{"Chown", func(f *File) error { return f.Chown(0, 0) }},
+	{"Read", func(f *File) error { _, err := f.Read(make([]byte, 0)); return err }},
+	{"ReadAt", func(f *File) error { _, err := f.ReadAt(make([]byte, 0), 0); return err }},
+	{"Readdir", func(f *File) error { _, err := f.Readdir(1); return err }},
+	{"Readdirnames", func(f *File) error { _, err := f.Readdirnames(1); return err }},
+	{"Seek", func(f *File) error { _, err := f.Seek(0, 0); return err }},
+	{"Stat", func(f *File) error { _, err := f.Stat(); return err }},
+	{"Sync", func(f *File) error { return f.Sync() }},
+	{"Truncate", func(f *File) error { return f.Truncate(0) }},
+	{"Write", func(f *File) error { _, err := f.Write(make([]byte, 0)); return err }},
+	{"WriteAt", func(f *File) error { _, err := f.WriteAt(make([]byte, 0), 0); return err }},
+	{"WriteString", func(f *File) error { _, err := f.WriteString(""); return err }},
+}
+
+// Test that all File methods give ErrInvalid if the receiver is nil.
+func TestNilFileMethods(t *testing.T) {
+	for _, tt := range nilFileMethodTests {
+		var file *File
+		got := tt.f(file)
+		if got != ErrInvalid {
+			t.Errorf("%v should fail when f is nil; got %v", tt.name, got)
+		}
+	}
+}
diff --git a/src/pkg/os/os_unix_test.go b/src/pkg/os/os_unix_test.go
index b0fc025..21d40cc 100644
--- a/src/pkg/os/os_unix_test.go
+++ b/src/pkg/os/os_unix_test.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 netbsd openbsd solaris
 
 package os_test
 
@@ -74,41 +74,3 @@ func TestChown(t *testing.T) {
 		checkUidGid(t, f.Name(), int(sys.Uid), gid)
 	}
 }
-
-func TestReaddirWithBadLstat(t *testing.T) {
-	handle, err := Open(sfdir)
-	failfile := sfdir + "/" + sfname
-	if err != nil {
-		t.Fatalf("Couldn't open %s: %s", sfdir, err)
-	}
-
-	*LstatP = func(file string) (FileInfo, error) {
-		if file == failfile {
-			var fi FileInfo
-			return fi, ErrInvalid
-		}
-		return Lstat(file)
-	}
-	defer func() { *LstatP = Lstat }()
-
-	dirs, err := handle.Readdir(-1)
-	if err != nil {
-		t.Fatalf("Expected Readdir to return no error, got %v", err)
-	}
-	foundfail := false
-	for _, dir := range dirs {
-		if dir.Name() == sfname {
-			foundfail = true
-			if dir.Sys() != nil {
-				t.Errorf("Expected Readdir for %s should not contain Sys", failfile)
-			}
-		} else {
-			if dir.Sys() == nil {
-				t.Errorf("Readdir for every file other than %s should contain Sys, but %s/%s didn't either", failfile, sfdir, dir.Name())
-			}
-		}
-	}
-	if !foundfail {
-		t.Fatalf("Expected %s from Readdir, but didn't find it", failfile)
-	}
-}
diff --git a/src/pkg/os/path_test.go b/src/pkg/os/path_test.go
index 27abf59..3af21cd 100644
--- a/src/pkg/os/path_test.go
+++ b/src/pkg/os/path_test.go
@@ -167,8 +167,9 @@ func TestRemoveAll(t *testing.T) {
 }
 
 func TestMkdirAllWithSymlink(t *testing.T) {
-	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
-		t.Skip("Skipping test: symlinks don't exist under Windows/Plan 9")
+	switch runtime.GOOS {
+	case "nacl", "plan9", "windows":
+		t.Skipf("skipping on %s", runtime.GOOS)
 	}
 
 	tmpDir, err := ioutil.TempDir("", "TestMkdirAllWithSymlink-")
diff --git a/src/pkg/os/path_unix.go b/src/pkg/os/path_unix.go
index 3bf63bf..0211107 100644
--- a/src/pkg/os/path_unix.go
+++ b/src/pkg/os/path_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 os
 
diff --git a/src/pkg/os/pipe_bsd.go b/src/pkg/os/pipe_bsd.go
index 73d35b4..3b81ed2 100644
--- a/src/pkg/os/pipe_bsd.go
+++ b/src/pkg/os/pipe_bsd.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 netbsd openbsd
+// +build darwin dragonfly freebsd nacl netbsd openbsd solaris
 
 package os
 
diff --git a/src/pkg/os/signal/example_test.go b/src/pkg/os/signal/example_test.go
index 600ed31..079ee50 100644
--- a/src/pkg/os/signal/example_test.go
+++ b/src/pkg/os/signal/example_test.go
@@ -1,3 +1,7 @@
+// 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 signal_test
 
 import (
diff --git a/src/pkg/os/signal/sig.s b/src/pkg/os/signal/sig.s
index 888823c..f860924 100644
--- a/src/pkg/os/signal/sig.s
+++ b/src/pkg/os/signal/sig.s
@@ -4,7 +4,7 @@
 
 // Assembly to get into package runtime without using exported symbols.
 
-// +build amd64 arm 386
+// +build amd64 amd64p32 arm 386
 
 #include "../../../cmd/ld/textflag.h"
 
diff --git a/src/pkg/os/signal/signal_test.go b/src/pkg/os/signal/signal_test.go
index 741f2a0..076fe3f 100644
--- a/src/pkg/os/signal/signal_test.go
+++ b/src/pkg/os/signal/signal_test.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 netbsd openbsd solaris
 
 package signal
 
diff --git a/src/pkg/os/signal/signal_unix.go b/src/pkg/os/signal/signal_unix.go
index 318488d..94b8ab3 100644
--- a/src/pkg/os/signal/signal_unix.go
+++ b/src/pkg/os/signal/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 windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package signal
 
diff --git a/src/pkg/os/signal/signal_windows_test.go b/src/pkg/os/signal/signal_windows_test.go
index 26712f3..f3e6706 100644
--- a/src/pkg/os/signal/signal_windows_test.go
+++ b/src/pkg/os/signal/signal_windows_test.go
@@ -6,6 +6,7 @@ package signal
 
 import (
 	"bytes"
+	"io/ioutil"
 	"os"
 	"os/exec"
 	"path/filepath"
@@ -55,9 +56,15 @@ func main() {
 	}
 }
 `
-	name := filepath.Join(os.TempDir(), "ctlbreak")
+	tmp, err := ioutil.TempDir("", "TestCtrlBreak")
+	if err != nil {
+		t.Fatal("TempDir failed: ", err)
+	}
+	defer os.RemoveAll(tmp)
+
+	// write ctrlbreak.go
+	name := filepath.Join(tmp, "ctlbreak")
 	src := name + ".go"
-	defer os.Remove(src)
 	f, err := os.Create(src)
 	if err != nil {
 		t.Fatalf("Failed to create %v: %v", src, err)
diff --git a/src/pkg/os/stat_nacl.go b/src/pkg/os/stat_nacl.go
new file mode 100644
index 0000000..a503b59
--- /dev/null
+++ b/src/pkg/os/stat_nacl.go
@@ -0,0 +1,62 @@
+// 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.
+
+package os
+
+import (
+	"syscall"
+	"time"
+)
+
+func sameFile(fs1, fs2 *fileStat) bool {
+	stat1 := fs1.sys.(*syscall.Stat_t)
+	stat2 := fs2.sys.(*syscall.Stat_t)
+	return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
+}
+
+func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
+	fs := &fileStat{
+		name:    basename(name),
+		size:    int64(st.Size),
+		modTime: timespecToTime(st.Mtime, st.MtimeNsec),
+		sys:     st,
+	}
+	fs.mode = FileMode(st.Mode & 0777)
+	switch st.Mode & syscall.S_IFMT {
+	case syscall.S_IFBLK:
+		fs.mode |= ModeDevice
+	case syscall.S_IFCHR:
+		fs.mode |= ModeDevice | ModeCharDevice
+	case syscall.S_IFDIR:
+		fs.mode |= ModeDir
+	case syscall.S_IFIFO:
+		fs.mode |= ModeNamedPipe
+	case syscall.S_IFLNK:
+		fs.mode |= ModeSymlink
+	case syscall.S_IFREG:
+		// nothing to do
+	case syscall.S_IFSOCK:
+		fs.mode |= ModeSocket
+	}
+	if st.Mode&syscall.S_ISGID != 0 {
+		fs.mode |= ModeSetgid
+	}
+	if st.Mode&syscall.S_ISUID != 0 {
+		fs.mode |= ModeSetuid
+	}
+	if st.Mode&syscall.S_ISVTX != 0 {
+		fs.mode |= ModeSticky
+	}
+	return fs
+}
+
+func timespecToTime(sec, nsec int64) time.Time {
+	return time.Unix(sec, nsec)
+}
+
+// For testing.
+func atime(fi FileInfo) time.Time {
+	st := fi.Sys().(*syscall.Stat_t)
+	return timespecToTime(st.Atime, st.AtimeNsec)
+}
diff --git a/src/pkg/os/stat_dragonfly.go b/src/pkg/os/stat_solaris.go
similarity index 100%
copy from src/pkg/os/stat_dragonfly.go
copy to src/pkg/os/stat_solaris.go
diff --git a/src/pkg/os/sys_bsd.go b/src/pkg/os/sys_bsd.go
index 9ad2f85..8ad5e21 100644
--- a/src/pkg/os/sys_bsd.go
+++ b/src/pkg/os/sys_bsd.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 netbsd openbsd
+// +build darwin dragonfly freebsd nacl netbsd openbsd
 
 // os code shared between *BSD systems including OS X (Darwin)
 // and FreeBSD.
diff --git a/src/pkg/os/sys_darwin.go b/src/pkg/os/sys_darwin.go
new file mode 100644
index 0000000..7a8330a
--- /dev/null
+++ b/src/pkg/os/sys_darwin.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.
+
+package os
+
+import "syscall"
+
+// supportsCloseOnExec reports whether the platform supports the
+// O_CLOEXEC flag.
+var supportsCloseOnExec bool
+
+func init() {
+	// Seems like kern.osreldate is veiled on latest OS X. We use
+	// kern.osrelease instead.
+	osver, err := syscall.Sysctl("kern.osrelease")
+	if err != nil {
+		return
+	}
+	var i int
+	for i = range osver {
+		if osver[i] != '.' {
+			continue
+		}
+	}
+	// The O_CLOEXEC flag was introduced in OS X 10.7 (Darwin
+	// 11.0.0). See http://support.apple.com/kb/HT1633.
+	if i > 2 || i == 2 && osver[0] >= '1' && osver[1] >= '1' {
+		supportsCloseOnExec = true
+	}
+}
diff --git a/src/pkg/os/sys_freebsd.go b/src/pkg/os/sys_freebsd.go
new file mode 100644
index 0000000..273c2df
--- /dev/null
+++ b/src/pkg/os/sys_freebsd.go
@@ -0,0 +1,23 @@
+// 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 os
+
+import "syscall"
+
+// supportsCloseOnExec reports whether the platform supports the
+// O_CLOEXEC flag.
+var supportsCloseOnExec bool
+
+func init() {
+	osrel, err := syscall.SysctlUint32("kern.osreldate")
+	if err != nil {
+		return
+	}
+	// The O_CLOEXEC flag was introduced in FreeBSD 8.3.
+	// See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
+	if osrel >= 803000 {
+		supportsCloseOnExec = true
+	}
+}
diff --git a/src/pkg/os/sys_nacl.go b/src/pkg/os/sys_nacl.go
new file mode 100644
index 0000000..07907c8
--- /dev/null
+++ b/src/pkg/os/sys_nacl.go
@@ -0,0 +1,9 @@
+// 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 os
+
+// supportsCloseOnExec reports whether the platform supports the
+// O_CLOEXEC flag.
+const supportsCloseOnExec = false
diff --git a/src/pkg/os/sys_solaris.go b/src/pkg/os/sys_solaris.go
new file mode 100644
index 0000000..917e8f2
--- /dev/null
+++ b/src/pkg/os/sys_solaris.go
@@ -0,0 +1,11 @@
+// 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 os
+
+import "syscall"
+
+func hostname() (name string, err error) {
+	return syscall.Gethostname()
+}
diff --git a/src/pkg/os/sys_unix.go b/src/pkg/os/sys_unix.go
new file mode 100644
index 0000000..39c20dc
--- /dev/null
+++ b/src/pkg/os/sys_unix.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.
+
+// +build dragonfly linux netbsd openbsd solaris
+
+package os
+
+// supportsCloseOnExec reports whether the platform supports the
+// O_CLOEXEC flag.
+const supportsCloseOnExec = true
diff --git a/src/pkg/os/user/lookup_unix.go b/src/pkg/os/user/lookup_unix.go
index 5459268..f2baf05 100644
--- a/src/pkg/os/user/lookup_unix.go
+++ b/src/pkg/os/user/lookup_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 netbsd openbsd solaris
 // +build cgo
 
 package user
diff --git a/src/pkg/path/filepath/export_test.go b/src/pkg/path/filepath/export_test.go
new file mode 100644
index 0000000..0cf9e3b
--- /dev/null
+++ b/src/pkg/path/filepath/export_test.go
@@ -0,0 +1,7 @@
+// 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 filepath
+
+var LstatP = &lstat
diff --git a/src/pkg/path/filepath/match.go b/src/pkg/path/filepath/match.go
index 3d84145..a9bcc10 100644
--- a/src/pkg/path/filepath/match.go
+++ b/src/pkg/path/filepath/match.go
@@ -230,7 +230,7 @@ func getEsc(chunk string) (r rune, nchunk string, err error) {
 //
 func Glob(pattern string) (matches []string, err error) {
 	if !hasMeta(pattern) {
-		if _, err = os.Stat(pattern); err != nil {
+		if _, err = os.Lstat(pattern); err != nil {
 			return nil, nil
 		}
 		return []string{pattern}, nil
diff --git a/src/pkg/path/filepath/match_test.go b/src/pkg/path/filepath/match_test.go
index 13108ce..382692e 100644
--- a/src/pkg/path/filepath/match_test.go
+++ b/src/pkg/path/filepath/match_test.go
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package filepath
+package filepath_test
 
 import (
+	"io/ioutil"
+	"os"
+	. "path/filepath"
 	"runtime"
 	"strings"
 	"testing"
@@ -153,3 +156,51 @@ func TestGlobError(t *testing.T) {
 		t.Error("expected error for bad pattern; got none")
 	}
 }
+
+var globSymlinkTests = []struct {
+	path, dest string
+	brokenLink bool
+}{
+	{"test1", "link1", false},
+	{"test2", "link2", true},
+}
+
+func TestGlobSymlink(t *testing.T) {
+	switch runtime.GOOS {
+	case "nacl", "plan9", "windows":
+		t.Skipf("skipping on %s", runtime.GOOS)
+	}
+
+	tmpDir, err := ioutil.TempDir("", "globsymlink")
+	if err != nil {
+		t.Fatal("creating temp dir:", err)
+	}
+	defer os.RemoveAll(tmpDir)
+
+	for _, tt := range globSymlinkTests {
+		path := Join(tmpDir, tt.path)
+		dest := Join(tmpDir, tt.dest)
+		f, err := os.Create(path)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if err := f.Close(); err != nil {
+			t.Fatal(err)
+		}
+		err = os.Symlink(path, dest)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if tt.brokenLink {
+			// Break the symlink.
+			os.Remove(path)
+		}
+		matches, err := Glob(dest)
+		if err != nil {
+			t.Errorf("GlobSymlink error for %q: %s", dest, err)
+		}
+		if !contains(matches, dest) {
+			t.Errorf("Glob(%#q) = %#v want %v", dest, matches, dest)
+		}
+	}
+}
diff --git a/src/pkg/path/filepath/path.go b/src/pkg/path/filepath/path.go
index f8c7e4b..71603cc 100644
--- a/src/pkg/path/filepath/path.go
+++ b/src/pkg/path/filepath/path.go
@@ -67,7 +67,7 @@ const (
 //	   along with the non-.. element that precedes it.
 //	4. Eliminate .. elements that begin a rooted path:
 //	   that is, replace "/.." by "/" at the beginning of a path,
-//         assuming Separator is '/'.
+//	   assuming Separator is '/'.
 //
 // The returned path ends in a slash only if it represents a root directory,
 // such as "/" on Unix or `C:\` on Windows.
@@ -336,6 +336,8 @@ var SkipDir = errors.New("skip this directory")
 // the next file.
 type WalkFunc func(path string, info os.FileInfo, err error) error
 
+var lstat = os.Lstat // for testing
+
 // walk recursively descends path, calling w.
 func walk(path string, info os.FileInfo, walkFn WalkFunc) error {
 	err := walkFn(path, info, nil)
@@ -350,17 +352,25 @@ func walk(path string, info os.FileInfo, walkFn WalkFunc) error {
 		return nil
 	}
 
-	list, err := readDir(path)
+	names, err := readDirNames(path)
 	if err != nil {
 		return walkFn(path, info, err)
 	}
 
-	for _, fileInfo := range list {
-		err = walk(Join(path, fileInfo.Name()), fileInfo, walkFn)
+	for _, name := range names {
+		filename := Join(path, name)
+		fileInfo, err := lstat(filename)
 		if err != nil {
-			if !fileInfo.IsDir() || err != SkipDir {
+			if err := walkFn(filename, fileInfo, err); err != nil && err != SkipDir {
 				return err
 			}
+		} else {
+			err = walk(filename, fileInfo, walkFn)
+			if err != nil {
+				if !fileInfo.IsDir() || err != SkipDir {
+					return err
+				}
+			}
 		}
 	}
 	return nil
@@ -380,30 +390,22 @@ func Walk(root string, walkFn WalkFunc) error {
 	return walk(root, info, walkFn)
 }
 
-// readDir reads the directory named by dirname and returns
+// readDirNames reads the directory named by dirname and returns
 // a sorted list of directory entries.
-// Copied from io/ioutil to avoid the circular import.
-func readDir(dirname string) ([]os.FileInfo, error) {
+func readDirNames(dirname string) ([]string, error) {
 	f, err := os.Open(dirname)
 	if err != nil {
 		return nil, err
 	}
-	list, err := f.Readdir(-1)
+	names, err := f.Readdirnames(-1)
 	f.Close()
 	if err != nil {
 		return nil, err
 	}
-	sort.Sort(byName(list))
-	return list, nil
+	sort.Strings(names)
+	return names, nil
 }
 
-// byName implements sort.Interface.
-type byName []os.FileInfo
-
-func (f byName) Len() int           { return len(f) }
-func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
-func (f byName) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }
-
 // Base returns the last element of path.
 // Trailing path separators are removed before extracting the last element.
 // If the path is empty, Base returns ".".
diff --git a/src/pkg/path/filepath/path_test.go b/src/pkg/path/filepath/path_test.go
index d32b70d..819bd21 100644
--- a/src/pkg/path/filepath/path_test.go
+++ b/src/pkg/path/filepath/path_test.go
@@ -5,6 +5,7 @@
 package filepath_test
 
 import (
+	"errors"
 	"io/ioutil"
 	"os"
 	"path/filepath"
@@ -458,6 +459,63 @@ func TestWalk(t *testing.T) {
 	}
 }
 
+func touch(t *testing.T, name string) {
+	f, err := os.Create(name)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := f.Close(); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestWalkFileError(t *testing.T) {
+	td, err := ioutil.TempDir("", "walktest")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(td)
+
+	touch(t, filepath.Join(td, "foo"))
+	touch(t, filepath.Join(td, "bar"))
+	dir := filepath.Join(td, "dir")
+	if err := os.MkdirAll(filepath.Join(td, "dir"), 0755); err != nil {
+		t.Fatal(err)
+	}
+	touch(t, filepath.Join(dir, "baz"))
+	touch(t, filepath.Join(dir, "stat-error"))
+	defer func() {
+		*filepath.LstatP = os.Lstat
+	}()
+	statErr := errors.New("some stat error")
+	*filepath.LstatP = func(path string) (os.FileInfo, error) {
+		if strings.HasSuffix(path, "stat-error") {
+			return nil, statErr
+		}
+		return os.Lstat(path)
+	}
+	got := map[string]error{}
+	err = filepath.Walk(td, func(path string, fi os.FileInfo, err error) error {
+		rel, _ := filepath.Rel(td, path)
+		got[filepath.ToSlash(rel)] = err
+		return nil
+	})
+	if err != nil {
+		t.Errorf("Walk error: %v", err)
+	}
+	want := map[string]error{
+		".":              nil,
+		"foo":            nil,
+		"bar":            nil,
+		"dir":            nil,
+		"dir/baz":        nil,
+		"dir/stat-error": statErr,
+	}
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("Walked %#v; want %#v", got, want)
+	}
+}
+
 var basetests = []PathTest{
 	{"", "."},
 	{".", "."},
@@ -633,8 +691,9 @@ func simpleJoin(dir, path string) string {
 }
 
 func TestEvalSymlinks(t *testing.T) {
-	if runtime.GOOS == "plan9" {
-		t.Skip("Skipping test: symlinks don't exist under Plan 9")
+	switch runtime.GOOS {
+	case "nacl", "plan9":
+		t.Skipf("skipping on %s", runtime.GOOS)
 	}
 
 	tmpDir, err := ioutil.TempDir("", "evalsymlink")
diff --git a/src/pkg/path/filepath/path_unix.go b/src/pkg/path/filepath/path_unix.go
index d927b34..7aba0ab 100644
--- a/src/pkg/path/filepath/path_unix.go
+++ b/src/pkg/path/filepath/path_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 filepath
 
diff --git a/src/pkg/path/filepath/path_windows_test.go b/src/pkg/path/filepath/path_windows_test.go
index d8926ad..8a9be8e 100644
--- a/src/pkg/path/filepath/path_windows_test.go
+++ b/src/pkg/path/filepath/path_windows_test.go
@@ -1,3 +1,7 @@
+// 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 filepath_test
 
 import (
diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go
index e9a2096..e994901 100644
--- a/src/pkg/reflect/all_test.go
+++ b/src/pkg/reflect/all_test.go
@@ -15,6 +15,7 @@ import (
 	. "reflect"
 	"runtime"
 	"sort"
+	"strings"
 	"sync"
 	"testing"
 	"time"
@@ -678,6 +679,7 @@ var deepEqualTests = []DeepEqualTest{
 	{1, nil, false},
 	{fn1, fn3, false},
 	{fn3, fn3, false},
+	{[][]int{[]int{1}}, [][]int{[]int{2}}, false},
 
 	// Nil vs empty: not the same.
 	{[]int{}, []int(nil), false},
@@ -971,6 +973,31 @@ func TestMap(t *testing.T) {
 	}
 }
 
+func TestNilMap(t *testing.T) {
+	var m map[string]int
+	mv := ValueOf(m)
+	keys := mv.MapKeys()
+	if len(keys) != 0 {
+		t.Errorf(">0 keys for nil map: %v", keys)
+	}
+
+	// Check that value for missing key is zero.
+	x := mv.MapIndex(ValueOf("hello"))
+	if x.Kind() != Invalid {
+		t.Errorf("m.MapIndex(\"hello\") for nil map = %v, want Invalid Value", x)
+	}
+
+	// Check big value too.
+	var mbig map[string][10 << 20]byte
+	x = ValueOf(mbig).MapIndex(ValueOf("hello"))
+	if x.Kind() != Invalid {
+		t.Errorf("mbig.MapIndex(\"hello\") for nil map = %v, want Invalid Value", x)
+	}
+
+	// Test that deletes from a nil map succeed.
+	mv.SetMapIndex(ValueOf("hi"), Value{})
+}
+
 func TestChan(t *testing.T) {
 	for loop := 0; loop < 2; loop++ {
 		var c chan int
@@ -1434,6 +1461,46 @@ func TestFunc(t *testing.T) {
 	}
 }
 
+type emptyStruct struct{}
+
+type nonEmptyStruct struct {
+	member int
+}
+
+func returnEmpty() emptyStruct {
+	return emptyStruct{}
+}
+
+func takesEmpty(e emptyStruct) {
+}
+
+func returnNonEmpty(i int) nonEmptyStruct {
+	return nonEmptyStruct{member: i}
+}
+
+func takesNonEmpty(n nonEmptyStruct) int {
+	return n.member
+}
+
+func TestCallWithStruct(t *testing.T) {
+	r := ValueOf(returnEmpty).Call(nil)
+	if len(r) != 1 || r[0].Type() != TypeOf(emptyStruct{}) {
+		t.Errorf("returning empty struct returned %#v instead", r)
+	}
+	r = ValueOf(takesEmpty).Call([]Value{ValueOf(emptyStruct{})})
+	if len(r) != 0 {
+		t.Errorf("takesEmpty returned values: %#v", r)
+	}
+	r = ValueOf(returnNonEmpty).Call([]Value{ValueOf(42)})
+	if len(r) != 1 || r[0].Type() != TypeOf(nonEmptyStruct{}) || r[0].Field(0).Int() != 42 {
+		t.Errorf("returnNonEmpty returned %#v", r)
+	}
+	r = ValueOf(takesNonEmpty).Call([]Value{ValueOf(nonEmptyStruct{member: 42})})
+	if len(r) != 1 || r[0].Type() != TypeOf(1) || r[0].Int() != 42 {
+		t.Errorf("takesNonEmpty returned %#v", r)
+	}
+}
+
 func TestMakeFunc(t *testing.T) {
 	f := dummy
 	fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in })
@@ -1470,6 +1537,23 @@ func TestMakeFuncInterface(t *testing.T) {
 	}
 }
 
+func TestMakeFuncVariadic(t *testing.T) {
+	// Test that variadic arguments are packed into a slice and passed as last arg
+	fn := func(_ int, is ...int) []int { return nil }
+	fv := MakeFunc(TypeOf(fn), func(in []Value) []Value { return in[1:2] })
+	ValueOf(&fn).Elem().Set(fv)
+
+	r := fv.Call([]Value{ValueOf(1), ValueOf(2), ValueOf(3)})[0].Interface().([]int)
+	if r[0] != 2 || r[1] != 3 {
+		t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
+	}
+
+	r = fv.CallSlice([]Value{ValueOf(1), ValueOf([]int{2, 3})})[0].Interface().([]int)
+	if r[0] != 2 || r[1] != 3 {
+		t.Errorf("Call returned [%v, %v]; want 2, 3", r[0], r[1])
+	}
+}
+
 type Point struct {
 	x, y int
 }
@@ -3616,3 +3700,142 @@ func (x *exhaustive) Choose(max int) int {
 func (x *exhaustive) Maybe() bool {
 	return x.Choose(2) == 1
 }
+
+func GCFunc(args []Value) []Value {
+	runtime.GC()
+	return []Value{}
+}
+
+func TestReflectFuncTraceback(t *testing.T) {
+	f := MakeFunc(TypeOf(func() {}), GCFunc)
+	f.Call([]Value{})
+}
+
+func (p Point) GCMethod(k int) int {
+	runtime.GC()
+	return k + p.x
+}
+
+func TestReflectMethodTraceback(t *testing.T) {
+	p := Point{3, 4}
+	m := ValueOf(p).MethodByName("GCMethod")
+	i := ValueOf(m.Interface()).Call([]Value{ValueOf(5)})[0].Int()
+	if i != 8 {
+		t.Errorf("Call returned %d; want 8", i)
+	}
+}
+
+func TestBigZero(t *testing.T) {
+	const size = 1 << 10
+	var v [size]byte
+	z := Zero(ValueOf(v).Type()).Interface().([size]byte)
+	for i := 0; i < size; i++ {
+		if z[i] != 0 {
+			t.Fatalf("Zero object not all zero, index %d", i)
+		}
+	}
+}
+
+func TestFieldByIndexNil(t *testing.T) {
+	type P struct {
+		F int
+	}
+	type T struct {
+		*P
+	}
+	v := ValueOf(T{})
+
+	v.FieldByName("P") // should be fine
+
+	defer func() {
+		if err := recover(); err == nil {
+			t.Fatalf("no error")
+		} else if !strings.Contains(fmt.Sprint(err), "nil pointer to embedded struct") {
+			t.Fatalf(`err=%q, wanted error containing "nil pointer to embedded struct"`, err)
+		}
+	}()
+	v.FieldByName("F") // should panic
+
+	t.Fatalf("did not panic")
+}
+
+// Given
+//	type Outer struct {
+//		*Inner
+//		...
+//	}
+// the compiler generates the implementation of (*Outer).M dispatching to the embedded Inner.
+// The implementation is logically:
+//	func (p *Outer) M() {
+//		(p.Inner).M()
+//	}
+// but since the only change here is the replacement of one pointer receiver with another,
+// the actual generated code overwrites the original receiver with the p.Inner pointer and
+// then jumps to the M method expecting the *Inner receiver.
+//
+// During reflect.Value.Call, we create an argument frame and the associated data structures
+// to describe it to the garbage collector, populate the frame, call reflect.call to
+// run a function call using that frame, and then copy the results back out of the frame.
+// The reflect.call function does a memmove of the frame structure onto the
+// stack (to set up the inputs), runs the call, and the memmoves the stack back to
+// the frame structure (to preserve the outputs).
+//
+// Originally reflect.call did not distinguish inputs from outputs: both memmoves
+// were for the full stack frame. However, in the case where the called function was
+// one of these wrappers, the rewritten receiver is almost certainly a different type
+// than the original receiver. This is not a problem on the stack, where we use the
+// program counter to determine the type information and understand that
+// during (*Outer).M the receiver is an *Outer while during (*Inner).M the receiver in the same
+// memory word is now an *Inner. But in the statically typed argument frame created
+// by reflect, the receiver is always an *Outer. Copying the modified receiver pointer
+// off the stack into the frame will store an *Inner there, and then if a garbage collection
+// happens to scan that argument frame before it is discarded, it will scan the *Inner
+// memory as if it were an *Outer. If the two have different memory layouts, the
+// collection will intepret the memory incorrectly.
+//
+// One such possible incorrect interpretation is to treat two arbitrary memory words
+// (Inner.P1 and Inner.P2 below) as an interface (Outer.R below). Because interpreting
+// an interface requires dereferencing the itab word, the misinterpretation will try to
+// deference Inner.P1, causing a crash during garbage collection.
+//
+// This came up in a real program in issue 7725.
+
+type Outer struct {
+	*Inner
+	R io.Reader
+}
+
+type Inner struct {
+	X  *Outer
+	P1 uintptr
+	P2 uintptr
+}
+
+func (pi *Inner) M() {
+	// Clear references to pi so that the only way the
+	// garbage collection will find the pointer is in the
+	// argument frame, typed as a *Outer.
+	pi.X.Inner = nil
+
+	// Set up an interface value that will cause a crash.
+	// P1 = 1 is a non-zero, so the interface looks non-nil.
+	// P2 = pi ensures that the data word points into the
+	// allocated heap; if not the collection skips the interface
+	// value as irrelevant, without dereferencing P1.
+	pi.P1 = 1
+	pi.P2 = uintptr(unsafe.Pointer(pi))
+}
+
+func TestCallMethodJump(t *testing.T) {
+	// In reflect.Value.Call, trigger a garbage collection after reflect.call
+	// returns but before the args frame has been discarded.
+	// This is a little clumsy but makes the failure repeatable.
+	*CallGC = true
+
+	p := &Outer{Inner: new(Inner)}
+	p.Inner.X = p
+	ValueOf(p).Method(0).Call(nil)
+
+	// Stop garbage collecting during reflect.call.
+	*CallGC = false
+}
diff --git a/src/pkg/reflect/asm_386.s b/src/pkg/reflect/asm_amd64p32.s
similarity index 100%
copy from src/pkg/reflect/asm_386.s
copy to src/pkg/reflect/asm_amd64p32.s
diff --git a/src/pkg/reflect/deepequal.go b/src/pkg/reflect/deepequal.go
index e3bf3dc..f63715c 100644
--- a/src/pkg/reflect/deepequal.go
+++ b/src/pkg/reflect/deepequal.go
@@ -62,9 +62,6 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool {
 
 	switch v1.Kind() {
 	case Array:
-		if v1.Len() != v2.Len() {
-			return false
-		}
 		for i := 0; i < v1.Len(); i++ {
 			if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) {
 				return false
diff --git a/src/pkg/reflect/export_test.go b/src/pkg/reflect/export_test.go
index cd8cf2c..0778ad3 100644
--- a/src/pkg/reflect/export_test.go
+++ b/src/pkg/reflect/export_test.go
@@ -16,3 +16,4 @@ func IsRO(v Value) bool {
 }
 
 var ArrayOf = arrayOf
+var CallGC = &callGC
diff --git a/src/pkg/reflect/makefunc.go b/src/pkg/reflect/makefunc.go
index e1608ea..0e61fde 100644
--- a/src/pkg/reflect/makefunc.go
+++ b/src/pkg/reflect/makefunc.go
@@ -56,7 +56,7 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
 
 	impl := &makeFuncImpl{code: code, typ: ftyp, fn: fn}
 
-	return Value{t, unsafe.Pointer(impl), flag(Func) << flagKindShift}
+	return Value{t, unsafe.Pointer(impl), 0, flag(Func) << flagKindShift}
 }
 
 // makeFuncStub is an assembly function that is the code half of
@@ -81,13 +81,13 @@ type methodValue struct {
 // by code like Convert and Interface and Assign.
 func makeMethodValue(op string, v Value) Value {
 	if v.flag&flagMethod == 0 {
-		panic("reflect: internal error: invalid use of makePartialFunc")
+		panic("reflect: internal error: invalid use of makeMethodValue")
 	}
 
 	// Ignoring the flagMethod bit, v describes the receiver, not the method type.
 	fl := v.flag & (flagRO | flagAddr | flagIndir)
 	fl |= flag(v.typ.Kind()) << flagKindShift
-	rcvr := Value{v.typ, v.val, fl}
+	rcvr := Value{v.typ, v.ptr, v.scalar, fl}
 
 	// v.Type returns the actual type of the method value.
 	funcType := v.Type().(*rtype)
@@ -109,7 +109,7 @@ func makeMethodValue(op string, v Value) Value {
 	// but we want Interface() and other operations to fail early.
 	methodReceiver(op, fv.rcvr, fv.method)
 
-	return Value{funcType, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)<<flagKindShift}
+	return Value{funcType, unsafe.Pointer(fv), 0, v.flag&flagRO | flag(Func)<<flagKindShift}
 }
 
 // methodValueCall is an assembly function that is the code half of
diff --git a/src/pkg/reflect/type.go b/src/pkg/reflect/type.go
index 7afb7de..40d76f9 100644
--- a/src/pkg/reflect/type.go
+++ b/src/pkg/reflect/type.go
@@ -16,6 +16,7 @@
 package reflect
 
 import (
+	"runtime"
 	"strconv"
 	"sync"
 	"unsafe"
@@ -252,6 +253,7 @@ type rtype struct {
 	string        *string        // string form; unnecessary but undeniably useful
 	*uncommonType                // (relatively) uncommon fields
 	ptrToThis     *rtype         // type for pointer to this type, if used in binary or has methods
+	zero          unsafe.Pointer // pointer to zero value
 }
 
 // Method on non-interface type
@@ -477,6 +479,8 @@ func (t *rtype) FieldAlign() int { return int(t.fieldAlign) }
 
 func (t *rtype) Kind() Kind { return Kind(t.kind & kindMask) }
 
+func (t *rtype) pointers() bool { return t.kind&kindNoPointers == 0 }
+
 func (t *rtype) common() *rtype { return t }
 
 func (t *uncommonType) Method(i int) (m Method) {
@@ -495,7 +499,7 @@ func (t *uncommonType) Method(i int) (m Method) {
 	mt := p.typ
 	m.Type = mt
 	fn := unsafe.Pointer(&p.tfn)
-	m.Func = Value{mt, fn, fl}
+	m.Func = Value{mt, fn, 0, fl}
 	m.Index = i
 	return
 }
@@ -1089,6 +1093,7 @@ func (t *rtype) ptrTo() *rtype {
 
 	p.uncommonType = nil
 	p.ptrToThis = nil
+	p.zero = unsafe.Pointer(&make([]byte, p.size)[0])
 	p.elem = t
 
 	if t.kind&kindNoPointers != 0 {
@@ -1475,6 +1480,7 @@ func ChanOf(dir ChanDir, t Type) Type {
 	ch.elem = typ
 	ch.uncommonType = nil
 	ch.ptrToThis = nil
+	ch.zero = unsafe.Pointer(&make([]byte, ch.size)[0])
 
 	ch.gc = unsafe.Pointer(&chanGC{
 		width: ch.size,
@@ -1534,6 +1540,14 @@ func MapOf(key, elem Type) Type {
 	mt.hmap = hMapOf(mt.bucket)
 	mt.uncommonType = nil
 	mt.ptrToThis = nil
+	mt.zero = unsafe.Pointer(&make([]byte, mt.size)[0])
+	mt.gc = unsafe.Pointer(&ptrGC{
+		width:  unsafe.Sizeof(uintptr(0)),
+		op:     _GC_PTR,
+		off:    0,
+		elemgc: mt.hmap.gc,
+		end:    _GC_END,
+	})
 
 	// INCORRECT. Uncomment to check that TestMapOfGC and TestMapOfGCValues
 	// fail when mt.gc is wrong.
@@ -1566,6 +1580,10 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
 	gc = append(gc, _GC_PTR, offset, 0 /*self pointer set below*/) // overflow
 	offset += ptrsize
 
+	if runtime.GOARCH == "amd64p32" {
+		offset += 4
+	}
+
 	// keys
 	if ktyp.kind&kindNoPointers == 0 {
 		gc = append(gc, _GC_ARRAY_START, offset, _BUCKETSIZE, ktyp.size)
@@ -1709,6 +1727,7 @@ func SliceOf(t Type) Type {
 	slice.elem = typ
 	slice.uncommonType = nil
 	slice.ptrToThis = nil
+	slice.zero = unsafe.Pointer(&make([]byte, slice.size)[0])
 
 	if typ.size == 0 {
 		slice.gc = unsafe.Pointer(&sliceEmptyGCProg)
@@ -1778,6 +1797,7 @@ func arrayOf(count int, elem Type) Type {
 	// TODO: array.gc
 	array.uncommonType = nil
 	array.ptrToThis = nil
+	array.zero = unsafe.Pointer(&make([]byte, array.size)[0])
 	array.len = uintptr(count)
 	array.slice = slice.(*rtype)
 
@@ -1795,3 +1815,112 @@ func toType(t *rtype) Type {
 	}
 	return t
 }
+
+type layoutKey struct {
+	t    *rtype // function signature
+	rcvr *rtype // receiver type, or nil if none
+}
+
+type layoutType struct {
+	t         *rtype
+	argSize   uintptr // size of arguments
+	retOffset uintptr // offset of return values.
+}
+
+var layoutCache struct {
+	sync.RWMutex
+	m map[layoutKey]layoutType
+}
+
+// funcLayout computes a struct type representing the layout of the
+// function arguments and return values for the function type t.
+// If rcvr != nil, rcvr specifies the type of the receiver.
+// The returned type exists only for GC, so we only fill out GC relevant info.
+// Currently, that's just size and the GC program.  We also fill in
+// the name for possible debugging use.
+func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr) {
+	if t.Kind() != Func {
+		panic("reflect: funcLayout of non-func type")
+	}
+	if rcvr != nil && rcvr.Kind() == Interface {
+		panic("reflect: funcLayout with interface receiver " + rcvr.String())
+	}
+	k := layoutKey{t, rcvr}
+	layoutCache.RLock()
+	if x := layoutCache.m[k]; x.t != nil {
+		layoutCache.RUnlock()
+		return x.t, x.argSize, x.retOffset
+	}
+	layoutCache.RUnlock()
+	layoutCache.Lock()
+	if x := layoutCache.m[k]; x.t != nil {
+		layoutCache.Unlock()
+		return x.t, x.argSize, x.retOffset
+	}
+
+	tt := (*funcType)(unsafe.Pointer(t))
+
+	// compute gc program for arguments
+	gc := make([]uintptr, 1) // first entry is size, filled in at the end
+	offset := uintptr(0)
+	if rcvr != nil {
+		// Reflect uses the "interface" calling convention for
+		// methods, where receivers take one word of argument
+		// space no matter how big they actually are.
+		if rcvr.size > ptrSize {
+			// we pass a pointer to the receiver.
+			gc = append(gc, _GC_PTR, offset, uintptr(rcvr.gc))
+		} else if rcvr.pointers() {
+			// rcvr is a one-word pointer object.  Its gc program
+			// is just what we need here.
+			gc = appendGCProgram(gc, rcvr)
+		}
+		offset += ptrSize
+	}
+	for _, arg := range tt.in {
+		offset = align(offset, uintptr(arg.align))
+		if arg.pointers() {
+			gc = append(gc, _GC_REGION, offset, arg.size, uintptr(arg.gc))
+		}
+		offset += arg.size
+	}
+	argSize = offset
+	if runtime.GOARCH == "amd64p32" {
+		offset = align(offset, 8)
+	}
+	offset = align(offset, ptrSize)
+	retOffset = offset
+	for _, res := range tt.out {
+		offset = align(offset, uintptr(res.align))
+		if res.pointers() {
+			gc = append(gc, _GC_REGION, offset, res.size, uintptr(res.gc))
+		}
+		offset += res.size
+	}
+	gc = append(gc, _GC_END)
+	gc[0] = offset
+
+	// build dummy rtype holding gc program
+	x := new(rtype)
+	x.size = offset
+	x.gc = unsafe.Pointer(&gc[0])
+	var s string
+	if rcvr != nil {
+		s = "methodargs(" + *rcvr.string + ")(" + *t.string + ")"
+	} else {
+		s = "funcargs(" + *t.string + ")"
+	}
+	x.string = &s
+
+	// cache result for future callers
+	if layoutCache.m == nil {
+		layoutCache.m = make(map[layoutKey]layoutType)
+	}
+	layoutCache.m[k] = layoutType{
+		t:         x,
+		argSize:   argSize,
+		retOffset: retOffset,
+	}
+	layoutCache.Unlock()
+	return x, argSize, retOffset
+}
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go
index df549f5..576cbc3 100644
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -62,14 +62,15 @@ type Value struct {
 	// typ holds the type of the value represented by a Value.
 	typ *rtype
 
-	// val holds the 1-word representation of the value.
-	// If flag's flagIndir bit is set, then val is a pointer to the data.
-	// Otherwise val is a word holding the actual data.
-	// When the data is smaller than a word, it begins at
-	// the first byte (in the memory address sense) of val.
-	// We use unsafe.Pointer so that the garbage collector
-	// knows that val could be a pointer.
-	val unsafe.Pointer
+	// Pointer-valued data or, if flagIndir is set, pointer to data.
+	// Valid when either flagIndir is set or typ.pointers() is true.
+	ptr unsafe.Pointer
+
+	// Non-pointer-valued data.  When the data is smaller
+	// than a word, it begins at the first byte (in the memory
+	// address sense) of this field.
+	// Valid when flagIndir is not set and typ.pointers() is false.
+	scalar uintptr
 
 	// flag holds metadata about the value.
 	// The lowest bits are flag bits:
@@ -108,6 +109,78 @@ func (f flag) kind() Kind {
 	return Kind((f >> flagKindShift) & flagKindMask)
 }
 
+// pointer returns the underlying pointer represented by v.
+// v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointer
+func (v Value) pointer() unsafe.Pointer {
+	if v.typ.size != ptrSize || !v.typ.pointers() {
+		panic("can't call pointer on a non-pointer Value")
+	}
+	if v.flag&flagIndir != 0 {
+		return *(*unsafe.Pointer)(v.ptr)
+	}
+	return v.ptr
+}
+
+// packEface converts v to the empty interface.
+func packEface(v Value) interface{} {
+	t := v.typ
+	var i interface{}
+	e := (*emptyInterface)(unsafe.Pointer(&i))
+	// First, fill in the data portion of the interface.
+	switch {
+	case t.size > ptrSize:
+		// Value is indirect, and so is the interface we're making.
+		ptr := v.ptr
+		if v.flag&flagAddr != 0 {
+			// TODO: pass safe boolean from valueInterface so
+			// we don't need to copy if safe==true?
+			c := unsafe_New(t)
+			memmove(c, ptr, t.size)
+			ptr = c
+		}
+		e.word = iword(ptr)
+	case v.flag&flagIndir != 0:
+		// Value is indirect, but interface is direct.  We need
+		// to load the data at v.ptr into the interface data word.
+		if t.pointers() {
+			e.word = iword(*(*unsafe.Pointer)(v.ptr))
+		} else {
+			e.word = iword(loadScalar(v.ptr, t.size))
+		}
+	default:
+		// Value is direct, and so is the interface.
+		if t.pointers() {
+			e.word = iword(v.ptr)
+		} else {
+			e.word = iword(v.scalar)
+		}
+	}
+	// Now, fill in the type portion.  We're very careful here not
+	// to have any operation between the e.word and e.typ assignments
+	// that would let the garbage collector observe the partially-built
+	// interface value.
+	e.typ = t
+	return i
+}
+
+// unpackEface converts the empty interface i to a Value.
+func unpackEface(i interface{}) Value {
+	e := (*emptyInterface)(unsafe.Pointer(&i))
+	// NOTE: don't read e.word until we know whether it is really a pointer or not.
+	t := e.typ
+	if t == nil {
+		return Value{}
+	}
+	f := flag(t.Kind()) << flagKindShift
+	if t.size > ptrSize {
+		return Value{t, unsafe.Pointer(e.word), 0, f | flagIndir}
+	}
+	if t.pointers() {
+		return Value{t, unsafe.Pointer(e.word), 0, f}
+	}
+	return Value{t, nil, uintptr(e.word), f}
+}
+
 // A ValueError occurs when a Value method is invoked on
 // a Value that does not support it.  Such cases are documented
 // in the description of each method.
@@ -139,28 +212,21 @@ func methodName() string {
 // bigger than a pointer, its word is a pointer to v's data.
 // Otherwise, its word holds the data stored
 // in its leading bytes (so is not a pointer).
-// Because the value sometimes holds a pointer, we use
-// unsafe.Pointer to represent it, so that if iword appears
-// in a struct, the garbage collector knows that might be
-// a pointer.
+// This type is very dangerous for the garbage collector because
+// it must be treated conservatively.  We try to never expose it
+// to the GC here so that GC remains precise.
 type iword unsafe.Pointer
 
-func (v Value) iword() iword {
-	if v.flag&flagIndir != 0 && v.typ.size <= ptrSize {
-		// Have indirect but want direct word.
-		return loadIword(v.val, v.typ.size)
-	}
-	return iword(v.val)
-}
-
-// loadIword loads n bytes at p from memory into an iword.
-func loadIword(p unsafe.Pointer, n uintptr) iword {
+// loadScalar loads n bytes at p from memory into a uintptr
+// that forms the second word of an interface.  The data
+// must be non-pointer in nature.
+func loadScalar(p unsafe.Pointer, n uintptr) uintptr {
 	// Run the copy ourselves instead of calling memmove
 	// to avoid moving w to the heap.
-	var w iword
+	var w uintptr
 	switch n {
 	default:
-		panic("reflect: internal error: loadIword of " + strconv.Itoa(int(n)) + "-byte value")
+		panic("reflect: internal error: loadScalar of " + strconv.Itoa(int(n)) + "-byte value")
 	case 0:
 	case 1:
 		*(*uint8)(unsafe.Pointer(&w)) = *(*uint8)(p)
@@ -182,13 +248,13 @@ func loadIword(p unsafe.Pointer, n uintptr) iword {
 	return w
 }
 
-// storeIword stores n bytes from w into p.
-func storeIword(p unsafe.Pointer, w iword, n uintptr) {
+// storeScalar stores n bytes from w into p.
+func storeScalar(p unsafe.Pointer, w uintptr, n uintptr) {
 	// Run the copy ourselves instead of calling memmove
 	// to avoid moving w to the heap.
 	switch n {
 	default:
-		panic("reflect: internal error: storeIword of " + strconv.Itoa(int(n)) + "-byte value")
+		panic("reflect: internal error: storeScalar of " + strconv.Itoa(int(n)) + "-byte value")
 	case 0:
 	case 1:
 		*(*uint8)(p) = *(*uint8)(unsafe.Pointer(&w))
@@ -278,7 +344,7 @@ func (v Value) Addr() Value {
 	if v.flag&flagAddr == 0 {
 		panic("reflect.Value.Addr of unaddressable value")
 	}
-	return Value{v.typ.ptrTo(), v.val, (v.flag & flagRO) | flag(Ptr)<<flagKindShift}
+	return Value{v.typ.ptrTo(), v.ptr, 0, (v.flag & flagRO) | flag(Ptr)<<flagKindShift}
 }
 
 // Bool returns v's underlying value.
@@ -286,9 +352,9 @@ func (v Value) Addr() Value {
 func (v Value) Bool() bool {
 	v.mustBe(Bool)
 	if v.flag&flagIndir != 0 {
-		return *(*bool)(v.val)
+		return *(*bool)(v.ptr)
 	}
-	return *(*bool)(unsafe.Pointer(&v.val))
+	return *(*bool)(unsafe.Pointer(&v.scalar))
 }
 
 // Bytes returns v's underlying value.
@@ -299,7 +365,7 @@ func (v Value) Bytes() []byte {
 		panic("reflect.Value.Bytes of non-byte slice")
 	}
 	// Slice is always bigger than a word; assume flagIndir.
-	return *(*[]byte)(v.val)
+	return *(*[]byte)(v.ptr)
 }
 
 // runes returns v's underlying value.
@@ -310,7 +376,7 @@ func (v Value) runes() []rune {
 		panic("reflect.Value.Bytes of non-rune slice")
 	}
 	// Slice is always bigger than a word; assume flagIndir.
-	return *(*[]rune)(v.val)
+	return *(*[]rune)(v.ptr)
 }
 
 // CanAddr returns true if the value's address can be obtained with Addr.
@@ -358,19 +424,28 @@ func (v Value) CallSlice(in []Value) []Value {
 	return v.call("CallSlice", in)
 }
 
+var callGC bool // for testing; see TestCallMethodJump
+
+var makeFuncStubFn = makeFuncStub
+var makeFuncStubCode = **(**uintptr)(unsafe.Pointer(&makeFuncStubFn))
+var methodValueCallFn = methodValueCall
+var methodValueCallCode = **(**uintptr)(unsafe.Pointer(&methodValueCallFn))
+
 func (v Value) call(op string, in []Value) []Value {
 	// Get function pointer, type.
 	t := v.typ
 	var (
-		fn   unsafe.Pointer
-		rcvr iword
+		fn       unsafe.Pointer
+		rcvr     Value
+		rcvrtype *rtype
 	)
 	if v.flag&flagMethod != 0 {
-		t, fn, rcvr = methodReceiver(op, v, int(v.flag)>>flagMethodShift)
+		rcvr = v
+		rcvrtype, t, fn = methodReceiver(op, v, int(v.flag)>>flagMethodShift)
 	} else if v.flag&flagIndir != 0 {
-		fn = *(*unsafe.Pointer)(v.val)
+		fn = *(*unsafe.Pointer)(v.ptr)
 	} else {
-		fn = v.val
+		fn = v.ptr
 	}
 
 	if fn == nil {
@@ -434,23 +509,36 @@ func (v Value) call(op string, in []Value) []Value {
 	}
 	nout := t.NumOut()
 
-	// Compute arg size & allocate.
-	// This computation is 5g/6g/8g-dependent
-	// and probably wrong for gccgo, but so
-	// is most of this function.
-	size, _, _, _ := frameSize(t, v.flag&flagMethod != 0)
-
-	// Copy into args.
-	//
-	// TODO(rsc): This will need to be updated for any new garbage collector.
-	// For now make everything look like a pointer by allocating
-	// a []unsafe.Pointer.
-	args := make([]unsafe.Pointer, size/ptrSize)
-	ptr := unsafe.Pointer(&args[0])
+	// If target is makeFuncStub, short circuit the unpack onto stack /
+	// pack back into []Value for the args and return values.  Just do the
+	// call directly.
+	// We need to do this here because otherwise we have a situation where
+	// reflect.callXX calls makeFuncStub, neither of which knows the
+	// layout of the args.  That's bad for precise gc & stack copying.
+	x := (*makeFuncImpl)(fn)
+	if x.code == makeFuncStubCode {
+		return x.fn(in)
+	}
+
+	// If the target is methodValueCall, do its work here: add the receiver
+	// argument and call the real target directly.
+	// We need to do this here because otherwise we have a situation where
+	// reflect.callXX calls methodValueCall, neither of which knows the
+	// layout of the args.  That's bad for precise gc & stack copying.
+	y := (*methodValue)(fn)
+	if y.fn == methodValueCallCode {
+		rcvr = y.rcvr
+		rcvrtype, t, fn = methodReceiver("call", rcvr, y.method)
+	}
+
+	// Compute frame type, allocate a chunk of memory for frame
+	frametype, _, retOffset := funcLayout(t, rcvrtype)
+	args := unsafe_New(frametype)
 	off := uintptr(0)
-	if v.flag&flagMethod != 0 {
-		// Hard-wired first argument.
-		*(*iword)(ptr) = rcvr
+
+	// Copy inputs into args.
+	if rcvrtype != nil {
+		storeRcvr(rcvr, args)
 		off = ptrSize
 	}
 	for i, v := range in {
@@ -459,30 +547,35 @@ func (v Value) call(op string, in []Value) []Value {
 		a := uintptr(targ.align)
 		off = (off + a - 1) &^ (a - 1)
 		n := targ.size
-		addr := unsafe.Pointer(uintptr(ptr) + off)
+		addr := unsafe.Pointer(uintptr(args) + off)
 		v = v.assignTo("reflect.Value.Call", targ, (*interface{})(addr))
-		if v.flag&flagIndir == 0 {
-			storeIword(addr, iword(v.val), n)
+		if v.flag&flagIndir != 0 {
+			memmove(addr, v.ptr, n)
+		} else if targ.pointers() {
+			*(*unsafe.Pointer)(addr) = v.ptr
 		} else {
-			memmove(addr, v.val, n)
+			storeScalar(addr, v.scalar, n)
 		}
 		off += n
 	}
-	off = (off + ptrSize - 1) &^ (ptrSize - 1)
 
 	// Call.
-	call(fn, ptr, uint32(size))
+	call(fn, args, uint32(frametype.size), uint32(retOffset))
+
+	// For testing; see TestCallMethodJump.
+	if callGC {
+		runtime.GC()
+	}
 
 	// Copy return values out of args.
-	//
-	// TODO(rsc): revisit like above.
 	ret := make([]Value, nout)
+	off = retOffset
 	for i := 0; i < nout; i++ {
 		tv := t.Out(i)
 		a := uintptr(tv.Align())
 		off = (off + a - 1) &^ (a - 1)
 		fl := flagIndir | flag(tv.Kind())<<flagKindShift
-		ret[i] = Value{tv.common(), unsafe.Pointer(uintptr(ptr) + off), fl}
+		ret[i] = Value{tv.common(), unsafe.Pointer(uintptr(args) + off), 0, fl}
 		off += tv.Size()
 	}
 
@@ -512,18 +605,20 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
 	for _, arg := range ftyp.in {
 		typ := arg
 		off += -off & uintptr(typ.align-1)
-		v := Value{typ, nil, flag(typ.Kind()) << flagKindShift}
-		if typ.size <= ptrSize {
-			// value fits in word.
-			v.val = unsafe.Pointer(loadIword(unsafe.Pointer(uintptr(ptr)+off), typ.size))
-		} else {
+		addr := unsafe.Pointer(uintptr(ptr) + off)
+		v := Value{typ, nil, 0, flag(typ.Kind()) << flagKindShift}
+		if typ.size > ptrSize {
 			// value does not fit in word.
 			// Must make a copy, because f might keep a reference to it,
 			// and we cannot let f keep a reference to the stack frame
 			// after this function returns, not even a read-only reference.
-			v.val = unsafe_New(typ)
-			memmove(v.val, unsafe.Pointer(uintptr(ptr)+off), typ.size)
+			v.ptr = unsafe_New(typ)
+			memmove(v.ptr, addr, typ.size)
 			v.flag |= flagIndir
+		} else if typ.pointers() {
+			v.ptr = *(*unsafe.Pointer)(addr)
+		} else {
+			v.scalar = loadScalar(addr, typ.size)
 		}
 		in = append(in, v)
 		off += typ.size
@@ -538,6 +633,9 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
 	// Copy results back into argument frame.
 	if len(ftyp.out) > 0 {
 		off += -off & (ptrSize - 1)
+		if runtime.GOARCH == "amd64p32" {
+			off = align(off, 8)
+		}
 		for i, arg := range ftyp.out {
 			typ := arg
 			v := out[i]
@@ -552,10 +650,12 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
 			}
 			off += -off & uintptr(typ.align-1)
 			addr := unsafe.Pointer(uintptr(ptr) + off)
-			if v.flag&flagIndir == 0 {
-				storeIword(addr, iword(v.val), typ.size)
+			if v.flag&flagIndir != 0 {
+				memmove(addr, v.ptr, typ.size)
+			} else if typ.pointers() {
+				*(*unsafe.Pointer)(addr) = v.ptr
 			} else {
-				memmove(addr, v.val, typ.size)
+				storeScalar(addr, v.scalar, typ.size)
 			}
 			off += typ.size
 		}
@@ -566,7 +666,10 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
 // described by v. The Value v may or may not have the
 // flagMethod bit set, so the kind cached in v.flag should
 // not be used.
-func methodReceiver(op string, v Value, methodIndex int) (t *rtype, fn unsafe.Pointer, rcvr iword) {
+// The return value rcvrtype gives the method's actual receiver type.
+// The return value t gives the method type signature (without the receiver).
+// The return value fn is a pointer to the method code.
+func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn unsafe.Pointer) {
 	i := methodIndex
 	if v.typ.Kind() == Interface {
 		tt := (*interfaceType)(unsafe.Pointer(v.typ))
@@ -577,14 +680,15 @@ func methodReceiver(op string, v Value, methodIndex int) (t *rtype, fn unsafe.Po
 		if m.pkgPath != nil {
 			panic("reflect: " + op + " of unexported method")
 		}
-		t = m.typ
-		iface := (*nonEmptyInterface)(v.val)
+		iface := (*nonEmptyInterface)(v.ptr)
 		if iface.itab == nil {
 			panic("reflect: " + op + " of method on nil interface value")
 		}
+		rcvrtype = iface.itab.typ
 		fn = unsafe.Pointer(&iface.itab.fun[i])
-		rcvr = iface.word
+		t = m.typ
 	} else {
+		rcvrtype = v.typ
 		ut := v.typ.uncommon()
 		if ut == nil || i < 0 || i >= len(ut.methods) {
 			panic("reflect: internal error: invalid method index")
@@ -595,58 +699,41 @@ func methodReceiver(op string, v Value, methodIndex int) (t *rtype, fn unsafe.Po
 		}
 		fn = unsafe.Pointer(&m.ifn)
 		t = m.mtyp
-		rcvr = v.iword()
 	}
 	return
 }
 
+// v is a method receiver.  Store at p the word which is used to
+// encode that receiver at the start of the argument list.
+// Reflect uses the "interface" calling convention for
+// methods, which always uses one word to record the receiver.
+func storeRcvr(v Value, p unsafe.Pointer) {
+	t := v.typ
+	if t.Kind() == Interface {
+		// the interface data word becomes the receiver word
+		iface := (*nonEmptyInterface)(v.ptr)
+		*(*unsafe.Pointer)(p) = unsafe.Pointer(iface.word)
+	} else if v.flag&flagIndir != 0 {
+		if t.size > ptrSize {
+			*(*unsafe.Pointer)(p) = v.ptr
+		} else if t.pointers() {
+			*(*unsafe.Pointer)(p) = *(*unsafe.Pointer)(v.ptr)
+		} else {
+			*(*uintptr)(p) = loadScalar(v.ptr, t.size)
+		}
+	} else if t.pointers() {
+		*(*unsafe.Pointer)(p) = v.ptr
+	} else {
+		*(*uintptr)(p) = v.scalar
+	}
+}
+
 // align returns the result of rounding x up to a multiple of n.
 // n must be a power of two.
 func align(x, n uintptr) uintptr {
 	return (x + n - 1) &^ (n - 1)
 }
 
-// frameSize returns the sizes of the argument and result frame
-// for a function of the given type. The rcvr bool specifies whether
-// a one-word receiver should be included in the total.
-func frameSize(t *rtype, rcvr bool) (total, in, outOffset, out uintptr) {
-	if rcvr {
-		// extra word for receiver interface word
-		total += ptrSize
-	}
-
-	nin := t.NumIn()
-	in = -total
-	for i := 0; i < nin; i++ {
-		tv := t.In(i)
-		total = align(total, uintptr(tv.Align()))
-		total += tv.Size()
-	}
-	in += total
-	total = align(total, ptrSize)
-	nout := t.NumOut()
-	outOffset = total
-	out = -total
-	for i := 0; i < nout; i++ {
-		tv := t.Out(i)
-		total = align(total, uintptr(tv.Align()))
-		total += tv.Size()
-	}
-	out += total
-
-	// total must be > 0 in order for &args[0] to be valid.
-	// the argument copying is going to round it up to
-	// a multiple of ptrSize anyway, so make it ptrSize to begin with.
-	if total < ptrSize {
-		total = ptrSize
-	}
-
-	// round to pointer
-	total = align(total, ptrSize)
-
-	return
-}
-
 // callMethod is the call implementation used by a function returned
 // by makeMethodValue (used by v.Method(i).Interface()).
 // It is a streamlined version of the usual reflect call: the caller has
@@ -659,24 +746,31 @@ func frameSize(t *rtype, rcvr bool) (total, in, outOffset, out uintptr) {
 // so that the linker can make it work correctly for panic and recover.
 // The gc compilers know to do that for the name "reflect.callMethod".
 func callMethod(ctxt *methodValue, frame unsafe.Pointer) {
-	t, fn, rcvr := methodReceiver("call", ctxt.rcvr, ctxt.method)
-	total, in, outOffset, out := frameSize(t, true)
-
-	// Copy into args.
-	//
-	// TODO(rsc): This will need to be updated for any new garbage collector.
-	// For now make everything look like a pointer by allocating
-	// a []unsafe.Pointer.
-	args := make([]unsafe.Pointer, total/ptrSize)
-	args[0] = unsafe.Pointer(rcvr)
-	base := unsafe.Pointer(&args[0])
-	memmove(unsafe.Pointer(uintptr(base)+ptrSize), frame, in)
+	rcvr := ctxt.rcvr
+	rcvrtype, t, fn := methodReceiver("call", rcvr, ctxt.method)
+	frametype, argSize, retOffset := funcLayout(t, rcvrtype)
+
+	// Make a new frame that is one word bigger so we can store the receiver.
+	args := unsafe_New(frametype)
+
+	// Copy in receiver and rest of args.
+	storeRcvr(rcvr, args)
+	memmove(unsafe.Pointer(uintptr(args)+ptrSize), frame, argSize-ptrSize)
 
 	// Call.
-	call(fn, unsafe.Pointer(&args[0]), uint32(total))
+	call(fn, args, uint32(frametype.size), uint32(retOffset))
 
-	// Copy return values.
-	memmove(unsafe.Pointer(uintptr(frame)+outOffset-ptrSize), unsafe.Pointer(uintptr(base)+outOffset), out)
+	// Copy return values. On amd64p32, the beginning of return values
+	// is 64-bit aligned, so the caller's frame layout (which doesn't have
+	// a receiver) is different from the layout of the fn call, which has
+	// a receiver.
+	// Ignore any changes to args and just copy return values.
+	callerRetOffset := retOffset - ptrSize
+	if runtime.GOARCH == "amd64p32" {
+		callerRetOffset = align(argSize-ptrSize, 8)
+	}
+	memmove(unsafe.Pointer(uintptr(frame)+callerRetOffset),
+		unsafe.Pointer(uintptr(args)+retOffset), frametype.size-retOffset)
 }
 
 // funcName returns the name of f, for use in error messages.
@@ -697,10 +791,10 @@ func (v Value) Cap() int {
 	case Array:
 		return v.typ.Len()
 	case Chan:
-		return int(chancap(v.iword()))
+		return int(chancap(v.pointer()))
 	case Slice:
 		// Slice is always bigger than a word; assume flagIndir.
-		return (*SliceHeader)(v.val).Cap
+		return (*sliceHeader)(v.ptr).Cap
 	}
 	panic(&ValueError{"reflect.Value.Cap", k})
 }
@@ -710,7 +804,7 @@ func (v Value) Cap() int {
 func (v Value) Close() {
 	v.mustBe(Chan)
 	v.mustBeExported()
-	chanclose(v.iword())
+	chanclose(v.pointer())
 }
 
 // Complex returns v's underlying value, as a complex128.
@@ -720,12 +814,12 @@ func (v Value) Complex() complex128 {
 	switch k {
 	case Complex64:
 		if v.flag&flagIndir != 0 {
-			return complex128(*(*complex64)(v.val))
+			return complex128(*(*complex64)(v.ptr))
 		}
-		return complex128(*(*complex64)(unsafe.Pointer(&v.val)))
+		return complex128(*(*complex64)(unsafe.Pointer(&v.scalar)))
 	case Complex128:
 		// complex128 is always bigger than a word; assume flagIndir.
-		return *(*complex128)(v.val)
+		return *(*complex128)(v.ptr)
 	}
 	panic(&ValueError{"reflect.Value.Complex", k})
 }
@@ -738,48 +832,31 @@ func (v Value) Elem() Value {
 	k := v.kind()
 	switch k {
 	case Interface:
-		var (
-			typ *rtype
-			val unsafe.Pointer
-		)
+		var eface interface{}
 		if v.typ.NumMethod() == 0 {
-			eface := (*emptyInterface)(v.val)
-			if eface.typ == nil {
-				// nil interface value
-				return Value{}
-			}
-			typ = eface.typ
-			val = unsafe.Pointer(eface.word)
+			eface = *(*interface{})(v.ptr)
 		} else {
-			iface := (*nonEmptyInterface)(v.val)
-			if iface.itab == nil {
-				// nil interface value
-				return Value{}
-			}
-			typ = iface.itab.typ
-			val = unsafe.Pointer(iface.word)
-		}
-		fl := v.flag & flagRO
-		fl |= flag(typ.Kind()) << flagKindShift
-		if typ.size > ptrSize {
-			fl |= flagIndir
+			eface = (interface{})(*(*interface {
+				M()
+			})(v.ptr))
 		}
-		return Value{typ, val, fl}
-
+		x := unpackEface(eface)
+		x.flag |= v.flag & flagRO
+		return x
 	case Ptr:
-		val := v.val
+		ptr := v.ptr
 		if v.flag&flagIndir != 0 {
-			val = *(*unsafe.Pointer)(val)
+			ptr = *(*unsafe.Pointer)(ptr)
 		}
 		// The returned value's address is v's value.
-		if val == nil {
+		if ptr == nil {
 			return Value{}
 		}
 		tt := (*ptrType)(unsafe.Pointer(v.typ))
 		typ := tt.elem
 		fl := v.flag&flagRO | flagIndir | flagAddr
 		fl |= flag(typ.Kind() << flagKindShift)
-		return Value{typ, val, fl}
+		return Value{typ, ptr, 0, fl}
 	}
 	panic(&ValueError{"reflect.Value.Elem", k})
 }
@@ -803,20 +880,26 @@ func (v Value) Field(i int) Value {
 	}
 	fl |= flag(typ.Kind()) << flagKindShift
 
-	var val unsafe.Pointer
+	var ptr unsafe.Pointer
+	var scalar uintptr
 	switch {
 	case fl&flagIndir != 0:
 		// Indirect.  Just bump pointer.
-		val = unsafe.Pointer(uintptr(v.val) + field.offset)
+		ptr = unsafe.Pointer(uintptr(v.ptr) + field.offset)
+	case typ.pointers():
+		if field.offset != 0 {
+			panic("field access of ptr value isn't at offset 0")
+		}
+		ptr = v.ptr
 	case bigEndian:
-		// Direct.  Discard leading bytes.
-		val = unsafe.Pointer(uintptr(v.val) << (field.offset * 8))
+		// Must be scalar.  Discard leading bytes.
+		scalar = v.scalar << (field.offset * 8)
 	default:
-		// Direct.  Discard leading bytes.
-		val = unsafe.Pointer(uintptr(v.val) >> (field.offset * 8))
+		// Must be scalar.  Discard leading bytes.
+		scalar = v.scalar >> (field.offset * 8)
 	}
 
-	return Value{typ, val, fl}
+	return Value{typ, ptr, scalar, fl}
 }
 
 // FieldByIndex returns the nested field corresponding to index.
@@ -825,7 +908,10 @@ func (v Value) FieldByIndex(index []int) Value {
 	v.mustBe(Struct)
 	for i, x := range index {
 		if i > 0 {
-			if v.Kind() == Ptr && v.Elem().Kind() == Struct {
+			if v.Kind() == Ptr && v.typ.Elem().Kind() == Struct {
+				if v.IsNil() {
+					panic("reflect: indirection through nil pointer to embedded struct")
+				}
 				v = v.Elem()
 			}
 		}
@@ -864,14 +950,14 @@ func (v Value) Float() float64 {
 	switch k {
 	case Float32:
 		if v.flag&flagIndir != 0 {
-			return float64(*(*float32)(v.val))
+			return float64(*(*float32)(v.ptr))
 		}
-		return float64(*(*float32)(unsafe.Pointer(&v.val)))
+		return float64(*(*float32)(unsafe.Pointer(&v.scalar)))
 	case Float64:
 		if v.flag&flagIndir != 0 {
-			return *(*float64)(v.val)
+			return *(*float64)(v.ptr)
 		}
-		return *(*float64)(unsafe.Pointer(&v.val))
+		return *(*float64)(unsafe.Pointer(&v.scalar))
 	}
 	panic(&ValueError{"reflect.Value.Float", k})
 }
@@ -894,41 +980,48 @@ func (v Value) Index(i int) Value {
 		offset := uintptr(i) * typ.size
 
 		var val unsafe.Pointer
+		var scalar uintptr
 		switch {
 		case fl&flagIndir != 0:
 			// Indirect.  Just bump pointer.
-			val = unsafe.Pointer(uintptr(v.val) + offset)
+			val = unsafe.Pointer(uintptr(v.ptr) + offset)
+		case typ.pointers():
+			if offset != 0 {
+				panic("can't Index(i) with i!=0 on ptrLike value")
+			}
+			val = v.ptr
 		case bigEndian:
 			// Direct.  Discard leading bytes.
-			val = unsafe.Pointer(uintptr(v.val) << (offset * 8))
+			scalar = v.scalar << (offset * 8)
 		default:
 			// Direct.  Discard leading bytes.
-			val = unsafe.Pointer(uintptr(v.val) >> (offset * 8))
+			scalar = v.scalar >> (offset * 8)
 		}
-		return Value{typ, val, fl}
+		return Value{typ, val, scalar, fl}
 
 	case Slice:
 		// Element flag same as Elem of Ptr.
 		// Addressable, indirect, possibly read-only.
 		fl := flagAddr | flagIndir | v.flag&flagRO
-		s := (*SliceHeader)(v.val)
+		s := (*sliceHeader)(v.ptr)
 		if i < 0 || i >= s.Len {
 			panic("reflect: slice index out of range")
 		}
 		tt := (*sliceType)(unsafe.Pointer(v.typ))
 		typ := tt.elem
 		fl |= flag(typ.Kind()) << flagKindShift
-		val := unsafe.Pointer(s.Data + uintptr(i)*typ.size)
-		return Value{typ, val, fl}
+		val := unsafe.Pointer(uintptr(s.Data) + uintptr(i)*typ.size)
+		return Value{typ, val, 0, fl}
 
 	case String:
 		fl := v.flag&flagRO | flag(Uint8<<flagKindShift)
-		s := (*StringHeader)(v.val)
+		s := (*stringHeader)(v.ptr)
 		if i < 0 || i >= s.Len {
 			panic("reflect: string index out of range")
 		}
-		val := *(*byte)(unsafe.Pointer(s.Data + uintptr(i)))
-		return Value{uint8Type, unsafe.Pointer(uintptr(val)), fl}
+		b := uintptr(0)
+		*(*byte)(unsafe.Pointer(&b)) = *(*byte)(unsafe.Pointer(uintptr(s.Data) + uintptr(i)))
+		return Value{uint8Type, nil, b, fl}
 	}
 	panic(&ValueError{"reflect.Value.Index", k})
 }
@@ -939,11 +1032,11 @@ func (v Value) Int() int64 {
 	k := v.kind()
 	var p unsafe.Pointer
 	if v.flag&flagIndir != 0 {
-		p = v.val
+		p = v.ptr
 	} else {
-		// The escape analysis is good enough that &v.val
+		// The escape analysis is good enough that &v.scalar
 		// does not trigger a heap allocation.
-		p = unsafe.Pointer(&v.val)
+		p = unsafe.Pointer(&v.scalar)
 	}
 	switch k {
 	case Int:
@@ -991,51 +1084,42 @@ func valueInterface(v Value, safe bool) interface{} {
 		v = makeMethodValue("Interface", v)
 	}
 
-	k := v.kind()
-	if k == Interface {
+	if v.kind() == Interface {
 		// Special case: return the element inside the interface.
 		// Empty interface has one layout, all interfaces with
 		// methods have a second layout.
 		if v.NumMethod() == 0 {
-			return *(*interface{})(v.val)
+			return *(*interface{})(v.ptr)
 		}
 		return *(*interface {
 			M()
-		})(v.val)
-	}
-
-	// Non-interface value.
-	var eface emptyInterface
-	eface.typ = v.typ
-	eface.word = v.iword()
-
-	// Don't need to allocate if v is not addressable or fits in one word.
-	if v.flag&flagAddr != 0 && v.typ.size > ptrSize {
-		// eface.word is a pointer to the actual data,
-		// which might be changed.  We need to return
-		// a pointer to unchanging data, so make a copy.
-		ptr := unsafe_New(v.typ)
-		memmove(ptr, unsafe.Pointer(eface.word), v.typ.size)
-		eface.word = iword(ptr)
+		})(v.ptr)
 	}
 
-	return *(*interface{})(unsafe.Pointer(&eface))
+	// TODO: pass safe to packEface so we don't need to copy if safe==true?
+	return packEface(v)
 }
 
 // InterfaceData returns the interface v's value as a uintptr pair.
 // It panics if v's Kind is not Interface.
 func (v Value) InterfaceData() [2]uintptr {
+	// TODO: deprecate this
 	v.mustBe(Interface)
 	// We treat this as a read operation, so we allow
 	// it even for unexported data, because the caller
 	// has to import "unsafe" to turn it into something
 	// that can be abused.
 	// Interface value is always bigger than a word; assume flagIndir.
-	return *(*[2]uintptr)(v.val)
+	return *(*[2]uintptr)(v.ptr)
 }
 
-// IsNil returns true if v is a nil value.
-// It panics if v's Kind is not Chan, Func, Interface, Map, Ptr, or Slice.
+// IsNil reports whether its argument v is nil. The argument must be
+// a chan, func, interface, map, pointer, or slice value; if it is
+// not, IsNil panics. Note that IsNil is not always equivalent to a
+// regular comparison with nil in Go. For example, if v was created
+// by calling ValueOf with an uninitialized interface variable i,
+// i==nil will be true but v.IsNil will panic as v will be the zero
+// Value.
 func (v Value) IsNil() bool {
 	k := v.kind()
 	switch k {
@@ -1043,7 +1127,7 @@ func (v Value) IsNil() bool {
 		if v.flag&flagMethod != 0 {
 			return false
 		}
-		ptr := v.val
+		ptr := v.ptr
 		if v.flag&flagIndir != 0 {
 			ptr = *(*unsafe.Pointer)(ptr)
 		}
@@ -1051,7 +1135,7 @@ func (v Value) IsNil() bool {
 	case Interface, Slice:
 		// Both interface and slice are nil if first word is 0.
 		// Both are always bigger than a word; assume flagIndir.
-		return *(*unsafe.Pointer)(v.val) == nil
+		return *(*unsafe.Pointer)(v.ptr) == nil
 	}
 	panic(&ValueError{"reflect.Value.IsNil", k})
 }
@@ -1080,15 +1164,15 @@ func (v Value) Len() int {
 		tt := (*arrayType)(unsafe.Pointer(v.typ))
 		return int(tt.len)
 	case Chan:
-		return chanlen(v.iword())
+		return chanlen(v.pointer())
 	case Map:
-		return maplen(v.iword())
+		return maplen(v.pointer())
 	case Slice:
 		// Slice is bigger than a word; assume flagIndir.
-		return (*SliceHeader)(v.val).Len
+		return (*sliceHeader)(v.ptr).Len
 	case String:
 		// String is bigger than a word; assume flagIndir.
-		return (*StringHeader)(v.val).Len
+		return (*stringHeader)(v.ptr).Len
 	}
 	panic(&ValueError{"reflect.Value.Len", k})
 }
@@ -1110,17 +1194,32 @@ func (v Value) MapIndex(key Value) Value {
 	// of unexported fields.
 	key = key.assignTo("reflect.Value.MapIndex", tt.key, nil)
 
-	word, ok := mapaccess(v.typ, v.iword(), key.iword())
-	if !ok {
+	var k unsafe.Pointer
+	if key.flag&flagIndir != 0 {
+		k = key.ptr
+	} else if key.typ.pointers() {
+		k = unsafe.Pointer(&key.ptr)
+	} else {
+		k = unsafe.Pointer(&key.scalar)
+	}
+	e := mapaccess(v.typ, v.pointer(), k)
+	if e == nil {
 		return Value{}
 	}
 	typ := tt.elem
 	fl := (v.flag | key.flag) & flagRO
+	fl |= flag(typ.Kind()) << flagKindShift
 	if typ.size > ptrSize {
-		fl |= flagIndir
+		// Copy result so future changes to the map
+		// won't change the underlying value.
+		c := unsafe_New(typ)
+		memmove(c, e, typ.size)
+		return Value{typ, c, 0, fl | flagIndir}
+	} else if typ.pointers() {
+		return Value{typ, *(*unsafe.Pointer)(e), 0, fl}
+	} else {
+		return Value{typ, nil, loadScalar(e, typ.size), fl}
 	}
-	fl |= flag(typ.Kind()) << flagKindShift
-	return Value{typ, unsafe.Pointer(word), fl}
 }
 
 // MapKeys returns a slice containing all the keys present in the map,
@@ -1132,13 +1231,9 @@ func (v Value) MapKeys() []Value {
 	tt := (*mapType)(unsafe.Pointer(v.typ))
 	keyType := tt.key
 
-	fl := v.flag & flagRO
-	fl |= flag(keyType.Kind()) << flagKindShift
-	if keyType.size > ptrSize {
-		fl |= flagIndir
-	}
+	fl := v.flag&flagRO | flag(keyType.Kind())<<flagKindShift
 
-	m := v.iword()
+	m := v.pointer()
 	mlen := int(0)
 	if m != nil {
 		mlen = maplen(m)
@@ -1147,11 +1242,24 @@ func (v Value) MapKeys() []Value {
 	a := make([]Value, mlen)
 	var i int
 	for i = 0; i < len(a); i++ {
-		keyWord, ok := mapiterkey(it)
-		if !ok {
+		key := mapiterkey(it)
+		if key == nil {
+			// Someone deleted an entry from the map since we
+			// called maplen above.  It's a data race, but nothing
+			// we can do about it.
 			break
 		}
-		a[i] = Value{keyType, unsafe.Pointer(keyWord), fl}
+		if keyType.size > ptrSize {
+			// Copy result so future changes to the map
+			// won't change the underlying value.
+			c := unsafe_New(keyType)
+			memmove(c, key, keyType.size)
+			a[i] = Value{keyType, c, 0, fl | flagIndir}
+		} else if keyType.pointers() {
+			a[i] = Value{keyType, *(*unsafe.Pointer)(key), 0, fl}
+		} else {
+			a[i] = Value{keyType, nil, loadScalar(key, keyType.size), fl}
+		}
 		mapiternext(it)
 	}
 	return a[:i]
@@ -1174,7 +1282,7 @@ func (v Value) Method(i int) Value {
 	fl := v.flag & (flagRO | flagIndir)
 	fl |= flag(Func) << flagKindShift
 	fl |= flag(i)<<flagMethodShift | flagMethod
-	return Value{v.typ, v.val, fl}
+	return Value{v.typ, v.ptr, v.scalar, fl}
 }
 
 // NumMethod returns the number of methods in the value's method set.
@@ -1284,15 +1392,16 @@ func (v Value) OverflowUint(x uint64) bool {
 // code pointer, but not necessarily enough to identify a
 // single function uniquely. The only guarantee is that the
 // result is zero if and only if v is a nil func Value.
+//
+// If v's Kind is Slice, the returned pointer is to the first
+// element of the slice.  If the slice is nil the returned value
+// is 0.  If the slice is empty but non-nil the return value is non-zero.
 func (v Value) Pointer() uintptr {
+	// TODO: deprecate
 	k := v.kind()
 	switch k {
 	case Chan, Map, Ptr, UnsafePointer:
-		p := v.val
-		if v.flag&flagIndir != 0 {
-			p = *(*unsafe.Pointer)(p)
-		}
-		return uintptr(p)
+		return uintptr(v.pointer())
 	case Func:
 		if v.flag&flagMethod != 0 {
 			// As the doc comment says, the returned pointer is an
@@ -1304,10 +1413,7 @@ func (v Value) Pointer() uintptr {
 			f := methodValueCall
 			return **(**uintptr)(unsafe.Pointer(&f))
 		}
-		p := v.val
-		if v.flag&flagIndir != 0 {
-			p = *(*unsafe.Pointer)(p)
-		}
+		p := v.pointer()
 		// Non-nil func value points at data block.
 		// First word of data block is actual code.
 		if p != nil {
@@ -1316,7 +1422,7 @@ func (v Value) Pointer() uintptr {
 		return uintptr(p)
 
 	case Slice:
-		return (*SliceHeader)(v.val).Data
+		return (*SliceHeader)(v.ptr).Data
 	}
 	panic(&ValueError{"reflect.Value.Pointer", k})
 }
@@ -1339,14 +1445,21 @@ func (v Value) recv(nb bool) (val Value, ok bool) {
 	if ChanDir(tt.dir)&RecvDir == 0 {
 		panic("reflect: recv on send-only channel")
 	}
-	word, selected, ok := chanrecv(v.typ, v.iword(), nb)
-	if selected {
-		typ := tt.elem
-		fl := flag(typ.Kind()) << flagKindShift
-		if typ.size > ptrSize {
-			fl |= flagIndir
-		}
-		val = Value{typ, unsafe.Pointer(word), fl}
+	t := tt.elem
+	val = Value{t, nil, 0, flag(t.Kind()) << flagKindShift}
+	var p unsafe.Pointer
+	if t.size > ptrSize {
+		p = unsafe_New(t)
+		val.ptr = p
+		val.flag |= flagIndir
+	} else if t.pointers() {
+		p = unsafe.Pointer(&val.ptr)
+	} else {
+		p = unsafe.Pointer(&val.scalar)
+	}
+	selected, ok := chanrecv(v.typ, v.pointer(), nb, p)
+	if !selected {
+		val = Value{}
 	}
 	return
 }
@@ -1369,7 +1482,15 @@ func (v Value) send(x Value, nb bool) (selected bool) {
 	}
 	x.mustBeExported()
 	x = x.assignTo("reflect.Value.Send", tt.elem, nil)
-	return chansend(v.typ, v.iword(), x.iword(), nb)
+	var p unsafe.Pointer
+	if x.flag&flagIndir != 0 {
+		p = x.ptr
+	} else if x.typ.pointers() {
+		p = unsafe.Pointer(&x.ptr)
+	} else {
+		p = unsafe.Pointer(&x.scalar)
+	}
+	return chansend(v.typ, v.pointer(), p, nb)
 }
 
 // Set assigns x to the value v.
@@ -1380,13 +1501,15 @@ func (v Value) Set(x Value) {
 	x.mustBeExported() // do not let unexported x leak
 	var target *interface{}
 	if v.kind() == Interface {
-		target = (*interface{})(v.val)
+		target = (*interface{})(v.ptr)
 	}
 	x = x.assignTo("reflect.Set", v.typ, target)
 	if x.flag&flagIndir != 0 {
-		memmove(v.val, x.val, v.typ.size)
+		memmove(v.ptr, x.ptr, v.typ.size)
+	} else if x.typ.pointers() {
+		*(*unsafe.Pointer)(v.ptr) = x.ptr
 	} else {
-		storeIword(v.val, iword(x.val), v.typ.size)
+		memmove(v.ptr, unsafe.Pointer(&x.scalar), v.typ.size)
 	}
 }
 
@@ -1395,7 +1518,7 @@ func (v Value) Set(x Value) {
 func (v Value) SetBool(x bool) {
 	v.mustBeAssignable()
 	v.mustBe(Bool)
-	*(*bool)(v.val) = x
+	*(*bool)(v.ptr) = x
 }
 
 // SetBytes sets v's underlying value.
@@ -1406,7 +1529,7 @@ func (v Value) SetBytes(x []byte) {
 	if v.typ.Elem().Kind() != Uint8 {
 		panic("reflect.Value.SetBytes of non-byte slice")
 	}
-	*(*[]byte)(v.val) = x
+	*(*[]byte)(v.ptr) = x
 }
 
 // setRunes sets v's underlying value.
@@ -1417,7 +1540,7 @@ func (v Value) setRunes(x []rune) {
 	if v.typ.Elem().Kind() != Int32 {
 		panic("reflect.Value.setRunes of non-rune slice")
 	}
-	*(*[]rune)(v.val) = x
+	*(*[]rune)(v.ptr) = x
 }
 
 // SetComplex sets v's underlying value to x.
@@ -1428,9 +1551,9 @@ func (v Value) SetComplex(x complex128) {
 	default:
 		panic(&ValueError{"reflect.Value.SetComplex", k})
 	case Complex64:
-		*(*complex64)(v.val) = complex64(x)
+		*(*complex64)(v.ptr) = complex64(x)
 	case Complex128:
-		*(*complex128)(v.val) = x
+		*(*complex128)(v.ptr) = x
 	}
 }
 
@@ -1442,9 +1565,9 @@ func (v Value) SetFloat(x float64) {
 	default:
 		panic(&ValueError{"reflect.Value.SetFloat", k})
 	case Float32:
-		*(*float32)(v.val) = float32(x)
+		*(*float32)(v.ptr) = float32(x)
 	case Float64:
-		*(*float64)(v.val) = x
+		*(*float64)(v.ptr) = x
 	}
 }
 
@@ -1456,15 +1579,15 @@ func (v Value) SetInt(x int64) {
 	default:
 		panic(&ValueError{"reflect.Value.SetInt", k})
 	case Int:
-		*(*int)(v.val) = int(x)
+		*(*int)(v.ptr) = int(x)
 	case Int8:
-		*(*int8)(v.val) = int8(x)
+		*(*int8)(v.ptr) = int8(x)
 	case Int16:
-		*(*int16)(v.val) = int16(x)
+		*(*int16)(v.ptr) = int16(x)
 	case Int32:
-		*(*int32)(v.val) = int32(x)
+		*(*int32)(v.ptr) = int32(x)
 	case Int64:
-		*(*int64)(v.val) = x
+		*(*int64)(v.ptr) = x
 	}
 }
 
@@ -1474,7 +1597,7 @@ func (v Value) SetInt(x int64) {
 func (v Value) SetLen(n int) {
 	v.mustBeAssignable()
 	v.mustBe(Slice)
-	s := (*SliceHeader)(v.val)
+	s := (*sliceHeader)(v.ptr)
 	if n < 0 || n > int(s.Cap) {
 		panic("reflect: slice length out of range in SetLen")
 	}
@@ -1487,7 +1610,7 @@ func (v Value) SetLen(n int) {
 func (v Value) SetCap(n int) {
 	v.mustBeAssignable()
 	v.mustBe(Slice)
-	s := (*SliceHeader)(v.val)
+	s := (*sliceHeader)(v.ptr)
 	if n < int(s.Len) || n > int(s.Cap) {
 		panic("reflect: slice capacity out of range in SetCap")
 	}
@@ -1497,6 +1620,7 @@ func (v Value) SetCap(n int) {
 // SetMapIndex sets the value associated with key in the map v to val.
 // It panics if v's Kind is not Map.
 // If val is the zero Value, SetMapIndex deletes the key from the map.
+// Otherwise if v holds a nil map, SetMapIndex will panic.
 // As in Go, key's value must be assignable to the map's key type,
 // and val's value must be assignable to the map's value type.
 func (v Value) SetMapIndex(key, val Value) {
@@ -1505,11 +1629,29 @@ func (v Value) SetMapIndex(key, val Value) {
 	key.mustBeExported()
 	tt := (*mapType)(unsafe.Pointer(v.typ))
 	key = key.assignTo("reflect.Value.SetMapIndex", tt.key, nil)
-	if val.typ != nil {
-		val.mustBeExported()
-		val = val.assignTo("reflect.Value.SetMapIndex", tt.elem, nil)
+	var k unsafe.Pointer
+	if key.flag&flagIndir != 0 {
+		k = key.ptr
+	} else if key.typ.pointers() {
+		k = unsafe.Pointer(&key.ptr)
+	} else {
+		k = unsafe.Pointer(&key.scalar)
+	}
+	if val.typ == nil {
+		mapdelete(v.typ, v.pointer(), k)
+		return
+	}
+	val.mustBeExported()
+	val = val.assignTo("reflect.Value.SetMapIndex", tt.elem, nil)
+	var e unsafe.Pointer
+	if val.flag&flagIndir != 0 {
+		e = val.ptr
+	} else if val.typ.pointers() {
+		e = unsafe.Pointer(&val.ptr)
+	} else {
+		e = unsafe.Pointer(&val.scalar)
 	}
-	mapassign(v.typ, v.iword(), key.iword(), val.iword(), val.typ != nil)
+	mapassign(v.typ, v.pointer(), k, e)
 }
 
 // SetUint sets v's underlying value to x.
@@ -1520,17 +1662,17 @@ func (v Value) SetUint(x uint64) {
 	default:
 		panic(&ValueError{"reflect.Value.SetUint", k})
 	case Uint:
-		*(*uint)(v.val) = uint(x)
+		*(*uint)(v.ptr) = uint(x)
 	case Uint8:
-		*(*uint8)(v.val) = uint8(x)
+		*(*uint8)(v.ptr) = uint8(x)
 	case Uint16:
-		*(*uint16)(v.val) = uint16(x)
+		*(*uint16)(v.ptr) = uint16(x)
 	case Uint32:
-		*(*uint32)(v.val) = uint32(x)
+		*(*uint32)(v.ptr) = uint32(x)
 	case Uint64:
-		*(*uint64)(v.val) = x
+		*(*uint64)(v.ptr) = x
 	case Uintptr:
-		*(*uintptr)(v.val) = uintptr(x)
+		*(*uintptr)(v.ptr) = uintptr(x)
 	}
 }
 
@@ -1539,7 +1681,7 @@ func (v Value) SetUint(x uint64) {
 func (v Value) SetPointer(x unsafe.Pointer) {
 	v.mustBeAssignable()
 	v.mustBe(UnsafePointer)
-	*(*unsafe.Pointer)(v.val) = x
+	*(*unsafe.Pointer)(v.ptr) = x
 }
 
 // SetString sets v's underlying value to x.
@@ -1547,7 +1689,7 @@ func (v Value) SetPointer(x unsafe.Pointer) {
 func (v Value) SetString(x string) {
 	v.mustBeAssignable()
 	v.mustBe(String)
-	*(*string)(v.val) = x
+	*(*string)(v.ptr) = x
 }
 
 // Slice returns v[i:j].
@@ -1570,24 +1712,21 @@ func (v Value) Slice(i, j int) Value {
 		tt := (*arrayType)(unsafe.Pointer(v.typ))
 		cap = int(tt.len)
 		typ = (*sliceType)(unsafe.Pointer(tt.slice))
-		base = v.val
+		base = v.ptr
 
 	case Slice:
 		typ = (*sliceType)(unsafe.Pointer(v.typ))
-		s := (*SliceHeader)(v.val)
+		s := (*sliceHeader)(v.ptr)
 		base = unsafe.Pointer(s.Data)
 		cap = s.Cap
 
 	case String:
-		s := (*StringHeader)(v.val)
+		s := (*stringHeader)(v.ptr)
 		if i < 0 || j < i || j > s.Len {
 			panic("reflect.Value.Slice: string slice index out of bounds")
 		}
-		var x string
-		val := (*StringHeader)(unsafe.Pointer(&x))
-		val.Data = s.Data + uintptr(i)
-		val.Len = j - i
-		return Value{v.typ, unsafe.Pointer(&x), v.flag}
+		t := stringHeader{unsafe.Pointer(uintptr(s.Data) + uintptr(i)), j - i}
+		return Value{v.typ, unsafe.Pointer(&t), 0, v.flag}
 	}
 
 	if i < 0 || j < i || j > cap {
@@ -1597,14 +1736,14 @@ func (v Value) Slice(i, j int) Value {
 	// Declare slice so that gc can see the base pointer in it.
 	var x []unsafe.Pointer
 
-	// Reinterpret as *SliceHeader to edit.
-	s := (*SliceHeader)(unsafe.Pointer(&x))
-	s.Data = uintptr(base) + uintptr(i)*typ.elem.Size()
+	// Reinterpret as *sliceHeader to edit.
+	s := (*sliceHeader)(unsafe.Pointer(&x))
+	s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
 	s.Len = j - i
 	s.Cap = cap - i
 
 	fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift
-	return Value{typ.common(), unsafe.Pointer(&x), fl}
+	return Value{typ.common(), unsafe.Pointer(&x), 0, fl}
 }
 
 // Slice3 is the 3-index form of the slice operation: it returns v[i:j:k].
@@ -1622,17 +1761,17 @@ func (v Value) Slice3(i, j, k int) Value {
 
 	case Array:
 		if v.flag&flagAddr == 0 {
-			panic("reflect.Value.Slice: slice of unaddressable array")
+			panic("reflect.Value.Slice3: slice of unaddressable array")
 		}
 		tt := (*arrayType)(unsafe.Pointer(v.typ))
 		cap = int(tt.len)
 		typ = (*sliceType)(unsafe.Pointer(tt.slice))
-		base = v.val
+		base = v.ptr
 
 	case Slice:
 		typ = (*sliceType)(unsafe.Pointer(v.typ))
-		s := (*SliceHeader)(v.val)
-		base = unsafe.Pointer(s.Data)
+		s := (*sliceHeader)(v.ptr)
+		base = s.Data
 		cap = s.Cap
 	}
 
@@ -1644,14 +1783,14 @@ func (v Value) Slice3(i, j, k int) Value {
 	// can see the base pointer in it.
 	var x []unsafe.Pointer
 
-	// Reinterpret as *SliceHeader to edit.
-	s := (*SliceHeader)(unsafe.Pointer(&x))
-	s.Data = uintptr(base) + uintptr(i)*typ.elem.Size()
+	// Reinterpret as *sliceHeader to edit.
+	s := (*sliceHeader)(unsafe.Pointer(&x))
+	s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
 	s.Len = j - i
 	s.Cap = k - i
 
 	fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift
-	return Value{typ.common(), unsafe.Pointer(&x), fl}
+	return Value{typ.common(), unsafe.Pointer(&x), 0, fl}
 }
 
 // String returns the string v's underlying value, as a string.
@@ -1663,7 +1802,7 @@ func (v Value) String() string {
 	case Invalid:
 		return "<invalid Value>"
 	case String:
-		return *(*string)(v.val)
+		return *(*string)(v.ptr)
 	}
 	// If you call String on a reflect.Value of other type, it's better to
 	// print something than to panic. Useful in debugging.
@@ -1672,9 +1811,9 @@ func (v Value) String() string {
 
 // TryRecv attempts to receive a value from the channel v but will not block.
 // It panics if v's Kind is not Chan.
-// If the receive cannot finish without blocking, x is the zero Value.
-// The boolean ok is true if the value x corresponds to a send
-// on the channel, false if it is a zero value received because the channel is closed.
+// If the receive delivers a value, x is the transferred value and ok is true.
+// If the receive cannot finish without blocking, x is the zero Value and ok is false.
+// If the channel is closed, x is the zero value for the channel's element type and ok is false.
 func (v Value) TryRecv() (x Value, ok bool) {
 	v.mustBe(Chan)
 	v.mustBeExported()
@@ -1729,11 +1868,11 @@ func (v Value) Uint() uint64 {
 	k := v.kind()
 	var p unsafe.Pointer
 	if v.flag&flagIndir != 0 {
-		p = v.val
+		p = v.ptr
 	} else {
-		// The escape analysis is good enough that &v.val
+		// The escape analysis is good enough that &v.scalar
 		// does not trigger a heap allocation.
-		p = unsafe.Pointer(&v.val)
+		p = unsafe.Pointer(&v.scalar)
 	}
 	switch k {
 	case Uint:
@@ -1756,13 +1895,14 @@ func (v Value) Uint() uint64 {
 // It is for advanced clients that also import the "unsafe" package.
 // It panics if v is not addressable.
 func (v Value) UnsafeAddr() uintptr {
+	// TODO: deprecate
 	if v.typ == nil {
 		panic(&ValueError{"reflect.Value.UnsafeAddr", Invalid})
 	}
 	if v.flag&flagAddr == 0 {
 		panic("reflect.Value.UnsafeAddr of unaddressable value")
 	}
-	return uintptr(v.val)
+	return uintptr(v.ptr)
 }
 
 // StringHeader is the runtime representation of a string.
@@ -1776,6 +1916,12 @@ type StringHeader struct {
 	Len  int
 }
 
+// stringHeader is a safe version of StringHeader used within this package.
+type stringHeader struct {
+	Data unsafe.Pointer
+	Len  int
+}
+
 // SliceHeader is the runtime representation of a slice.
 // It cannot be used safely or portably and its representation may
 // change in a later release.
@@ -1788,6 +1934,13 @@ type SliceHeader struct {
 	Cap  int
 }
 
+// sliceHeader is a safe version of SliceHeader used within this package.
+type sliceHeader struct {
+	Data unsafe.Pointer
+	Len  int
+	Cap  int
+}
+
 func typesMustMatch(what string, t1, t2 Type) {
 	if t1 != t2 {
 		panic(what + ": " + t1.String() + " != " + t2.String())
@@ -1876,6 +2029,8 @@ func Copy(dst, src Value) int {
 
 	// If sk is an in-line array, cannot take its address.
 	// Instead, copy element by element.
+	// TODO: memmove would be ok for this (sa = unsafe.Pointer(&v.scalar))
+	// if we teach the compiler that ptrs don't escape from memmove.
 	if src.flag&flagIndir == 0 {
 		for i := 0; i < n; i++ {
 			dst.Index(i).Set(src.Index(i))
@@ -1886,14 +2041,14 @@ func Copy(dst, src Value) int {
 	// Copy via memmove.
 	var da, sa unsafe.Pointer
 	if dk == Array {
-		da = dst.val
+		da = dst.ptr
 	} else {
-		da = unsafe.Pointer((*SliceHeader)(dst.val).Data)
+		da = (*sliceHeader)(dst.ptr).Data
 	}
 	if sk == Array {
-		sa = src.val
+		sa = src.ptr
 	} else {
-		sa = unsafe.Pointer((*SliceHeader)(src.val).Data)
+		sa = (*sliceHeader)(src.ptr).Data
 	}
 	memmove(da, sa, uintptr(n)*de.Size())
 	return n
@@ -1902,17 +2057,18 @@ func Copy(dst, src Value) int {
 // A runtimeSelect is a single case passed to rselect.
 // This must match ../runtime/chan.c:/runtimeSelect
 type runtimeSelect struct {
-	dir uintptr // 0, SendDir, or RecvDir
-	typ *rtype  // channel type
-	ch  iword   // interface word for channel
-	val iword   // interface word for value (for SendDir)
+	dir uintptr        // 0, SendDir, or RecvDir
+	typ *rtype         // channel type
+	ch  unsafe.Pointer // channel
+	val unsafe.Pointer // ptr to data (SendDir) or ptr to receive buffer (RecvDir)
 }
 
-// rselect runs a select. It returns the index of the chosen case,
-// and if the case was a receive, the interface word of the received
-// value and the conventional OK bool to indicate whether the receive
-// corresponds to a sent value.
-func rselect([]runtimeSelect) (chosen int, recv iword, recvOK bool)
+// rselect runs a select.  It returns the index of the chosen case.
+// If the case was a receive, val is filled in with the received value.
+// The conventional OK bool indicates whether the receive corresponds
+// to a sent value.
+//go:noescape
+func rselect([]runtimeSelect) (chosen int, recvOK bool)
 
 // A SelectDir describes the communication direction of a select case.
 type SelectDir int
@@ -1992,7 +2148,7 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
 			if ChanDir(tt.dir)&SendDir == 0 {
 				panic("reflect.Select: SendDir case using recv-only channel")
 			}
-			rc.ch = ch.iword()
+			rc.ch = ch.pointer()
 			rc.typ = &tt.rtype
 			v := c.Send
 			if !v.IsValid() {
@@ -2000,7 +2156,13 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
 			}
 			v.mustBeExported()
 			v = v.assignTo("reflect.Select", tt.elem, nil)
-			rc.val = v.iword()
+			if v.flag&flagIndir != 0 {
+				rc.val = v.ptr
+			} else if v.typ.pointers() {
+				rc.val = unsafe.Pointer(&v.ptr)
+			} else {
+				rc.val = unsafe.Pointer(&v.scalar)
+			}
 
 		case SelectRecv:
 			if c.Send.IsValid() {
@@ -2013,23 +2175,28 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
 			ch.mustBe(Chan)
 			ch.mustBeExported()
 			tt := (*chanType)(unsafe.Pointer(ch.typ))
-			rc.typ = &tt.rtype
 			if ChanDir(tt.dir)&RecvDir == 0 {
 				panic("reflect.Select: RecvDir case using send-only channel")
 			}
-			rc.ch = ch.iword()
+			rc.ch = ch.pointer()
+			rc.typ = &tt.rtype
+			rc.val = unsafe_New(tt.elem)
 		}
 	}
 
-	chosen, word, recvOK := rselect(runcases)
+	chosen, recvOK = rselect(runcases)
 	if runcases[chosen].dir == uintptr(SelectRecv) {
 		tt := (*chanType)(unsafe.Pointer(runcases[chosen].typ))
-		typ := tt.elem
-		fl := flag(typ.Kind()) << flagKindShift
-		if typ.size > ptrSize {
-			fl |= flagIndir
+		t := tt.elem
+		p := runcases[chosen].val
+		fl := flag(t.Kind()) << flagKindShift
+		if t.size > ptrSize {
+			recv = Value{t, p, 0, fl | flagIndir}
+		} else if t.pointers() {
+			recv = Value{t, *(*unsafe.Pointer)(p), 0, fl}
+		} else {
+			recv = Value{t, nil, loadScalar(p, t.size), fl}
 		}
-		recv = Value{typ, unsafe.Pointer(word), fl}
 	}
 	return chosen, recv, recvOK
 }
@@ -2058,16 +2225,8 @@ func MakeSlice(typ Type, len, cap int) Value {
 		panic("reflect.MakeSlice: len > cap")
 	}
 
-	// Declare slice so that gc can see the base pointer in it.
-	var x []unsafe.Pointer
-
-	// Reinterpret as *SliceHeader to edit.
-	s := (*SliceHeader)(unsafe.Pointer(&x))
-	s.Data = uintptr(unsafe_NewArray(typ.Elem().(*rtype), cap))
-	s.Len = len
-	s.Cap = cap
-
-	return Value{typ.common(), unsafe.Pointer(&x), flagIndir | flag(Slice)<<flagKindShift}
+	s := sliceHeader{unsafe_NewArray(typ.Elem().(*rtype), cap), len, cap}
+	return Value{typ.common(), unsafe.Pointer(&s), 0, flagIndir | flag(Slice)<<flagKindShift}
 }
 
 // MakeChan creates a new channel with the specified type and buffer size.
@@ -2082,7 +2241,7 @@ func MakeChan(typ Type, buffer int) Value {
 		panic("reflect.MakeChan: unidirectional channel type")
 	}
 	ch := makechan(typ.(*rtype), uint64(buffer))
-	return Value{typ.common(), unsafe.Pointer(ch), flag(Chan) << flagKindShift}
+	return Value{typ.common(), ch, 0, flag(Chan) << flagKindShift}
 }
 
 // MakeMap creates a new map of the specified type.
@@ -2091,7 +2250,7 @@ func MakeMap(typ Type) Value {
 		panic("reflect.MakeMap of non-map type")
 	}
 	m := makemap(typ.(*rtype))
-	return Value{typ.common(), unsafe.Pointer(m), flag(Map) << flagKindShift}
+	return Value{typ.common(), m, 0, flag(Map) << flagKindShift}
 }
 
 // Indirect returns the value that v points to.
@@ -2112,21 +2271,13 @@ func ValueOf(i interface{}) Value {
 	}
 
 	// TODO(rsc): Eliminate this terrible hack.
-	// In the call to packValue, eface.typ doesn't escape,
-	// and eface.word is an integer.  So it looks like
-	// i (= eface) doesn't escape.  But really it does,
-	// because eface.word is actually a pointer.
+	// In the call to unpackEface, i.typ doesn't escape,
+	// and i.word is an integer.  So it looks like
+	// i doesn't escape.  But really it does,
+	// because i.word is actually a pointer.
 	escapes(i)
 
-	// For an interface value with the noAddr bit set,
-	// the representation is identical to an empty interface.
-	eface := *(*emptyInterface)(unsafe.Pointer(&i))
-	typ := eface.typ
-	fl := flag(typ.Kind()) << flagKindShift
-	if typ.size > ptrSize {
-		fl |= flagIndir
-	}
-	return Value{typ, unsafe.Pointer(eface.word), fl}
+	return unpackEface(i)
 }
 
 // Zero returns a Value representing the zero value for the specified type.
@@ -2141,27 +2292,27 @@ func Zero(typ Type) Value {
 	t := typ.common()
 	fl := flag(t.Kind()) << flagKindShift
 	if t.size <= ptrSize {
-		return Value{t, nil, fl}
+		return Value{t, nil, 0, fl}
 	}
-	return Value{t, unsafe_New(typ.(*rtype)), fl | flagIndir}
+	return Value{t, unsafe_New(typ.(*rtype)), 0, fl | flagIndir}
 }
 
 // New returns a Value representing a pointer to a new zero value
-// for the specified type.  That is, the returned Value's Type is PtrTo(t).
+// for the specified type.  That is, the returned Value's Type is PtrTo(typ).
 func New(typ Type) Value {
 	if typ == nil {
 		panic("reflect: New(nil)")
 	}
 	ptr := unsafe_New(typ.(*rtype))
 	fl := flag(Ptr) << flagKindShift
-	return Value{typ.common().ptrTo(), ptr, fl}
+	return Value{typ.common().ptrTo(), ptr, 0, fl}
 }
 
 // NewAt returns a Value representing a pointer to a value of the
 // specified type, using p as that pointer.
 func NewAt(typ Type, p unsafe.Pointer) Value {
 	fl := flag(Ptr) << flagKindShift
-	return Value{typ.common().ptrTo(), p, fl}
+	return Value{typ.common().ptrTo(), p, 0, fl}
 }
 
 // assignTo returns a value v that can be assigned directly to typ.
@@ -2179,7 +2330,7 @@ func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value {
 		v.typ = dst
 		fl := v.flag & (flagRO | flagAddr | flagIndir)
 		fl |= flag(dst.Kind()) << flagKindShift
-		return Value{dst, v.val, fl}
+		return Value{dst, v.ptr, v.scalar, fl}
 
 	case implements(dst, v.typ):
 		if target == nil {
@@ -2191,7 +2342,7 @@ func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value {
 		} else {
 			ifaceE2I(dst, x, unsafe.Pointer(target))
 		}
-		return Value{dst, unsafe.Pointer(target), flagIndir | flag(Interface)<<flagKindShift}
+		return Value{dst, unsafe.Pointer(target), 0, flagIndir | flag(Interface)<<flagKindShift}
 	}
 
 	// Failed.
@@ -2303,20 +2454,20 @@ func makeInt(f flag, bits uint64, t Type) Value {
 		// Assume ptrSize >= 4, so this must be uint64.
 		ptr := unsafe_New(typ)
 		*(*uint64)(unsafe.Pointer(ptr)) = bits
-		return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift}
+		return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift}
 	}
-	var w iword
+	var s uintptr
 	switch typ.size {
 	case 1:
-		*(*uint8)(unsafe.Pointer(&w)) = uint8(bits)
+		*(*uint8)(unsafe.Pointer(&s)) = uint8(bits)
 	case 2:
-		*(*uint16)(unsafe.Pointer(&w)) = uint16(bits)
+		*(*uint16)(unsafe.Pointer(&s)) = uint16(bits)
 	case 4:
-		*(*uint32)(unsafe.Pointer(&w)) = uint32(bits)
+		*(*uint32)(unsafe.Pointer(&s)) = uint32(bits)
 	case 8:
-		*(*uint64)(unsafe.Pointer(&w)) = uint64(bits)
+		*(*uint64)(unsafe.Pointer(&s)) = uint64(bits)
 	}
-	return Value{typ, unsafe.Pointer(w), f | flag(typ.Kind())<<flagKindShift}
+	return Value{typ, nil, s, f | flag(typ.Kind())<<flagKindShift}
 }
 
 // makeFloat returns a Value of type t equal to v (possibly truncated to float32),
@@ -2327,17 +2478,17 @@ func makeFloat(f flag, v float64, t Type) Value {
 		// Assume ptrSize >= 4, so this must be float64.
 		ptr := unsafe_New(typ)
 		*(*float64)(unsafe.Pointer(ptr)) = v
-		return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift}
+		return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift}
 	}
 
-	var w iword
+	var s uintptr
 	switch typ.size {
 	case 4:
-		*(*float32)(unsafe.Pointer(&w)) = float32(v)
+		*(*float32)(unsafe.Pointer(&s)) = float32(v)
 	case 8:
-		*(*float64)(unsafe.Pointer(&w)) = v
+		*(*float64)(unsafe.Pointer(&s)) = v
 	}
-	return Value{typ, unsafe.Pointer(w), f | flag(typ.Kind())<<flagKindShift}
+	return Value{typ, nil, s, f | flag(typ.Kind())<<flagKindShift}
 }
 
 // makeComplex returns a Value of type t equal to v (possibly truncated to complex64),
@@ -2352,13 +2503,13 @@ func makeComplex(f flag, v complex128, t Type) Value {
 		case 16:
 			*(*complex128)(unsafe.Pointer(ptr)) = v
 		}
-		return Value{typ, ptr, f | flagIndir | flag(typ.Kind())<<flagKindShift}
+		return Value{typ, ptr, 0, f | flagIndir | flag(typ.Kind())<<flagKindShift}
 	}
 
 	// Assume ptrSize <= 8 so this must be complex64.
-	var w iword
-	*(*complex64)(unsafe.Pointer(&w)) = complex64(v)
-	return Value{typ, unsafe.Pointer(w), f | flag(typ.Kind())<<flagKindShift}
+	var s uintptr
+	*(*complex64)(unsafe.Pointer(&s)) = complex64(v)
+	return Value{typ, nil, s, f | flag(typ.Kind())<<flagKindShift}
 }
 
 func makeString(f flag, v string, t Type) Value {
@@ -2461,15 +2612,15 @@ func cvtStringRunes(v Value, t Type) Value {
 func cvtDirect(v Value, typ Type) Value {
 	f := v.flag
 	t := typ.common()
-	val := v.val
+	ptr := v.ptr
 	if f&flagAddr != 0 {
 		// indirect, mutable word - make a copy
-		ptr := unsafe_New(t)
-		memmove(ptr, val, t.size)
-		val = ptr
+		c := unsafe_New(t)
+		memmove(c, ptr, t.size)
+		ptr = c
 		f &^= flagAddr
 	}
-	return Value{t, val, v.flag&flagRO | f}
+	return Value{t, ptr, v.scalar, v.flag&flagRO | f} // v.flag&flagRO|f == f?
 }
 
 // convertOp: concrete -> interface
@@ -2481,7 +2632,7 @@ func cvtT2I(v Value, typ Type) Value {
 	} else {
 		ifaceE2I(typ.(*rtype), x, unsafe.Pointer(target))
 	}
-	return Value{typ.common(), unsafe.Pointer(target), v.flag&flagRO | flagIndir | flag(Interface)<<flagKindShift}
+	return Value{typ.common(), unsafe.Pointer(target), 0, v.flag&flagRO | flagIndir | flag(Interface)<<flagKindShift}
 }
 
 // convertOp: interface -> interface
@@ -2495,22 +2646,27 @@ func cvtI2I(v Value, typ Type) Value {
 }
 
 // implemented in ../pkg/runtime
-func chancap(ch iword) int
-func chanclose(ch iword)
-func chanlen(ch iword) int
-func chanrecv(t *rtype, ch iword, nb bool) (val iword, selected, received bool)
-func chansend(t *rtype, ch iword, val iword, nb bool) bool
-
-func makechan(typ *rtype, size uint64) (ch iword)
-func makemap(t *rtype) (m iword)
-func mapaccess(t *rtype, m iword, key iword) (val iword, ok bool)
-func mapassign(t *rtype, m iword, key, val iword, ok bool)
-func mapiterinit(t *rtype, m iword) *byte
-func mapiterkey(it *byte) (key iword, ok bool)
-func mapiternext(it *byte)
-func maplen(m iword) int
-
-func call(fn, arg unsafe.Pointer, n uint32)
+func chancap(ch unsafe.Pointer) int
+func chanclose(ch unsafe.Pointer)
+func chanlen(ch unsafe.Pointer) int
+
+//go:noescape
+func chanrecv(t *rtype, ch unsafe.Pointer, nb bool, val unsafe.Pointer) (selected, received bool)
+
+//go:noescape
+func chansend(t *rtype, ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool
+
+func makechan(typ *rtype, size uint64) (ch unsafe.Pointer)
+func makemap(t *rtype) (m unsafe.Pointer)
+func mapaccess(t *rtype, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer)
+func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer)
+func mapdelete(t *rtype, m unsafe.Pointer, key unsafe.Pointer)
+func mapiterinit(t *rtype, m unsafe.Pointer) unsafe.Pointer
+func mapiterkey(it unsafe.Pointer) (key unsafe.Pointer)
+func mapiternext(it unsafe.Pointer)
+func maplen(m unsafe.Pointer) int
+
+func call(fn, arg unsafe.Pointer, n uint32, retoffset uint32)
 func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer)
 
 // Dummy annotation marking that the value x escapes,
diff --git a/src/pkg/regexp/all_test.go b/src/pkg/regexp/all_test.go
index e914a7c..301a1df 100644
--- a/src/pkg/regexp/all_test.go
+++ b/src/pkg/regexp/all_test.go
@@ -473,6 +473,11 @@ func TestSplit(t *testing.T) {
 	}
 }
 
+// This ran out of stack before issue 7608 was fixed.
+func TestOnePassCutoff(t *testing.T) {
+	MustCompile(`^(?:x{1,1000}){1,1000}$`)
+}
+
 func BenchmarkLiteral(b *testing.B) {
 	x := strings.Repeat("x", 50) + "y"
 	b.StopTimer()
@@ -578,3 +583,63 @@ func BenchmarkAnchoredLongMatch(b *testing.B) {
 		re.Match(x)
 	}
 }
+
+func BenchmarkOnePassShortA(b *testing.B) {
+	b.StopTimer()
+	x := []byte("abcddddddeeeededd")
+	re := MustCompile("^.bc(d|e)*$")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		re.Match(x)
+	}
+}
+
+func BenchmarkNotOnePassShortA(b *testing.B) {
+	b.StopTimer()
+	x := []byte("abcddddddeeeededd")
+	re := MustCompile(".bc(d|e)*$")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		re.Match(x)
+	}
+}
+
+func BenchmarkOnePassShortB(b *testing.B) {
+	b.StopTimer()
+	x := []byte("abcddddddeeeededd")
+	re := MustCompile("^.bc(?:d|e)*$")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		re.Match(x)
+	}
+}
+
+func BenchmarkNotOnePassShortB(b *testing.B) {
+	b.StopTimer()
+	x := []byte("abcddddddeeeededd")
+	re := MustCompile(".bc(?:d|e)*$")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		re.Match(x)
+	}
+}
+
+func BenchmarkOnePassLongPrefix(b *testing.B) {
+	b.StopTimer()
+	x := []byte("abcdefghijklmnopqrstuvwxyz")
+	re := MustCompile("^abcdefghijklmnopqrstuvwxyz.*$")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		re.Match(x)
+	}
+}
+
+func BenchmarkOnePassLongNotPrefix(b *testing.B) {
+	b.StopTimer()
+	x := []byte("abcdefghijklmnopqrstuvwxyz")
+	re := MustCompile("^.bcdefghijklmnopqrstuvwxyz.*$")
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		re.Match(x)
+	}
+}
diff --git a/src/pkg/regexp/example_test.go b/src/pkg/regexp/example_test.go
index b0ad9d3..a4e0da8 100644
--- a/src/pkg/regexp/example_test.go
+++ b/src/pkg/regexp/example_test.go
@@ -1,3 +1,7 @@
+// 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 regexp_test
 
 import (
diff --git a/src/pkg/regexp/exec.go b/src/pkg/regexp/exec.go
index 333ca25..c4cb201 100644
--- a/src/pkg/regexp/exec.go
+++ b/src/pkg/regexp/exec.go
@@ -37,6 +37,7 @@ type thread struct {
 type machine struct {
 	re       *Regexp      // corresponding Regexp
 	p        *syntax.Prog // compiled program
+	op       *onePassProg // compiled onepass program, or notOnePass
 	q0, q1   queue        // two queues for runq, nextq
 	pool     []*thread    // pool of available threads
 	matched  bool         // whether a match was found
@@ -66,8 +67,8 @@ func (m *machine) newInputReader(r io.RuneReader) input {
 }
 
 // progMachine returns a new machine running the prog p.
-func progMachine(p *syntax.Prog) *machine {
-	m := &machine{p: p}
+func progMachine(p *syntax.Prog, op *onePassProg) *machine {
+	m := &machine{p: p, op: op}
 	n := len(m.p.Inst)
 	m.q0 = queue{make([]uint32, n), make([]entry, 0, n)}
 	m.q1 = queue{make([]uint32, n), make([]entry, 0, n)}
@@ -312,6 +313,105 @@ func (m *machine) add(q *queue, pc uint32, pos int, cap []int, cond syntax.Empty
 	return t
 }
 
+// onepass runs the machine over the input starting at pos.
+// It reports whether a match was found.
+// If so, m.matchcap holds the submatch information.
+func (m *machine) onepass(i input, pos int) bool {
+	startCond := m.re.cond
+	if startCond == ^syntax.EmptyOp(0) { // impossible
+		return false
+	}
+	m.matched = false
+	for i := range m.matchcap {
+		m.matchcap[i] = -1
+	}
+	r, r1 := endOfText, endOfText
+	width, width1 := 0, 0
+	r, width = i.step(pos)
+	if r != endOfText {
+		r1, width1 = i.step(pos + width)
+	}
+	var flag syntax.EmptyOp
+	if pos == 0 {
+		flag = syntax.EmptyOpContext(-1, r)
+	} else {
+		flag = i.context(pos)
+	}
+	pc := m.op.Start
+	inst := m.op.Inst[pc]
+	// If there is a simple literal prefix, skip over it.
+	if pos == 0 && syntax.EmptyOp(inst.Arg)&^flag == 0 &&
+		len(m.re.prefix) > 0 && i.canCheckPrefix() {
+		// Match requires literal prefix; fast search for it.
+		if i.hasPrefix(m.re) {
+			pos += len(m.re.prefix)
+			r, width = i.step(pos)
+			r1, width1 = i.step(pos + width)
+			flag = i.context(pos)
+			pc = int(m.re.prefixEnd)
+		} else {
+			return m.matched
+		}
+	}
+	for {
+		inst = m.op.Inst[pc]
+		pc = int(inst.Out)
+		switch inst.Op {
+		default:
+			panic("bad inst")
+		case syntax.InstMatch:
+			m.matched = true
+			if len(m.matchcap) > 0 {
+				m.matchcap[0] = 0
+				m.matchcap[1] = pos
+			}
+			return m.matched
+		case syntax.InstRune:
+			if !inst.MatchRune(r) {
+				return m.matched
+			}
+		case syntax.InstRune1:
+			if r != inst.Rune[0] {
+				return m.matched
+			}
+		case syntax.InstRuneAny:
+			// Nothing
+		case syntax.InstRuneAnyNotNL:
+			if r == '\n' {
+				return m.matched
+			}
+		// peek at the input rune to see which branch of the Alt to take
+		case syntax.InstAlt, syntax.InstAltMatch:
+			pc = int(onePassNext(&inst, r))
+			continue
+		case syntax.InstFail:
+			return m.matched
+		case syntax.InstNop:
+			continue
+		case syntax.InstEmptyWidth:
+			if syntax.EmptyOp(inst.Arg)&^flag != 0 {
+				return m.matched
+			}
+			continue
+		case syntax.InstCapture:
+			if int(inst.Arg) < len(m.matchcap) {
+				m.matchcap[inst.Arg] = pos
+			}
+			continue
+		}
+		if width == 0 {
+			break
+		}
+		flag = syntax.EmptyOpContext(r, r1)
+		pos += width
+		r, width = r1, width1
+		if r != endOfText {
+			r1, width1 = i.step(pos + width)
+		}
+	}
+	return m.matched
+}
+
 // empty is a non-nil 0-element slice,
 // so doExecute can avoid an allocation
 // when 0 captures are requested from a successful match.
@@ -329,16 +429,23 @@ func (re *Regexp) doExecute(r io.RuneReader, b []byte, s string, pos int, ncap i
 	} else {
 		i = m.newInputString(s)
 	}
-	m.init(ncap)
-	if !m.match(i, pos) {
-		re.put(m)
-		return nil
+	if m.op != notOnePass {
+		if !m.onepass(i, pos) {
+			re.put(m)
+			return nil
+		}
+	} else {
+		m.init(ncap)
+		if !m.match(i, pos) {
+			re.put(m)
+			return nil
+		}
 	}
 	if ncap == 0 {
 		re.put(m)
 		return empty // empty but not nil
 	}
-	cap := make([]int, ncap)
+	cap := make([]int, len(m.matchcap))
 	copy(cap, m.matchcap)
 	re.put(m)
 	return cap
diff --git a/src/pkg/regexp/onepass.go b/src/pkg/regexp/onepass.go
new file mode 100644
index 0000000..501fb28
--- /dev/null
+++ b/src/pkg/regexp/onepass.go
@@ -0,0 +1,582 @@
+// Copyright 2014 The Go Authors.  All rights reserved.
+
+package regexp
+
+import (
+	"bytes"
+	"regexp/syntax"
+	"sort"
+	"unicode"
+)
+
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// "One-pass" regexp execution.
+// Some regexps can be analyzed to determine that they never need
+// backtracking: they are guaranteed to run in one pass over the string
+// without bothering to save all the usual NFA state.
+// Detect those and execute them more quickly.
+
+// A onePassProg is a compiled one-pass regular expression program.
+// It is the same as syntax.Prog except for the use of onePassInst.
+type onePassProg struct {
+	Inst   []onePassInst
+	Start  int // index of start instruction
+	NumCap int // number of InstCapture insts in re
+}
+
+// A onePassInst is a single instruction in a one-pass regular expression program.
+// It is the same as syntax.Inst except for the new 'Next' field.
+type onePassInst struct {
+	syntax.Inst
+	Next []uint32
+}
+
+// OnePassPrefix returns a literal string that all matches for the
+// regexp must start with.  Complete is true if the prefix
+// is the entire match. Pc is the index of the last rune instruction
+// in the string. The OnePassPrefix skips over the mandatory
+// EmptyBeginText
+func onePassPrefix(p *syntax.Prog) (prefix string, complete bool, pc uint32) {
+	i := &p.Inst[p.Start]
+	if i.Op != syntax.InstEmptyWidth || (syntax.EmptyOp(i.Arg))&syntax.EmptyBeginText == 0 {
+		return "", i.Op == syntax.InstMatch, uint32(p.Start)
+	}
+	pc = i.Out
+	i = &p.Inst[pc]
+	for i.Op == syntax.InstNop {
+		pc = i.Out
+		i = &p.Inst[pc]
+	}
+	// Avoid allocation of buffer if prefix is empty.
+	if iop(i) != syntax.InstRune || len(i.Rune) != 1 {
+		return "", i.Op == syntax.InstMatch, uint32(p.Start)
+	}
+
+	// Have prefix; gather characters.
+	var buf bytes.Buffer
+	for iop(i) == syntax.InstRune && len(i.Rune) == 1 && syntax.Flags(i.Arg)&syntax.FoldCase == 0 {
+		buf.WriteRune(i.Rune[0])
+		pc, i = i.Out, &p.Inst[i.Out]
+	}
+	return buf.String(), i.Op == syntax.InstEmptyWidth && (syntax.EmptyOp(i.Arg))&syntax.EmptyBeginText != 0, pc
+}
+
+// OnePassNext selects the next actionable state of the prog, based on the input character.
+// It should only be called when i.Op == InstAlt or InstAltMatch, and from the one-pass machine.
+// One of the alternates may ultimately lead without input to end of line. If the instruction
+// is InstAltMatch the path to the InstMatch is in i.Out, the normal node in i.Next.
+func onePassNext(i *onePassInst, r rune) uint32 {
+	next := i.MatchRunePos(r)
+	if next >= 0 {
+		return i.Next[next]
+	}
+	if i.Op == syntax.InstAltMatch {
+		return i.Out
+	}
+	return 0
+}
+
+func iop(i *syntax.Inst) syntax.InstOp {
+	op := i.Op
+	switch op {
+	case syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL:
+		op = syntax.InstRune
+	}
+	return op
+}
+
+// Sparse Array implementation is used as a queueOnePass.
+type queueOnePass struct {
+	sparse          []uint32
+	dense           []uint32
+	size, nextIndex uint32
+}
+
+func (q *queueOnePass) empty() bool {
+	return q.nextIndex >= q.size
+}
+
+func (q *queueOnePass) next() (n uint32) {
+	n = q.dense[q.nextIndex]
+	q.nextIndex++
+	return
+}
+
+func (q *queueOnePass) clear() {
+	q.size = 0
+	q.nextIndex = 0
+}
+
+func (q *queueOnePass) reset() {
+	q.nextIndex = 0
+}
+
+func (q *queueOnePass) contains(u uint32) bool {
+	if u >= uint32(len(q.sparse)) {
+		return false
+	}
+	return q.sparse[u] < q.size && q.dense[q.sparse[u]] == u
+}
+
+func (q *queueOnePass) insert(u uint32) {
+	if !q.contains(u) {
+		q.insertNew(u)
+	}
+}
+
+func (q *queueOnePass) insertNew(u uint32) {
+	if u >= uint32(len(q.sparse)) {
+		return
+	}
+	q.sparse[u] = q.size
+	q.dense[q.size] = u
+	q.size++
+}
+
+func newQueue(size int) (q *queueOnePass) {
+	return &queueOnePass{
+		sparse: make([]uint32, size),
+		dense:  make([]uint32, size),
+	}
+}
+
+// mergeRuneSets merges two non-intersecting runesets, and returns the merged result,
+// and a NextIp array. The idea is that if a rune matches the OnePassRunes at index
+// i, NextIp[i/2] is the target. If the input sets intersect, an empty runeset and a
+// NextIp array with the single element mergeFailed is returned.
+// The code assumes that both inputs contain ordered and non-intersecting rune pairs.
+const mergeFailed = uint32(0xffffffff)
+
+var (
+	noRune = []rune{}
+	noNext = []uint32{mergeFailed}
+)
+
+func mergeRuneSets(leftRunes, rightRunes *[]rune, leftPC, rightPC uint32) ([]rune, []uint32) {
+	leftLen := len(*leftRunes)
+	rightLen := len(*rightRunes)
+	if leftLen&0x1 != 0 || rightLen&0x1 != 0 {
+		panic("mergeRuneSets odd length []rune")
+	}
+	var (
+		lx, rx int
+	)
+	merged := make([]rune, 0)
+	next := make([]uint32, 0)
+	ok := true
+	defer func() {
+		if !ok {
+			merged = nil
+			next = nil
+		}
+	}()
+
+	ix := -1
+	extend := func(newLow *int, newArray *[]rune, pc uint32) bool {
+		if ix > 0 && (*newArray)[*newLow] <= merged[ix] {
+			return false
+		}
+		merged = append(merged, (*newArray)[*newLow], (*newArray)[*newLow+1])
+		*newLow += 2
+		ix += 2
+		next = append(next, pc)
+		return true
+	}
+
+	for lx < leftLen || rx < rightLen {
+		switch {
+		case rx >= rightLen:
+			ok = extend(&lx, leftRunes, leftPC)
+		case lx >= leftLen:
+			ok = extend(&rx, rightRunes, rightPC)
+		case (*rightRunes)[rx] < (*leftRunes)[lx]:
+			ok = extend(&rx, rightRunes, rightPC)
+		default:
+			ok = extend(&lx, leftRunes, leftPC)
+		}
+		if !ok {
+			return noRune, noNext
+		}
+	}
+	return merged, next
+}
+
+// cleanupOnePass drops working memory, and restores certain shortcut instructions.
+func cleanupOnePass(prog *onePassProg, original *syntax.Prog) {
+	for ix, instOriginal := range original.Inst {
+		switch instOriginal.Op {
+		case syntax.InstAlt, syntax.InstAltMatch, syntax.InstRune:
+		case syntax.InstCapture, syntax.InstEmptyWidth, syntax.InstNop, syntax.InstMatch, syntax.InstFail:
+			prog.Inst[ix].Next = nil
+		case syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL:
+			prog.Inst[ix].Next = nil
+			prog.Inst[ix] = onePassInst{Inst: instOriginal}
+		}
+	}
+}
+
+// onePassCopy creates a copy of the original Prog, as we'll be modifying it
+func onePassCopy(prog *syntax.Prog) *onePassProg {
+	p := &onePassProg{
+		Start:  prog.Start,
+		NumCap: prog.NumCap,
+	}
+	for _, inst := range prog.Inst {
+		p.Inst = append(p.Inst, onePassInst{Inst: inst})
+	}
+
+	// rewrites one or more common Prog constructs that enable some otherwise
+	// non-onepass Progs to be onepass. A:BD (for example) means an InstAlt at
+	// ip A, that points to ips B & C.
+	// A:BC + B:DA => A:BC + B:CD
+	// A:BC + B:DC => A:DC + B:DC
+	for pc := range p.Inst {
+		switch p.Inst[pc].Op {
+		default:
+			continue
+		case syntax.InstAlt, syntax.InstAltMatch:
+			// A:Bx + B:Ay
+			p_A_Other := &p.Inst[pc].Out
+			p_A_Alt := &p.Inst[pc].Arg
+			// make sure a target is another Alt
+			instAlt := p.Inst[*p_A_Alt]
+			if !(instAlt.Op == syntax.InstAlt || instAlt.Op == syntax.InstAltMatch) {
+				p_A_Alt, p_A_Other = p_A_Other, p_A_Alt
+				instAlt = p.Inst[*p_A_Alt]
+				if !(instAlt.Op == syntax.InstAlt || instAlt.Op == syntax.InstAltMatch) {
+					continue
+				}
+			}
+			instOther := p.Inst[*p_A_Other]
+			// Analyzing both legs pointing to Alts is for another day
+			if instOther.Op == syntax.InstAlt || instOther.Op == syntax.InstAltMatch {
+				// too complicated
+				continue
+			}
+			// simple empty transition loop
+			// A:BC + B:DA => A:BC + B:DC
+			p_B_Alt := &p.Inst[*p_A_Alt].Out
+			p_B_Other := &p.Inst[*p_A_Alt].Arg
+			patch := false
+			if instAlt.Out == uint32(pc) {
+				patch = true
+			} else if instAlt.Arg == uint32(pc) {
+				patch = true
+				p_B_Alt, p_B_Other = p_B_Other, p_B_Alt
+			}
+			if patch {
+				*p_B_Alt = *p_A_Other
+			}
+
+			// empty transition to common target
+			// A:BC + B:DC => A:DC + B:DC
+			if *p_A_Other == *p_B_Alt {
+				*p_A_Alt = *p_B_Other
+			}
+		}
+	}
+	return p
+}
+
+// runeSlice exists to permit sorting the case-folded rune sets.
+type runeSlice []rune
+
+func (p runeSlice) Len() int           { return len(p) }
+func (p runeSlice) Less(i, j int) bool { return p[i] < p[j] }
+func (p runeSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
+
+// Sort is a convenience method.
+func (p runeSlice) Sort() {
+	sort.Sort(p)
+}
+
+var anyRuneNotNL = []rune{0, '\n' - 1, '\n' + 1, unicode.MaxRune}
+var anyRune = []rune{0, unicode.MaxRune}
+
+// makeOnePass creates a onepass Prog, if possible. It is possible if at any alt,
+// the match engine can always tell which branch to take. The routine may modify
+// p if it is turned into a onepass Prog. If it isn't possible for this to be a
+// onepass Prog, the Prog notOnePass is returned. makeOnePass is recursive
+// to the size of the Prog.
+func makeOnePass(p *onePassProg) *onePassProg {
+	// If the machine is very long, it's not worth the time to check if we can use one pass.
+	if len(p.Inst) >= 1000 {
+		return notOnePass
+	}
+
+	var (
+		instQueue    = newQueue(len(p.Inst))
+		visitQueue   = newQueue(len(p.Inst))
+		build        func(uint32, *queueOnePass)
+		check        func(uint32, map[uint32]bool) bool
+		onePassRunes = make([][]rune, len(p.Inst))
+	)
+	build = func(pc uint32, q *queueOnePass) {
+		if q.contains(pc) {
+			return
+		}
+		inst := p.Inst[pc]
+		switch inst.Op {
+		case syntax.InstAlt, syntax.InstAltMatch:
+			q.insert(inst.Out)
+			build(inst.Out, q)
+			q.insert(inst.Arg)
+		case syntax.InstMatch, syntax.InstFail:
+		default:
+			q.insert(inst.Out)
+		}
+	}
+
+	// check that paths from Alt instructions are unambiguous, and rebuild the new
+	// program as a onepass program
+	check = func(pc uint32, m map[uint32]bool) (ok bool) {
+		ok = true
+		inst := &p.Inst[pc]
+		if visitQueue.contains(pc) {
+			return
+		}
+		visitQueue.insert(pc)
+		switch inst.Op {
+		case syntax.InstAlt, syntax.InstAltMatch:
+			ok = check(inst.Out, m) && check(inst.Arg, m)
+			// check no-input paths to InstMatch
+			matchOut := m[inst.Out]
+			matchArg := m[inst.Arg]
+			if matchOut && matchArg {
+				ok = false
+				break
+			}
+			// Match on empty goes in inst.Out
+			if matchArg {
+				inst.Out, inst.Arg = inst.Arg, inst.Out
+				matchOut, matchArg = matchArg, matchOut
+			}
+			if matchOut {
+				m[pc] = true
+				inst.Op = syntax.InstAltMatch
+			}
+
+			// build a dispatch operator from the two legs of the alt.
+			onePassRunes[pc], inst.Next = mergeRuneSets(
+				&onePassRunes[inst.Out], &onePassRunes[inst.Arg], inst.Out, inst.Arg)
+			if len(inst.Next) > 0 && inst.Next[0] == mergeFailed {
+				ok = false
+				break
+			}
+		case syntax.InstCapture, syntax.InstNop:
+			ok = check(inst.Out, m)
+			m[pc] = m[inst.Out]
+			// pass matching runes back through these no-ops.
+			onePassRunes[pc] = append([]rune{}, onePassRunes[inst.Out]...)
+			inst.Next = []uint32{}
+			for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
+				inst.Next = append(inst.Next, inst.Out)
+			}
+		case syntax.InstEmptyWidth:
+			ok = check(inst.Out, m)
+			m[pc] = m[inst.Out]
+			onePassRunes[pc] = append([]rune{}, onePassRunes[inst.Out]...)
+			inst.Next = []uint32{}
+			for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
+				inst.Next = append(inst.Next, inst.Out)
+			}
+		case syntax.InstMatch, syntax.InstFail:
+			m[pc] = inst.Op == syntax.InstMatch
+			break
+		case syntax.InstRune:
+			ok = check(inst.Out, m)
+			m[pc] = false
+			if len(inst.Next) > 0 {
+				break
+			}
+			if len(inst.Rune) == 0 {
+				onePassRunes[pc] = []rune{}
+				inst.Next = []uint32{inst.Out}
+				break
+			}
+			runes := make([]rune, 0)
+			if len(inst.Rune) == 1 && syntax.Flags(inst.Arg)&syntax.FoldCase != 0 {
+				r0 := inst.Rune[0]
+				runes = append(runes, r0, r0)
+				for r1 := unicode.SimpleFold(r0); r1 != r0; r1 = unicode.SimpleFold(r1) {
+					runes = append(runes, r1, r1)
+				}
+				sort.Sort(runeSlice(runes))
+			} else {
+				runes = append(runes, inst.Rune...)
+			}
+			onePassRunes[pc] = runes
+			inst.Next = []uint32{}
+			for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
+				inst.Next = append(inst.Next, inst.Out)
+			}
+			inst.Op = syntax.InstRune
+		case syntax.InstRune1:
+			ok = check(inst.Out, m)
+			m[pc] = false
+			if len(inst.Next) > 0 {
+				break
+			}
+			runes := []rune{}
+			// expand case-folded runes
+			if syntax.Flags(inst.Arg)&syntax.FoldCase != 0 {
+				r0 := inst.Rune[0]
+				runes = append(runes, r0, r0)
+				for r1 := unicode.SimpleFold(r0); r1 != r0; r1 = unicode.SimpleFold(r1) {
+					runes = append(runes, r1, r1)
+				}
+				sort.Sort(runeSlice(runes))
+			} else {
+				runes = append(runes, inst.Rune[0], inst.Rune[0])
+			}
+			onePassRunes[pc] = runes
+			inst.Next = []uint32{}
+			for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
+				inst.Next = append(inst.Next, inst.Out)
+			}
+			inst.Op = syntax.InstRune
+		case syntax.InstRuneAny:
+			ok = check(inst.Out, m)
+			m[pc] = false
+			if len(inst.Next) > 0 {
+				break
+			}
+			onePassRunes[pc] = append([]rune{}, anyRune...)
+			inst.Next = []uint32{inst.Out}
+		case syntax.InstRuneAnyNotNL:
+			ok = check(inst.Out, m)
+			m[pc] = false
+			if len(inst.Next) > 0 {
+				break
+			}
+			onePassRunes[pc] = append([]rune{}, anyRuneNotNL...)
+			inst.Next = []uint32{}
+			for i := len(onePassRunes[pc]) / 2; i >= 0; i-- {
+				inst.Next = append(inst.Next, inst.Out)
+			}
+		}
+		return
+	}
+
+	instQueue.clear()
+	instQueue.insert(uint32(p.Start))
+	m := make(map[uint32]bool, len(p.Inst))
+	for !instQueue.empty() {
+		pc := instQueue.next()
+		inst := p.Inst[pc]
+		visitQueue.clear()
+		if !check(uint32(pc), m) {
+			p = notOnePass
+			break
+		}
+		switch inst.Op {
+		case syntax.InstAlt, syntax.InstAltMatch:
+			instQueue.insert(inst.Out)
+			instQueue.insert(inst.Arg)
+		case syntax.InstCapture, syntax.InstEmptyWidth, syntax.InstNop:
+			instQueue.insert(inst.Out)
+		case syntax.InstMatch:
+		case syntax.InstFail:
+		case syntax.InstRune, syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL:
+		default:
+		}
+	}
+	if p != notOnePass {
+		for i, _ := range p.Inst {
+			p.Inst[i].Rune = onePassRunes[i]
+		}
+	}
+	return p
+}
+
+// walk visits each Inst in the prog once, and applies the argument
+// function(ip, next), in pre-order.
+func walk(prog *syntax.Prog, funcs ...func(ip, next uint32)) {
+	var walk1 func(uint32)
+	progQueue := newQueue(len(prog.Inst))
+	walk1 = func(ip uint32) {
+		if progQueue.contains(ip) {
+			return
+		}
+		progQueue.insert(ip)
+		inst := prog.Inst[ip]
+		switch inst.Op {
+		case syntax.InstAlt, syntax.InstAltMatch:
+			for _, f := range funcs {
+				f(ip, inst.Out)
+				f(ip, inst.Arg)
+			}
+			walk1(inst.Out)
+			walk1(inst.Arg)
+		default:
+			for _, f := range funcs {
+				f(ip, inst.Out)
+			}
+			walk1(inst.Out)
+		}
+	}
+	walk1(uint32(prog.Start))
+}
+
+// find returns the Insts that match the argument predicate function
+func find(prog *syntax.Prog, f func(*syntax.Prog, int) bool) (matches []uint32) {
+	matches = []uint32{}
+
+	for ip := range prog.Inst {
+		if f(prog, ip) {
+			matches = append(matches, uint32(ip))
+		}
+	}
+	return
+}
+
+var notOnePass *onePassProg = nil
+
+// compileOnePass returns a new *syntax.Prog suitable for onePass execution if the original Prog
+// can be recharacterized as a one-pass regexp program, or syntax.notOnePass if the
+// Prog cannot be converted. For a one pass prog, the fundamental condition that must
+// be true is: at any InstAlt, there must be no ambiguity about what branch to  take.
+func compileOnePass(prog *syntax.Prog) (p *onePassProg) {
+	if prog.Start == 0 {
+		return notOnePass
+	}
+	// onepass regexp is anchored
+	if prog.Inst[prog.Start].Op != syntax.InstEmptyWidth ||
+		syntax.EmptyOp(prog.Inst[prog.Start].Arg)&syntax.EmptyBeginText != syntax.EmptyBeginText {
+		return notOnePass
+	}
+	// every instruction leading to InstMatch must be EmptyEndText
+	for _, inst := range prog.Inst {
+		opOut := prog.Inst[inst.Out].Op
+		switch inst.Op {
+		default:
+			if opOut == syntax.InstMatch {
+				return notOnePass
+			}
+		case syntax.InstAlt, syntax.InstAltMatch:
+			if opOut == syntax.InstMatch || prog.Inst[inst.Arg].Op == syntax.InstMatch {
+				return notOnePass
+			}
+		case syntax.InstEmptyWidth:
+			if opOut == syntax.InstMatch {
+				if syntax.EmptyOp(inst.Arg)&syntax.EmptyEndText == syntax.EmptyEndText {
+					continue
+				}
+				return notOnePass
+			}
+		}
+	}
+	// Creates a slightly optimized copy of the original Prog
+	// that cleans up some Prog idioms that block valid onepass programs
+	p = onePassCopy(prog)
+
+	// checkAmbiguity on InstAlts, build onepass Prog if possible
+	p = makeOnePass(p)
+
+	if p != notOnePass {
+		cleanupOnePass(p, prog)
+	}
+	return p
+}
diff --git a/src/pkg/regexp/onepass_test.go b/src/pkg/regexp/onepass_test.go
new file mode 100644
index 0000000..7b2beea
--- /dev/null
+++ b/src/pkg/regexp/onepass_test.go
@@ -0,0 +1,208 @@
+// 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 regexp
+
+import (
+	"reflect"
+	"regexp/syntax"
+	"testing"
+)
+
+var runeMergeTests = []struct {
+	left, right, merged []rune
+	next                []uint32
+	leftPC, rightPC     uint32
+}{
+	{
+		// empty rhs
+		[]rune{69, 69},
+		[]rune{},
+		[]rune{69, 69},
+		[]uint32{1},
+		1, 2,
+	},
+	{
+		// identical runes, identical targets
+		[]rune{69, 69},
+		[]rune{69, 69},
+		[]rune{},
+		[]uint32{mergeFailed},
+		1, 1,
+	},
+	{
+		// identical runes, different targets
+		[]rune{69, 69},
+		[]rune{69, 69},
+		[]rune{},
+		[]uint32{mergeFailed},
+		1, 2,
+	},
+	{
+		// append right-first
+		[]rune{69, 69},
+		[]rune{71, 71},
+		[]rune{69, 69, 71, 71},
+		[]uint32{1, 2},
+		1, 2,
+	},
+	{
+		// append, left-first
+		[]rune{71, 71},
+		[]rune{69, 69},
+		[]rune{69, 69, 71, 71},
+		[]uint32{2, 1},
+		1, 2,
+	},
+	{
+		// successful interleave
+		[]rune{60, 60, 71, 71, 101, 101},
+		[]rune{69, 69, 88, 88},
+		[]rune{60, 60, 69, 69, 71, 71, 88, 88, 101, 101},
+		[]uint32{1, 2, 1, 2, 1},
+		1, 2,
+	},
+	{
+		// left surrounds right
+		[]rune{69, 74},
+		[]rune{71, 71},
+		[]rune{},
+		[]uint32{mergeFailed},
+		1, 2,
+	},
+	{
+		// right surrounds left
+		[]rune{69, 74},
+		[]rune{68, 75},
+		[]rune{},
+		[]uint32{mergeFailed},
+		1, 2,
+	},
+	{
+		// overlap at interval begin
+		[]rune{69, 74},
+		[]rune{74, 75},
+		[]rune{},
+		[]uint32{mergeFailed},
+		1, 2,
+	},
+	{
+		// overlap ar interval end
+		[]rune{69, 74},
+		[]rune{65, 69},
+		[]rune{},
+		[]uint32{mergeFailed},
+		1, 2,
+	},
+	{
+		// overlap from above
+		[]rune{69, 74},
+		[]rune{71, 74},
+		[]rune{},
+		[]uint32{mergeFailed},
+		1, 2,
+	},
+	{
+		// overlap from below
+		[]rune{69, 74},
+		[]rune{65, 71},
+		[]rune{},
+		[]uint32{mergeFailed},
+		1, 2,
+	},
+	{
+		// out of order []rune
+		[]rune{69, 74, 60, 65},
+		[]rune{66, 67},
+		[]rune{},
+		[]uint32{mergeFailed},
+		1, 2,
+	},
+}
+
+func TestMergeRuneSet(t *testing.T) {
+	for ix, test := range runeMergeTests {
+		merged, next := mergeRuneSets(&test.left, &test.right, test.leftPC, test.rightPC)
+		if !reflect.DeepEqual(merged, test.merged) {
+			t.Errorf("mergeRuneSet :%d (%v, %v) merged\n have\n%v\nwant\n%v", ix, test.left, test.right, merged, test.merged)
+		}
+		if !reflect.DeepEqual(next, test.next) {
+			t.Errorf("mergeRuneSet :%d(%v, %v) next\n have\n%v\nwant\n%v", ix, test.left, test.right, next, test.next)
+		}
+	}
+}
+
+const noStr = `!`
+
+var onePass = &onePassProg{}
+
+var onePassTests = []struct {
+	re      string
+	onePass *onePassProg
+	prog    string
+}{
+	{`^(?:a|(?:a*))$`, notOnePass, noStr},
+	{`^(?:(a)|(?:a*))$`, notOnePass, noStr},
+	{`^(?:(?:(?:.(?:$))?))$`, onePass, `a`},
+	{`^abcd$`, onePass, `abcd`},
+	{`^abcd$`, onePass, `abcde`},
+	{`^(?:(?:a{0,})*?)$`, onePass, `a`},
+	{`^(?:(?:a+)*)$`, onePass, ``},
+	{`^(?:(?:a|(?:aa)))$`, onePass, ``},
+	{`^(?:[^\s\S])$`, onePass, ``},
+	{`^(?:(?:a{3,4}){0,})$`, notOnePass, `aaaaaa`},
+	{`^(?:(?:a+)*)$`, onePass, `a`},
+	{`^(?:(?:(?:a*)+))$`, onePass, noStr},
+	{`^(?:(?:a+)*)$`, onePass, ``},
+	{`^[a-c]+$`, onePass, `abc`},
+	{`^[a-c]*$`, onePass, `abcdabc`},
+	{`^(?:a*)$`, onePass, `aaaaaaa`},
+	{`^(?:(?:aa)|a)$`, onePass, `a`},
+	{`^[a-c]*`, notOnePass, `abcdabc`},
+	{`^[a-c]*$`, onePass, `abc`},
+	{`^...$`, onePass, ``},
+	{`^(?:a|(?:aa))$`, onePass, `a`},
+	{`^[a-c]*`, notOnePass, `abcabc`},
+	{`^a((b))c$`, onePass, noStr},
+	{`^a.[l-nA-Cg-j]?e$`, onePass, noStr},
+	{`^a((b))$`, onePass, noStr},
+	{`^a(?:(b)|(c))c$`, onePass, noStr},
+	{`^a(?:(b*)|(c))c$`, notOnePass, noStr},
+	{`^a(?:b|c)$`, onePass, noStr},
+	{`^a(?:b?|c)$`, onePass, noStr},
+	{`^a(?:b?|c?)$`, notOnePass, noStr},
+	{`^a(?:b?|c+)$`, onePass, noStr},
+	{`^a(?:b+|(bc))d$`, notOnePass, noStr},
+	{`^a(?:bc)+$`, onePass, noStr},
+	{`^a(?:[bcd])+$`, onePass, noStr},
+	{`^a((?:[bcd])+)$`, onePass, noStr},
+	{`^a(:?b|c)*d$`, onePass, `abbbccbbcbbd"`},
+	{`^.bc(d|e)*$`, onePass, `abcddddddeeeededd`},
+	{`^(?:(?:aa)|.)$`, notOnePass, `a`},
+	{`^(?:(?:a{1,2}){1,2})$`, notOnePass, `aaaa`},
+}
+
+func TestCompileOnePass(t *testing.T) {
+	var (
+		p   *syntax.Prog
+		re  *syntax.Regexp
+		err error
+	)
+	for _, test := range onePassTests {
+		if re, err = syntax.Parse(test.re, syntax.Perl); err != nil {
+			t.Errorf("Parse(%q) got err:%s, want success", test.re, err)
+			continue
+		}
+		// needs to be done before compile...
+		re = re.Simplify()
+		if p, err = syntax.Compile(re); err != nil {
+			t.Errorf("Compile(%q) got err:%s, want success", test.re, err)
+			continue
+		}
+		onePass = compileOnePass(p)
+		if (onePass == notOnePass) != (test.onePass == notOnePass) {
+			t.Errorf("CompileOnePass(%q) got %v, expected %v", test.re, onePass, test.onePass)
+		}
+	}
+}
diff --git a/src/pkg/regexp/regexp.go b/src/pkg/regexp/regexp.go
index 0046026..0b8336a 100644
--- a/src/pkg/regexp/regexp.go
+++ b/src/pkg/regexp/regexp.go
@@ -11,6 +11,14 @@
 // For an overview of the syntax, run
 //   godoc regexp/syntax
 //
+// The regexp implementation provided by this package is
+// guaranteed to run in time linear in the size of the input.
+// (This is a property not guaranteed by most open source
+// implementations of regular expressions.) For more information
+// about this property, see
+//	http://swtch.com/~rsc/regexp/regexp1.html
+// or any book about automata theory.
+//
 // All characters are UTF-8-encoded code points.
 //
 // There are 16 methods of Regexp that match a regular expression and identify
@@ -70,16 +78,17 @@ import (
 var debug = false
 
 // Regexp is the representation of a compiled regular expression.
-// The public interface is entirely through methods.
 // A Regexp is safe for concurrent use by multiple goroutines.
 type Regexp struct {
 	// read-only after Compile
 	expr           string         // as passed to Compile
 	prog           *syntax.Prog   // compiled program
+	onepass        *onePassProg   // onpass program or nil
 	prefix         string         // required prefix in unanchored matches
 	prefixBytes    []byte         // prefix, as a []byte
 	prefixComplete bool           // prefix is the entire regexp
 	prefixRune     rune           // first rune in prefix
+	prefixEnd      uint32         // pc for last rune in prefix
 	cond           syntax.EmptyOp // empty-width conditions required at start of match
 	numSubexp      int
 	subexpNames    []string
@@ -156,12 +165,17 @@ func compile(expr string, mode syntax.Flags, longest bool) (*Regexp, error) {
 	regexp := &Regexp{
 		expr:        expr,
 		prog:        prog,
+		onepass:     compileOnePass(prog),
 		numSubexp:   maxCap,
 		subexpNames: capNames,
 		cond:        prog.StartCond(),
 		longest:     longest,
 	}
-	regexp.prefix, regexp.prefixComplete = prog.Prefix()
+	if regexp.onepass == notOnePass {
+		regexp.prefix, regexp.prefixComplete = prog.Prefix()
+	} else {
+		regexp.prefix, regexp.prefixComplete, regexp.prefixEnd = onePassPrefix(prog)
+	}
 	if regexp.prefix != "" {
 		// TODO(rsc): Remove this allocation by adding
 		// IndexString to package bytes.
@@ -183,7 +197,7 @@ func (re *Regexp) get() *machine {
 		return z
 	}
 	re.mu.Unlock()
-	z := progMachine(re.prog)
+	z := progMachine(re.prog, re.onepass)
 	z.re = re
 	return z
 }
diff --git a/src/pkg/regexp/syntax/doc.go b/src/pkg/regexp/syntax/doc.go
index e52632e..8e72c90 100644
--- a/src/pkg/regexp/syntax/doc.go
+++ b/src/pkg/regexp/syntax/doc.go
@@ -46,6 +46,10 @@ Repetitions:
   x{n,}?         n or more x, prefer fewer
   x{n}?          exactly n x
 
+Implementation restriction: The counting forms x{n} etc. (but not the other
+forms x* etc.) have an upper limit of n=1000. Negative or higher explicit
+counts yield the parse error ErrInvalidRepeatSize.
+
 Grouping:
   (re)           numbered capturing group (submatch)
   (?P<name>re)   named & numbered capturing group (submatch)
diff --git a/src/pkg/regexp/syntax/make_perl_groups.pl b/src/pkg/regexp/syntax/make_perl_groups.pl
index d024f50..90040fc 100755
--- a/src/pkg/regexp/syntax/make_perl_groups.pl
+++ b/src/pkg/regexp/syntax/make_perl_groups.pl
@@ -92,6 +92,10 @@ sub PrintClasses($@) {
 }
 
 print <<EOF;
+// 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.
+
 // GENERATED BY make_perl_groups.pl; DO NOT EDIT.
 // make_perl_groups.pl >perl_groups.go
 
diff --git a/src/pkg/regexp/syntax/parse.go b/src/pkg/regexp/syntax/parse.go
index 42d0bf4..cb25dca 100644
--- a/src/pkg/regexp/syntax/parse.go
+++ b/src/pkg/regexp/syntax/parse.go
@@ -668,7 +668,6 @@ func Parse(s string, flags Flags) (*Regexp, error) {
 		c          rune
 		op         Op
 		lastRepeat string
-		min, max   int
 	)
 	p.flags = flags
 	p.wholeRegexp = s
@@ -740,7 +739,7 @@ func Parse(s string, flags Flags) (*Regexp, error) {
 				op = OpQuest
 			}
 			after := t[1:]
-			if after, err = p.repeat(op, min, max, before, after, lastRepeat); err != nil {
+			if after, err = p.repeat(op, 0, 0, before, after, lastRepeat); err != nil {
 				return nil, err
 			}
 			repeat = before
diff --git a/src/pkg/regexp/syntax/parse_test.go b/src/pkg/regexp/syntax/parse_test.go
index 269d6c3..f308929 100644
--- a/src/pkg/regexp/syntax/parse_test.go
+++ b/src/pkg/regexp/syntax/parse_test.go
@@ -100,12 +100,12 @@ var parseTests = []parseTest{
 	{`\P{Braille}`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
 	{`\p{^Braille}`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
 	{`\P{^Braille}`, `cc{0x2800-0x28ff}`},
-	{`\pZ`, `cc{0x20 0xa0 0x1680 0x180e 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}`},
+	{`\pZ`, `cc{0x20 0xa0 0x1680 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}`},
 	{`[\p{Braille}]`, `cc{0x2800-0x28ff}`},
 	{`[\P{Braille}]`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
 	{`[\p{^Braille}]`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
 	{`[\P{^Braille}]`, `cc{0x2800-0x28ff}`},
-	{`[\pZ]`, `cc{0x20 0xa0 0x1680 0x180e 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}`},
+	{`[\pZ]`, `cc{0x20 0xa0 0x1680 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}`},
 	{`\p{Lu}`, mkCharClass(unicode.IsUpper)},
 	{`[\p{Lu}]`, mkCharClass(unicode.IsUpper)},
 	{`(?i)[\p{Lu}]`, mkCharClass(isUpperFold)},
diff --git a/src/pkg/regexp/syntax/perl_groups.go b/src/pkg/regexp/syntax/perl_groups.go
index 1a11ca6..effe4e6 100644
--- a/src/pkg/regexp/syntax/perl_groups.go
+++ b/src/pkg/regexp/syntax/perl_groups.go
@@ -1,3 +1,7 @@
+// 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.
+
 // GENERATED BY make_perl_groups.pl; DO NOT EDIT.
 // make_perl_groups.pl >perl_groups.go
 
diff --git a/src/pkg/regexp/syntax/prog.go b/src/pkg/regexp/syntax/prog.go
index a482a82..29bd282 100644
--- a/src/pkg/regexp/syntax/prog.go
+++ b/src/pkg/regexp/syntax/prog.go
@@ -37,6 +37,27 @@ const (
 	InstRuneAnyNotNL
 )
 
+var instOpNames = []string{
+	"InstAlt",
+	"InstAltMatch",
+	"InstCapture",
+	"InstEmptyWidth",
+	"InstMatch",
+	"InstFail",
+	"InstNop",
+	"InstRune",
+	"InstRune1",
+	"InstRuneAny",
+	"InstRuneAnyNotNL",
+}
+
+func (i InstOp) String() string {
+	if uint(i) >= uint(len(instOpNames)) {
+		return ""
+	}
+	return instOpNames[i]
+}
+
 // An EmptyOp specifies a kind or mixture of zero-width assertions.
 type EmptyOp uint8
 
@@ -103,13 +124,13 @@ func (p *Prog) String() string {
 
 // skipNop follows any no-op or capturing instructions
 // and returns the resulting pc.
-func (p *Prog) skipNop(pc uint32) *Inst {
+func (p *Prog) skipNop(pc uint32) (*Inst, uint32) {
 	i := &p.Inst[pc]
 	for i.Op == InstNop || i.Op == InstCapture {
 		pc = i.Out
 		i = &p.Inst[pc]
 	}
-	return i
+	return i, pc
 }
 
 // op returns i.Op but merges all the Rune special cases into InstRune
@@ -126,7 +147,7 @@ func (i *Inst) op() InstOp {
 // regexp must start with.  Complete is true if the prefix
 // is the entire match.
 func (p *Prog) Prefix() (prefix string, complete bool) {
-	i := p.skipNop(uint32(p.Start))
+	i, _ := p.skipNop(uint32(p.Start))
 
 	// Avoid allocation of buffer if prefix is empty.
 	if i.op() != InstRune || len(i.Rune) != 1 {
@@ -137,7 +158,7 @@ func (p *Prog) Prefix() (prefix string, complete bool) {
 	var buf bytes.Buffer
 	for i.op() == InstRune && len(i.Rune) == 1 && Flags(i.Arg)&FoldCase == 0 {
 		buf.WriteRune(i.Rune[0])
-		i = p.skipNop(i.Out)
+		i, _ = p.skipNop(i.Out)
 	}
 	return buf.String(), i.Op == InstMatch
 }
@@ -166,35 +187,46 @@ Loop:
 	return flag
 }
 
+const noMatch = -1
+
 // MatchRune returns true if the instruction matches (and consumes) r.
 // It should only be called when i.Op == InstRune.
 func (i *Inst) MatchRune(r rune) bool {
+	return i.MatchRunePos(r) != noMatch
+}
+
+// MatchRunePos checks whether the instruction matches (and consumes) r.
+// If so, MatchRunePos returns the index of the matching rune pair
+// (or, when len(i.Rune) == 1, rune singleton).
+// If not, MatchRunePos returns -1.
+// MatchRunePos should only be called when i.Op == InstRune.
+func (i *Inst) MatchRunePos(r rune) int {
 	rune := i.Rune
 
 	// Special case: single-rune slice is from literal string, not char class.
 	if len(rune) == 1 {
 		r0 := rune[0]
 		if r == r0 {
-			return true
+			return 0
 		}
 		if Flags(i.Arg)&FoldCase != 0 {
 			for r1 := unicode.SimpleFold(r0); r1 != r0; r1 = unicode.SimpleFold(r1) {
 				if r == r1 {
-					return true
+					return 0
 				}
 			}
 		}
-		return false
+		return noMatch
 	}
 
 	// Peek at the first few pairs.
 	// Should handle ASCII well.
 	for j := 0; j < len(rune) && j <= 8; j += 2 {
 		if r < rune[j] {
-			return false
+			return noMatch
 		}
 		if r <= rune[j+1] {
-			return true
+			return j / 2
 		}
 	}
 
@@ -205,14 +237,14 @@ func (i *Inst) MatchRune(r rune) bool {
 		m := lo + (hi-lo)/2
 		if c := rune[2*m]; c <= r {
 			if r <= rune[2*m+1] {
-				return true
+				return m
 			}
 			lo = m + 1
 		} else {
 			hi = m
 		}
 	}
-	return false
+	return noMatch
 }
 
 // As per re2's Prog::IsWordChar. Determines whether rune is an ASCII word char.
diff --git a/src/pkg/regexp/syntax/prog_test.go b/src/pkg/regexp/syntax/prog_test.go
index cd71abc..50bfa3d 100644
--- a/src/pkg/regexp/syntax/prog_test.go
+++ b/src/pkg/regexp/syntax/prog_test.go
@@ -4,9 +4,7 @@
 
 package syntax
 
-import (
-	"testing"
-)
+import "testing"
 
 var compileTests = []struct {
 	Regexp string
diff --git a/src/pkg/runtime/alg.c b/src/pkg/runtime/alg.c
deleted file mode 100644
index c3a8396..0000000
--- a/src/pkg/runtime/alg.c
+++ /dev/null
@@ -1,541 +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 "runtime.h"
-#include "type.h"
-#include "../../cmd/ld/textflag.h"
-
-#define M0 (sizeof(uintptr)==4 ? 2860486313UL : 33054211828000289ULL)
-#define M1 (sizeof(uintptr)==4 ? 3267000013UL : 23344194077549503ULL)
-
-static bool use_aeshash;
-
-/*
- * map and chan helpers for
- * dealing with unknown types
- */
-void
-runtime·memhash(uintptr *h, uintptr s, void *a)
-{
-	byte *b;
-	uintptr hash;
-	if(use_aeshash) {
-		runtime·aeshash(h, s, a);
-		return;
-	}
-
-	b = a;
-	hash = M0 ^ *h;
-	while(s > 0) {
-		hash = (hash ^ *b) * M1;
-		b++;
-		s--;
-	}
-	*h = hash;
-}
-
-void
-runtime·memequal(bool *eq, uintptr s, void *a, void *b)
-{
-	if(a == b) {
-		*eq = 1;
-		return;
-	}
-	*eq = runtime·memeq(a, b, s);
-}
-
-void
-runtime·memprint(uintptr s, void *a)
-{
-	uint64 v;
-
-	v = 0xbadb00b;
-	switch(s) {
-	case 1:
-		v = *(uint8*)a;
-		break;
-	case 2:
-		v = *(uint16*)a;
-		break;
-	case 4:
-		v = *(uint32*)a;
-		break;
-	case 8:
-		v = *(uint64*)a;
-		break;
-	}
-	runtime·printint(v);
-}
-
-void
-runtime·memcopy(uintptr s, void *a, void *b)
-{
-	if(b == nil) {
-		runtime·memclr(a, s);
-		return;
-	}
-	runtime·memmove(a, b, s);
-}
-
-void
-runtime·memequal0(bool *eq, uintptr s, void *a, void *b)
-{
-	USED(s);
-	USED(a);
-	USED(b);
-	*eq = true;
-}
-
-void
-runtime·memcopy0(uintptr s, void *a, void *b)
-{
-	USED(s);
-	USED(a);
-	USED(b);
-}
-
-void
-runtime·memequal8(bool *eq, uintptr s, void *a, void *b)
-{
-	USED(s);
-	*eq = *(uint8*)a == *(uint8*)b;
-}
-
-void
-runtime·memcopy8(uintptr s, void *a, void *b)
-{
-	USED(s);
-	if(b == nil) {
-		*(uint8*)a = 0;
-		return;
-	}
-	*(uint8*)a = *(uint8*)b;
-}
-
-void
-runtime·memequal16(bool *eq, uintptr s, void *a, void *b)
-{
-	USED(s);
-	*eq = *(uint16*)a == *(uint16*)b;
-}
-
-void
-runtime·memcopy16(uintptr s, void *a, void *b)
-{
-	USED(s);
-	if(b == nil) {
-		*(uint16*)a = 0;
-		return;
-	}
-	*(uint16*)a = *(uint16*)b;
-}
-
-void
-runtime·memequal32(bool *eq, uintptr s, void *a, void *b)
-{
-	USED(s);
-	*eq = *(uint32*)a == *(uint32*)b;
-}
-
-void
-runtime·memcopy32(uintptr s, void *a, void *b)
-{
-	USED(s);
-	if(b == nil) {
-		*(uint32*)a = 0;
-		return;
-	}
-	*(uint32*)a = *(uint32*)b;
-}
-
-void
-runtime·memequal64(bool *eq, uintptr s, void *a, void *b)
-{
-	USED(s);
-	*eq = *(uint64*)a == *(uint64*)b;
-}
-
-void
-runtime·memcopy64(uintptr s, void *a, void *b)
-{
-	USED(s);
-	if(b == nil) {
-		*(uint64*)a = 0;
-		return;
-	}
-	*(uint64*)a = *(uint64*)b;
-}
-
-void
-runtime·memequal128(bool *eq, uintptr s, void *a, void *b)
-{
-	USED(s);
-	*eq = ((uint64*)a)[0] == ((uint64*)b)[0] && ((uint64*)a)[1] == ((uint64*)b)[1];
-}
-
-void
-runtime·memcopy128(uintptr s, void *a, void *b)
-{
-	USED(s);
-	if(b == nil) {
-		((uint64*)a)[0] = 0;
-		((uint64*)a)[1] = 0;
-		return;
-	}
-	((uint64*)a)[0] = ((uint64*)b)[0];
-	((uint64*)a)[1] = ((uint64*)b)[1];
-}
-
-void
-runtime·f32equal(bool *eq, uintptr s, void *a, void *b)
-{
-	USED(s);
-	*eq = *(float32*)a == *(float32*)b;
-}
-
-void
-runtime·f64equal(bool *eq, uintptr s, void *a, void *b)
-{
-	USED(s);
-	*eq = *(float64*)a == *(float64*)b;
-}
-
-void
-runtime·c64equal(bool *eq, uintptr s, void *a, void *b)
-{	
-	Complex64 *ca, *cb;
-	
-	USED(s);
-	ca = a;
-	cb = b;
-	*eq = ca->real == cb->real && ca->imag == cb->imag;
-}
-
-void
-runtime·c128equal(bool *eq, uintptr s, void *a, void *b)
-{	
-	Complex128 *ca, *cb;
-	
-	USED(s);
-	ca = a;
-	cb = b;
-	*eq = ca->real == cb->real && ca->imag == cb->imag;
-}
-
-// NOTE: Because NaN != NaN, a map can contain any
-// number of (mostly useless) entries keyed with NaNs.
-// To avoid long hash chains, we assign a random number
-// as the hash value for a NaN.
-
-void
-runtime·f32hash(uintptr *h, uintptr s, void *a)
-{
-	uintptr hash;
-	float32 f;
-
-	USED(s);
-	f = *(float32*)a;
-	if(f == 0)
-		hash = 0;  // +0, -0
-	else if(f != f)
-		hash = runtime·fastrand1();  // any kind of NaN
-	else
-		hash = *(uint32*)a;
-	*h = (*h ^ hash ^ M0) * M1;
-}
-
-void
-runtime·f64hash(uintptr *h, uintptr s, void *a)
-{
-	uintptr hash;
-	float64 f;
-	uint64 u;
-
-	USED(s);
-	f = *(float64*)a;
-	if(f == 0)
-		hash = 0;	// +0, -0
-	else if(f != f)
-		hash = runtime·fastrand1();  // any kind of NaN
-	else {
-		u = *(uint64*)a;
-		if(sizeof(uintptr) == 4)
-			hash = ((uint32)(u>>32) * M1) ^ (uint32)u;
-		else
-			hash = u;
-	}
-	*h = (*h ^ hash ^ M0) * M1;
-}
-
-void
-runtime·c64hash(uintptr *h, uintptr s, void *a)
-{
-	USED(s);
-	runtime·f32hash(h, 0, a);
-	runtime·f32hash(h, 0, (float32*)a+1);
-}
-
-void
-runtime·c128hash(uintptr *h, uintptr s, void *a)
-{
-	USED(s);
-	runtime·f64hash(h, 0, a);
-	runtime·f64hash(h, 0, (float64*)a+1);
-}
-
-void
-runtime·slicecopy(uintptr s, void *a, void *b)
-{
-	USED(s);
-	if(b == nil) {
-		((Slice*)a)->array = 0;
-		((Slice*)a)->len = 0;
-		((Slice*)a)->cap = 0;
-		return;
-	}
-	((Slice*)a)->array = ((Slice*)b)->array;
-	((Slice*)a)->len = ((Slice*)b)->len;
-	((Slice*)a)->cap = ((Slice*)b)->cap;
-}
-
-void
-runtime·strhash(uintptr *h, uintptr s, void *a)
-{
-	USED(s);
-	runtime·memhash(h, ((String*)a)->len, ((String*)a)->str);
-}
-
-void
-runtime·strequal(bool *eq, uintptr s, void *a, void *b)
-{
-	intgo alen;
-	byte *s1, *s2;
-
-	USED(s);
-	alen = ((String*)a)->len;
-	if(alen != ((String*)b)->len) {
-		*eq = false;
-		return;
-	}
-	s1 = ((String*)a)->str;
-	s2 = ((String*)b)->str;
-	if(s1 == s2) {
-		*eq = true;
-		return;
-	}
-	*eq = runtime·memeq(s1, s2, alen);
-}
-
-void
-runtime·strprint(uintptr s, void *a)
-{
-	USED(s);
-	runtime·printstring(*(String*)a);
-}
-
-void
-runtime·strcopy(uintptr s, void *a, void *b)
-{
-	USED(s);
-	if(b == nil) {
-		((String*)a)->str = 0;
-		((String*)a)->len = 0;
-		return;
-	}
-	((String*)a)->str = ((String*)b)->str;
-	((String*)a)->len = ((String*)b)->len;
-}
-
-void
-runtime·interhash(uintptr *h, uintptr s, void *a)
-{
-	USED(s);
-	*h = runtime·ifacehash(*(Iface*)a, *h ^ M0) * M1;
-}
-
-void
-runtime·interprint(uintptr s, void *a)
-{
-	USED(s);
-	runtime·printiface(*(Iface*)a);
-}
-
-void
-runtime·interequal(bool *eq, uintptr s, void *a, void *b)
-{
-	USED(s);
-	*eq = runtime·ifaceeq_c(*(Iface*)a, *(Iface*)b);
-}
-
-void
-runtime·intercopy(uintptr s, void *a, void *b)
-{
-	USED(s);
-	if(b == nil) {
-		((Iface*)a)->tab = 0;
-		((Iface*)a)->data = 0;
-		return;
-	}
-	((Iface*)a)->tab = ((Iface*)b)->tab;
-	((Iface*)a)->data = ((Iface*)b)->data;
-}
-
-void
-runtime·nilinterhash(uintptr *h, uintptr s, void *a)
-{
-	USED(s);
-	*h = runtime·efacehash(*(Eface*)a, *h ^ M0) * M1;
-}
-
-void
-runtime·nilinterprint(uintptr s, void *a)
-{
-	USED(s);
-	runtime·printeface(*(Eface*)a);
-}
-
-void
-runtime·nilinterequal(bool *eq, uintptr s, void *a, void *b)
-{
-	USED(s);
-	*eq = runtime·efaceeq_c(*(Eface*)a, *(Eface*)b);
-}
-
-void
-runtime·nilintercopy(uintptr s, void *a, void *b)
-{
-	USED(s);
-	if(b == nil) {
-		((Eface*)a)->type = 0;
-		((Eface*)a)->data = 0;
-		return;
-	}
-	((Eface*)a)->type = ((Eface*)b)->type;
-	((Eface*)a)->data = ((Eface*)b)->data;
-}
-
-void
-runtime·nohash(uintptr *h, uintptr s, void *a)
-{
-	USED(s);
-	USED(a);
-	USED(h);
-	runtime·panicstring("hash of unhashable type");
-}
-
-void
-runtime·noequal(bool *eq, uintptr s, void *a, void *b)
-{
-	USED(s);
-	USED(a);
-	USED(b);
-	USED(eq);
-	runtime·panicstring("comparing uncomparable types");
-}
-
-Alg
-runtime·algarray[] =
-{
-[AMEM]		{ runtime·memhash, runtime·memequal, runtime·memprint, runtime·memcopy },
-[ANOEQ]		{ runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy },
-[ASTRING]	{ runtime·strhash, runtime·strequal, runtime·strprint, runtime·strcopy },
-[AINTER]	{ runtime·interhash, runtime·interequal, runtime·interprint, runtime·intercopy },
-[ANILINTER]	{ runtime·nilinterhash, runtime·nilinterequal, runtime·nilinterprint, runtime·nilintercopy },
-[ASLICE]	{ runtime·nohash, runtime·noequal, runtime·memprint, runtime·slicecopy },
-[AFLOAT32]	{ runtime·f32hash, runtime·f32equal, runtime·memprint, runtime·memcopy },
-[AFLOAT64]	{ runtime·f64hash, runtime·f64equal, runtime·memprint, runtime·memcopy },
-[ACPLX64]	{ runtime·c64hash, runtime·c64equal, runtime·memprint, runtime·memcopy },
-[ACPLX128]	{ runtime·c128hash, runtime·c128equal, runtime·memprint, runtime·memcopy },
-[AMEM0]		{ runtime·memhash, runtime·memequal0, runtime·memprint, runtime·memcopy0 },
-[AMEM8]		{ runtime·memhash, runtime·memequal8, runtime·memprint, runtime·memcopy8 },
-[AMEM16]	{ runtime·memhash, runtime·memequal16, runtime·memprint, runtime·memcopy16 },
-[AMEM32]	{ runtime·memhash, runtime·memequal32, runtime·memprint, runtime·memcopy32 },
-[AMEM64]	{ runtime·memhash, runtime·memequal64, runtime·memprint, runtime·memcopy64 },
-[AMEM128]	{ runtime·memhash, runtime·memequal128, runtime·memprint, runtime·memcopy128 },
-[ANOEQ0]	{ runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy0 },
-[ANOEQ8]	{ runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy8 },
-[ANOEQ16]	{ runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy16 },
-[ANOEQ32]	{ runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy32 },
-[ANOEQ64]	{ runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy64 },
-[ANOEQ128]	{ runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy128 },
-};
-
-// Runtime helpers.
-
-// used in asm_{386,amd64}.s
-byte runtime·aeskeysched[HashRandomBytes];
-
-void
-runtime·hashinit(void)
-{
-	// Install aes hash algorithm if we have the instructions we need
-	if((runtime·cpuid_ecx & (1 << 25)) != 0 &&  // aes (aesenc)
-	   (runtime·cpuid_ecx & (1 << 9)) != 0 &&   // sse3 (pshufb)
-	   (runtime·cpuid_ecx & (1 << 19)) != 0) {  // sse4.1 (pinsr{d,q})
-		byte *rnd;
-		int32 n;
-		use_aeshash = true;
-		runtime·algarray[AMEM].hash = runtime·aeshash;
-		runtime·algarray[AMEM8].hash = runtime·aeshash;
-		runtime·algarray[AMEM16].hash = runtime·aeshash;
-		runtime·algarray[AMEM32].hash = runtime·aeshash32;
-		runtime·algarray[AMEM64].hash = runtime·aeshash64;
-		runtime·algarray[AMEM128].hash = runtime·aeshash;
-		runtime·algarray[ASTRING].hash = runtime·aeshashstr;
-
-		// Initialize with random data so hash collisions will be hard to engineer.
-		runtime·get_random_data(&rnd, &n);
-		if(n > HashRandomBytes)
-			n = HashRandomBytes;
-		runtime·memmove(runtime·aeskeysched, rnd, n);
-		if(n < HashRandomBytes) {
-			// Not very random, but better than nothing.
-			int64 t = runtime·nanotime();
-			while (n < HashRandomBytes) {
-				runtime·aeskeysched[n++] = (int8)(t >> (8 * (n % 8)));
-			}
-		}
-	}
-}
-
-// func equal(t *Type, x T, y T) (ret bool)
-#pragma textflag NOSPLIT
-void
-runtime·equal(Type *t, ...)
-{
-	byte *x, *y;
-	uintptr ret;
-	
-	x = (byte*)(&t+1);
-	y = x + t->size;
-	ret = (uintptr)(y + t->size);
-	ret = ROUND(ret, Structrnd);
-	t->alg->equal((bool*)ret, t->size, x, y);
-}
-
-// Testing adapters for hash quality tests (see hash_test.go)
-void runtime·haveGoodHash(bool res) {
-	res = use_aeshash;
-	FLUSH(&res);
-}
-void runtime·stringHash(String s, uintptr seed, uintptr res) {
-	runtime·algarray[ASTRING].hash(&seed, sizeof(String), &s);
-	res = seed;
-	FLUSH(&res);
-}
-void runtime·bytesHash(Slice s, uintptr seed, uintptr res) {
-	runtime·algarray[AMEM].hash(&seed, s.len, s.array);
-	res = seed;
-	FLUSH(&res);
-}
-void runtime·int32Hash(uint32 i, uintptr seed, uintptr res) {
-	runtime·algarray[AMEM32].hash(&seed, sizeof(uint32), &i);
-	res = seed;
-	FLUSH(&res);
-}
-void runtime·int64Hash(uint64 i, uintptr seed, uintptr res) {
-	runtime·algarray[AMEM64].hash(&seed, sizeof(uint64), &i);
-	res = seed;
-	FLUSH(&res);
-}
diff --git a/src/pkg/runtime/alg.goc b/src/pkg/runtime/alg.goc
new file mode 100644
index 0000000..f1b8d59
--- /dev/null
+++ b/src/pkg/runtime/alg.goc
@@ -0,0 +1,549 @@
+// 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.
+
+package runtime
+#include "runtime.h"
+#include "type.h"
+#include "../../cmd/ld/textflag.h"
+
+#define M0 (sizeof(uintptr)==4 ? 2860486313UL : 33054211828000289ULL)
+#define M1 (sizeof(uintptr)==4 ? 3267000013UL : 23344194077549503ULL)
+
+static bool use_aeshash;
+
+/*
+ * map and chan helpers for
+ * dealing with unknown types
+ */
+void
+runtime·memhash(uintptr *h, uintptr s, void *a)
+{
+	byte *b;
+	uintptr hash;
+	if(!NaCl && use_aeshash) {
+		runtime·aeshash(h, s, a);
+		return;
+	}
+
+	b = a;
+	hash = M0 ^ *h;
+	while(s > 0) {
+		hash = (hash ^ *b) * M1;
+		b++;
+		s--;
+	}
+	*h = hash;
+}
+
+void
+runtime·memequal(bool *eq, uintptr s, void *a, void *b)
+{
+	if(a == b) {
+		*eq = 1;
+		return;
+	}
+	*eq = runtime·memeq(a, b, s);
+}
+
+void
+runtime·memprint(uintptr s, void *a)
+{
+	uint64 v;
+
+	v = 0xbadb00b;
+	switch(s) {
+	case 1:
+		v = *(uint8*)a;
+		break;
+	case 2:
+		v = *(uint16*)a;
+		break;
+	case 4:
+		v = *(uint32*)a;
+		break;
+	case 8:
+		v = *(uint64*)a;
+		break;
+	}
+	runtime·printint(v);
+}
+
+void
+runtime·memcopy(uintptr s, void *a, void *b)
+{
+	if(b == nil) {
+		runtime·memclr(a, s);
+		return;
+	}
+	runtime·memmove(a, b, s);
+}
+
+void
+runtime·memequal0(bool *eq, uintptr s, void *a, void *b)
+{
+	USED(s);
+	USED(a);
+	USED(b);
+	*eq = true;
+}
+
+void
+runtime·memcopy0(uintptr s, void *a, void *b)
+{
+	USED(s);
+	USED(a);
+	USED(b);
+}
+
+void
+runtime·memequal8(bool *eq, uintptr s, void *a, void *b)
+{
+	USED(s);
+	*eq = *(uint8*)a == *(uint8*)b;
+}
+
+void
+runtime·memcopy8(uintptr s, void *a, void *b)
+{
+	USED(s);
+	if(b == nil) {
+		*(uint8*)a = 0;
+		return;
+	}
+	*(uint8*)a = *(uint8*)b;
+}
+
+void
+runtime·memequal16(bool *eq, uintptr s, void *a, void *b)
+{
+	USED(s);
+	*eq = *(uint16*)a == *(uint16*)b;
+}
+
+void
+runtime·memcopy16(uintptr s, void *a, void *b)
+{
+	USED(s);
+	if(b == nil) {
+		*(uint16*)a = 0;
+		return;
+	}
+	*(uint16*)a = *(uint16*)b;
+}
+
+void
+runtime·memequal32(bool *eq, uintptr s, void *a, void *b)
+{
+	USED(s);
+	*eq = *(uint32*)a == *(uint32*)b;
+}
+
+void
+runtime·memcopy32(uintptr s, void *a, void *b)
+{
+	USED(s);
+	if(b == nil) {
+		*(uint32*)a = 0;
+		return;
+	}
+	*(uint32*)a = *(uint32*)b;
+}
+
+void
+runtime·memequal64(bool *eq, uintptr s, void *a, void *b)
+{
+	USED(s);
+	*eq = *(uint64*)a == *(uint64*)b;
+}
+
+void
+runtime·memcopy64(uintptr s, void *a, void *b)
+{
+	USED(s);
+	if(b == nil) {
+		*(uint64*)a = 0;
+		return;
+	}
+	*(uint64*)a = *(uint64*)b;
+}
+
+void
+runtime·memequal128(bool *eq, uintptr s, void *a, void *b)
+{
+	USED(s);
+	*eq = ((uint64*)a)[0] == ((uint64*)b)[0] && ((uint64*)a)[1] == ((uint64*)b)[1];
+}
+
+void
+runtime·memcopy128(uintptr s, void *a, void *b)
+{
+	USED(s);
+	if(b == nil) {
+		((uint64*)a)[0] = 0;
+		((uint64*)a)[1] = 0;
+		return;
+	}
+	((uint64*)a)[0] = ((uint64*)b)[0];
+	((uint64*)a)[1] = ((uint64*)b)[1];
+}
+
+void
+runtime·f32equal(bool *eq, uintptr s, void *a, void *b)
+{
+	USED(s);
+	*eq = *(float32*)a == *(float32*)b;
+}
+
+void
+runtime·f64equal(bool *eq, uintptr s, void *a, void *b)
+{
+	USED(s);
+	*eq = *(float64*)a == *(float64*)b;
+}
+
+void
+runtime·c64equal(bool *eq, uintptr s, void *a, void *b)
+{	
+	Complex64 *ca, *cb;
+	
+	USED(s);
+	ca = a;
+	cb = b;
+	*eq = ca->real == cb->real && ca->imag == cb->imag;
+}
+
+void
+runtime·c128equal(bool *eq, uintptr s, void *a, void *b)
+{	
+	Complex128 *ca, *cb;
+	
+	USED(s);
+	ca = a;
+	cb = b;
+	*eq = ca->real == cb->real && ca->imag == cb->imag;
+}
+
+// NOTE: Because NaN != NaN, a map can contain any
+// number of (mostly useless) entries keyed with NaNs.
+// To avoid long hash chains, we assign a random number
+// as the hash value for a NaN.
+
+void
+runtime·f32hash(uintptr *h, uintptr s, void *a)
+{
+	uintptr hash;
+	float32 f;
+
+	USED(s);
+	f = *(float32*)a;
+	if(f == 0)
+		hash = 0;  // +0, -0
+	else if(f != f)
+		hash = runtime·fastrand1();  // any kind of NaN
+	else
+		hash = *(uint32*)a;
+	*h = (*h ^ hash ^ M0) * M1;
+}
+
+void
+runtime·f64hash(uintptr *h, uintptr s, void *a)
+{
+	uintptr hash;
+	float64 f;
+	uint64 u;
+
+	USED(s);
+	f = *(float64*)a;
+	if(f == 0)
+		hash = 0;	// +0, -0
+	else if(f != f)
+		hash = runtime·fastrand1();  // any kind of NaN
+	else {
+		u = *(uint64*)a;
+		if(sizeof(uintptr) == 4)
+			hash = ((uint32)(u>>32) * M1) ^ (uint32)u;
+		else
+			hash = u;
+	}
+	*h = (*h ^ hash ^ M0) * M1;
+}
+
+void
+runtime·c64hash(uintptr *h, uintptr s, void *a)
+{
+	USED(s);
+	runtime·f32hash(h, 0, a);
+	runtime·f32hash(h, 0, (float32*)a+1);
+}
+
+void
+runtime·c128hash(uintptr *h, uintptr s, void *a)
+{
+	USED(s);
+	runtime·f64hash(h, 0, a);
+	runtime·f64hash(h, 0, (float64*)a+1);
+}
+
+void
+runtime·slicecopy(uintptr s, void *a, void *b)
+{
+	USED(s);
+	if(b == nil) {
+		((Slice*)a)->array = 0;
+		((Slice*)a)->len = 0;
+		((Slice*)a)->cap = 0;
+		return;
+	}
+	((Slice*)a)->array = ((Slice*)b)->array;
+	((Slice*)a)->len = ((Slice*)b)->len;
+	((Slice*)a)->cap = ((Slice*)b)->cap;
+}
+
+void
+runtime·strhash(uintptr *h, uintptr s, void *a)
+{
+	USED(s);
+	runtime·memhash(h, ((String*)a)->len, ((String*)a)->str);
+}
+
+void
+runtime·strequal(bool *eq, uintptr s, void *a, void *b)
+{
+	intgo alen;
+	byte *s1, *s2;
+
+	USED(s);
+	alen = ((String*)a)->len;
+	if(alen != ((String*)b)->len) {
+		*eq = false;
+		return;
+	}
+	s1 = ((String*)a)->str;
+	s2 = ((String*)b)->str;
+	if(s1 == s2) {
+		*eq = true;
+		return;
+	}
+	*eq = runtime·memeq(s1, s2, alen);
+}
+
+void
+runtime·strprint(uintptr s, void *a)
+{
+	USED(s);
+	runtime·printstring(*(String*)a);
+}
+
+void
+runtime·strcopy(uintptr s, void *a, void *b)
+{
+	USED(s);
+	if(b == nil) {
+		((String*)a)->str = 0;
+		((String*)a)->len = 0;
+		return;
+	}
+	((String*)a)->str = ((String*)b)->str;
+	((String*)a)->len = ((String*)b)->len;
+}
+
+void
+runtime·interhash(uintptr *h, uintptr s, void *a)
+{
+	USED(s);
+	*h = runtime·ifacehash(*(Iface*)a, *h ^ M0) * M1;
+}
+
+void
+runtime·interprint(uintptr s, void *a)
+{
+	USED(s);
+	runtime·printiface(*(Iface*)a);
+}
+
+void
+runtime·interequal(bool *eq, uintptr s, void *a, void *b)
+{
+	USED(s);
+	*eq = runtime·ifaceeq_c(*(Iface*)a, *(Iface*)b);
+}
+
+void
+runtime·intercopy(uintptr s, void *a, void *b)
+{
+	USED(s);
+	if(b == nil) {
+		((Iface*)a)->tab = 0;
+		((Iface*)a)->data = 0;
+		return;
+	}
+	((Iface*)a)->tab = ((Iface*)b)->tab;
+	((Iface*)a)->data = ((Iface*)b)->data;
+}
+
+void
+runtime·nilinterhash(uintptr *h, uintptr s, void *a)
+{
+	USED(s);
+	*h = runtime·efacehash(*(Eface*)a, *h ^ M0) * M1;
+}
+
+void
+runtime·nilinterprint(uintptr s, void *a)
+{
+	USED(s);
+	runtime·printeface(*(Eface*)a);
+}
+
+void
+runtime·nilinterequal(bool *eq, uintptr s, void *a, void *b)
+{
+	USED(s);
+	*eq = runtime·efaceeq_c(*(Eface*)a, *(Eface*)b);
+}
+
+void
+runtime·nilintercopy(uintptr s, void *a, void *b)
+{
+	USED(s);
+	if(b == nil) {
+		((Eface*)a)->type = 0;
+		((Eface*)a)->data = 0;
+		return;
+	}
+	((Eface*)a)->type = ((Eface*)b)->type;
+	((Eface*)a)->data = ((Eface*)b)->data;
+}
+
+void
+runtime·nohash(uintptr *h, uintptr s, void *a)
+{
+	USED(s);
+	USED(a);
+	USED(h);
+	runtime·panicstring("hash of unhashable type");
+}
+
+void
+runtime·noequal(bool *eq, uintptr s, void *a, void *b)
+{
+	USED(s);
+	USED(a);
+	USED(b);
+	USED(eq);
+	runtime·panicstring("comparing uncomparable types");
+}
+
+Alg
+runtime·algarray[] =
+{
+[AMEM]		{ runtime·memhash, runtime·memequal, runtime·memprint, runtime·memcopy },
+[ANOEQ]		{ runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy },
+[ASTRING]	{ runtime·strhash, runtime·strequal, runtime·strprint, runtime·strcopy },
+[AINTER]	{ runtime·interhash, runtime·interequal, runtime·interprint, runtime·intercopy },
+[ANILINTER]	{ runtime·nilinterhash, runtime·nilinterequal, runtime·nilinterprint, runtime·nilintercopy },
+[ASLICE]	{ runtime·nohash, runtime·noequal, runtime·memprint, runtime·slicecopy },
+[AFLOAT32]	{ runtime·f32hash, runtime·f32equal, runtime·memprint, runtime·memcopy },
+[AFLOAT64]	{ runtime·f64hash, runtime·f64equal, runtime·memprint, runtime·memcopy },
+[ACPLX64]	{ runtime·c64hash, runtime·c64equal, runtime·memprint, runtime·memcopy },
+[ACPLX128]	{ runtime·c128hash, runtime·c128equal, runtime·memprint, runtime·memcopy },
+[AMEM0]		{ runtime·memhash, runtime·memequal0, runtime·memprint, runtime·memcopy0 },
+[AMEM8]		{ runtime·memhash, runtime·memequal8, runtime·memprint, runtime·memcopy8 },
+[AMEM16]	{ runtime·memhash, runtime·memequal16, runtime·memprint, runtime·memcopy16 },
+[AMEM32]	{ runtime·memhash, runtime·memequal32, runtime·memprint, runtime·memcopy32 },
+[AMEM64]	{ runtime·memhash, runtime·memequal64, runtime·memprint, runtime·memcopy64 },
+[AMEM128]	{ runtime·memhash, runtime·memequal128, runtime·memprint, runtime·memcopy128 },
+[ANOEQ0]	{ runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy0 },
+[ANOEQ8]	{ runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy8 },
+[ANOEQ16]	{ runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy16 },
+[ANOEQ32]	{ runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy32 },
+[ANOEQ64]	{ runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy64 },
+[ANOEQ128]	{ runtime·nohash, runtime·noequal, runtime·memprint, runtime·memcopy128 },
+};
+
+// Runtime helpers.
+
+// used in asm_{386,amd64}.s
+#pragma dataflag NOPTR
+byte runtime·aeskeysched[HashRandomBytes];
+
+void
+runtime·hashinit(void)
+{
+        if(NaCl)
+                return;
+
+	// Install aes hash algorithm if we have the instructions we need
+	if((runtime·cpuid_ecx & (1 << 25)) != 0 &&  // aes (aesenc)
+	   (runtime·cpuid_ecx & (1 << 9)) != 0 &&   // sse3 (pshufb)
+	   (runtime·cpuid_ecx & (1 << 19)) != 0) {  // sse4.1 (pinsr{d,q})
+		byte *rnd;
+		int32 n;
+		use_aeshash = true;
+		runtime·algarray[AMEM].hash = runtime·aeshash;
+		runtime·algarray[AMEM8].hash = runtime·aeshash;
+		runtime·algarray[AMEM16].hash = runtime·aeshash;
+		runtime·algarray[AMEM32].hash = runtime·aeshash32;
+		runtime·algarray[AMEM64].hash = runtime·aeshash64;
+		runtime·algarray[AMEM128].hash = runtime·aeshash;
+		runtime·algarray[ASTRING].hash = runtime·aeshashstr;
+
+		// Initialize with random data so hash collisions will be hard to engineer.
+		runtime·get_random_data(&rnd, &n);
+		if(n > HashRandomBytes)
+			n = HashRandomBytes;
+		runtime·memmove(runtime·aeskeysched, rnd, n);
+		if(n < HashRandomBytes) {
+			// Not very random, but better than nothing.
+			int64 t = runtime·nanotime();
+			while (n < HashRandomBytes) {
+				runtime·aeskeysched[n++] = (int8)(t >> (8 * (n % 8)));
+			}
+		}
+	}
+}
+
+// func equal(t *Type, x T, y T) (ret bool)
+#pragma textflag NOSPLIT
+void
+runtime·equal(Type *t, ...)
+{
+	byte *x, *y;
+	bool *ret;
+	
+	x = (byte*)ROUND((uintptr)(&t+1), t->align);
+	y = x + t->size;
+	ret = (bool*)ROUND((uintptr)(y+t->size), Structrnd);
+	t->alg->equal(ret, t->size, x, y);
+}
+
+// Testing adapter for memclr
+func memclrBytes(s Slice) {
+	runtime·memclr(s.array, s.len);
+}
+
+// Testing adapters for hash quality tests (see hash_test.go)
+func haveGoodHash() (res bool) {
+	res = use_aeshash;
+}
+
+func stringHash(s String, seed uintptr) (res uintptr) {
+	runtime·algarray[ASTRING].hash(&seed, sizeof(String), &s);
+	res = seed;
+}
+
+func bytesHash(s Slice, seed uintptr) (res uintptr) {
+	runtime·algarray[AMEM].hash(&seed, s.len, s.array);
+	res = seed;
+}
+
+func int32Hash(i uint32, seed uintptr) (res uintptr) {
+	runtime·algarray[AMEM32].hash(&seed, sizeof(uint32), &i);
+	res = seed;
+}
+
+func int64Hash(i uint64, seed uintptr) (res uintptr) {
+	runtime·algarray[AMEM64].hash(&seed, sizeof(uint64), &i);
+	res = seed;
+}
diff --git a/src/pkg/runtime/append_test.go b/src/pkg/runtime/append_test.go
index 937c825..a67dc9b 100644
--- a/src/pkg/runtime/append_test.go
+++ b/src/pkg/runtime/append_test.go
@@ -19,6 +19,25 @@ func BenchmarkAppend(b *testing.B) {
 	}
 }
 
+func BenchmarkAppendGrowByte(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		var x []byte
+		for j := 0; j < 1<<20; j++ {
+			x = append(x, byte(j))
+		}
+	}
+}
+
+func BenchmarkAppendGrowString(b *testing.B) {
+	var s string
+	for i := 0; i < b.N; i++ {
+		var x []string
+		for j := 0; j < 1<<20; j++ {
+			x = append(x, s)
+		}
+	}
+}
+
 func benchmarkAppendBytes(b *testing.B, length int) {
 	b.StopTimer()
 	x := make([]byte, 0, N)
diff --git a/src/pkg/runtime/arch_386.h b/src/pkg/runtime/arch_386.h
index ebdb3ff..5c0a54f 100644
--- a/src/pkg/runtime/arch_386.h
+++ b/src/pkg/runtime/arch_386.h
@@ -7,5 +7,10 @@ enum {
 	BigEndian = 0,
 	CacheLineSize = 64,
 	RuntimeGogoBytes = 64,
+#ifdef GOOS_nacl
+	PhysPageSize = 65536,
+#else
+	PhysPageSize = 4096,
+#endif
 	PCQuantum = 1
 };
diff --git a/src/pkg/runtime/arch_amd64.h b/src/pkg/runtime/arch_amd64.h
index 2bddf07..c8a2184 100644
--- a/src/pkg/runtime/arch_amd64.h
+++ b/src/pkg/runtime/arch_amd64.h
@@ -6,6 +6,15 @@ enum {
 	thechar = '6',
 	BigEndian = 0,
 	CacheLineSize = 64,
+#ifdef GOOS_solaris
+	RuntimeGogoBytes = 80,
+#else
+#ifdef GOOS_windows
+	RuntimeGogoBytes = 80,
+#else
 	RuntimeGogoBytes = 64,
+#endif	// Windows
+#endif	// Solaris
+	PhysPageSize = 4096,
 	PCQuantum = 1
 };
diff --git a/src/pkg/runtime/arch_amd64p32.h b/src/pkg/runtime/arch_amd64p32.h
new file mode 100644
index 0000000..073a9e3
--- /dev/null
+++ b/src/pkg/runtime/arch_amd64p32.h
@@ -0,0 +1,16 @@
+// 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.
+
+enum {
+	thechar = '6',
+	BigEndian = 0,
+	CacheLineSize = 64,
+	RuntimeGogoBytes = 64,
+#ifdef GOOS_nacl
+	PhysPageSize = 65536,
+#else
+	PhysPageSize = 4096,
+#endif
+	PCQuantum = 1
+};
diff --git a/src/pkg/runtime/arch_arm.h b/src/pkg/runtime/arch_arm.h
index e5da01c..b971128 100644
--- a/src/pkg/runtime/arch_arm.h
+++ b/src/pkg/runtime/arch_arm.h
@@ -7,5 +7,6 @@ enum {
 	BigEndian = 0,
 	CacheLineSize = 32,
 	RuntimeGogoBytes = 80,
+	PhysPageSize = 4096,
 	PCQuantum = 4
 };
diff --git a/src/pkg/runtime/asm_386.s b/src/pkg/runtime/asm_386.s
index 5c642c0..9531208 100644
--- a/src/pkg/runtime/asm_386.s
+++ b/src/pkg/runtime/asm_386.s
@@ -247,6 +247,10 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0
 	MOVL	$0, 0x1003	// crash if newstack returns
 	RET
 
+TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0-0
+	MOVL	$0, DX
+	JMP runtime·morestack(SB)
+
 // Called from panic.  Mimics morestack,
 // reuses stack growth code to create a frame
 // with the desired args running the desired function.
@@ -307,7 +311,7 @@ TEXT runtime·newstackcall(SB), NOSPLIT, $0-12
 	JMP	AX
 // Note: can't just "JMP runtime·NAME(SB)" - bad inlining results.
 
-TEXT reflect·call(SB), NOSPLIT, $0-12
+TEXT reflect·call(SB), NOSPLIT, $0-16
 	MOVL	argsize+8(FP), CX
 	DISPATCH(call16, 16)
 	DISPATCH(call32, 32)
@@ -339,8 +343,22 @@ TEXT reflect·call(SB), NOSPLIT, $0-12
 	MOVL	$runtime·badreflectcall(SB), AX
 	JMP	AX
 
+// Argument map for the callXX frames.  Each has one
+// stack map (for the single call) with 3 arguments.
+DATA gcargs_reflectcall<>+0x00(SB)/4, $1  // 1 stackmap
+DATA gcargs_reflectcall<>+0x04(SB)/4, $6  // 3 args
+DATA gcargs_reflectcall<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4))
+GLOBL gcargs_reflectcall<>(SB),RODATA,$12
+
+// callXX frames have no locals
+DATA gclocals_reflectcall<>+0x00(SB)/4, $1  // 1 stackmap
+DATA gclocals_reflectcall<>+0x04(SB)/4, $0  // 0 locals
+GLOBL gclocals_reflectcall<>(SB),RODATA,$8
+
 #define CALLFN(NAME,MAXSIZE)			\
-TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-12;		\
+TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-16;	\
+	FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB);	\
+	FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\
 	/* copy arguments to stack */		\
 	MOVL	argptr+4(FP), SI;		\
 	MOVL	argsize+8(FP), CX;		\
@@ -348,11 +366,17 @@ TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-12;		\
 	REP;MOVSB;				\
 	/* call function */			\
 	MOVL	f+0(FP), DX;			\
-	CALL	(DX);				\
+	MOVL	(DX), AX; 			\
+	PCDATA  $PCDATA_StackMapIndex, $0;	\
+	CALL	AX;				\
 	/* copy return values back */		\
 	MOVL	argptr+4(FP), DI;		\
 	MOVL	argsize+8(FP), CX;		\
+	MOVL	retoffset+12(FP), BX;		\
 	MOVL	SP, SI;				\
+	ADDL	BX, DI;				\
+	ADDL	BX, SI;				\
+	SUBL	BX, CX;				\
 	REP;MOVSB;				\
 	RET
 
@@ -483,6 +507,12 @@ TEXT runtime·xchg(SB), NOSPLIT, $0-8
 	XCHGL	AX, 0(BX)
 	RET
 
+TEXT runtime·xchgp(SB), NOSPLIT, $0-8
+	MOVL	4(SP), BX
+	MOVL	8(SP), AX
+	XCHGL	AX, 0(BX)
+	RET
+
 TEXT runtime·procyield(SB),NOSPLIT,$0-0
 	MOVL	4(SP), AX
 again:
@@ -646,7 +676,6 @@ havem:
 	// Save current sp in m->g0->sched.sp in preparation for
 	// switch back to m->curg stack.
 	// NOTE: unwindm knows that the saved g->sched.sp is at 0(SP).
-	// On Windows, the SEH is at 4(SP) and 8(SP).
 	MOVL	m_g0(BP), SI
 	MOVL	(g_sched+gobuf_sp)(SI), AX
 	MOVL	AX, 0(SP)
@@ -747,21 +776,6 @@ TEXT runtime·stackcheck(SB), NOSPLIT, $0-0
 	INT	$3
 	RET
 
-TEXT runtime·memclr(SB),NOSPLIT,$0-8
-	MOVL	4(SP), DI		// arg 1 addr
-	MOVL	8(SP), CX		// arg 2 count
-	MOVL	CX, BX
-	ANDL	$3, BX
-	SHRL	$2, CX
-	MOVL	$0, AX
-	CLD
-	REP
-	STOSL
-	MOVL	BX, CX
-	REP
-	STOSB
-	RET
-
 TEXT runtime·getcallerpc(SB),NOSPLIT,$0-4
 	MOVL	x+0(FP),AX		// addr of first arg
 	MOVL	-4(AX),AX		// get calling pc
@@ -1353,3 +1367,800 @@ cmp_allsame:
 	SETEQ	CX	// 1 if alen == blen
 	LEAL	-1(CX)(AX*2), AX	// 1,0,-1 result
 	RET
+
+// A Duff's device for zeroing memory.
+// The compiler jumps to computed addresses within
+// this routine to zero chunks of memory.  Do not
+// change this code without also changing the code
+// in ../../cmd/8g/ggen.c:clearfat.
+// AX: zero
+// DI: ptr to memory to be zeroed
+// DI is updated as a side effect.
+TEXT runtime·duffzero(SB), NOSPLIT, $0-0
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	RET
+
+// A Duff's device for copying memory.
+// The compiler jumps to computed addresses within
+// this routine to copy chunks of memory.  Source
+// and destination must not overlap.  Do not
+// change this code without also changing the code
+// in ../../cmd/6g/cgen.c:sgen.
+// SI: ptr to source memory
+// DI: ptr to destination memory
+// SI and DI are updated as a side effect.
+
+// NOTE: this is equivalent to a sequence of MOVSL but
+// for some reason MOVSL is really slow.
+TEXT runtime·duffcopy(SB), NOSPLIT, $0-0
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	MOVL	(SI),CX
+	ADDL	$4,SI
+	MOVL	CX,(DI)
+	ADDL	$4,DI
+	
+	RET
+
+TEXT runtime·timenow(SB), NOSPLIT, $0-0
+	JMP	time·now(SB)
diff --git a/src/pkg/runtime/asm_amd64.s b/src/pkg/runtime/asm_amd64.s
index 2c2ffed..3c7eaf3 100644
--- a/src/pkg/runtime/asm_amd64.s
+++ b/src/pkg/runtime/asm_amd64.s
@@ -53,6 +53,9 @@ needtls:
 	// skip TLS setup on Plan 9
 	CMPL	runtime·isplan9(SB), $1
 	JEQ ok
+	// skip TLS setup on Solaris
+	CMPL	runtime·issolaris(SB), $1
+	JEQ ok
 
 	LEAQ	runtime·tls0(SB), DI
 	CALL	runtime·settls(SB)
@@ -286,7 +289,7 @@ TEXT runtime·newstackcall(SB), NOSPLIT, $0-20
 	JMP	AX
 // Note: can't just "JMP runtime·NAME(SB)" - bad inlining results.
 
-TEXT reflect·call(SB), NOSPLIT, $0-20
+TEXT reflect·call(SB), NOSPLIT, $0-24
 	MOVLQZX argsize+16(FP), CX
 	DISPATCH(call16, 16)
 	DISPATCH(call32, 32)
@@ -318,8 +321,22 @@ TEXT reflect·call(SB), NOSPLIT, $0-20
 	MOVQ	$runtime·badreflectcall(SB), AX
 	JMP	AX
 
+// Argument map for the callXX frames.  Each has one
+// stack map (for the single call) with 3 arguments.
+DATA gcargs_reflectcall<>+0x00(SB)/4, $1  // 1 stackmap
+DATA gcargs_reflectcall<>+0x04(SB)/4, $6  // 3 args
+DATA gcargs_reflectcall<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4))
+GLOBL gcargs_reflectcall<>(SB),RODATA,$12
+
+// callXX frames have no locals
+DATA gclocals_reflectcall<>+0x00(SB)/4, $1  // 1 stackmap
+DATA gclocals_reflectcall<>+0x04(SB)/4, $0  // 0 locals
+GLOBL gclocals_reflectcall<>(SB),RODATA,$8
+
 #define CALLFN(NAME,MAXSIZE)			\
-TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-20;		\
+TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-24;	\
+	FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB);	\
+	FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\
 	/* copy arguments to stack */		\
 	MOVQ	argptr+8(FP), SI;		\
 	MOVLQZX argsize+16(FP), CX;		\
@@ -327,11 +344,16 @@ TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-20;		\
 	REP;MOVSB;				\
 	/* call function */			\
 	MOVQ	f+0(FP), DX;			\
+	PCDATA  $PCDATA_StackMapIndex, $0;	\
 	CALL	(DX);				\
 	/* copy return values back */		\
 	MOVQ	argptr+8(FP), DI;		\
 	MOVLQZX	argsize+16(FP), CX;		\
+	MOVLQZX retoffset+20(FP), BX;		\
 	MOVQ	SP, SI;				\
+	ADDQ	BX, DI;				\
+	ADDQ	BX, SI;				\
+	SUBQ	BX, CX;				\
 	REP;MOVSB;				\
 	RET
 
@@ -453,6 +475,46 @@ TEXT morestack<>(SB),NOSPLIT,$0
 	MOVQ	$runtime·morestack(SB), AX
 	JMP	AX
 
+TEXT runtime·morestack00_noctxt(SB),NOSPLIT,$0
+	MOVL	$0, DX
+	JMP	runtime·morestack00(SB)
+
+TEXT runtime·morestack01_noctxt(SB),NOSPLIT,$0
+	MOVL	$0, DX
+	JMP	runtime·morestack01(SB)
+
+TEXT runtime·morestack10_noctxt(SB),NOSPLIT,$0
+	MOVL	$0, DX
+	JMP	runtime·morestack10(SB)
+
+TEXT runtime·morestack11_noctxt(SB),NOSPLIT,$0
+	MOVL	$0, DX
+	JMP	runtime·morestack11(SB)
+
+TEXT runtime·morestack8_noctxt(SB),NOSPLIT,$0
+	MOVL	$0, DX
+	JMP	runtime·morestack8(SB)
+
+TEXT runtime·morestack16_noctxt(SB),NOSPLIT,$0
+	MOVL	$0, DX
+	JMP	runtime·morestack16(SB)
+
+TEXT runtime·morestack24_noctxt(SB),NOSPLIT,$0
+	MOVL	$0, DX
+	JMP	runtime·morestack24(SB)
+
+TEXT runtime·morestack32_noctxt(SB),NOSPLIT,$0
+	MOVL	$0, DX
+	JMP	runtime·morestack32(SB)
+
+TEXT runtime·morestack40_noctxt(SB),NOSPLIT,$0
+	MOVL	$0, DX
+	JMP	runtime·morestack40(SB)
+
+TEXT runtime·morestack48_noctxt(SB),NOSPLIT,$0
+	MOVL	$0, DX
+	JMP	runtime·morestack48(SB)
+
 // bool cas(int32 *val, int32 old, int32 new)
 // Atomically:
 //	if(*val == old){
@@ -546,6 +608,12 @@ TEXT runtime·xchg64(SB), NOSPLIT, $0-16
 	XCHGQ	AX, 0(BX)
 	RET
 
+TEXT runtime·xchgp(SB), NOSPLIT, $0-16
+	MOVQ	8(SP), BX
+	MOVQ	16(SP), AX
+	XCHGQ	AX, 0(BX)
+	RET
+
 TEXT runtime·procyield(SB),NOSPLIT,$0-0
 	MOVL	8(SP), AX
 again:
@@ -614,10 +682,16 @@ TEXT runtime·asmcgocall(SB),NOSPLIT,$0-16
 	MOVQ	m_g0(BP), SI
 	MOVQ	g(CX), DI
 	CMPQ	SI, DI
-	JEQ	4(PC)
+	JEQ	nosave
+	MOVQ	m_gsignal(BP), SI
+	CMPQ	SI, DI
+	JEQ	nosave
+	
+	MOVQ	m_g0(BP), SI
 	CALL	gosave<>(SB)
 	MOVQ	SI, g(CX)
 	MOVQ	(g_sched+gobuf_sp)(SI), SP
+nosave:
 
 	// Now on a scheduling stack (a pthread-created stack).
 	// Make sure we have enough room for 4 stack-backed fast-call
@@ -779,21 +853,6 @@ TEXT runtime·stackcheck(SB), NOSPLIT, $0-0
 	INT	$3
 	RET
 
-TEXT runtime·memclr(SB),NOSPLIT,$0-16
-	MOVQ	8(SP), DI		// arg 1 addr
-	MOVQ	16(SP), CX		// arg 2 count
-	MOVQ	CX, BX
-	ANDQ	$7, BX
-	SHRQ	$3, CX
-	MOVQ	$0, AX
-	CLD
-	REP
-	STOSQ
-	MOVQ	BX, CX
-	REP
-	STOSB
-	RET
-
 TEXT runtime·getcallerpc(SB),NOSPLIT,$0-8
 	MOVQ	x+0(FP),AX		// addr of first arg
 	MOVQ	-8(AX),AX		// get calling pc
@@ -1340,3 +1399,801 @@ TEXT bytes·Equal(SB),NOSPLIT,$0-49
 eqret:
 	MOVB	AX, ret+48(FP)
 	RET
+
+// A Duff's device for zeroing memory.
+// The compiler jumps to computed addresses within
+// this routine to zero chunks of memory.  Do not
+// change this code without also changing the code
+// in ../../cmd/6g/ggen.c:clearfat.
+// AX: zero
+// DI: ptr to memory to be zeroed
+// DI is updated as a side effect.
+TEXT runtime·duffzero(SB), NOSPLIT, $0-0
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	RET
+
+// A Duff's device for copying memory.
+// The compiler jumps to computed addresses within
+// this routine to copy chunks of memory.  Source
+// and destination must not overlap.  Do not
+// change this code without also changing the code
+// in ../../cmd/6g/cgen.c:sgen.
+// SI: ptr to source memory
+// DI: ptr to destination memory
+// SI and DI are updated as a side effect.
+
+// NOTE: this is equivalent to a sequence of MOVSQ but
+// for some reason that is 3.5x slower than this code.
+// The STOSQ above seem fine, though.
+TEXT runtime·duffcopy(SB), NOSPLIT, $0-0
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	MOVQ	(SI),CX
+	ADDQ	$8,SI
+	MOVQ	CX,(DI)
+	ADDQ	$8,DI
+
+	RET
+
+TEXT runtime·timenow(SB), NOSPLIT, $0-0
+	JMP	time·now(SB)
diff --git a/src/pkg/runtime/asm_amd64p32.s b/src/pkg/runtime/asm_amd64p32.s
new file mode 100644
index 0000000..d47f122
--- /dev/null
+++ b/src/pkg/runtime/asm_amd64p32.s
@@ -0,0 +1,1073 @@
+// 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 "zasm_GOOS_GOARCH.h"
+#include "funcdata.h"
+#include "../../cmd/ld/textflag.h"
+
+TEXT _rt0_go(SB),NOSPLIT,$0
+	// copy arguments forward on an even stack
+	MOVL	argc+0(FP), AX
+	MOVL	argv+4(FP), BX
+	MOVL	SP, CX
+	SUBL	$128, SP		// plenty of scratch
+	ANDL	$~15, CX
+	MOVL	CX, SP
+
+	MOVL	AX, 16(SP)
+	MOVL	BX, 24(SP)
+	
+	// create istack out of the given (operating system) stack.
+	MOVL	$runtime·g0(SB), DI
+	LEAL	(-64*1024+104)(SP), DI
+	MOVL	BX, g_stackguard(DI)
+	MOVL	BX, g_stackguard0(DI)
+	MOVL	SP, g_stackbase(DI)
+
+	// find out information about the processor we're on
+	MOVQ	$0, AX
+	CPUID
+	CMPQ	AX, $0
+	JE	nocpuinfo
+	MOVQ	$1, AX
+	CPUID
+	MOVL	CX, runtime·cpuid_ecx(SB)
+	MOVL	DX, runtime·cpuid_edx(SB)
+nocpuinfo:	
+	
+needtls:
+	LEAL	runtime·tls0(SB), DI
+	CALL	runtime·settls(SB)
+
+	// store through it, to make sure it works
+	get_tls(BX)
+	MOVQ	$0x123, g(BX)
+	MOVQ	runtime·tls0(SB), AX
+	CMPQ	AX, $0x123
+	JEQ 2(PC)
+	MOVL	AX, 0	// abort
+ok:
+	// set the per-goroutine and per-mach "registers"
+	get_tls(BX)
+	LEAL	runtime·g0(SB), CX
+	MOVL	CX, g(BX)
+	LEAL	runtime·m0(SB), AX
+	MOVL	AX, m(BX)
+
+	// save m->g0 = g0
+	MOVL	CX, m_g0(AX)
+
+	CLD				// convention is D is always left cleared
+	CALL	runtime·check(SB)
+
+	MOVL	16(SP), AX		// copy argc
+	MOVL	AX, 0(SP)
+	MOVL	24(SP), AX		// copy argv
+	MOVL	AX, 4(SP)
+	CALL	runtime·args(SB)
+	CALL	runtime·osinit(SB)
+	CALL	runtime·hashinit(SB)
+	CALL	runtime·schedinit(SB)
+
+	// create a new goroutine to start program
+	MOVL	$runtime·main·f(SB), AX	// entry
+	MOVL	$0, 0(SP)
+	MOVL	AX, 4(SP)
+	ARGSIZE(8)
+	CALL	runtime·newproc(SB)
+	ARGSIZE(-1)
+
+	// start this M
+	CALL	runtime·mstart(SB)
+
+	MOVL	$0xf1, 0xf1  // crash
+	RET
+
+DATA	runtime·main·f+0(SB)/4,$runtime·main(SB)
+GLOBL	runtime·main·f(SB),RODATA,$4
+
+TEXT runtime·breakpoint(SB),NOSPLIT,$0-0
+	INT $3
+	RET
+
+TEXT runtime·asminit(SB),NOSPLIT,$0-0
+	// No per-thread init.
+	RET
+
+/*
+ *  go-routine
+ */
+
+// void gosave(Gobuf*)
+// save state in Gobuf; setjmp
+TEXT runtime·gosave(SB), NOSPLIT, $0-4
+	MOVL	b+0(FP), AX	// gobuf
+	LEAL	b+0(FP), BX	// caller's SP
+	MOVL	BX, gobuf_sp(AX)
+	MOVL	0(SP), BX		// caller's PC
+	MOVL	BX, gobuf_pc(AX)
+	MOVL	$0, gobuf_ctxt(AX)
+	MOVQ	$0, gobuf_ret(AX)
+	get_tls(CX)
+	MOVL	g(CX), BX
+	MOVL	BX, gobuf_g(AX)
+	RET
+
+// void gogo(Gobuf*)
+// restore state from Gobuf; longjmp
+TEXT runtime·gogo(SB), NOSPLIT, $0-4
+	MOVL	b+0(FP), BX		// gobuf
+	MOVL	gobuf_g(BX), DX
+	MOVL	0(DX), CX		// make sure g != nil
+	get_tls(CX)
+	MOVL	DX, g(CX)
+	MOVL	gobuf_sp(BX), SP	// restore SP
+	MOVL	gobuf_ctxt(BX), DX
+	MOVQ	gobuf_ret(BX), AX
+	MOVL	$0, gobuf_sp(BX)	// clear to help garbage collector
+	MOVQ	$0, gobuf_ret(BX)
+	MOVL	$0, gobuf_ctxt(BX)
+	MOVL	gobuf_pc(BX), BX
+	JMP	BX
+
+// void mcall(void (*fn)(G*))
+// Switch to m->g0's stack, call fn(g).
+// Fn must never return.  It should gogo(&g->sched)
+// to keep running g.
+TEXT runtime·mcall(SB), NOSPLIT, $0-4
+	MOVL	fn+0(FP), DI
+	
+	get_tls(CX)
+	MOVL	g(CX), AX	// save state in g->sched
+	MOVL	0(SP), BX	// caller's PC
+	MOVL	BX, (g_sched+gobuf_pc)(AX)
+	LEAL	fn+0(FP), BX	// caller's SP
+	MOVL	BX, (g_sched+gobuf_sp)(AX)
+	MOVL	AX, (g_sched+gobuf_g)(AX)
+
+	// switch to m->g0 & its stack, call fn
+	MOVL	m(CX), BX
+	MOVL	m_g0(BX), SI
+	CMPL	SI, AX	// if g == m->g0 call badmcall
+	JNE	3(PC)
+	MOVL	$runtime·badmcall(SB), AX
+	JMP	AX
+	MOVL	SI, g(CX)	// g = m->g0
+	MOVL	(g_sched+gobuf_sp)(SI), SP	// sp = m->g0->sched.sp
+	PUSHQ	AX
+	ARGSIZE(8)
+	CALL	DI
+	POPQ	AX
+	MOVL	$runtime·badmcall2(SB), AX
+	JMP	AX
+	RET
+
+/*
+ * support for morestack
+ */
+
+// Called during function prolog when more stack is needed.
+// Caller has already done get_tls(CX); MOVQ m(CX), BX.
+//
+// The traceback routines see morestack on a g0 as being
+// the top of a stack (for example, morestack calling newstack
+// calling the scheduler calling newm calling gc), so we must
+// record an argument size. For that purpose, it has no arguments.
+TEXT runtime·morestack(SB),NOSPLIT,$0-0
+	// Cannot grow scheduler stack (m->g0).
+	MOVL	m_g0(BX), SI
+	CMPL	g(CX), SI
+	JNE	2(PC)
+	MOVL	0, AX
+
+	// Called from f.
+	// Set m->morebuf to f's caller.
+	MOVL	8(SP), AX	// f's caller's PC
+	MOVL	AX, (m_morebuf+gobuf_pc)(BX)
+	LEAL	16(SP), AX	// f's caller's SP
+	MOVL	AX, (m_morebuf+gobuf_sp)(BX)
+	MOVL	AX, m_moreargp(BX)
+	get_tls(CX)
+	MOVL	g(CX), SI
+	MOVL	SI, (m_morebuf+gobuf_g)(BX)
+
+	// Set g->sched to context in f.
+	MOVL	0(SP), AX // f's PC
+	MOVL	AX, (g_sched+gobuf_pc)(SI)
+	MOVL	SI, (g_sched+gobuf_g)(SI)
+	LEAL	8(SP), AX // f's SP
+	MOVL	AX, (g_sched+gobuf_sp)(SI)
+	MOVL	DX, (g_sched+gobuf_ctxt)(SI)
+
+	// Call newstack on m->g0's stack.
+	MOVL	m_g0(BX), BX
+	MOVL	BX, g(CX)
+	MOVL	(g_sched+gobuf_sp)(BX), SP
+	CALL	runtime·newstack(SB)
+	MOVL	$0, 0x1003	// crash if newstack returns
+	RET
+
+// Called from panic.  Mimics morestack,
+// reuses stack growth code to create a frame
+// with the desired args running the desired function.
+//
+// func call(fn *byte, arg *byte, argsize uint32).
+TEXT runtime·newstackcall(SB), NOSPLIT, $0-20
+	get_tls(CX)
+	MOVL	m(CX), BX
+
+	// Save our caller's state as the PC and SP to
+	// restore when returning from f.
+	MOVL	0(SP), AX	// our caller's PC
+	MOVL	AX, (m_morebuf+gobuf_pc)(BX)
+	LEAL	8(SP), AX	// our caller's SP
+	MOVL	AX, (m_morebuf+gobuf_sp)(BX)
+	MOVL	g(CX), AX
+	MOVL	AX, (m_morebuf+gobuf_g)(BX)
+	
+	// Save our own state as the PC and SP to restore
+	// if this goroutine needs to be restarted.
+	MOVL	$runtime·newstackcall(SB), DI
+	MOVL	DI, (g_sched+gobuf_pc)(AX)
+	MOVL	SP, (g_sched+gobuf_sp)(AX)
+
+	// Set up morestack arguments to call f on a new stack.
+	// We set f's frame size to 1, as a hint to newstack
+	// that this is a call from runtime·newstackcall.
+	// If it turns out that f needs a larger frame than
+	// the default stack, f's usual stack growth prolog will
+	// allocate a new segment (and recopy the arguments).
+	MOVL	8(SP), AX	// fn
+	MOVL	12(SP), DX	// arg frame
+	MOVL	16(SP), CX	// arg size
+
+	MOVQ	AX, m_cret(BX)	// f's PC
+	MOVL	DX, m_moreargp(BX)	// argument frame pointer
+	MOVL	CX, m_moreargsize(BX)	// f's argument size
+	MOVL	$1, m_moreframesize(BX)	// f's frame size
+
+	// Call newstack on m->g0's stack.
+	MOVL	m_g0(BX), BX
+	get_tls(CX)
+	MOVL	BX, g(CX)
+	MOVL	(g_sched+gobuf_sp)(BX), SP
+	CALL	runtime·newstack(SB)
+	MOVL	$0, 0x1103	// crash if newstack returns
+	RET
+
+// reflect·call: call a function with the given argument list
+// func call(f *FuncVal, arg *byte, argsize uint32).
+// we don't have variable-sized frames, so we use a small number
+// of constant-sized-frame functions to encode a few bits of size in the pc.
+// Caution: ugly multiline assembly macros in your future!
+
+#define DISPATCH(NAME,MAXSIZE)		\
+	CMPL	CX, $MAXSIZE;		\
+	JA	3(PC);			\
+	MOVL	$runtime·NAME(SB), AX;	\
+	JMP	AX
+// Note: can't just "JMP runtime·NAME(SB)" - bad inlining results.
+
+TEXT reflect·call(SB), NOSPLIT, $0-20
+	MOVLQZX argsize+8(FP), CX
+	DISPATCH(call16, 16)
+	DISPATCH(call32, 32)
+	DISPATCH(call64, 64)
+	DISPATCH(call128, 128)
+	DISPATCH(call256, 256)
+	DISPATCH(call512, 512)
+	DISPATCH(call1024, 1024)
+	DISPATCH(call2048, 2048)
+	DISPATCH(call4096, 4096)
+	DISPATCH(call8192, 8192)
+	DISPATCH(call16384, 16384)
+	DISPATCH(call32768, 32768)
+	DISPATCH(call65536, 65536)
+	DISPATCH(call131072, 131072)
+	DISPATCH(call262144, 262144)
+	DISPATCH(call524288, 524288)
+	DISPATCH(call1048576, 1048576)
+	DISPATCH(call2097152, 2097152)
+	DISPATCH(call4194304, 4194304)
+	DISPATCH(call8388608, 8388608)
+	DISPATCH(call16777216, 16777216)
+	DISPATCH(call33554432, 33554432)
+	DISPATCH(call67108864, 67108864)
+	DISPATCH(call134217728, 134217728)
+	DISPATCH(call268435456, 268435456)
+	DISPATCH(call536870912, 536870912)
+	DISPATCH(call1073741824, 1073741824)
+	MOVL	$runtime·badreflectcall(SB), AX
+	JMP	AX
+
+#define CALLFN(NAME,MAXSIZE)			\
+TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-16;		\
+	/* copy arguments to stack */		\
+	MOVL	argptr+4(FP), SI;		\
+	MOVL	argsize+8(FP), CX;		\
+	MOVL	SP, DI;				\
+	REP;MOVSB;				\
+	/* call function */			\
+	MOVL	f+0(FP), DX;			\
+	MOVL	(DX), AX;				\
+	CALL	AX; \
+	/* copy return values back */		\
+	MOVL	argptr+4(FP), DI;		\
+	MOVL	argsize+8(FP), CX;		\
+	MOVL	retoffset+12(FP), BX;		\
+	MOVL	SP, SI;				\
+	ADDL	BX, DI;				\
+	ADDL	BX, SI;				\
+	SUBL	BX, CX;				\
+	REP;MOVSB;				\
+	RET
+
+CALLFN(call16, 16)
+CALLFN(call32, 32)
+CALLFN(call64, 64)
+CALLFN(call128, 128)
+CALLFN(call256, 256)
+CALLFN(call512, 512)
+CALLFN(call1024, 1024)
+CALLFN(call2048, 2048)
+CALLFN(call4096, 4096)
+CALLFN(call8192, 8192)
+CALLFN(call16384, 16384)
+CALLFN(call32768, 32768)
+CALLFN(call65536, 65536)
+CALLFN(call131072, 131072)
+CALLFN(call262144, 262144)
+CALLFN(call524288, 524288)
+CALLFN(call1048576, 1048576)
+CALLFN(call2097152, 2097152)
+CALLFN(call4194304, 4194304)
+CALLFN(call8388608, 8388608)
+CALLFN(call16777216, 16777216)
+CALLFN(call33554432, 33554432)
+CALLFN(call67108864, 67108864)
+CALLFN(call134217728, 134217728)
+CALLFN(call268435456, 268435456)
+CALLFN(call536870912, 536870912)
+CALLFN(call1073741824, 1073741824)
+
+// Return point when leaving stack.
+//
+// Lessstack can appear in stack traces for the same reason
+// as morestack; in that context, it has 0 arguments.
+TEXT runtime·lessstack(SB), NOSPLIT, $0-0
+	// Save return value in m->cret
+	get_tls(CX)
+	MOVL	m(CX), BX
+	MOVQ	AX, m_cret(BX)	// MOVQ, to save all 64 bits
+
+	// Call oldstack on m->g0's stack.
+	MOVL	m_g0(BX), BX
+	MOVL	BX, g(CX)
+	MOVL	(g_sched+gobuf_sp)(BX), SP
+	CALL	runtime·oldstack(SB)
+	MOVL	$0, 0x1004	// crash if oldstack returns
+	RET
+
+// morestack trampolines
+TEXT runtime·morestack00(SB),NOSPLIT,$0
+	get_tls(CX)
+	MOVL	m(CX), BX
+	MOVQ	$0, AX
+	MOVQ	AX, m_moreframesize(BX)
+	MOVL	$runtime·morestack(SB), AX
+	JMP	AX
+
+TEXT runtime·morestack01(SB),NOSPLIT,$0
+	get_tls(CX)
+	MOVL	m(CX), BX
+	SHLQ	$32, AX
+	MOVQ	AX, m_moreframesize(BX)
+	MOVL	$runtime·morestack(SB), AX
+	JMP	AX
+
+TEXT runtime·morestack10(SB),NOSPLIT,$0
+	get_tls(CX)
+	MOVL	m(CX), BX
+	MOVLQZX	AX, AX
+	MOVQ	AX, m_moreframesize(BX)
+	MOVL	$runtime·morestack(SB), AX
+	JMP	AX
+
+TEXT runtime·morestack11(SB),NOSPLIT,$0
+	get_tls(CX)
+	MOVL	m(CX), BX
+	MOVQ	AX, m_moreframesize(BX)
+	MOVL	$runtime·morestack(SB), AX
+	JMP	AX
+
+// subcases of morestack01
+// with const of 8,16,...48
+TEXT runtime·morestack8(SB),NOSPLIT,$0
+	MOVQ	$1, R8
+	MOVL	$morestack<>(SB), AX
+	JMP	AX
+
+TEXT runtime·morestack16(SB),NOSPLIT,$0
+	MOVQ	$2, R8
+	MOVL	$morestack<>(SB), AX
+	JMP	AX
+
+TEXT runtime·morestack24(SB),NOSPLIT,$0
+	MOVQ	$3, R8
+	MOVL	$morestack<>(SB), AX
+	JMP	AX
+
+TEXT runtime·morestack32(SB),NOSPLIT,$0
+	MOVQ	$4, R8
+	MOVL	$morestack<>(SB), AX
+	JMP	AX
+
+TEXT runtime·morestack40(SB),NOSPLIT,$0
+	MOVQ	$5, R8
+	MOVL	$morestack<>(SB), AX
+	JMP	AX
+
+TEXT runtime·morestack48(SB),NOSPLIT,$0
+	MOVQ	$6, R8
+	MOVL	$morestack<>(SB), AX
+	JMP	AX
+
+TEXT morestack<>(SB),NOSPLIT,$0
+	get_tls(CX)
+	MOVL	m(CX), BX
+	SHLQ	$35, R8
+	MOVQ	R8, m_moreframesize(BX)
+	MOVL	$runtime·morestack(SB), AX
+	JMP	AX
+
+TEXT runtime·morestack00_noctxt(SB),NOSPLIT,$0
+	MOVL	$0, DX
+	JMP	runtime·morestack00(SB)
+
+TEXT runtime·morestack01_noctxt(SB),NOSPLIT,$0
+	MOVL	$0, DX
+	JMP	runtime·morestack01(SB)
+
+TEXT runtime·morestack10_noctxt(SB),NOSPLIT,$0
+	MOVL	$0, DX
+	JMP	runtime·morestack10(SB)
+
+TEXT runtime·morestack11_noctxt(SB),NOSPLIT,$0
+	MOVL	$0, DX
+	JMP	runtime·morestack11(SB)
+
+TEXT runtime·morestack8_noctxt(SB),NOSPLIT,$0
+	MOVL	$0, DX
+	JMP	runtime·morestack8(SB)
+
+TEXT runtime·morestack16_noctxt(SB),NOSPLIT,$0
+	MOVL	$0, DX
+	JMP	runtime·morestack16(SB)
+
+TEXT runtime·morestack24_noctxt(SB),NOSPLIT,$0
+	MOVL	$0, DX
+	JMP	runtime·morestack24(SB)
+
+TEXT runtime·morestack32_noctxt(SB),NOSPLIT,$0
+	MOVL	$0, DX
+	JMP	runtime·morestack32(SB)
+
+TEXT runtime·morestack40_noctxt(SB),NOSPLIT,$0
+	MOVL	$0, DX
+	JMP	runtime·morestack40(SB)
+
+TEXT runtime·morestack48_noctxt(SB),NOSPLIT,$0
+	MOVL	$0, DX
+	JMP	runtime·morestack48(SB)
+
+// bool cas(int32 *val, int32 old, int32 new)
+// Atomically:
+//	if(*val == old){
+//		*val = new;
+//		return 1;
+//	} else
+//		return 0;
+TEXT runtime·cas(SB), NOSPLIT, $0-12
+	MOVL	val+0(FP), BX
+	MOVL	old+4(FP), AX
+	MOVL	new+8(FP), CX
+	LOCK
+	CMPXCHGL	CX, 0(BX)
+	JZ 3(PC)
+	MOVL	$0, AX
+	RET
+	MOVL	$1, AX
+	RET
+
+// bool	runtime·cas64(uint64 *val, uint64 old, uint64 new)
+// Atomically:
+//	if(*val == *old){
+//		*val = new;
+//		return 1;
+//	} else {
+//		return 0;
+//	}
+TEXT runtime·cas64(SB), NOSPLIT, $0-24
+	MOVL	val+0(FP), BX
+	MOVQ	old+8(FP), AX
+	MOVQ	new+16(FP), CX
+	LOCK
+	CMPXCHGQ	CX, 0(BX)
+	JNZ	cas64_fail
+	MOVL	$1, AX
+	RET
+cas64_fail:
+	MOVL	$0, AX
+	RET
+
+// bool casp(void **val, void *old, void *new)
+// Atomically:
+//	if(*val == old){
+//		*val = new;
+//		return 1;
+//	} else
+//		return 0;
+TEXT runtime·casp(SB), NOSPLIT, $0-12
+	MOVL	val+0(FP), BX
+	MOVL	old+4(FP), AX
+	MOVL	new+8(FP), CX
+	LOCK
+	CMPXCHGL	CX, 0(BX)
+	JZ 3(PC)
+	MOVL	$0, AX
+	RET
+	MOVL	$1, AX
+	RET
+
+// uint32 xadd(uint32 volatile *val, int32 delta)
+// Atomically:
+//	*val += delta;
+//	return *val;
+TEXT runtime·xadd(SB), NOSPLIT, $0-8
+	MOVL	val+0(FP), BX
+	MOVL	delta+4(FP), AX
+	MOVL	AX, CX
+	LOCK
+	XADDL	AX, 0(BX)
+	ADDL	CX, AX
+	RET
+
+TEXT runtime·xadd64(SB), NOSPLIT, $0-16
+	MOVL	val+0(FP), BX
+	MOVQ	delta+8(FP), AX
+	MOVQ	AX, CX
+	LOCK
+	XADDQ	AX, 0(BX)
+	ADDQ	CX, AX
+	RET
+
+TEXT runtime·xchg(SB), NOSPLIT, $0-8
+	MOVL	val+0(FP), BX
+	MOVL	new+4(FP), AX
+	XCHGL	AX, 0(BX)
+	RET
+
+TEXT runtime·xchg64(SB), NOSPLIT, $0-16
+	MOVL	val+0(FP), BX
+	MOVQ	new+8(FP), AX
+	XCHGQ	AX, 0(BX)
+	RET
+
+TEXT runtime·procyield(SB),NOSPLIT,$0-0
+	MOVL	val+0(FP), AX
+again:
+	PAUSE
+	SUBL	$1, AX
+	JNZ	again
+	RET
+
+TEXT runtime·atomicstorep(SB), NOSPLIT, $0-8
+	MOVL	ptr+0(FP), BX
+	MOVL	val+4(FP), AX
+	XCHGL	AX, 0(BX)
+	RET
+
+TEXT runtime·atomicstore(SB), NOSPLIT, $0-8
+	MOVL	ptr+0(FP), BX
+	MOVL	val+4(FP), AX
+	XCHGL	AX, 0(BX)
+	RET
+
+TEXT runtime·atomicstore64(SB), NOSPLIT, $0-16
+	MOVL	ptr+0(FP), BX
+	MOVQ	val+8(FP), AX
+	XCHGQ	AX, 0(BX)
+	RET
+
+// void jmpdefer(fn, sp);
+// called from deferreturn.
+// 1. pop the caller
+// 2. sub 5 bytes from the callers return
+// 3. jmp to the argument
+TEXT runtime·jmpdefer(SB), NOSPLIT, $0-16
+	MOVL	fn+0(FP), DX
+	MOVL	callersp+4(FP), BX
+	LEAL	-8(BX), SP	// caller sp after CALL
+	SUBL	$5, (SP)	// return to CALL again
+	MOVL	0(DX), BX
+	JMP	BX	// but first run the deferred function
+
+// asmcgocall(void(*fn)(void*), void *arg)
+// Not implemented.
+TEXT runtime·asmcgocall(SB),NOSPLIT,$0-8
+	MOVL	0, AX
+	RET
+
+// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
+// Not implemented.
+TEXT runtime·cgocallback(SB),NOSPLIT,$0-12
+	MOVL	0, AX
+	RET
+
+// void setmg(M*, G*); set m and g. for use by needm.
+// Not implemented.
+TEXT runtime·setmg(SB), NOSPLIT, $0-8
+	MOVL	0, AX
+	RET
+
+// check that SP is in range [g->stackbase, g->stackguard)
+TEXT runtime·stackcheck(SB), NOSPLIT, $0-0
+	get_tls(CX)
+	MOVL	g(CX), AX
+	CMPL	g_stackbase(AX), SP
+	JHI	2(PC)
+	MOVL	0, AX
+	CMPL	SP, g_stackguard(AX)
+	JHI	2(PC)
+	MOVL	0, AX
+	RET
+
+TEXT runtime·memclr(SB),NOSPLIT,$0-8
+	MOVL	addr+0(FP), DI
+	MOVL	count+4(FP), CX
+	MOVQ	CX, BX
+	ANDQ	$7, BX
+	SHRQ	$3, CX
+	MOVQ	$0, AX
+	CLD
+	REP
+	STOSQ
+	MOVQ	BX, CX
+	REP
+	STOSB
+	RET
+
+TEXT runtime·getcallerpc(SB),NOSPLIT,$0-8
+	MOVL	x+0(FP),AX		// addr of first arg
+	MOVL	-8(AX),AX		// get calling pc
+	RET
+
+TEXT runtime·setcallerpc(SB),NOSPLIT,$0-16
+	MOVL	x+0(FP),AX		// addr of first arg
+	MOVL	pc+4(FP), BX		// pc to set
+	MOVQ	BX, -8(AX)		// set calling pc
+	RET
+
+TEXT runtime·getcallersp(SB),NOSPLIT,$0-8
+	MOVL	sp+0(FP), AX
+	RET
+
+// int64 runtime·cputicks(void)
+TEXT runtime·cputicks(SB),NOSPLIT,$0-0
+	RDTSC
+	SHLQ	$32, DX
+	ADDQ	DX, AX
+	RET
+
+TEXT runtime·stackguard(SB),NOSPLIT,$0-16
+	MOVL	SP, DX
+	MOVL	DX, sp+0(FP)
+	get_tls(CX)
+	MOVL	g(CX), BX
+	MOVL	g_stackguard(BX), DX
+	MOVL	DX, limit+4(FP)
+	RET
+
+GLOBL runtime·tls0(SB), $64
+
+// hash function using AES hardware instructions
+// For now, our one amd64p32 system (NaCl) does not
+// support using AES instructions, so have not bothered to
+// write the implementations. Can copy and adjust the ones
+// in asm_amd64.s when the time comes.
+
+TEXT runtime·aeshash(SB),NOSPLIT,$0-24
+	RET
+
+TEXT runtime·aeshashstr(SB),NOSPLIT,$0-24
+	RET
+
+TEXT runtime·aeshash32(SB),NOSPLIT,$0-24
+	RET
+
+TEXT runtime·aeshash64(SB),NOSPLIT,$0-24
+	RET
+
+TEXT runtime·memeq(SB),NOSPLIT,$0-12
+	MOVL	a+0(FP), SI
+	MOVL	b+4(FP), DI
+	MOVL	count+8(FP), BX
+	JMP	runtime·memeqbody(SB)
+
+// a in SI
+// b in DI
+// count in BX
+TEXT runtime·memeqbody(SB),NOSPLIT,$0-0
+	XORQ	AX, AX
+
+	CMPQ	BX, $8
+	JB	small
+	
+	// 64 bytes at a time using xmm registers
+hugeloop:
+	CMPQ	BX, $64
+	JB	bigloop
+	MOVOU	(SI), X0
+	MOVOU	(DI), X1
+	MOVOU	16(SI), X2
+	MOVOU	16(DI), X3
+	MOVOU	32(SI), X4
+	MOVOU	32(DI), X5
+	MOVOU	48(SI), X6
+	MOVOU	48(DI), X7
+	PCMPEQB	X1, X0
+	PCMPEQB	X3, X2
+	PCMPEQB	X5, X4
+	PCMPEQB	X7, X6
+	PAND	X2, X0
+	PAND	X6, X4
+	PAND	X4, X0
+	PMOVMSKB X0, DX
+	ADDQ	$64, SI
+	ADDQ	$64, DI
+	SUBQ	$64, BX
+	CMPL	DX, $0xffff
+	JEQ	hugeloop
+	RET
+
+	// 8 bytes at a time using 64-bit register
+bigloop:
+	CMPQ	BX, $8
+	JBE	leftover
+	MOVQ	(SI), CX
+	MOVQ	(DI), DX
+	ADDQ	$8, SI
+	ADDQ	$8, DI
+	SUBQ	$8, BX
+	CMPQ	CX, DX
+	JEQ	bigloop
+	RET
+
+	// remaining 0-8 bytes
+leftover:
+	ADDQ	BX, SI
+	ADDQ	BX, DI
+	MOVQ	-8(SI), CX
+	MOVQ	-8(DI), DX
+	CMPQ	CX, DX
+	SETEQ	AX
+	RET
+
+small:
+	CMPQ	BX, $0
+	JEQ	equal
+
+	LEAQ	0(BX*8), CX
+	NEGQ	CX
+
+	CMPB	SI, $0xf8
+	JA	si_high
+
+	// load at SI won't cross a page boundary.
+	MOVQ	(SI), SI
+	JMP	si_finish
+si_high:
+	// address ends in 11111xxx.  Load up to bytes we want, move to correct position.
+	MOVQ	BX, DX
+	ADDQ	SI, DX
+	MOVQ	-8(DX), SI
+	SHRQ	CX, SI
+si_finish:
+
+	// same for DI.
+	CMPB	DI, $0xf8
+	JA	di_high
+	MOVQ	(DI), DI
+	JMP	di_finish
+di_high:
+	MOVQ	BX, DX
+	ADDQ	DI, DX
+	MOVQ	-8(DX), DI
+	SHRQ	CX, DI
+di_finish:
+
+	SUBQ	SI, DI
+	SHLQ	CX, DI
+equal:
+	SETEQ	AX
+	RET
+
+TEXT runtime·cmpstring(SB),NOSPLIT,$0-20
+	MOVL	s1+0(FP), SI
+	MOVL	s1+4(FP), BX
+	MOVL	s2+8(FP), DI
+	MOVL	s2+12(FP), DX
+	CALL	runtime·cmpbody(SB)
+	MOVL	AX, res+16(FP)
+	RET
+
+TEXT bytes·Compare(SB),NOSPLIT,$0-28
+	MOVL	s1+0(FP), SI
+	MOVL	s1+4(FP), BX
+	MOVL	s2+12(FP), DI
+	MOVL	s2+16(FP), DX
+	CALL	runtime·cmpbody(SB)
+	MOVQ	AX, res+24(FP)
+	RET
+
+// input:
+//   SI = a
+//   DI = b
+//   BX = alen
+//   DX = blen
+// output:
+//   AX = 1/0/-1
+TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
+	CMPQ	SI, DI
+	JEQ	cmp_allsame
+	CMPQ	BX, DX
+	MOVQ	DX, R8
+	CMOVQLT	BX, R8 // R8 = min(alen, blen) = # of bytes to compare
+	CMPQ	R8, $8
+	JB	cmp_small
+
+cmp_loop:
+	CMPQ	R8, $16
+	JBE	cmp_0through16
+	MOVOU	(SI), X0
+	MOVOU	(DI), X1
+	PCMPEQB X0, X1
+	PMOVMSKB X1, AX
+	XORQ	$0xffff, AX	// convert EQ to NE
+	JNE	cmp_diff16	// branch if at least one byte is not equal
+	ADDQ	$16, SI
+	ADDQ	$16, DI
+	SUBQ	$16, R8
+	JMP	cmp_loop
+	
+	// AX = bit mask of differences
+cmp_diff16:
+	BSFQ	AX, BX	// index of first byte that differs
+	XORQ	AX, AX
+	ADDQ	BX, SI
+	MOVB	(SI), CX
+	ADDQ	BX, DI
+	CMPB	CX, (DI)
+	SETHI	AX
+	LEAQ	-1(AX*2), AX	// convert 1/0 to +1/-1
+	RET
+
+	// 0 through 16 bytes left, alen>=8, blen>=8
+cmp_0through16:
+	CMPQ	R8, $8
+	JBE	cmp_0through8
+	MOVQ	(SI), AX
+	MOVQ	(DI), CX
+	CMPQ	AX, CX
+	JNE	cmp_diff8
+cmp_0through8:
+	ADDQ	R8, SI
+	ADDQ	R8, DI
+	MOVQ	-8(SI), AX
+	MOVQ	-8(DI), CX
+	CMPQ	AX, CX
+	JEQ	cmp_allsame
+
+	// AX and CX contain parts of a and b that differ.
+cmp_diff8:
+	BSWAPQ	AX	// reverse order of bytes
+	BSWAPQ	CX
+	XORQ	AX, CX
+	BSRQ	CX, CX	// index of highest bit difference
+	SHRQ	CX, AX	// move a's bit to bottom
+	ANDQ	$1, AX	// mask bit
+	LEAQ	-1(AX*2), AX // 1/0 => +1/-1
+	RET
+
+	// 0-7 bytes in common
+cmp_small:
+	LEAQ	(R8*8), CX	// bytes left -> bits left
+	NEGQ	CX		//  - bits lift (== 64 - bits left mod 64)
+	JEQ	cmp_allsame
+
+	// load bytes of a into high bytes of AX
+	CMPB	SI, $0xf8
+	JA	cmp_si_high
+	MOVQ	(SI), SI
+	JMP	cmp_si_finish
+cmp_si_high:
+	ADDQ	R8, SI
+	MOVQ	-8(SI), SI
+	SHRQ	CX, SI
+cmp_si_finish:
+	SHLQ	CX, SI
+
+	// load bytes of b in to high bytes of BX
+	CMPB	DI, $0xf8
+	JA	cmp_di_high
+	MOVQ	(DI), DI
+	JMP	cmp_di_finish
+cmp_di_high:
+	ADDQ	R8, DI
+	MOVQ	-8(DI), DI
+	SHRQ	CX, DI
+cmp_di_finish:
+	SHLQ	CX, DI
+
+	BSWAPQ	SI	// reverse order of bytes
+	BSWAPQ	DI
+	XORQ	SI, DI	// find bit differences
+	JEQ	cmp_allsame
+	BSRQ	DI, CX	// index of highest bit difference
+	SHRQ	CX, SI	// move a's bit to bottom
+	ANDQ	$1, SI	// mask bit
+	LEAQ	-1(SI*2), AX // 1/0 => +1/-1
+	RET
+
+cmp_allsame:
+	XORQ	AX, AX
+	XORQ	CX, CX
+	CMPQ	BX, DX
+	SETGT	AX	// 1 if alen > blen
+	SETEQ	CX	// 1 if alen == blen
+	LEAQ	-1(CX)(AX*2), AX	// 1,0,-1 result
+	RET
+
+TEXT bytes·IndexByte(SB),NOSPLIT,$0
+	MOVL s+0(FP), SI
+	MOVL s_len+4(FP), BX
+	MOVB c+12(FP), AL
+	CALL runtime·indexbytebody(SB)
+	MOVL AX, ret+16(FP)
+	RET
+
+TEXT strings·IndexByte(SB),NOSPLIT,$0
+	MOVL s+0(FP), SI
+	MOVL s_len+4(FP), BX
+	MOVB c+8(FP), AL
+	CALL runtime·indexbytebody(SB)
+	MOVL AX, ret+16(FP)
+	RET
+
+// input:
+//   SI: data
+//   BX: data len
+//   AL: byte sought
+// output:
+//   AX
+TEXT runtime·indexbytebody(SB),NOSPLIT,$0
+	MOVL SI, DI
+
+	CMPL BX, $16
+	JLT indexbyte_small
+
+	// round up to first 16-byte boundary
+	TESTL $15, SI
+	JZ aligned
+	MOVL SI, CX
+	ANDL $~15, CX
+	ADDL $16, CX
+
+	// search the beginning
+	SUBL SI, CX
+	REPN; SCASB
+	JZ success
+
+// DI is 16-byte aligned; get ready to search using SSE instructions
+aligned:
+	// round down to last 16-byte boundary
+	MOVL BX, R11
+	ADDL SI, R11
+	ANDL $~15, R11
+
+	// shuffle X0 around so that each byte contains c
+	MOVD AX, X0
+	PUNPCKLBW X0, X0
+	PUNPCKLBW X0, X0
+	PSHUFL $0, X0, X0
+	JMP condition
+
+sse:
+	// move the next 16-byte chunk of the buffer into X1
+	MOVO (DI), X1
+	// compare bytes in X0 to X1
+	PCMPEQB X0, X1
+	// take the top bit of each byte in X1 and put the result in DX
+	PMOVMSKB X1, DX
+	TESTL DX, DX
+	JNZ ssesuccess
+	ADDL $16, DI
+
+condition:
+	CMPL DI, R11
+	JLT sse
+
+	// search the end
+	MOVL SI, CX
+	ADDL BX, CX
+	SUBL R11, CX
+	// if CX == 0, the zero flag will be set and we'll end up
+	// returning a false success
+	JZ failure
+	REPN; SCASB
+	JZ success
+
+failure:
+	MOVL $-1, AX
+	RET
+
+// handle for lengths < 16
+indexbyte_small:
+	MOVL BX, CX
+	REPN; SCASB
+	JZ success
+	MOVL $-1, AX
+	RET
+
+// we've found the chunk containing the byte
+// now just figure out which specific byte it is
+ssesuccess:
+	// get the index of the least significant set bit
+	BSFW DX, DX
+	SUBL SI, DI
+	ADDL DI, DX
+	MOVL DX, AX
+	RET
+
+success:
+	SUBL SI, DI
+	SUBL $1, DI
+	MOVL DI, AX
+	RET
+
+TEXT bytes·Equal(SB),NOSPLIT,$0-25
+	MOVL	a_len+4(FP), BX
+	MOVL	b_len+16(FP), CX
+	XORL	AX, AX
+	CMPL	BX, CX
+	JNE	eqret
+	MOVL	a+0(FP), SI
+	MOVL	b+12(FP), DI
+	CALL	runtime·memeqbody(SB)
+eqret:
+	MOVB	AX, ret+24(FP)
+	RET
+
+TEXT runtime·timenow(SB), NOSPLIT, $0-0
+	JMP	time·now(SB)
diff --git a/src/pkg/runtime/asm_arm.s b/src/pkg/runtime/asm_arm.s
index f483e6f..1aea903 100644
--- a/src/pkg/runtime/asm_arm.s
+++ b/src/pkg/runtime/asm_arm.s
@@ -89,11 +89,9 @@ TEXT runtime·breakpoint(SB),NOSPLIT,$0-0
 	WORD	$0xe1200071	// BKPT 0x0001
 	RET
 
-GLOBL runtime·goarm(SB), $4
-
 TEXT runtime·asminit(SB),NOSPLIT,$0-0
 	// disable runfast (flush-to-zero) mode of vfp if runtime.goarm > 5
-	MOVW	runtime·goarm(SB), R11
+	MOVB	runtime·goarm(SB), R11
 	CMP	$5, R11
 	BLE	4(PC)
 	WORD	$0xeef1ba10	// vmrs r11, fpscr
@@ -215,6 +213,10 @@ TEXT runtime·morestack(SB),NOSPLIT,$-4-0
 	// is still in this function, and not the beginning of the next.
 	RET
 
+TEXT runtime·morestack_noctxt(SB),NOSPLIT,$-4-0
+	MOVW	$0, R7
+	B runtime·morestack(SB)
+
 // Called from panic.  Mimics morestack,
 // reuses stack growth code to create a frame
 // with the desired args running the desired function.
@@ -267,7 +269,7 @@ TEXT runtime·newstackcall(SB), NOSPLIT, $-4-12
 	MOVW	$runtime·NAME(SB), R1;	\
 	B	(R1)
 
-TEXT reflect·call(SB), NOSPLIT, $-4-12
+TEXT reflect·call(SB), NOSPLIT, $-4-16
 	MOVW	argsize+8(FP), R0
 	DISPATCH(call16, 16)
 	DISPATCH(call32, 32)
@@ -299,8 +301,22 @@ TEXT reflect·call(SB), NOSPLIT, $-4-12
 	MOVW	$runtime·badreflectcall(SB), R1
 	B	(R1)
 
+// Argument map for the callXX frames.  Each has one
+// stack map (for the single call) with 3 arguments.
+DATA gcargs_reflectcall<>+0x00(SB)/4, $1  // 1 stackmap
+DATA gcargs_reflectcall<>+0x04(SB)/4, $6  // 3 args
+DATA gcargs_reflectcall<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4))
+GLOBL gcargs_reflectcall<>(SB),RODATA,$12
+
+// callXX frames have no locals
+DATA gclocals_reflectcall<>+0x00(SB)/4, $1  // 1 stackmap
+DATA gclocals_reflectcall<>+0x04(SB)/4, $0  // 0 locals
+GLOBL gclocals_reflectcall<>(SB),RODATA,$8
+
 #define CALLFN(NAME,MAXSIZE)			\
-TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-12;		\
+TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-16;	\
+	FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB);	\
+	FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\
 	/* copy arguments to stack */		\
 	MOVW	argptr+4(FP), R0;		\
 	MOVW	argsize+8(FP), R2;		\
@@ -314,11 +330,16 @@ TEXT runtime·NAME(SB), WRAPPER, $MAXSIZE-12;		\
 	/* call function */			\
 	MOVW	f+0(FP), R7;			\
 	MOVW	(R7), R0;			\
+	PCDATA  $PCDATA_StackMapIndex, $0;	\
 	BL	(R0);				\
 	/* copy return values back */		\
 	MOVW	argptr+4(FP), R0;		\
 	MOVW	argsize+8(FP), R2;		\
+	MOVW	retoffset+12(FP), R3;		\
 	ADD	$4, SP, R1;			\
+	ADD	R3, R1;				\
+	ADD	R3, R0;				\
+	SUB	R3, R2;				\
 	CMP	$0, R2;				\
 	RET.EQ	;				\
 	MOVBU.P	1(R1), R5;			\
@@ -373,6 +394,10 @@ TEXT runtime·lessstack(SB), NOSPLIT, $-4-0
 // 1. grab stored LR for caller
 // 2. sub 4 bytes to get back to BL deferreturn
 // 3. B to fn
+// TODO(rsc): Push things on stack and then use pop
+// to load all registers simultaneously, so that a profiling
+// interrupt can never see mismatched SP/LR/PC.
+// (And double-check that pop is atomic in that way.)
 TEXT runtime·jmpdefer(SB), NOSPLIT, $0-8
 	MOVW	0(SP), LR
 	MOVW	$-4(LR), LR	// BL deferreturn
@@ -629,17 +654,33 @@ _next:
 // Note: all three functions will clobber R0, and the last
 // two can be called from 5c ABI code.
 
-// g (R10) at 8(TP), m (R9) at 12(TP)
+// save_gm saves the g and m registers into pthread-provided
+// thread-local memory, so that we can call externally compiled
+// ARM code that will overwrite those registers.
+// NOTE: runtime.gogo assumes that R1 is preserved by this function.
 TEXT runtime·save_gm(SB),NOSPLIT,$0
-	MRC		15, 0, R0, C13, C0, 3 // Fetch TLS register
-	MOVW	g, 8(R0)
-	MOVW	m, 12(R0)
+	MRC		15, 0, R0, C13, C0, 3 // fetch TLS base pointer
+	// $runtime.tlsgm(SB) is a special linker symbol.
+	// It is the offset from the TLS base pointer to our
+	// thread-local storage for g and m.
+	MOVW	$runtime·tlsgm(SB), R11
+	ADD	R11, R0
+	MOVW	g, 0(R0)
+	MOVW	m, 4(R0)
 	RET
 
+// load_gm loads the g and m registers from pthread-provided
+// thread-local memory, for use after calling externally compiled
+// ARM code that overwrote those registers.
 TEXT runtime·load_gm(SB),NOSPLIT,$0
-	MRC		15, 0, R0, C13, C0, 3 // Fetch TLS register
-	MOVW	8(R0), g
-	MOVW	12(R0), m
+	MRC		15, 0, R0, C13, C0, 3 // fetch TLS base pointer
+	// $runtime.tlsgm(SB) is a special linker symbol.
+	// It is the offset from the TLS base pointer to our
+	// thread-local storage for g and m.
+	MOVW	$runtime·tlsgm(SB), R11
+	ADD	R11, R0
+	MOVW	0(R0), g
+	MOVW	4(R0), m
 	RET
 
 // void setmg_gcc(M*, G*); set m and g called from gcc.
@@ -648,7 +689,6 @@ TEXT setmg_gcc<>(SB),NOSPLIT,$0
 	MOVW	R1, g
 	B		runtime·save_gm(SB)
 
-
 // TODO: share code with memeq?
 TEXT bytes·Equal(SB),NOSPLIT,$0
 	MOVW	a_len+4(FP), R1
@@ -726,3 +766,414 @@ _sib_notfound:
 	MOVW	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
+
+TEXT runtime·timenow(SB), NOSPLIT, $0-0
+	B	time·now(SB)
+
+// A Duff's device for zeroing memory.
+// The compiler jumps to computed addresses within
+// this routine to zero chunks of memory.  Do not
+// change this code without also changing the code
+// in ../../cmd/5g/ggen.c:clearfat.
+// R0: zero
+// R1: ptr to memory to be zeroed
+// R1 is updated as a side effect.
+TEXT runtime·duffzero(SB), NOSPLIT, $0-0
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	RET
+
+// A Duff's device for copying memory.
+// The compiler jumps to computed addresses within
+// this routine to copy chunks of memory.  Source
+// and destination must not overlap.  Do not
+// change this code without also changing the code
+// in ../../cmd/5g/cgen.c:sgen.
+// R0: scratch space
+// R1: ptr to source memory
+// R2: ptr to destination memory
+// R1 and R2 are updated as a side effect
+TEXT runtime·duffcopy(SB), NOSPLIT, $0-0
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+	RET
diff --git a/src/pkg/runtime/atomic_amd64.c b/src/pkg/runtime/atomic_amd64.c
deleted file mode 100644
index 0bd4d90..0000000
--- a/src/pkg/runtime/atomic_amd64.c
+++ /dev/null
@@ -1,27 +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 "runtime.h"
-#include "../../cmd/ld/textflag.h"
-
-#pragma textflag NOSPLIT
-uint32
-runtime·atomicload(uint32 volatile* addr)
-{
-	return *addr;
-}
-
-#pragma textflag NOSPLIT
-uint64
-runtime·atomicload64(uint64 volatile* addr)
-{
-	return *addr;
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·atomicloadp(void* volatile* addr)
-{
-	return *addr;
-}
diff --git a/src/pkg/runtime/atomic_amd64x.c b/src/pkg/runtime/atomic_amd64x.c
new file mode 100644
index 0000000..11b5789
--- /dev/null
+++ b/src/pkg/runtime/atomic_amd64x.c
@@ -0,0 +1,29 @@
+// 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.
+
+// +build amd64 amd64p32
+
+#include "runtime.h"
+#include "../../cmd/ld/textflag.h"
+
+#pragma textflag NOSPLIT
+uint32
+runtime·atomicload(uint32 volatile* addr)
+{
+	return *addr;
+}
+
+#pragma textflag NOSPLIT
+uint64
+runtime·atomicload64(uint64 volatile* addr)
+{
+	return *addr;
+}
+
+#pragma textflag NOSPLIT
+void*
+runtime·atomicloadp(void* volatile* addr)
+{
+	return *addr;
+}
diff --git a/src/pkg/runtime/atomic_arm.c b/src/pkg/runtime/atomic_arm.c
index b1e97b2..d914475 100644
--- a/src/pkg/runtime/atomic_arm.c
+++ b/src/pkg/runtime/atomic_arm.c
@@ -42,6 +42,19 @@ runtime·xchg(uint32 volatile* addr, uint32 v)
 }
 
 #pragma textflag NOSPLIT
+void*
+runtime·xchgp(void* volatile* addr, void* v)
+{
+	void *old;
+
+	for(;;) {
+		old = *addr;
+		if(runtime·casp(addr, old, v))
+			return old;
+	}
+}
+
+#pragma textflag NOSPLIT
 void
 runtime·procyield(uint32 cnt)
 {
diff --git a/src/pkg/runtime/callback_windows.c b/src/pkg/runtime/callback_windows.c
index 88ee53b..285678f 100644
--- a/src/pkg/runtime/callback_windows.c
+++ b/src/pkg/runtime/callback_windows.c
@@ -49,7 +49,7 @@ runtime·compilecallback(Eface fn, bool cleanstack)
 		runtime·cbctxts = &(cbs.ctxt[0]);
 	n = cbs.n;
 	for(i=0; i<n; i++) {
-		if(cbs.ctxt[i]->gobody == fn.data) {
+		if(cbs.ctxt[i]->gobody == fn.data && cbs.ctxt[i]->cleanstack == cleanstack) {
 			runtime·unlock(&cbs);
 			// runtime·callbackasm is just a series of CALL instructions
 			// (each is 5 bytes long), and we want callback to arrive at
@@ -63,6 +63,7 @@ runtime·compilecallback(Eface fn, bool cleanstack)
 	c = runtime·mal(sizeof *c);
 	c->gobody = fn.data;
 	c->argsize = argsize;
+	c->cleanstack = cleanstack;
 	if(cleanstack && argsize!=0)
 		c->restorestack = argsize;
 	else
diff --git a/src/pkg/runtime/cgo/asm_nacl_amd64p32.s b/src/pkg/runtime/cgo/asm_nacl_amd64p32.s
new file mode 100644
index 0000000..377cf72
--- /dev/null
+++ b/src/pkg/runtime/cgo/asm_nacl_amd64p32.s
@@ -0,0 +1,13 @@
+// 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 "../../../cmd/ld/textflag.h"
+
+/*
+ * void crosscall2(void (*fn)(void*, int32), void*, int32)
+ * Save registers and call fn with two arguments.
+ */
+TEXT crosscall2(SB),NOSPLIT,$0
+	INT $3
+	RET
diff --git a/src/pkg/runtime/cgo/gcc_dragonfly_386.c b/src/pkg/runtime/cgo/gcc_dragonfly_386.c
index 6797824..695c166 100644
--- a/src/pkg/runtime/cgo/gcc_dragonfly_386.c
+++ b/src/pkg/runtime/cgo/gcc_dragonfly_386.c
@@ -36,14 +36,14 @@ _cgo_sys_thread_start(ThreadStart *ts)
 	int err;
 
 	SIGFILLSET(ign);
-	sigprocmask(SIG_SETMASK, &ign, &oset);
+	pthread_sigmask(SIG_SETMASK, &ign, &oset);
 
 	pthread_attr_init(&attr);
 	pthread_attr_getstacksize(&attr, &size);
 	ts->g->stackguard = size;
 	err = pthread_create(&p, &attr, threadentry, ts);
 
-	sigprocmask(SIG_SETMASK, &oset, nil);
+	pthread_sigmask(SIG_SETMASK, &oset, nil);
 
 	if (err != 0) {
 		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_dragonfly_amd64.c b/src/pkg/runtime/cgo/gcc_dragonfly_amd64.c
index eb342a2..a46c121 100644
--- a/src/pkg/runtime/cgo/gcc_dragonfly_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_dragonfly_amd64.c
@@ -35,7 +35,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 	int err;
 
 	SIGFILLSET(ign);
-	sigprocmask(SIG_SETMASK, &ign, &oset);
+	pthread_sigmask(SIG_SETMASK, &ign, &oset);
 
 	pthread_attr_init(&attr);
 	pthread_attr_getstacksize(&attr, &size);
@@ -43,7 +43,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 	ts->g->stackguard = size;
 	err = pthread_create(&p, &attr, threadentry, ts);
 
-	sigprocmask(SIG_SETMASK, &oset, nil);
+	pthread_sigmask(SIG_SETMASK, &oset, nil);
 
 	if (err != 0) {
 		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_freebsd_386.c b/src/pkg/runtime/cgo/gcc_freebsd_386.c
index 6797824..695c166 100644
--- a/src/pkg/runtime/cgo/gcc_freebsd_386.c
+++ b/src/pkg/runtime/cgo/gcc_freebsd_386.c
@@ -36,14 +36,14 @@ _cgo_sys_thread_start(ThreadStart *ts)
 	int err;
 
 	SIGFILLSET(ign);
-	sigprocmask(SIG_SETMASK, &ign, &oset);
+	pthread_sigmask(SIG_SETMASK, &ign, &oset);
 
 	pthread_attr_init(&attr);
 	pthread_attr_getstacksize(&attr, &size);
 	ts->g->stackguard = size;
 	err = pthread_create(&p, &attr, threadentry, ts);
 
-	sigprocmask(SIG_SETMASK, &oset, nil);
+	pthread_sigmask(SIG_SETMASK, &oset, nil);
 
 	if (err != 0) {
 		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_freebsd_amd64.c b/src/pkg/runtime/cgo/gcc_freebsd_amd64.c
index eb342a2..a46c121 100644
--- a/src/pkg/runtime/cgo/gcc_freebsd_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_freebsd_amd64.c
@@ -35,7 +35,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 	int err;
 
 	SIGFILLSET(ign);
-	sigprocmask(SIG_SETMASK, &ign, &oset);
+	pthread_sigmask(SIG_SETMASK, &ign, &oset);
 
 	pthread_attr_init(&attr);
 	pthread_attr_getstacksize(&attr, &size);
@@ -43,7 +43,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 	ts->g->stackguard = size;
 	err = pthread_create(&p, &attr, threadentry, ts);
 
-	sigprocmask(SIG_SETMASK, &oset, nil);
+	pthread_sigmask(SIG_SETMASK, &oset, nil);
 
 	if (err != 0) {
 		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_freebsd_arm.c b/src/pkg/runtime/cgo/gcc_freebsd_arm.c
index 211dca7..6175e1d 100644
--- a/src/pkg/runtime/cgo/gcc_freebsd_arm.c
+++ b/src/pkg/runtime/cgo/gcc_freebsd_arm.c
@@ -4,7 +4,9 @@
 
 #include <sys/types.h>
 #include <machine/sysarch.h>
+#include <sys/signalvar.h>
 #include <pthread.h>
+#include <signal.h>
 #include <string.h>
 #include "libcgo.h"
 
@@ -39,10 +41,14 @@ void
 _cgo_sys_thread_start(ThreadStart *ts)
 {
 	pthread_attr_t attr;
+	sigset_t ign, oset;
 	pthread_t p;
 	size_t size;
 	int err;
 
+	SIGFILLSET(ign);
+	pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
 	// Not sure why the memset is necessary here,
 	// but without it, we get a bogus stack size
 	// out of pthread_attr_getstacksize.  C'est la Linux.
@@ -52,6 +58,9 @@ _cgo_sys_thread_start(ThreadStart *ts)
 	pthread_attr_getstacksize(&attr, &size);
 	ts->g->stackguard = size;
 	err = pthread_create(&p, &attr, threadentry, ts);
+
+	pthread_sigmask(SIG_SETMASK, &oset, nil);
+
 	if (err != 0) {
 		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
 		abort();
diff --git a/src/pkg/runtime/cgo/gcc_linux_386.c b/src/pkg/runtime/cgo/gcc_linux_386.c
index c25c7b7..0a46c9b 100644
--- a/src/pkg/runtime/cgo/gcc_linux_386.c
+++ b/src/pkg/runtime/cgo/gcc_linux_386.c
@@ -34,7 +34,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 	int err;
 
 	sigfillset(&ign);
-	sigprocmask(SIG_SETMASK, &ign, &oset);
+	pthread_sigmask(SIG_SETMASK, &ign, &oset);
 
 	// Not sure why the memset is necessary here,
 	// but without it, we get a bogus stack size
@@ -46,7 +46,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 	ts->g->stackguard = size;
 	err = pthread_create(&p, &attr, threadentry, ts);
 
-	sigprocmask(SIG_SETMASK, &oset, nil);
+	pthread_sigmask(SIG_SETMASK, &oset, nil);
 
 	if (err != 0) {
 		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_linux_amd64.c b/src/pkg/runtime/cgo/gcc_linux_amd64.c
index bd7c88d..c530183 100644
--- a/src/pkg/runtime/cgo/gcc_linux_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_linux_amd64.c
@@ -34,14 +34,14 @@ _cgo_sys_thread_start(ThreadStart *ts)
 	int err;
 
 	sigfillset(&ign);
-	sigprocmask(SIG_SETMASK, &ign, &oset);
+	pthread_sigmask(SIG_SETMASK, &ign, &oset);
 
 	pthread_attr_init(&attr);
 	pthread_attr_getstacksize(&attr, &size);
 	ts->g->stackguard = size;
 	err = pthread_create(&p, &attr, threadentry, ts);
 
-	sigprocmask(SIG_SETMASK, &oset, nil);
+	pthread_sigmask(SIG_SETMASK, &oset, nil);
 
 	if (err != 0) {
 		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_linux_arm.c b/src/pkg/runtime/cgo/gcc_linux_arm.c
index 9a6e585..0325681 100644
--- a/src/pkg/runtime/cgo/gcc_linux_arm.c
+++ b/src/pkg/runtime/cgo/gcc_linux_arm.c
@@ -4,6 +4,7 @@
 
 #include <pthread.h>
 #include <string.h>
+#include <signal.h>
 #include "libcgo.h"
 
 static void *threadentry(void*);
@@ -28,10 +29,14 @@ void
 _cgo_sys_thread_start(ThreadStart *ts)
 {
 	pthread_attr_t attr;
+	sigset_t ign, oset;
 	pthread_t p;
 	size_t size;
 	int err;
 
+	sigfillset(&ign);
+	pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
 	// Not sure why the memset is necessary here,
 	// but without it, we get a bogus stack size
 	// out of pthread_attr_getstacksize.  C'est la Linux.
@@ -41,6 +46,9 @@ _cgo_sys_thread_start(ThreadStart *ts)
 	pthread_attr_getstacksize(&attr, &size);
 	ts->g->stackguard = size;
 	err = pthread_create(&p, &attr, threadentry, ts);
+
+	pthread_sigmask(SIG_SETMASK, &oset, nil);
+
 	if (err != 0) {
 		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
 		abort();
diff --git a/src/pkg/runtime/cgo/gcc_netbsd_386.c b/src/pkg/runtime/cgo/gcc_netbsd_386.c
index b399e16..28690cc 100644
--- a/src/pkg/runtime/cgo/gcc_netbsd_386.c
+++ b/src/pkg/runtime/cgo/gcc_netbsd_386.c
@@ -35,14 +35,14 @@ _cgo_sys_thread_start(ThreadStart *ts)
 	int err;
 
 	sigfillset(&ign);
-	sigprocmask(SIG_SETMASK, &ign, &oset);
+	pthread_sigmask(SIG_SETMASK, &ign, &oset);
 
 	pthread_attr_init(&attr);
 	pthread_attr_getstacksize(&attr, &size);
 	ts->g->stackguard = size;
 	err = pthread_create(&p, &attr, threadentry, ts);
 
-	sigprocmask(SIG_SETMASK, &oset, nil);
+	pthread_sigmask(SIG_SETMASK, &oset, nil);
 
 	if (err != 0) {
 		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_netbsd_amd64.c b/src/pkg/runtime/cgo/gcc_netbsd_amd64.c
index f27e142..6e0482d 100644
--- a/src/pkg/runtime/cgo/gcc_netbsd_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_netbsd_amd64.c
@@ -35,7 +35,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 	int err;
 
 	sigfillset(&ign);
-	sigprocmask(SIG_SETMASK, &ign, &oset);
+	pthread_sigmask(SIG_SETMASK, &ign, &oset);
 
 	pthread_attr_init(&attr);
 	pthread_attr_getstacksize(&attr, &size);
@@ -43,7 +43,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 	ts->g->stackguard = size;
 	err = pthread_create(&p, &attr, threadentry, ts);
 
-	sigprocmask(SIG_SETMASK, &oset, nil);
+	pthread_sigmask(SIG_SETMASK, &oset, nil);
 
 	if (err != 0) {
 		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_netbsd_arm.c b/src/pkg/runtime/cgo/gcc_netbsd_arm.c
index 68c8b6e..ba2ae25 100644
--- a/src/pkg/runtime/cgo/gcc_netbsd_arm.c
+++ b/src/pkg/runtime/cgo/gcc_netbsd_arm.c
@@ -36,14 +36,14 @@ _cgo_sys_thread_start(ThreadStart *ts)
 	int err;
 
 	sigfillset(&ign);
-	sigprocmask(SIG_SETMASK, &ign, &oset);
+	pthread_sigmask(SIG_SETMASK, &ign, &oset);
 
 	pthread_attr_init(&attr);
 	pthread_attr_getstacksize(&attr, &size);
 	ts->g->stackguard = size;
 	err = pthread_create(&p, &attr, threadentry, ts);
 
-	sigprocmask(SIG_SETMASK, &oset, nil);
+	pthread_sigmask(SIG_SETMASK, &oset, nil);
 
 	if (err != 0) {
 		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_openbsd_386.c b/src/pkg/runtime/cgo/gcc_openbsd_386.c
index 6422d1b..e682c37 100644
--- a/src/pkg/runtime/cgo/gcc_openbsd_386.c
+++ b/src/pkg/runtime/cgo/gcc_openbsd_386.c
@@ -122,14 +122,14 @@ _cgo_sys_thread_start(ThreadStart *ts)
 	int err;
 
 	sigfillset(&ign);
-	sigprocmask(SIG_SETMASK, &ign, &oset);
+	pthread_sigmask(SIG_SETMASK, &ign, &oset);
 
 	pthread_attr_init(&attr);
 	pthread_attr_getstacksize(&attr, &size);
 	ts->g->stackguard = size;
 	err = sys_pthread_create(&p, &attr, threadentry, ts);
 
-	sigprocmask(SIG_SETMASK, &oset, nil);
+	pthread_sigmask(SIG_SETMASK, &oset, nil);
 
 	if (err != 0) {
 		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_openbsd_amd64.c b/src/pkg/runtime/cgo/gcc_openbsd_amd64.c
index 5a5a171..64d29a9 100644
--- a/src/pkg/runtime/cgo/gcc_openbsd_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_openbsd_amd64.c
@@ -122,7 +122,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 	int err;
 
 	sigfillset(&ign);
-	sigprocmask(SIG_SETMASK, &ign, &oset);
+	pthread_sigmask(SIG_SETMASK, &ign, &oset);
 
 	pthread_attr_init(&attr);
 	pthread_attr_getstacksize(&attr, &size);
@@ -130,7 +130,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 	ts->g->stackguard = size;
 	err = sys_pthread_create(&p, &attr, threadentry, ts);
 
-	sigprocmask(SIG_SETMASK, &oset, nil);
+	pthread_sigmask(SIG_SETMASK, &oset, nil);
 
 	if (err != 0) {
 		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
diff --git a/src/pkg/runtime/cgo/gcc_windows_386.c b/src/pkg/runtime/cgo/gcc_windows_386.c
index 02eab12..cdc8664 100644
--- a/src/pkg/runtime/cgo/gcc_windows_386.c
+++ b/src/pkg/runtime/cgo/gcc_windows_386.c
@@ -5,6 +5,8 @@
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include <process.h>
+#include <stdlib.h>
+#include <stdio.h>
 #include "libcgo.h"
 
 static void threadentry(void*);
@@ -25,14 +27,19 @@ x_cgo_init(G *g)
 void
 _cgo_sys_thread_start(ThreadStart *ts)
 {
-	_beginthread(threadentry, 0, ts);
+	uintptr_t thandle;
+
+	thandle = _beginthread(threadentry, 0, ts);
+	if(thandle == -1) {
+		fprintf(stderr, "runtime: failed to create new OS thread (%d)\n", errno);
+		abort();
+	}
 }
 
 static void
 threadentry(void *v)
 {
 	ThreadStart ts;
-	void *tls0;
 
 	ts = *(ThreadStart*)v;
 	free(v);
@@ -43,16 +50,13 @@ threadentry(void *v)
 	/*
 	 * Set specific keys in thread local storage.
 	 */
-	tls0 = (void*)LocalAlloc(LPTR, 32);
 	asm volatile (
 		"movl %0, %%fs:0x14\n"	// MOVL tls0, 0x14(FS)
 		"movl %%fs:0x14, %%eax\n"	// MOVL 0x14(FS), tmp
 		"movl %1, 0(%%eax)\n"	// MOVL g, 0(FS)
 		"movl %2, 4(%%eax)\n"	// MOVL m, 4(FS)
-		:: "r"(tls0), "r"(ts.g), "r"(ts.m) : "%eax"
+		:: "r"(ts.tls), "r"(ts.g), "r"(ts.m) : "%eax"
 	);
 	
 	crosscall_386(ts.fn);
-	
-	LocalFree(tls0);
 }
diff --git a/src/pkg/runtime/cgo/gcc_windows_amd64.c b/src/pkg/runtime/cgo/gcc_windows_amd64.c
index f7695a1..d8dd69b 100644
--- a/src/pkg/runtime/cgo/gcc_windows_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_windows_amd64.c
@@ -5,6 +5,8 @@
 #define WIN64_LEAN_AND_MEAN
 #include <windows.h>
 #include <process.h>
+#include <stdlib.h>
+#include <stdio.h>
 #include "libcgo.h"
 
 static void threadentry(void*);
@@ -25,14 +27,19 @@ x_cgo_init(G *g)
 void
 _cgo_sys_thread_start(ThreadStart *ts)
 {
-	_beginthread(threadentry, 0, ts);
+	uintptr_t thandle;
+
+	thandle = _beginthread(threadentry, 0, ts);
+	if(thandle == -1) {
+		fprintf(stderr, "runtime: failed to create new OS thread (%d)\n", errno);
+		abort();
+	}
 }
 
 static void
 threadentry(void *v)
 {
 	ThreadStart ts;
-	void *tls0;
 
 	ts = *(ThreadStart*)v;
 	free(v);
@@ -43,13 +50,12 @@ threadentry(void *v)
 	/*
 	 * Set specific keys in thread local storage.
 	 */
-	tls0 = (void*)LocalAlloc(LPTR, 64);
 	asm volatile (
 	  "movq %0, %%gs:0x28\n"	// MOVL tls0, 0x28(GS)
 	  "movq %%gs:0x28, %%rax\n" // MOVQ 0x28(GS), tmp
 	  "movq %1, 0(%%rax)\n" // MOVQ g, 0(GS)
 	  "movq %2, 8(%%rax)\n" // MOVQ m, 8(GS)
-	  :: "r"(tls0), "r"(ts.g), "r"(ts.m) : "%rax"
+	  :: "r"(ts.tls), "r"(ts.g), "r"(ts.m) : "%rax"
 	);
 
 	crosscall_amd64(ts.fn);
diff --git a/src/pkg/runtime/cgo/libcgo.h b/src/pkg/runtime/cgo/libcgo.h
index 41a371c..65ea3f3 100644
--- a/src/pkg/runtime/cgo/libcgo.h
+++ b/src/pkg/runtime/cgo/libcgo.h
@@ -34,6 +34,7 @@ struct ThreadStart
 {
 	uintptr m;
 	G *g;
+	uintptr *tls;
 	void (*fn)(void);
 };
 
diff --git a/src/pkg/runtime/cgocall.c b/src/pkg/runtime/cgocall.c
index 2a04453..7b2ec26 100644
--- a/src/pkg/runtime/cgocall.c
+++ b/src/pkg/runtime/cgocall.c
@@ -99,12 +99,7 @@ runtime·cgocall(void (*fn)(void*), void *arg)
 {
 	Defer d;
 
-	if(m->racecall) {
-		runtime·asmcgocall(fn, arg);
-		return;
-	}
-
-	if(!runtime·iscgo && !Windows)
+	if(!runtime·iscgo && !Solaris && !Windows)
 		runtime·throw("cgocall unavailable");
 
 	if(fn == 0)
@@ -127,11 +122,10 @@ runtime·cgocall(void (*fn)(void*), void *arg)
 	d.fn = &endcgoV;
 	d.siz = 0;
 	d.link = g->defer;
-	d.argp = (void*)-1;  // unused because unlockm never recovers
+	d.argp = NoArgs;
 	d.special = true;
-	d.free = false;
 	g->defer = &d;
-
+	
 	m->ncgo++;
 
 	/*
@@ -171,17 +165,6 @@ endcgo(void)
 		runtime·raceacquire(&cgosync);
 }
 
-void
-runtime·NumCgoCall(int64 ret)
-{
-	M *mp;
-
-	ret = 0;
-	for(mp=runtime·atomicloadp(&runtime·allm); mp; mp=mp->alllink)
-		ret += mp->ncgocall;
-	FLUSH(&ret);
-}
-
 // Helper functions for cgo code.
 
 void (*_cgo_malloc)(void*);
@@ -235,6 +218,11 @@ struct CallbackArgs
 #define CBARGS (CallbackArgs*)((byte*)m->g0->sched.sp+2*sizeof(void*))
 #endif
 
+// Unimplemented on amd64p32
+#ifdef GOARCH_amd64p32
+#define CBARGS (CallbackArgs*)(nil)
+#endif
+
 // On 386, stack frame is three words, plus caller PC.
 #ifdef GOARCH_386
 #define CBARGS (CallbackArgs*)((byte*)m->g0->sched.sp+4*sizeof(void*))
@@ -251,21 +239,9 @@ runtime·cgocallbackg(void)
 		runtime·exit(2);
 	}
 
-	if(m->racecall) {
-		// We were not in syscall, so no need to call runtime·exitsyscall.
-		// However we must set m->locks for the following reason.
-		// Race detector runtime makes __tsan_symbolize cgo callback
-		// holding internal mutexes. The mutexes are not cooperative with Go scheduler.
-		// So if we deschedule a goroutine that holds race detector internal mutex
-		// (e.g. preempt it), another goroutine will deadlock trying to acquire the same mutex.
-		m->locks++;
-		runtime·cgocallbackg1();
-		m->locks--;
-	} else {
-		runtime·exitsyscall();	// coming out of cgo call
-		runtime·cgocallbackg1();
-		runtime·entersyscall();	// going back to cgo call
-	}
+	runtime·exitsyscall();	// coming out of cgo call
+	runtime·cgocallbackg1();
+	runtime·entersyscall();	// going back to cgo call
 }
 
 void
@@ -283,19 +259,18 @@ runtime·cgocallbackg1(void)
 	d.fn = &unwindmf;
 	d.siz = 0;
 	d.link = g->defer;
-	d.argp = (void*)-1;  // unused because unwindm never recovers
+	d.argp = NoArgs;
 	d.special = true;
-	d.free = false;
 	g->defer = &d;
 
-	if(raceenabled && !m->racecall)
+	if(raceenabled)
 		runtime·raceacquire(&cgosync);
 
 	// Invoke callback.
 	cb = CBARGS;
 	runtime·newstackcall(cb->fn, cb->arg, cb->argsize);
 
-	if(raceenabled && !m->racecall)
+	if(raceenabled)
 		runtime·racereleasemerge(&cgosync);
 
 	// Pop defer.
diff --git a/src/pkg/runtime/chan.c b/src/pkg/runtime/chan.c
deleted file mode 100644
index 48cc41e..0000000
--- a/src/pkg/runtime/chan.c
+++ /dev/null
@@ -1,1377 +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 "runtime.h"
-#include "arch_GOARCH.h"
-#include "type.h"
-#include "race.h"
-#include "malloc.h"
-#include "../../cmd/ld/textflag.h"
-
-#define	MAXALIGN	8
-#define	NOSELGEN	1
-
-typedef	struct	WaitQ	WaitQ;
-typedef	struct	SudoG	SudoG;
-typedef	struct	Select	Select;
-typedef	struct	Scase	Scase;
-
-struct	SudoG
-{
-	G*	g;		// g and selgen constitute
-	uint32	selgen;		// a weak pointer to g
-	SudoG*	link;
-	int64	releasetime;
-	byte*	elem;		// data element
-};
-
-struct	WaitQ
-{
-	SudoG*	first;
-	SudoG*	last;
-};
-
-// The garbage collector is assuming that Hchan can only contain pointers into the stack
-// and cannot contain pointers into the heap.
-struct	Hchan
-{
-	uintgo	qcount;			// total data in the q
-	uintgo	dataqsiz;		// size of the circular q
-	uint16	elemsize;
-	uint16	pad;			// ensures proper alignment of the buffer that follows Hchan in memory
-	bool	closed;
-	Alg*	elemalg;		// interface for element type
-	uintgo	sendx;			// send index
-	uintgo	recvx;			// receive index
-	WaitQ	recvq;			// list of recv waiters
-	WaitQ	sendq;			// list of send waiters
-	Lock;
-};
-
-uint32 runtime·Hchansize = sizeof(Hchan);
-
-// Buffer follows Hchan immediately in memory.
-// chanbuf(c, i) is pointer to the i'th slot in the buffer.
-#define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i))
-
-enum
-{
-	debug = 0,
-
-	// Scase.kind
-	CaseRecv,
-	CaseSend,
-	CaseDefault,
-};
-
-struct	Scase
-{
-	SudoG	sg;			// must be first member (cast to Scase)
-	Hchan*	chan;			// chan
-	byte*	pc;			// return pc
-	uint16	kind;
-	uint16	so;			// vararg of selected bool
-	bool*	receivedp;		// pointer to received bool (recv2)
-};
-
-struct	Select
-{
-	uint16	tcase;			// total count of scase[]
-	uint16	ncase;			// currently filled scase[]
-	uint16*	pollorder;		// case poll order
-	Hchan**	lockorder;		// channel lock order
-	Scase	scase[1];		// one per case (in order of appearance)
-};
-
-static	void	dequeueg(WaitQ*);
-static	SudoG*	dequeue(WaitQ*);
-static	void	enqueue(WaitQ*, SudoG*);
-static	void	destroychan(Hchan*);
-static	void	racesync(Hchan*, SudoG*);
-
-Hchan*
-runtime·makechan_c(ChanType *t, int64 hint)
-{
-	Hchan *c;
-	Type *elem;
-
-	elem = t->elem;
-
-	// compiler checks this but be safe.
-	if(elem->size >= (1<<16))
-		runtime·throw("makechan: invalid channel element type");
-	if((sizeof(*c)%MAXALIGN) != 0 || elem->align > MAXALIGN)
-		runtime·throw("makechan: bad alignment");
-
-	if(hint < 0 || (intgo)hint != hint || (elem->size > 0 && hint > MaxMem / elem->size))
-		runtime·panicstring("makechan: size out of range");
-
-	// allocate memory in one call
-	c = (Hchan*)runtime·mallocgc(sizeof(*c) + hint*elem->size, (uintptr)t | TypeInfo_Chan, 0);
-	c->elemsize = elem->size;
-	c->elemalg = elem->alg;
-	c->dataqsiz = hint;
-
-	if(debug)
-		runtime·printf("makechan: chan=%p; elemsize=%D; elemalg=%p; dataqsiz=%D\n",
-			c, (int64)elem->size, elem->alg, (int64)c->dataqsiz);
-
-	return c;
-}
-
-// For reflect
-//	func makechan(typ *ChanType, size uint64) (chan)
-void
-reflect·makechan(ChanType *t, uint64 size, Hchan *c)
-{
-	c = runtime·makechan_c(t, size);
-	FLUSH(&c);
-}
-
-// makechan(t *ChanType, hint int64) (hchan *chan any);
-void
-runtime·makechan(ChanType *t, int64 hint, Hchan *ret)
-{
-	ret = runtime·makechan_c(t, hint);
-	FLUSH(&ret);
-}
-
-/*
- * generic single channel send/recv
- * if the bool pointer is nil,
- * then the full exchange will
- * occur. if pres is not nil,
- * then the protocol will not
- * sleep but return if it could
- * not complete.
- *
- * sleep can wake up with g->param == nil
- * when a channel involved in the sleep has
- * been closed.  it is easiest to loop and re-run
- * the operation; we'll see that it's now closed.
- */
-void
-runtime·chansend(ChanType *t, Hchan *c, byte *ep, bool *pres, void *pc)
-{
-	SudoG *sg;
-	SudoG mysg;
-	G* gp;
-	int64 t0;
-
-	if(c == nil) {
-		USED(t);
-		if(pres != nil) {
-			*pres = false;
-			return;
-		}
-		runtime·park(nil, nil, "chan send (nil chan)");
-		return;  // not reached
-	}
-
-	if(debug) {
-		runtime·printf("chansend: chan=%p; elem=", c);
-		c->elemalg->print(c->elemsize, ep);
-		runtime·prints("\n");
-	}
-
-	t0 = 0;
-	mysg.releasetime = 0;
-	if(runtime·blockprofilerate > 0) {
-		t0 = runtime·cputicks();
-		mysg.releasetime = -1;
-	}
-
-	runtime·lock(c);
-	if(raceenabled)
-		runtime·racereadpc(c, pc, runtime·chansend);
-	if(c->closed)
-		goto closed;
-
-	if(c->dataqsiz > 0)
-		goto asynch;
-
-	sg = dequeue(&c->recvq);
-	if(sg != nil) {
-		if(raceenabled)
-			racesync(c, sg);
-		runtime·unlock(c);
-
-		gp = sg->g;
-		gp->param = sg;
-		if(sg->elem != nil)
-			c->elemalg->copy(c->elemsize, sg->elem, ep);
-		if(sg->releasetime)
-			sg->releasetime = runtime·cputicks();
-		runtime·ready(gp);
-
-		if(pres != nil)
-			*pres = true;
-		return;
-	}
-
-	if(pres != nil) {
-		runtime·unlock(c);
-		*pres = false;
-		return;
-	}
-
-	mysg.elem = ep;
-	mysg.g = g;
-	mysg.selgen = NOSELGEN;
-	g->param = nil;
-	enqueue(&c->sendq, &mysg);
-	runtime·park(runtime·unlock, c, "chan send");
-
-	if(g->param == nil) {
-		runtime·lock(c);
-		if(!c->closed)
-			runtime·throw("chansend: spurious wakeup");
-		goto closed;
-	}
-
-	if(mysg.releasetime > 0)
-		runtime·blockevent(mysg.releasetime - t0, 2);
-
-	return;
-
-asynch:
-	if(c->closed)
-		goto closed;
-
-	if(c->qcount >= c->dataqsiz) {
-		if(pres != nil) {
-			runtime·unlock(c);
-			*pres = false;
-			return;
-		}
-		mysg.g = g;
-		mysg.elem = nil;
-		mysg.selgen = NOSELGEN;
-		enqueue(&c->sendq, &mysg);
-		runtime·park(runtime·unlock, c, "chan send");
-
-		runtime·lock(c);
-		goto asynch;
-	}
-
-	if(raceenabled)
-		runtime·racerelease(chanbuf(c, c->sendx));
-
-	c->elemalg->copy(c->elemsize, chanbuf(c, c->sendx), ep);
-	if(++c->sendx == c->dataqsiz)
-		c->sendx = 0;
-	c->qcount++;
-
-	sg = dequeue(&c->recvq);
-	if(sg != nil) {
-		gp = sg->g;
-		runtime·unlock(c);
-		if(sg->releasetime)
-			sg->releasetime = runtime·cputicks();
-		runtime·ready(gp);
-	} else
-		runtime·unlock(c);
-	if(pres != nil)
-		*pres = true;
-	if(mysg.releasetime > 0)
-		runtime·blockevent(mysg.releasetime - t0, 2);
-	return;
-
-closed:
-	runtime·unlock(c);
-	runtime·panicstring("send on closed channel");
-}
-
-
-void
-runtime·chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received)
-{
-	SudoG *sg;
-	SudoG mysg;
-	G *gp;
-	int64 t0;
-
-	if(debug)
-		runtime·printf("chanrecv: chan=%p\n", c);
-
-	if(c == nil) {
-		USED(t);
-		if(selected != nil) {
-			*selected = false;
-			return;
-		}
-		runtime·park(nil, nil, "chan receive (nil chan)");
-		return;  // not reached
-	}
-
-	t0 = 0;
-	mysg.releasetime = 0;
-	if(runtime·blockprofilerate > 0) {
-		t0 = runtime·cputicks();
-		mysg.releasetime = -1;
-	}
-
-	runtime·lock(c);
-	if(c->dataqsiz > 0)
-		goto asynch;
-
-	if(c->closed)
-		goto closed;
-
-	sg = dequeue(&c->sendq);
-	if(sg != nil) {
-		if(raceenabled)
-			racesync(c, sg);
-		runtime·unlock(c);
-
-		if(ep != nil)
-			c->elemalg->copy(c->elemsize, ep, sg->elem);
-		gp = sg->g;
-		gp->param = sg;
-		if(sg->releasetime)
-			sg->releasetime = runtime·cputicks();
-		runtime·ready(gp);
-
-		if(selected != nil)
-			*selected = true;
-		if(received != nil)
-			*received = true;
-		return;
-	}
-
-	if(selected != nil) {
-		runtime·unlock(c);
-		*selected = false;
-		return;
-	}
-
-	mysg.elem = ep;
-	mysg.g = g;
-	mysg.selgen = NOSELGEN;
-	g->param = nil;
-	enqueue(&c->recvq, &mysg);
-	runtime·park(runtime·unlock, c, "chan receive");
-
-	if(g->param == nil) {
-		runtime·lock(c);
-		if(!c->closed)
-			runtime·throw("chanrecv: spurious wakeup");
-		goto closed;
-	}
-
-	if(received != nil)
-		*received = true;
-	if(mysg.releasetime > 0)
-		runtime·blockevent(mysg.releasetime - t0, 2);
-	return;
-
-asynch:
-	if(c->qcount <= 0) {
-		if(c->closed)
-			goto closed;
-
-		if(selected != nil) {
-			runtime·unlock(c);
-			*selected = false;
-			if(received != nil)
-				*received = false;
-			return;
-		}
-		mysg.g = g;
-		mysg.elem = nil;
-		mysg.selgen = NOSELGEN;
-		enqueue(&c->recvq, &mysg);
-		runtime·park(runtime·unlock, c, "chan receive");
-
-		runtime·lock(c);
-		goto asynch;
-	}
-
-	if(raceenabled)
-		runtime·raceacquire(chanbuf(c, c->recvx));
-
-	if(ep != nil)
-		c->elemalg->copy(c->elemsize, ep, chanbuf(c, c->recvx));
-	c->elemalg->copy(c->elemsize, chanbuf(c, c->recvx), nil);
-	if(++c->recvx == c->dataqsiz)
-		c->recvx = 0;
-	c->qcount--;
-
-	sg = dequeue(&c->sendq);
-	if(sg != nil) {
-		gp = sg->g;
-		runtime·unlock(c);
-		if(sg->releasetime)
-			sg->releasetime = runtime·cputicks();
-		runtime·ready(gp);
-	} else
-		runtime·unlock(c);
-
-	if(selected != nil)
-		*selected = true;
-	if(received != nil)
-		*received = true;
-	if(mysg.releasetime > 0)
-		runtime·blockevent(mysg.releasetime - t0, 2);
-	return;
-
-closed:
-	if(ep != nil)
-		c->elemalg->copy(c->elemsize, ep, nil);
-	if(selected != nil)
-		*selected = true;
-	if(received != nil)
-		*received = false;
-	if(raceenabled)
-		runtime·raceacquire(c);
-	runtime·unlock(c);
-	if(mysg.releasetime > 0)
-		runtime·blockevent(mysg.releasetime - t0, 2);
-}
-
-// chansend1(hchan *chan any, elem any);
-#pragma textflag NOSPLIT
-void
-runtime·chansend1(ChanType *t, Hchan* c, ...)
-{
-	runtime·chansend(t, c, (byte*)(&c+1), nil, runtime·getcallerpc(&t));
-}
-
-// chanrecv1(hchan *chan any) (elem any);
-#pragma textflag NOSPLIT
-void
-runtime·chanrecv1(ChanType *t, Hchan* c, ...)
-{
-	runtime·chanrecv(t, c, (byte*)(&c+1), nil, nil);
-}
-
-// chanrecv2(hchan *chan any) (elem any, received bool);
-#pragma textflag NOSPLIT
-void
-runtime·chanrecv2(ChanType *t, Hchan* c, ...)
-{
-	byte *ae, *ap;
-
-	ae = (byte*)(&c+1);
-	ap = ae + t->elem->size;
-	runtime·chanrecv(t, c, ae, nil, ap);
-}
-
-// func selectnbsend(c chan any, elem any) bool
-//
-// compiler implements
-//
-//	select {
-//	case c <- v:
-//		... foo
-//	default:
-//		... bar
-//	}
-//
-// as
-//
-//	if selectnbsend(c, v) {
-//		... foo
-//	} else {
-//		... bar
-//	}
-//
-#pragma textflag NOSPLIT
-void
-runtime·selectnbsend(ChanType *t, Hchan *c, ...)
-{
-	byte *ae, *ap;
-
-	ae = (byte*)(&c + 1);
-	ap = ae + ROUND(t->elem->size, Structrnd);
-	runtime·chansend(t, c, ae, ap, runtime·getcallerpc(&t));
-}
-
-// func selectnbrecv(elem *any, c chan any) bool
-//
-// compiler implements
-//
-//	select {
-//	case v = <-c:
-//		... foo
-//	default:
-//		... bar
-//	}
-//
-// as
-//
-//	if selectnbrecv(&v, c) {
-//		... foo
-//	} else {
-//		... bar
-//	}
-//
-#pragma textflag NOSPLIT
-void
-runtime·selectnbrecv(ChanType *t, byte *v, Hchan *c, bool selected)
-{
-	runtime·chanrecv(t, c, v, &selected, nil);
-}
-
-// func selectnbrecv2(elem *any, ok *bool, c chan any) bool
-//
-// compiler implements
-//
-//	select {
-//	case v, ok = <-c:
-//		... foo
-//	default:
-//		... bar
-//	}
-//
-// as
-//
-//	if c != nil && selectnbrecv2(&v, &ok, c) {
-//		... foo
-//	} else {
-//		... bar
-//	}
-//
-#pragma textflag NOSPLIT
-void
-runtime·selectnbrecv2(ChanType *t, byte *v, bool *received, Hchan *c, bool selected)
-{
-	runtime·chanrecv(t, c, v, &selected, received);
-}
-
-// For reflect:
-//	func chansend(c chan, val iword, nb bool) (selected bool)
-// where an iword is the same word an interface value would use:
-// the actual data if it fits, or else a pointer to the data.
-//
-// The "uintptr selected" is really "bool selected" but saying
-// uintptr gets us the right alignment for the output parameter block.
-#pragma textflag NOSPLIT
-void
-reflect·chansend(ChanType *t, Hchan *c, uintptr val, bool nb, uintptr selected)
-{
-	bool *sp;
-	byte *vp;
-
-	if(nb) {
-		selected = false;
-		sp = (bool*)&selected;
-	} else {
-		*(bool*)&selected = true;
-		FLUSH(&selected);
-		sp = nil;
-	}
-	if(t->elem->size <= sizeof(val))
-		vp = (byte*)&val;
-	else
-		vp = (byte*)val;
-	runtime·chansend(t, c, vp, sp, runtime·getcallerpc(&t));
-}
-
-// For reflect:
-//	func chanrecv(c chan, nb bool) (val iword, selected, received bool)
-// where an iword is the same word an interface value would use:
-// the actual data if it fits, or else a pointer to the data.
-void
-reflect·chanrecv(ChanType *t, Hchan *c, bool nb, uintptr val, bool selected, bool received)
-{
-	byte *vp;
-	bool *sp;
-
-	if(nb) {
-		selected = false;
-		sp = &selected;
-	} else {
-		selected = true;
-		FLUSH(&selected);
-		sp = nil;
-	}
-	received = false;
-	FLUSH(&received);
-	if(t->elem->size <= sizeof(val)) {
-		val = 0;
-		vp = (byte*)&val;
-	} else {
-		vp = runtime·mal(t->elem->size);
-		val = (uintptr)vp;
-		FLUSH(&val);
-	}
-	runtime·chanrecv(t, c, vp, sp, &received);
-}
-
-static void newselect(int32, Select**);
-
-// newselect(size uint32) (sel *byte);
-#pragma textflag NOSPLIT
-void
-runtime·newselect(int32 size, ...)
-{
-	int32 o;
-	Select **selp;
-
-	o = ROUND(sizeof(size), Structrnd);
-	selp = (Select**)((byte*)&size + o);
-	newselect(size, selp);
-}
-
-static void
-newselect(int32 size, Select **selp)
-{
-	int32 n;
-	Select *sel;
-
-	n = 0;
-	if(size > 1)
-		n = size-1;
-
-	// allocate all the memory we need in a single allocation
-	// start with Select with size cases
-	// then lockorder with size entries
-	// then pollorder with size entries
-	sel = runtime·mal(sizeof(*sel) +
-		n*sizeof(sel->scase[0]) +
-		size*sizeof(sel->lockorder[0]) +
-		size*sizeof(sel->pollorder[0]));
-
-	sel->tcase = size;
-	sel->ncase = 0;
-	sel->lockorder = (void*)(sel->scase + size);
-	sel->pollorder = (void*)(sel->lockorder + size);
-	*selp = sel;
-
-	if(debug)
-		runtime·printf("newselect s=%p size=%d\n", sel, size);
-}
-
-// cut in half to give stack a chance to split
-static void selectsend(Select *sel, Hchan *c, void *pc, void *elem, int32 so);
-
-// selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
-#pragma textflag NOSPLIT
-void
-runtime·selectsend(Select *sel, Hchan *c, void *elem, bool selected)
-{
-	selected = false;
-	FLUSH(&selected);
-
-	// nil cases do not compete
-	if(c == nil)
-		return;
-
-	selectsend(sel, c, runtime·getcallerpc(&sel), elem, (byte*)&selected - (byte*)&sel);
-}
-
-static void
-selectsend(Select *sel, Hchan *c, void *pc, void *elem, int32 so)
-{
-	int32 i;
-	Scase *cas;
-
-	i = sel->ncase;
-	if(i >= sel->tcase)
-		runtime·throw("selectsend: too many cases");
-	sel->ncase = i+1;
-	cas = &sel->scase[i];
-
-	cas->pc = pc;
-	cas->chan = c;
-	cas->so = so;
-	cas->kind = CaseSend;
-	cas->sg.elem = elem;
-
-	if(debug)
-		runtime·printf("selectsend s=%p pc=%p chan=%p so=%d\n",
-			sel, cas->pc, cas->chan, cas->so);
-}
-
-// cut in half to give stack a chance to split
-static void selectrecv(Select *sel, Hchan *c, void *pc, void *elem, bool*, int32 so);
-
-// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
-#pragma textflag NOSPLIT
-void
-runtime·selectrecv(Select *sel, Hchan *c, void *elem, bool selected)
-{
-	selected = false;
-	FLUSH(&selected);
-
-	// nil cases do not compete
-	if(c == nil)
-		return;
-
-	selectrecv(sel, c, runtime·getcallerpc(&sel), elem, nil, (byte*)&selected - (byte*)&sel);
-}
-
-// selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
-#pragma textflag NOSPLIT
-void
-runtime·selectrecv2(Select *sel, Hchan *c, void *elem, bool *received, bool selected)
-{
-	selected = false;
-	FLUSH(&selected);
-
-	// nil cases do not compete
-	if(c == nil)
-		return;
-
-	selectrecv(sel, c, runtime·getcallerpc(&sel), elem, received, (byte*)&selected - (byte*)&sel);
-}
-
-static void
-selectrecv(Select *sel, Hchan *c, void *pc, void *elem, bool *received, int32 so)
-{
-	int32 i;
-	Scase *cas;
-
-	i = sel->ncase;
-	if(i >= sel->tcase)
-		runtime·throw("selectrecv: too many cases");
-	sel->ncase = i+1;
-	cas = &sel->scase[i];
-	cas->pc = pc;
-	cas->chan = c;
-
-	cas->so = so;
-	cas->kind = CaseRecv;
-	cas->sg.elem = elem;
-	cas->receivedp = received;
-
-	if(debug)
-		runtime·printf("selectrecv s=%p pc=%p chan=%p so=%d\n",
-			sel, cas->pc, cas->chan, cas->so);
-}
-
-// cut in half to give stack a chance to split
-static void selectdefault(Select*, void*, int32);
-
-// selectdefault(sel *byte) (selected bool);
-#pragma textflag NOSPLIT
-void
-runtime·selectdefault(Select *sel, bool selected)
-{
-	selected = false;
-	FLUSH(&selected);
-
-	selectdefault(sel, runtime·getcallerpc(&sel), (byte*)&selected - (byte*)&sel);
-}
-
-static void
-selectdefault(Select *sel, void *callerpc, int32 so)
-{
-	int32 i;
-	Scase *cas;
-
-	i = sel->ncase;
-	if(i >= sel->tcase)
-		runtime·throw("selectdefault: too many cases");
-	sel->ncase = i+1;
-	cas = &sel->scase[i];
-	cas->pc = callerpc;
-	cas->chan = nil;
-
-	cas->so = so;
-	cas->kind = CaseDefault;
-
-	if(debug)
-		runtime·printf("selectdefault s=%p pc=%p so=%d\n",
-			sel, cas->pc, cas->so);
-}
-
-static void
-sellock(Select *sel)
-{
-	uint32 i;
-	Hchan *c, *c0;
-
-	c = nil;
-	for(i=0; i<sel->ncase; i++) {
-		c0 = sel->lockorder[i];
-		if(c0 && c0 != c) {
-			c = sel->lockorder[i];
-			runtime·lock(c);
-		}
-	}
-}
-
-static void
-selunlock(Select *sel)
-{
-	int32 i, n, r;
-	Hchan *c;
-
-	// We must be very careful here to not touch sel after we have unlocked
-	// the last lock, because sel can be freed right after the last unlock.
-	// Consider the following situation.
-	// First M calls runtime·park() in runtime·selectgo() passing the sel.
-	// Once runtime·park() has unlocked the last lock, another M makes
-	// the G that calls select runnable again and schedules it for execution.
-	// When the G runs on another M, it locks all the locks and frees sel.
-	// Now if the first M touches sel, it will access freed memory.
-	n = (int32)sel->ncase;
-	r = 0;
-	// skip the default case
-	if(n>0 && sel->lockorder[0] == nil)
-		r = 1;
-	for(i = n-1; i >= r; i--) {
-		c = sel->lockorder[i];
-		if(i>0 && sel->lockorder[i-1] == c)
-			continue;  // will unlock it on the next iteration
-		runtime·unlock(c);
-	}
-}
-
-void
-runtime·block(void)
-{
-	runtime·park(nil, nil, "select (no cases)");	// forever
-}
-
-static void* selectgo(Select**);
-
-// selectgo(sel *byte);
-//
-// overwrites return pc on stack to signal which case of the select
-// to run, so cannot appear at the top of a split stack.
-#pragma textflag NOSPLIT
-void
-runtime·selectgo(Select *sel)
-{
-	runtime·setcallerpc(&sel, selectgo(&sel));
-}
-
-static void*
-selectgo(Select **selp)
-{
-	Select *sel;
-	uint32 o, i, j, k;
-	int64 t0;
-	Scase *cas, *dfl;
-	Hchan *c;
-	SudoG *sg;
-	G *gp;
-	byte *as;
-	void *pc;
-
-	sel = *selp;
-
-	if(debug)
-		runtime·printf("select: sel=%p\n", sel);
-
-	t0 = 0;
-	if(runtime·blockprofilerate > 0) {
-		t0 = runtime·cputicks();
-		for(i=0; i<sel->ncase; i++)
-			sel->scase[i].sg.releasetime = -1;
-	}
-
-	// The compiler rewrites selects that statically have
-	// only 0 or 1 cases plus default into simpler constructs.
-	// The only way we can end up with such small sel->ncase
-	// values here is for a larger select in which most channels
-	// have been nilled out.  The general code handles those
-	// cases correctly, and they are rare enough not to bother
-	// optimizing (and needing to test).
-
-	// generate permuted order
-	for(i=0; i<sel->ncase; i++)
-		sel->pollorder[i] = i;
-	for(i=1; i<sel->ncase; i++) {
-		o = sel->pollorder[i];
-		j = runtime·fastrand1()%(i+1);
-		sel->pollorder[i] = sel->pollorder[j];
-		sel->pollorder[j] = o;
-	}
-
-	// sort the cases by Hchan address to get the locking order.
-	// simple heap sort, to guarantee n log n time and constant stack footprint.
-	for(i=0; i<sel->ncase; i++) {
-		j = i;
-		c = sel->scase[j].chan;
-		while(j > 0 && sel->lockorder[k=(j-1)/2] < c) {
-			sel->lockorder[j] = sel->lockorder[k];
-			j = k;
-		}
-		sel->lockorder[j] = c;
-	}
-	for(i=sel->ncase; i-->0; ) {
-		c = sel->lockorder[i];
-		sel->lockorder[i] = sel->lockorder[0];
-		j = 0;
-		for(;;) {
-			k = j*2+1;
-			if(k >= i)
-				break;
-			if(k+1 < i && sel->lockorder[k] < sel->lockorder[k+1])
-				k++;
-			if(c < sel->lockorder[k]) {
-				sel->lockorder[j] = sel->lockorder[k];
-				j = k;
-				continue;
-			}
-			break;
-		}
-		sel->lockorder[j] = c;
-	}
-	/*
-	for(i=0; i+1<sel->ncase; i++)
-		if(sel->lockorder[i] > sel->lockorder[i+1]) {
-			runtime·printf("i=%d %p %p\n", i, sel->lockorder[i], sel->lockorder[i+1]);
-			runtime·throw("select: broken sort");
-		}
-	*/
-	sellock(sel);
-
-loop:
-	// pass 1 - look for something already waiting
-	dfl = nil;
-	for(i=0; i<sel->ncase; i++) {
-		o = sel->pollorder[i];
-		cas = &sel->scase[o];
-		c = cas->chan;
-
-		switch(cas->kind) {
-		case CaseRecv:
-			if(c->dataqsiz > 0) {
-				if(c->qcount > 0)
-					goto asyncrecv;
-			} else {
-				sg = dequeue(&c->sendq);
-				if(sg != nil)
-					goto syncrecv;
-			}
-			if(c->closed)
-				goto rclose;
-			break;
-
-		case CaseSend:
-			if(raceenabled)
-				runtime·racereadpc(c, cas->pc, runtime·chansend);
-			if(c->closed)
-				goto sclose;
-			if(c->dataqsiz > 0) {
-				if(c->qcount < c->dataqsiz)
-					goto asyncsend;
-			} else {
-				sg = dequeue(&c->recvq);
-				if(sg != nil)
-					goto syncsend;
-			}
-			break;
-
-		case CaseDefault:
-			dfl = cas;
-			break;
-		}
-	}
-
-	if(dfl != nil) {
-		selunlock(sel);
-		cas = dfl;
-		goto retc;
-	}
-
-
-	// pass 2 - enqueue on all chans
-	for(i=0; i<sel->ncase; i++) {
-		o = sel->pollorder[i];
-		cas = &sel->scase[o];
-		c = cas->chan;
-		sg = &cas->sg;
-		sg->g = g;
-		sg->selgen = g->selgen;
-
-		switch(cas->kind) {
-		case CaseRecv:
-			enqueue(&c->recvq, sg);
-			break;
-
-		case CaseSend:
-			enqueue(&c->sendq, sg);
-			break;
-		}
-	}
-
-	g->param = nil;
-	runtime·park((void(*)(Lock*))selunlock, (Lock*)sel, "select");
-
-	sellock(sel);
-	sg = g->param;
-
-	// pass 3 - dequeue from unsuccessful chans
-	// otherwise they stack up on quiet channels
-	for(i=0; i<sel->ncase; i++) {
-		cas = &sel->scase[i];
-		if(cas != (Scase*)sg) {
-			c = cas->chan;
-			if(cas->kind == CaseSend)
-				dequeueg(&c->sendq);
-			else
-				dequeueg(&c->recvq);
-		}
-	}
-
-	if(sg == nil)
-		goto loop;
-
-	cas = (Scase*)sg;
-	c = cas->chan;
-
-	if(c->dataqsiz > 0)
-		runtime·throw("selectgo: shouldn't happen");
-
-	if(debug)
-		runtime·printf("wait-return: sel=%p c=%p cas=%p kind=%d\n",
-			sel, c, cas, cas->kind);
-
-	if(cas->kind == CaseRecv) {
-		if(cas->receivedp != nil)
-			*cas->receivedp = true;
-	}
-
-	selunlock(sel);
-	goto retc;
-
-asyncrecv:
-	// can receive from buffer
-	if(raceenabled)
-		runtime·raceacquire(chanbuf(c, c->recvx));
-	if(cas->receivedp != nil)
-		*cas->receivedp = true;
-	if(cas->sg.elem != nil)
-		c->elemalg->copy(c->elemsize, cas->sg.elem, chanbuf(c, c->recvx));
-	c->elemalg->copy(c->elemsize, chanbuf(c, c->recvx), nil);
-	if(++c->recvx == c->dataqsiz)
-		c->recvx = 0;
-	c->qcount--;
-	sg = dequeue(&c->sendq);
-	if(sg != nil) {
-		gp = sg->g;
-		selunlock(sel);
-		if(sg->releasetime)
-			sg->releasetime = runtime·cputicks();
-		runtime·ready(gp);
-	} else {
-		selunlock(sel);
-	}
-	goto retc;
-
-asyncsend:
-	// can send to buffer
-	if(raceenabled)
-		runtime·racerelease(chanbuf(c, c->sendx));
-	c->elemalg->copy(c->elemsize, chanbuf(c, c->sendx), cas->sg.elem);
-	if(++c->sendx == c->dataqsiz)
-		c->sendx = 0;
-	c->qcount++;
-	sg = dequeue(&c->recvq);
-	if(sg != nil) {
-		gp = sg->g;
-		selunlock(sel);
-		if(sg->releasetime)
-			sg->releasetime = runtime·cputicks();
-		runtime·ready(gp);
-	} else {
-		selunlock(sel);
-	}
-	goto retc;
-
-syncrecv:
-	// can receive from sleeping sender (sg)
-	if(raceenabled)
-		racesync(c, sg);
-	selunlock(sel);
-	if(debug)
-		runtime·printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o);
-	if(cas->receivedp != nil)
-		*cas->receivedp = true;
-	if(cas->sg.elem != nil)
-		c->elemalg->copy(c->elemsize, cas->sg.elem, sg->elem);
-	gp = sg->g;
-	gp->param = sg;
-	if(sg->releasetime)
-		sg->releasetime = runtime·cputicks();
-	runtime·ready(gp);
-	goto retc;
-
-rclose:
-	// read at end of closed channel
-	selunlock(sel);
-	if(cas->receivedp != nil)
-		*cas->receivedp = false;
-	if(cas->sg.elem != nil)
-		c->elemalg->copy(c->elemsize, cas->sg.elem, nil);
-	if(raceenabled)
-		runtime·raceacquire(c);
-	goto retc;
-
-syncsend:
-	// can send to sleeping receiver (sg)
-	if(raceenabled)
-		racesync(c, sg);
-	selunlock(sel);
-	if(debug)
-		runtime·printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o);
-	if(sg->elem != nil)
-		c->elemalg->copy(c->elemsize, sg->elem, cas->sg.elem);
-	gp = sg->g;
-	gp->param = sg;
-	if(sg->releasetime)
-		sg->releasetime = runtime·cputicks();
-	runtime·ready(gp);
-
-retc:
-	// return pc corresponding to chosen case.
-	// Set boolean passed during select creation
-	// (at offset selp + cas->so) to true.
-	// If cas->so == 0, this is a reflect-driven select and we
-	// don't need to update the boolean.
-	pc = cas->pc;
-	if(cas->so > 0) {
-		as = (byte*)selp + cas->so;
-		*as = true;
-	}
-	if(cas->sg.releasetime > 0)
-		runtime·blockevent(cas->sg.releasetime - t0, 2);
-	runtime·free(sel);
-	return pc;
-
-sclose:
-	// send on closed channel
-	selunlock(sel);
-	runtime·panicstring("send on closed channel");
-	return nil;  // not reached
-}
-
-// This struct must match ../reflect/value.go:/runtimeSelect.
-typedef struct runtimeSelect runtimeSelect;
-struct runtimeSelect
-{
-	uintptr dir;
-	ChanType *typ;
-	Hchan *ch;
-	uintptr val;
-};
-
-// This enum must match ../reflect/value.go:/SelectDir.
-enum SelectDir {
-	SelectSend = 1,
-	SelectRecv,
-	SelectDefault,
-};
-
-// func rselect(cases []runtimeSelect) (chosen int, word uintptr, recvOK bool)
-void
-reflect·rselect(Slice cases, intgo chosen, uintptr word, bool recvOK)
-{
-	int32 i;
-	Select *sel;
-	runtimeSelect* rcase, *rc;
-	void *elem;
-	void *recvptr;
-	uintptr maxsize;
-
-	chosen = -1;
-	word = 0;
-	recvOK = false;
-
-	maxsize = 0;
-	rcase = (runtimeSelect*)cases.array;
-	for(i=0; i<cases.len; i++) {
-		rc = &rcase[i];
-		if(rc->dir == SelectRecv && rc->ch != nil && maxsize < rc->typ->elem->size)
-			maxsize = rc->typ->elem->size;
-	}
-
-	recvptr = nil;
-	if(maxsize > sizeof(void*))
-		recvptr = runtime·mal(maxsize);
-
-	newselect(cases.len, &sel);
-	for(i=0; i<cases.len; i++) {
-		rc = &rcase[i];
-		switch(rc->dir) {
-		case SelectDefault:
-			selectdefault(sel, (void*)i, 0);
-			break;
-		case SelectSend:
-			if(rc->ch == nil)
-				break;
-			if(rc->typ->elem->size > sizeof(void*))
-				elem = (void*)rc->val;
-			else
-				elem = (void*)&rc->val;
-			selectsend(sel, rc->ch, (void*)i, elem, 0);
-			break;
-		case SelectRecv:
-			if(rc->ch == nil)
-				break;
-			if(rc->typ->elem->size > sizeof(void*))
-				elem = recvptr;
-			else
-				elem = &word;
-			selectrecv(sel, rc->ch, (void*)i, elem, &recvOK, 0);
-			break;
-		}
-	}
-
-	chosen = (intgo)(uintptr)selectgo(&sel);
-	if(rcase[chosen].dir == SelectRecv && rcase[chosen].typ->elem->size > sizeof(void*))
-		word = (uintptr)recvptr;
-
-	FLUSH(&chosen);
-	FLUSH(&word);
-	FLUSH(&recvOK);
-}
-
-static void closechan(Hchan *c, void *pc);
-
-// closechan(sel *byte);
-#pragma textflag NOSPLIT
-void
-runtime·closechan(Hchan *c)
-{
-	closechan(c, runtime·getcallerpc(&c));
-}
-
-// For reflect
-//	func chanclose(c chan)
-#pragma textflag NOSPLIT
-void
-reflect·chanclose(Hchan *c)
-{
-	closechan(c, runtime·getcallerpc(&c));
-}
-
-static void
-closechan(Hchan *c, void *pc)
-{
-	SudoG *sg;
-	G* gp;
-
-	if(c == nil)
-		runtime·panicstring("close of nil channel");
-
-	runtime·lock(c);
-	if(c->closed) {
-		runtime·unlock(c);
-		runtime·panicstring("close of closed channel");
-	}
-
-	if(raceenabled) {
-		runtime·racewritepc(c, pc, runtime·closechan);
-		runtime·racerelease(c);
-	}
-
-	c->closed = true;
-
-	// release all readers
-	for(;;) {
-		sg = dequeue(&c->recvq);
-		if(sg == nil)
-			break;
-		gp = sg->g;
-		gp->param = nil;
-		if(sg->releasetime)
-			sg->releasetime = runtime·cputicks();
-		runtime·ready(gp);
-	}
-
-	// release all writers
-	for(;;) {
-		sg = dequeue(&c->sendq);
-		if(sg == nil)
-			break;
-		gp = sg->g;
-		gp->param = nil;
-		if(sg->releasetime)
-			sg->releasetime = runtime·cputicks();
-		runtime·ready(gp);
-	}
-
-	runtime·unlock(c);
-}
-
-// For reflect
-//	func chanlen(c chan) (len int)
-void
-reflect·chanlen(Hchan *c, intgo len)
-{
-	if(c == nil)
-		len = 0;
-	else
-		len = c->qcount;
-	FLUSH(&len);
-}
-
-// For reflect
-//	func chancap(c chan) int
-void
-reflect·chancap(Hchan *c, intgo cap)
-{
-	if(c == nil)
-		cap = 0;
-	else
-		cap = c->dataqsiz;
-	FLUSH(&cap);
-}
-
-static SudoG*
-dequeue(WaitQ *q)
-{
-	SudoG *sgp;
-
-loop:
-	sgp = q->first;
-	if(sgp == nil)
-		return nil;
-	q->first = sgp->link;
-
-	// if sgp is stale, ignore it
-	if(sgp->selgen != NOSELGEN &&
-		(sgp->selgen != sgp->g->selgen ||
-		!runtime·cas(&sgp->g->selgen, sgp->selgen, sgp->selgen + 2))) {
-		//prints("INVALID PSEUDOG POINTER\n");
-		goto loop;
-	}
-
-	return sgp;
-}
-
-static void
-dequeueg(WaitQ *q)
-{
-	SudoG **l, *sgp, *prevsgp;
-
-	prevsgp = nil;
-	for(l=&q->first; (sgp=*l) != nil; l=&sgp->link, prevsgp=sgp) {
-		if(sgp->g == g) {
-			*l = sgp->link;
-			if(q->last == sgp)
-				q->last = prevsgp;
-			break;
-		}
-	}
-}
-
-static void
-enqueue(WaitQ *q, SudoG *sgp)
-{
-	sgp->link = nil;
-	if(q->first == nil) {
-		q->first = sgp;
-		q->last = sgp;
-		return;
-	}
-	q->last->link = sgp;
-	q->last = sgp;
-}
-
-static void
-racesync(Hchan *c, SudoG *sg)
-{
-	runtime·racerelease(chanbuf(c, 0));
-	runtime·raceacquireg(sg->g, chanbuf(c, 0));
-	runtime·racereleaseg(sg->g, chanbuf(c, 0));
-	runtime·raceacquire(chanbuf(c, 0));
-}
diff --git a/src/pkg/runtime/chan.goc b/src/pkg/runtime/chan.goc
new file mode 100644
index 0000000..7a58471
--- /dev/null
+++ b/src/pkg/runtime/chan.goc
@@ -0,0 +1,1155 @@
+// 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.
+
+package runtime
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "type.h"
+#include "race.h"
+#include "malloc.h"
+#include "chan.h"
+#include "../../cmd/ld/textflag.h"
+
+uint32 runtime·Hchansize = sizeof(Hchan);
+
+static	void	dequeueg(WaitQ*);
+static	SudoG*	dequeue(WaitQ*);
+static	void	enqueue(WaitQ*, SudoG*);
+static	void	destroychan(Hchan*);
+static	void	racesync(Hchan*, SudoG*);
+
+static Hchan*
+makechan(ChanType *t, int64 hint)
+{
+	Hchan *c;
+	Type *elem;
+
+	elem = t->elem;
+
+	// compiler checks this but be safe.
+	if(elem->size >= (1<<16))
+		runtime·throw("makechan: invalid channel element type");
+	if((sizeof(*c)%MAXALIGN) != 0 || elem->align > MAXALIGN)
+		runtime·throw("makechan: bad alignment");
+
+	if(hint < 0 || (intgo)hint != hint || (elem->size > 0 && hint > (MaxMem - sizeof(*c)) / elem->size))
+		runtime·panicstring("makechan: size out of range");
+
+	// allocate memory in one call
+	c = (Hchan*)runtime·mallocgc(sizeof(*c) + hint*elem->size, (uintptr)t | TypeInfo_Chan, 0);
+	c->elemsize = elem->size;
+	c->elemtype = elem;
+	c->dataqsiz = hint;
+
+	if(debug)
+		runtime·printf("makechan: chan=%p; elemsize=%D; elemalg=%p; dataqsiz=%D\n",
+			c, (int64)elem->size, elem->alg, (int64)c->dataqsiz);
+
+	return c;
+}
+
+func reflect·makechan(t *ChanType, size uint64) (c *Hchan) {
+	c = makechan(t, size);
+}
+
+func makechan(t *ChanType, size int64) (c *Hchan) {
+	c = makechan(t, size);
+}
+
+/*
+ * generic single channel send/recv
+ * if the bool pointer is nil,
+ * then the full exchange will
+ * occur. if pres is not nil,
+ * then the protocol will not
+ * sleep but return if it could
+ * not complete.
+ *
+ * sleep can wake up with g->param == nil
+ * when a channel involved in the sleep has
+ * been closed.  it is easiest to loop and re-run
+ * the operation; we'll see that it's now closed.
+ */
+static bool
+chansend(ChanType *t, Hchan *c, byte *ep, bool block, void *pc)
+{
+	SudoG *sg;
+	SudoG mysg;
+	G* gp;
+	int64 t0;
+
+	if(raceenabled)
+		runtime·racereadobjectpc(ep, t->elem, runtime·getcallerpc(&t), chansend);
+
+	if(c == nil) {
+		USED(t);
+		if(!block)
+			return false;
+		runtime·park(nil, nil, "chan send (nil chan)");
+		return false;  // not reached
+	}
+
+	if(debug) {
+		runtime·printf("chansend: chan=%p; elem=", c);
+		c->elemtype->alg->print(c->elemsize, ep);
+		runtime·prints("\n");
+	}
+
+	t0 = 0;
+	mysg.releasetime = 0;
+	if(runtime·blockprofilerate > 0) {
+		t0 = runtime·cputicks();
+		mysg.releasetime = -1;
+	}
+
+	runtime·lock(c);
+	if(raceenabled)
+		runtime·racereadpc(c, pc, chansend);
+	if(c->closed)
+		goto closed;
+
+	if(c->dataqsiz > 0)
+		goto asynch;
+
+	sg = dequeue(&c->recvq);
+	if(sg != nil) {
+		if(raceenabled)
+			racesync(c, sg);
+		runtime·unlock(c);
+
+		gp = sg->g;
+		gp->param = sg;
+		if(sg->elem != nil)
+			c->elemtype->alg->copy(c->elemsize, sg->elem, ep);
+		if(sg->releasetime)
+			sg->releasetime = runtime·cputicks();
+		runtime·ready(gp);
+		return true;
+	}
+
+	if(!block) {
+		runtime·unlock(c);
+		return false;
+	}
+
+	mysg.elem = ep;
+	mysg.g = g;
+	mysg.selectdone = nil;
+	g->param = nil;
+	enqueue(&c->sendq, &mysg);
+	runtime·parkunlock(c, "chan send");
+
+	if(g->param == nil) {
+		runtime·lock(c);
+		if(!c->closed)
+			runtime·throw("chansend: spurious wakeup");
+		goto closed;
+	}
+
+	if(mysg.releasetime > 0)
+		runtime·blockevent(mysg.releasetime - t0, 2);
+
+	return true;
+
+asynch:
+	if(c->closed)
+		goto closed;
+
+	if(c->qcount >= c->dataqsiz) {
+		if(!block) {
+			runtime·unlock(c);
+			return false;
+		}
+		mysg.g = g;
+		mysg.elem = nil;
+		mysg.selectdone = nil;
+		enqueue(&c->sendq, &mysg);
+		runtime·parkunlock(c, "chan send");
+
+		runtime·lock(c);
+		goto asynch;
+	}
+
+	if(raceenabled) {
+		runtime·raceacquire(chanbuf(c, c->sendx));
+		runtime·racerelease(chanbuf(c, c->sendx));
+	}
+
+	c->elemtype->alg->copy(c->elemsize, chanbuf(c, c->sendx), ep);
+	if(++c->sendx == c->dataqsiz)
+		c->sendx = 0;
+	c->qcount++;
+
+	sg = dequeue(&c->recvq);
+	if(sg != nil) {
+		gp = sg->g;
+		runtime·unlock(c);
+		if(sg->releasetime)
+			sg->releasetime = runtime·cputicks();
+		runtime·ready(gp);
+	} else
+		runtime·unlock(c);
+	if(mysg.releasetime > 0)
+		runtime·blockevent(mysg.releasetime - t0, 2);
+	return true;
+
+closed:
+	runtime·unlock(c);
+	runtime·panicstring("send on closed channel");
+	return false;  // not reached
+}
+
+
+static bool
+chanrecv(ChanType *t, Hchan* c, byte *ep, bool block, bool *received)
+{
+	SudoG *sg;
+	SudoG mysg;
+	G *gp;
+	int64 t0;
+
+	// raceenabled: don't need to check ep, as it is always on the stack.
+
+	if(debug)
+		runtime·printf("chanrecv: chan=%p\n", c);
+
+	if(c == nil) {
+		USED(t);
+		if(!block)
+			return false;
+		runtime·park(nil, nil, "chan receive (nil chan)");
+		return false;  // not reached
+	}
+
+	t0 = 0;
+	mysg.releasetime = 0;
+	if(runtime·blockprofilerate > 0) {
+		t0 = runtime·cputicks();
+		mysg.releasetime = -1;
+	}
+
+	runtime·lock(c);
+	if(c->dataqsiz > 0)
+		goto asynch;
+
+	if(c->closed)
+		goto closed;
+
+	sg = dequeue(&c->sendq);
+	if(sg != nil) {
+		if(raceenabled)
+			racesync(c, sg);
+		runtime·unlock(c);
+
+		if(ep != nil)
+			c->elemtype->alg->copy(c->elemsize, ep, sg->elem);
+		gp = sg->g;
+		gp->param = sg;
+		if(sg->releasetime)
+			sg->releasetime = runtime·cputicks();
+		runtime·ready(gp);
+
+		if(received != nil)
+			*received = true;
+		return true;
+	}
+
+	if(!block) {
+		runtime·unlock(c);
+		return false;
+	}
+
+	mysg.elem = ep;
+	mysg.g = g;
+	mysg.selectdone = nil;
+	g->param = nil;
+	enqueue(&c->recvq, &mysg);
+	runtime·parkunlock(c, "chan receive");
+
+	if(g->param == nil) {
+		runtime·lock(c);
+		if(!c->closed)
+			runtime·throw("chanrecv: spurious wakeup");
+		goto closed;
+	}
+
+	if(received != nil)
+		*received = true;
+	if(mysg.releasetime > 0)
+		runtime·blockevent(mysg.releasetime - t0, 2);
+	return true;
+
+asynch:
+	if(c->qcount <= 0) {
+		if(c->closed)
+			goto closed;
+
+		if(!block) {
+			runtime·unlock(c);
+			if(received != nil)
+				*received = false;
+			return false;
+		}
+		mysg.g = g;
+		mysg.elem = nil;
+		mysg.selectdone = nil;
+		enqueue(&c->recvq, &mysg);
+		runtime·parkunlock(c, "chan receive");
+
+		runtime·lock(c);
+		goto asynch;
+	}
+
+	if(raceenabled) {
+		runtime·raceacquire(chanbuf(c, c->recvx));
+		runtime·racerelease(chanbuf(c, c->recvx));
+	}
+
+	if(ep != nil)
+		c->elemtype->alg->copy(c->elemsize, ep, chanbuf(c, c->recvx));
+	c->elemtype->alg->copy(c->elemsize, chanbuf(c, c->recvx), nil);
+	if(++c->recvx == c->dataqsiz)
+		c->recvx = 0;
+	c->qcount--;
+
+	sg = dequeue(&c->sendq);
+	if(sg != nil) {
+		gp = sg->g;
+		runtime·unlock(c);
+		if(sg->releasetime)
+			sg->releasetime = runtime·cputicks();
+		runtime·ready(gp);
+	} else
+		runtime·unlock(c);
+
+	if(received != nil)
+		*received = true;
+	if(mysg.releasetime > 0)
+		runtime·blockevent(mysg.releasetime - t0, 2);
+	return true;
+
+closed:
+	if(ep != nil)
+		c->elemtype->alg->copy(c->elemsize, ep, nil);
+	if(received != nil)
+		*received = false;
+	if(raceenabled)
+		runtime·raceacquire(c);
+	runtime·unlock(c);
+	if(mysg.releasetime > 0)
+		runtime·blockevent(mysg.releasetime - t0, 2);
+	return true;
+}
+
+#pragma textflag NOSPLIT
+func chansend1(t *ChanType, c *Hchan, elem *byte) {
+	chansend(t, c, elem, true, runtime·getcallerpc(&t));
+}
+
+#pragma textflag NOSPLIT
+func chanrecv1(t *ChanType, c *Hchan, elem *byte) {
+	chanrecv(t, c, elem, true, nil);
+}
+
+// chanrecv2(hchan *chan any, elem *any) (received bool);
+#pragma textflag NOSPLIT
+func chanrecv2(t *ChanType, c *Hchan, elem *byte) (received bool) {
+	chanrecv(t, c, elem, true, &received);
+}
+
+// compiler implements
+//
+//	select {
+//	case c <- v:
+//		... foo
+//	default:
+//		... bar
+//	}
+//
+// as
+//
+//	if selectnbsend(c, v) {
+//		... foo
+//	} else {
+//		... bar
+//	}
+//
+#pragma textflag NOSPLIT
+func selectnbsend(t *ChanType, c *Hchan, elem *byte) (selected bool) {
+	selected = chansend(t, c, elem, false, runtime·getcallerpc(&t));
+}
+
+// compiler implements
+//
+//	select {
+//	case v = <-c:
+//		... foo
+//	default:
+//		... bar
+//	}
+//
+// as
+//
+//	if selectnbrecv(&v, c) {
+//		... foo
+//	} else {
+//		... bar
+//	}
+//
+#pragma textflag NOSPLIT
+func selectnbrecv(t *ChanType, elem *byte, c *Hchan) (selected bool) {
+	selected = chanrecv(t, c, elem, false, nil);
+}
+
+// compiler implements
+//
+//	select {
+//	case v, ok = <-c:
+//		... foo
+//	default:
+//		... bar
+//	}
+//
+// as
+//
+//	if c != nil && selectnbrecv2(&v, &ok, c) {
+//		... foo
+//	} else {
+//		... bar
+//	}
+//
+#pragma textflag NOSPLIT
+func selectnbrecv2(t *ChanType, elem *byte, received *bool, c *Hchan) (selected bool) {
+	selected = chanrecv(t, c, elem, false, received);
+}
+
+#pragma textflag NOSPLIT
+func reflect·chansend(t *ChanType, c *Hchan, elem *byte, nb bool) (selected bool) {
+	selected = chansend(t, c, elem, !nb, runtime·getcallerpc(&t));
+}
+
+func reflect·chanrecv(t *ChanType, c *Hchan, nb bool, elem *byte) (selected bool, received bool) {
+	received = false;
+	selected = chanrecv(t, c, elem, !nb, &received);
+}
+
+static Select* newselect(int32);
+
+#pragma textflag NOSPLIT
+func newselect(size int32) (sel *byte) {
+	sel = (byte*)newselect(size);
+}
+
+static Select*
+newselect(int32 size)
+{
+	int32 n;
+	Select *sel;
+
+	n = 0;
+	if(size > 1)
+		n = size-1;
+
+	// allocate all the memory we need in a single allocation
+	// start with Select with size cases
+	// then lockorder with size entries
+	// then pollorder with size entries
+	sel = runtime·mal(sizeof(*sel) +
+		n*sizeof(sel->scase[0]) +
+		size*sizeof(sel->lockorder[0]) +
+		size*sizeof(sel->pollorder[0]));
+
+	sel->tcase = size;
+	sel->ncase = 0;
+	sel->lockorder = (void*)(sel->scase + size);
+	sel->pollorder = (void*)(sel->lockorder + size);
+
+	if(debug)
+		runtime·printf("newselect s=%p size=%d\n", sel, size);
+	return sel;
+}
+
+// cut in half to give stack a chance to split
+static void selectsend(Select *sel, Hchan *c, void *pc, void *elem, int32 so);
+
+#pragma textflag NOSPLIT
+func selectsend(sel *Select, c *Hchan, elem *byte) (selected bool) {
+	selected = false;
+
+	// nil cases do not compete
+	if(c != nil)
+		selectsend(sel, c, runtime·getcallerpc(&sel), elem, (byte*)&selected - (byte*)&sel);
+}
+
+static void
+selectsend(Select *sel, Hchan *c, void *pc, void *elem, int32 so)
+{
+	int32 i;
+	Scase *cas;
+
+	i = sel->ncase;
+	if(i >= sel->tcase)
+		runtime·throw("selectsend: too many cases");
+	sel->ncase = i+1;
+	cas = &sel->scase[i];
+
+	cas->pc = pc;
+	cas->chan = c;
+	cas->so = so;
+	cas->kind = CaseSend;
+	cas->sg.elem = elem;
+
+	if(debug)
+		runtime·printf("selectsend s=%p pc=%p chan=%p so=%d\n",
+			sel, cas->pc, cas->chan, cas->so);
+}
+
+// cut in half to give stack a chance to split
+static void selectrecv(Select *sel, Hchan *c, void *pc, void *elem, bool*, int32 so);
+
+#pragma textflag NOSPLIT
+func selectrecv(sel *Select, c *Hchan, elem *byte) (selected bool) {
+	selected = false;
+
+	// nil cases do not compete
+	if(c != nil)
+		selectrecv(sel, c, runtime·getcallerpc(&sel), elem, nil, (byte*)&selected - (byte*)&sel);
+}
+
+#pragma textflag NOSPLIT
+func selectrecv2(sel *Select, c *Hchan, elem *byte, received *bool) (selected bool) {
+	selected = false;
+
+	// nil cases do not compete
+	if(c != nil)
+		selectrecv(sel, c, runtime·getcallerpc(&sel), elem, received, (byte*)&selected - (byte*)&sel);
+}
+
+static void
+selectrecv(Select *sel, Hchan *c, void *pc, void *elem, bool *received, int32 so)
+{
+	int32 i;
+	Scase *cas;
+
+	i = sel->ncase;
+	if(i >= sel->tcase)
+		runtime·throw("selectrecv: too many cases");
+	sel->ncase = i+1;
+	cas = &sel->scase[i];
+	cas->pc = pc;
+	cas->chan = c;
+
+	cas->so = so;
+	cas->kind = CaseRecv;
+	cas->sg.elem = elem;
+	cas->receivedp = received;
+
+	if(debug)
+		runtime·printf("selectrecv s=%p pc=%p chan=%p so=%d\n",
+			sel, cas->pc, cas->chan, cas->so);
+}
+
+// cut in half to give stack a chance to split
+static void selectdefault(Select*, void*, int32);
+
+#pragma textflag NOSPLIT
+func selectdefault(sel *Select) (selected bool) {
+	selected = false;
+	selectdefault(sel, runtime·getcallerpc(&sel), (byte*)&selected - (byte*)&sel);
+}
+
+static void
+selectdefault(Select *sel, void *callerpc, int32 so)
+{
+	int32 i;
+	Scase *cas;
+
+	i = sel->ncase;
+	if(i >= sel->tcase)
+		runtime·throw("selectdefault: too many cases");
+	sel->ncase = i+1;
+	cas = &sel->scase[i];
+	cas->pc = callerpc;
+	cas->chan = nil;
+
+	cas->so = so;
+	cas->kind = CaseDefault;
+
+	if(debug)
+		runtime·printf("selectdefault s=%p pc=%p so=%d\n",
+			sel, cas->pc, cas->so);
+}
+
+static void
+sellock(Select *sel)
+{
+	uint32 i;
+	Hchan *c, *c0;
+
+	c = nil;
+	for(i=0; i<sel->ncase; i++) {
+		c0 = sel->lockorder[i];
+		if(c0 && c0 != c) {
+			c = sel->lockorder[i];
+			runtime·lock(c);
+		}
+	}
+}
+
+static void
+selunlock(Select *sel)
+{
+	int32 i, n, r;
+	Hchan *c;
+
+	// We must be very careful here to not touch sel after we have unlocked
+	// the last lock, because sel can be freed right after the last unlock.
+	// Consider the following situation.
+	// First M calls runtime·park() in runtime·selectgo() passing the sel.
+	// Once runtime·park() has unlocked the last lock, another M makes
+	// the G that calls select runnable again and schedules it for execution.
+	// When the G runs on another M, it locks all the locks and frees sel.
+	// Now if the first M touches sel, it will access freed memory.
+	n = (int32)sel->ncase;
+	r = 0;
+	// skip the default case
+	if(n>0 && sel->lockorder[0] == nil)
+		r = 1;
+	for(i = n-1; i >= r; i--) {
+		c = sel->lockorder[i];
+		if(i>0 && sel->lockorder[i-1] == c)
+			continue;  // will unlock it on the next iteration
+		runtime·unlock(c);
+	}
+}
+
+static bool
+selparkcommit(G *gp, void *sel)
+{
+	USED(gp);
+	selunlock(sel);
+	return true;
+}
+
+func block() {
+	runtime·park(nil, nil, "select (no cases)");	// forever
+}
+
+static void* selectgo(Select**);
+
+// selectgo(sel *byte);
+//
+// overwrites return pc on stack to signal which case of the select
+// to run, so cannot appear at the top of a split stack.
+#pragma textflag NOSPLIT
+func selectgo(sel *Select) {
+	runtime·setcallerpc(&sel, selectgo(&sel));
+}
+
+static void*
+selectgo(Select **selp)
+{
+	Select *sel;
+	uint32 o, i, j, k, done;
+	int64 t0;
+	Scase *cas, *dfl;
+	Hchan *c;
+	SudoG *sg;
+	G *gp;
+	byte *as;
+	void *pc;
+
+	sel = *selp;
+
+	if(debug)
+		runtime·printf("select: sel=%p\n", sel);
+
+	t0 = 0;
+	if(runtime·blockprofilerate > 0) {
+		t0 = runtime·cputicks();
+		for(i=0; i<sel->ncase; i++)
+			sel->scase[i].sg.releasetime = -1;
+	}
+
+	// The compiler rewrites selects that statically have
+	// only 0 or 1 cases plus default into simpler constructs.
+	// The only way we can end up with such small sel->ncase
+	// values here is for a larger select in which most channels
+	// have been nilled out.  The general code handles those
+	// cases correctly, and they are rare enough not to bother
+	// optimizing (and needing to test).
+
+	// generate permuted order
+	for(i=0; i<sel->ncase; i++)
+		sel->pollorder[i] = i;
+	for(i=1; i<sel->ncase; i++) {
+		o = sel->pollorder[i];
+		j = runtime·fastrand1()%(i+1);
+		sel->pollorder[i] = sel->pollorder[j];
+		sel->pollorder[j] = o;
+	}
+
+	// sort the cases by Hchan address to get the locking order.
+	// simple heap sort, to guarantee n log n time and constant stack footprint.
+	for(i=0; i<sel->ncase; i++) {
+		j = i;
+		c = sel->scase[j].chan;
+		while(j > 0 && sel->lockorder[k=(j-1)/2] < c) {
+			sel->lockorder[j] = sel->lockorder[k];
+			j = k;
+		}
+		sel->lockorder[j] = c;
+	}
+	for(i=sel->ncase; i-->0; ) {
+		c = sel->lockorder[i];
+		sel->lockorder[i] = sel->lockorder[0];
+		j = 0;
+		for(;;) {
+			k = j*2+1;
+			if(k >= i)
+				break;
+			if(k+1 < i && sel->lockorder[k] < sel->lockorder[k+1])
+				k++;
+			if(c < sel->lockorder[k]) {
+				sel->lockorder[j] = sel->lockorder[k];
+				j = k;
+				continue;
+			}
+			break;
+		}
+		sel->lockorder[j] = c;
+	}
+	/*
+	for(i=0; i+1<sel->ncase; i++)
+		if(sel->lockorder[i] > sel->lockorder[i+1]) {
+			runtime·printf("i=%d %p %p\n", i, sel->lockorder[i], sel->lockorder[i+1]);
+			runtime·throw("select: broken sort");
+		}
+	*/
+	sellock(sel);
+
+loop:
+	// pass 1 - look for something already waiting
+	dfl = nil;
+	for(i=0; i<sel->ncase; i++) {
+		o = sel->pollorder[i];
+		cas = &sel->scase[o];
+		c = cas->chan;
+
+		switch(cas->kind) {
+		case CaseRecv:
+			if(c->dataqsiz > 0) {
+				if(c->qcount > 0)
+					goto asyncrecv;
+			} else {
+				sg = dequeue(&c->sendq);
+				if(sg != nil)
+					goto syncrecv;
+			}
+			if(c->closed)
+				goto rclose;
+			break;
+
+		case CaseSend:
+			if(raceenabled)
+				runtime·racereadpc(c, cas->pc, chansend);
+			if(c->closed)
+				goto sclose;
+			if(c->dataqsiz > 0) {
+				if(c->qcount < c->dataqsiz)
+					goto asyncsend;
+			} else {
+				sg = dequeue(&c->recvq);
+				if(sg != nil)
+					goto syncsend;
+			}
+			break;
+
+		case CaseDefault:
+			dfl = cas;
+			break;
+		}
+	}
+
+	if(dfl != nil) {
+		selunlock(sel);
+		cas = dfl;
+		goto retc;
+	}
+
+
+	// pass 2 - enqueue on all chans
+	done = 0;
+	for(i=0; i<sel->ncase; i++) {
+		o = sel->pollorder[i];
+		cas = &sel->scase[o];
+		c = cas->chan;
+		sg = &cas->sg;
+		sg->g = g;
+		sg->selectdone = &done;
+
+		switch(cas->kind) {
+		case CaseRecv:
+			enqueue(&c->recvq, sg);
+			break;
+
+		case CaseSend:
+			enqueue(&c->sendq, sg);
+			break;
+		}
+	}
+
+	g->param = nil;
+	runtime·park(selparkcommit, sel, "select");
+
+	sellock(sel);
+	sg = g->param;
+
+	// pass 3 - dequeue from unsuccessful chans
+	// otherwise they stack up on quiet channels
+	for(i=0; i<sel->ncase; i++) {
+		cas = &sel->scase[i];
+		if(cas != (Scase*)sg) {
+			c = cas->chan;
+			if(cas->kind == CaseSend)
+				dequeueg(&c->sendq);
+			else
+				dequeueg(&c->recvq);
+		}
+	}
+
+	if(sg == nil)
+		goto loop;
+
+	cas = (Scase*)sg;
+	c = cas->chan;
+
+	if(c->dataqsiz > 0)
+		runtime·throw("selectgo: shouldn't happen");
+
+	if(debug)
+		runtime·printf("wait-return: sel=%p c=%p cas=%p kind=%d\n",
+			sel, c, cas, cas->kind);
+
+	if(cas->kind == CaseRecv) {
+		if(cas->receivedp != nil)
+			*cas->receivedp = true;
+	}
+
+	if(raceenabled) {
+		if(cas->kind == CaseRecv && cas->sg.elem != nil)
+			runtime·racewriteobjectpc(cas->sg.elem, c->elemtype, cas->pc, chanrecv);
+		else if(cas->kind == CaseSend)
+			runtime·racereadobjectpc(cas->sg.elem, c->elemtype, cas->pc, chansend);
+	}
+
+	selunlock(sel);
+	goto retc;
+
+asyncrecv:
+	// can receive from buffer
+	if(raceenabled) {
+		if(cas->sg.elem != nil)
+			runtime·racewriteobjectpc(cas->sg.elem, c->elemtype, cas->pc, chanrecv);
+		runtime·raceacquire(chanbuf(c, c->recvx));
+		runtime·racerelease(chanbuf(c, c->recvx));
+	}
+	if(cas->receivedp != nil)
+		*cas->receivedp = true;
+	if(cas->sg.elem != nil)
+		c->elemtype->alg->copy(c->elemsize, cas->sg.elem, chanbuf(c, c->recvx));
+	c->elemtype->alg->copy(c->elemsize, chanbuf(c, c->recvx), nil);
+	if(++c->recvx == c->dataqsiz)
+		c->recvx = 0;
+	c->qcount--;
+	sg = dequeue(&c->sendq);
+	if(sg != nil) {
+		gp = sg->g;
+		selunlock(sel);
+		if(sg->releasetime)
+			sg->releasetime = runtime·cputicks();
+		runtime·ready(gp);
+	} else {
+		selunlock(sel);
+	}
+	goto retc;
+
+asyncsend:
+	// can send to buffer
+	if(raceenabled) {
+		runtime·raceacquire(chanbuf(c, c->sendx));
+		runtime·racerelease(chanbuf(c, c->sendx));
+		runtime·racereadobjectpc(cas->sg.elem, c->elemtype, cas->pc, chansend);
+	}
+	c->elemtype->alg->copy(c->elemsize, chanbuf(c, c->sendx), cas->sg.elem);
+	if(++c->sendx == c->dataqsiz)
+		c->sendx = 0;
+	c->qcount++;
+	sg = dequeue(&c->recvq);
+	if(sg != nil) {
+		gp = sg->g;
+		selunlock(sel);
+		if(sg->releasetime)
+			sg->releasetime = runtime·cputicks();
+		runtime·ready(gp);
+	} else {
+		selunlock(sel);
+	}
+	goto retc;
+
+syncrecv:
+	// can receive from sleeping sender (sg)
+	if(raceenabled) {
+		if(cas->sg.elem != nil)
+			runtime·racewriteobjectpc(cas->sg.elem, c->elemtype, cas->pc, chanrecv);
+		racesync(c, sg);
+	}
+	selunlock(sel);
+	if(debug)
+		runtime·printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o);
+	if(cas->receivedp != nil)
+		*cas->receivedp = true;
+	if(cas->sg.elem != nil)
+		c->elemtype->alg->copy(c->elemsize, cas->sg.elem, sg->elem);
+	gp = sg->g;
+	gp->param = sg;
+	if(sg->releasetime)
+		sg->releasetime = runtime·cputicks();
+	runtime·ready(gp);
+	goto retc;
+
+rclose:
+	// read at end of closed channel
+	selunlock(sel);
+	if(cas->receivedp != nil)
+		*cas->receivedp = false;
+	if(cas->sg.elem != nil)
+		c->elemtype->alg->copy(c->elemsize, cas->sg.elem, nil);
+	if(raceenabled)
+		runtime·raceacquire(c);
+	goto retc;
+
+syncsend:
+	// can send to sleeping receiver (sg)
+	if(raceenabled) {
+		runtime·racereadobjectpc(cas->sg.elem, c->elemtype, cas->pc, chansend);
+		racesync(c, sg);
+	}
+	selunlock(sel);
+	if(debug)
+		runtime·printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o);
+	if(sg->elem != nil)
+		c->elemtype->alg->copy(c->elemsize, sg->elem, cas->sg.elem);
+	gp = sg->g;
+	gp->param = sg;
+	if(sg->releasetime)
+		sg->releasetime = runtime·cputicks();
+	runtime·ready(gp);
+
+retc:
+	// return pc corresponding to chosen case.
+	// Set boolean passed during select creation
+	// (at offset selp + cas->so) to true.
+	// If cas->so == 0, this is a reflect-driven select and we
+	// don't need to update the boolean.
+	pc = cas->pc;
+	if(cas->so > 0) {
+		as = (byte*)selp + cas->so;
+		*as = true;
+	}
+	if(cas->sg.releasetime > 0)
+		runtime·blockevent(cas->sg.releasetime - t0, 2);
+	runtime·free(sel);
+	return pc;
+
+sclose:
+	// send on closed channel
+	selunlock(sel);
+	runtime·panicstring("send on closed channel");
+	return nil;  // not reached
+}
+
+// This struct must match ../reflect/value.go:/runtimeSelect.
+typedef struct runtimeSelect runtimeSelect;
+struct runtimeSelect
+{
+	uintptr dir;
+	ChanType *typ;
+	Hchan *ch;
+	byte *val;
+};
+
+// This enum must match ../reflect/value.go:/SelectDir.
+enum SelectDir {
+	SelectSend = 1,
+	SelectRecv,
+	SelectDefault,
+};
+
+func reflect·rselect(cases Slice) (chosen int, recvOK bool) {
+	int32 i;
+	Select *sel;
+	runtimeSelect* rcase, *rc;
+
+	chosen = -1;
+	recvOK = false;
+
+	rcase = (runtimeSelect*)cases.array;
+
+	sel = newselect(cases.len);
+	for(i=0; i<cases.len; i++) {
+		rc = &rcase[i];
+		switch(rc->dir) {
+		case SelectDefault:
+			selectdefault(sel, (void*)i, 0);
+			break;
+		case SelectSend:
+			if(rc->ch == nil)
+				break;
+			selectsend(sel, rc->ch, (void*)i, rc->val, 0);
+			break;
+		case SelectRecv:
+			if(rc->ch == nil)
+				break;
+			selectrecv(sel, rc->ch, (void*)i, rc->val, &recvOK, 0);
+			break;
+		}
+	}
+
+	chosen = (intgo)(uintptr)selectgo(&sel);
+}
+
+static void closechan(Hchan *c, void *pc);
+
+#pragma textflag NOSPLIT
+func closechan(c *Hchan) {
+	closechan(c, runtime·getcallerpc(&c));
+}
+
+#pragma textflag NOSPLIT
+func reflect·chanclose(c *Hchan) {
+	closechan(c, runtime·getcallerpc(&c));
+}
+
+static void
+closechan(Hchan *c, void *pc)
+{
+	SudoG *sg;
+	G* gp;
+
+	if(c == nil)
+		runtime·panicstring("close of nil channel");
+
+	runtime·lock(c);
+	if(c->closed) {
+		runtime·unlock(c);
+		runtime·panicstring("close of closed channel");
+	}
+
+	if(raceenabled) {
+		runtime·racewritepc(c, pc, runtime·closechan);
+		runtime·racerelease(c);
+	}
+
+	c->closed = true;
+
+	// release all readers
+	for(;;) {
+		sg = dequeue(&c->recvq);
+		if(sg == nil)
+			break;
+		gp = sg->g;
+		gp->param = nil;
+		if(sg->releasetime)
+			sg->releasetime = runtime·cputicks();
+		runtime·ready(gp);
+	}
+
+	// release all writers
+	for(;;) {
+		sg = dequeue(&c->sendq);
+		if(sg == nil)
+			break;
+		gp = sg->g;
+		gp->param = nil;
+		if(sg->releasetime)
+			sg->releasetime = runtime·cputicks();
+		runtime·ready(gp);
+	}
+
+	runtime·unlock(c);
+}
+
+func reflect·chanlen(c *Hchan) (len int) {
+	if(c == nil)
+		len = 0;
+	else
+		len = c->qcount;
+}
+
+func reflect·chancap(c *Hchan) (cap int) {
+	if(c == nil)
+		cap = 0;
+	else
+		cap = c->dataqsiz;
+}
+
+static SudoG*
+dequeue(WaitQ *q)
+{
+	SudoG *sgp;
+
+loop:
+	sgp = q->first;
+	if(sgp == nil)
+		return nil;
+	q->first = sgp->link;
+
+	// if sgp participates in a select and is already signaled, ignore it
+	if(sgp->selectdone != nil) {
+		// claim the right to signal
+		if(*sgp->selectdone != 0 || !runtime·cas(sgp->selectdone, 0, 1))
+			goto loop;
+	}
+
+	return sgp;
+}
+
+static void
+dequeueg(WaitQ *q)
+{
+	SudoG **l, *sgp, *prevsgp;
+
+	prevsgp = nil;
+	for(l=&q->first; (sgp=*l) != nil; l=&sgp->link, prevsgp=sgp) {
+		if(sgp->g == g) {
+			*l = sgp->link;
+			if(q->last == sgp)
+				q->last = prevsgp;
+			break;
+		}
+	}
+}
+
+static void
+enqueue(WaitQ *q, SudoG *sgp)
+{
+	sgp->link = nil;
+	if(q->first == nil) {
+		q->first = sgp;
+		q->last = sgp;
+		return;
+	}
+	q->last->link = sgp;
+	q->last = sgp;
+}
+
+static void
+racesync(Hchan *c, SudoG *sg)
+{
+	runtime·racerelease(chanbuf(c, 0));
+	runtime·raceacquireg(sg->g, chanbuf(c, 0));
+	runtime·racereleaseg(sg->g, chanbuf(c, 0));
+	runtime·raceacquire(chanbuf(c, 0));
+}
diff --git a/src/pkg/runtime/chan.h b/src/pkg/runtime/chan.h
new file mode 100644
index 0000000..ce2eb9f
--- /dev/null
+++ b/src/pkg/runtime/chan.h
@@ -0,0 +1,75 @@
+// 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.
+
+#define	MAXALIGN	8
+
+typedef	struct	WaitQ	WaitQ;
+typedef	struct	SudoG	SudoG;
+typedef	struct	Select	Select;
+typedef	struct	Scase	Scase;
+
+struct	SudoG
+{
+	G*	g;
+	uint32*	selectdone;
+	SudoG*	link;
+	int64	releasetime;
+	byte*	elem;		// data element
+};
+
+struct	WaitQ
+{
+	SudoG*	first;
+	SudoG*	last;
+};
+
+// The garbage collector is assuming that Hchan can only contain pointers into the stack
+// and cannot contain pointers into the heap.
+struct	Hchan
+{
+	uintgo	qcount;			// total data in the q
+	uintgo	dataqsiz;		// size of the circular q
+	uint16	elemsize;
+	uint16	pad;			// ensures proper alignment of the buffer that follows Hchan in memory
+	bool	closed;
+	Type*	elemtype;		// element type
+	uintgo	sendx;			// send index
+	uintgo	recvx;			// receive index
+	WaitQ	recvq;			// list of recv waiters
+	WaitQ	sendq;			// list of send waiters
+	Lock;
+};
+
+// Buffer follows Hchan immediately in memory.
+// chanbuf(c, i) is pointer to the i'th slot in the buffer.
+#define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i))
+
+enum
+{
+	debug = 0,
+
+	// Scase.kind
+	CaseRecv,
+	CaseSend,
+	CaseDefault,
+};
+
+struct	Scase
+{
+	SudoG	sg;			// must be first member (cast to Scase)
+	Hchan*	chan;			// chan
+	byte*	pc;			// return pc
+	uint16	kind;
+	uint16	so;			// vararg of selected bool
+	bool*	receivedp;		// pointer to received bool (recv2)
+};
+
+struct	Select
+{
+	uint16	tcase;			// total count of scase[]
+	uint16	ncase;			// currently filled scase[]
+	uint16*	pollorder;		// case poll order
+	Hchan**	lockorder;		// channel lock order
+	Scase	scase[1];		// one per case (in order of appearance)
+};
diff --git a/src/pkg/runtime/chan_test.go b/src/pkg/runtime/chan_test.go
index eb2c7c6..ce4b396 100644
--- a/src/pkg/runtime/chan_test.go
+++ b/src/pkg/runtime/chan_test.go
@@ -9,8 +9,327 @@ import (
 	"sync"
 	"sync/atomic"
 	"testing"
+	"time"
 )
 
+func TestChan(t *testing.T) {
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+	N := 200
+	if testing.Short() {
+		N = 20
+	}
+	for chanCap := 0; chanCap < N; chanCap++ {
+		{
+			// Ensure that receive from empty chan blocks.
+			c := make(chan int, chanCap)
+			recv1 := false
+			go func() {
+				_ = <-c
+				recv1 = true
+			}()
+			recv2 := false
+			go func() {
+				_, _ = <-c
+				recv2 = true
+			}()
+			time.Sleep(time.Millisecond)
+			if recv1 || recv2 {
+				t.Fatalf("chan[%d]: receive from empty chan", chanCap)
+			}
+			// Ensure that non-blocking receive does not block.
+			select {
+			case _ = <-c:
+				t.Fatalf("chan[%d]: receive from empty chan", chanCap)
+			default:
+			}
+			select {
+			case _, _ = <-c:
+				t.Fatalf("chan[%d]: receive from empty chan", chanCap)
+			default:
+			}
+			c <- 0
+			c <- 0
+		}
+
+		{
+			// Ensure that send to full chan blocks.
+			c := make(chan int, chanCap)
+			for i := 0; i < chanCap; i++ {
+				c <- i
+			}
+			sent := uint32(0)
+			go func() {
+				c <- 0
+				atomic.StoreUint32(&sent, 1)
+			}()
+			time.Sleep(time.Millisecond)
+			if atomic.LoadUint32(&sent) != 0 {
+				t.Fatalf("chan[%d]: send to full chan", chanCap)
+			}
+			// Ensure that non-blocking send does not block.
+			select {
+			case c <- 0:
+				t.Fatalf("chan[%d]: send to full chan", chanCap)
+			default:
+			}
+			<-c
+		}
+
+		{
+			// Ensure that we receive 0 from closed chan.
+			c := make(chan int, chanCap)
+			for i := 0; i < chanCap; i++ {
+				c <- i
+			}
+			close(c)
+			for i := 0; i < chanCap; i++ {
+				v := <-c
+				if v != i {
+					t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i)
+				}
+			}
+			if v := <-c; v != 0 {
+				t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, 0)
+			}
+			if v, ok := <-c; v != 0 || ok {
+				t.Fatalf("chan[%d]: received %v/%v, expected %v/%v", chanCap, v, ok, 0, false)
+			}
+		}
+
+		{
+			// Ensure that close unblocks receive.
+			c := make(chan int, chanCap)
+			done := make(chan bool)
+			go func() {
+				v, ok := <-c
+				done <- v == 0 && ok == false
+			}()
+			time.Sleep(time.Millisecond)
+			close(c)
+			if !<-done {
+				t.Fatalf("chan[%d]: received non zero from closed chan", chanCap)
+			}
+		}
+
+		{
+			// Send 100 integers,
+			// ensure that we receive them non-corrupted in FIFO order.
+			c := make(chan int, chanCap)
+			go func() {
+				for i := 0; i < 100; i++ {
+					c <- i
+				}
+			}()
+			for i := 0; i < 100; i++ {
+				v := <-c
+				if v != i {
+					t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i)
+				}
+			}
+
+			// Same, but using recv2.
+			go func() {
+				for i := 0; i < 100; i++ {
+					c <- i
+				}
+			}()
+			for i := 0; i < 100; i++ {
+				v, ok := <-c
+				if !ok {
+					t.Fatalf("chan[%d]: receive failed, expected %v", chanCap, i)
+				}
+				if v != i {
+					t.Fatalf("chan[%d]: received %v, expected %v", chanCap, v, i)
+				}
+			}
+
+			// Send 1000 integers in 4 goroutines,
+			// ensure that we receive what we send.
+			const P = 4
+			const L = 1000
+			for p := 0; p < P; p++ {
+				go func() {
+					for i := 0; i < L; i++ {
+						c <- i
+					}
+				}()
+			}
+			done := make(chan map[int]int)
+			for p := 0; p < P; p++ {
+				go func() {
+					recv := make(map[int]int)
+					for i := 0; i < L; i++ {
+						v := <-c
+						recv[v] = recv[v] + 1
+					}
+					done <- recv
+				}()
+			}
+			recv := make(map[int]int)
+			for p := 0; p < P; p++ {
+				for k, v := range <-done {
+					recv[k] = recv[k] + v
+				}
+			}
+			if len(recv) != L {
+				t.Fatalf("chan[%d]: received %v values, expected %v", chanCap, len(recv), L)
+			}
+			for _, v := range recv {
+				if v != P {
+					t.Fatalf("chan[%d]: received %v values, expected %v", chanCap, v, P)
+				}
+			}
+		}
+
+		{
+			// Test len/cap.
+			c := make(chan int, chanCap)
+			if len(c) != 0 || cap(c) != chanCap {
+				t.Fatalf("chan[%d]: bad len/cap, expect %v/%v, got %v/%v", chanCap, 0, chanCap, len(c), cap(c))
+			}
+			for i := 0; i < chanCap; i++ {
+				c <- i
+			}
+			if len(c) != chanCap || cap(c) != chanCap {
+				t.Fatalf("chan[%d]: bad len/cap, expect %v/%v, got %v/%v", chanCap, chanCap, chanCap, len(c), cap(c))
+			}
+		}
+
+	}
+}
+
+func TestSelfSelect(t *testing.T) {
+	// Ensure that send/recv on the same chan in select
+	// does not crash nor deadlock.
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
+	for _, chanCap := range []int{0, 10} {
+		var wg sync.WaitGroup
+		wg.Add(2)
+		c := make(chan int, chanCap)
+		for p := 0; p < 2; p++ {
+			p := p
+			go func() {
+				defer wg.Done()
+				for i := 0; i < 1000; i++ {
+					if p == 0 || i%2 == 0 {
+						select {
+						case c <- p:
+						case v := <-c:
+							if chanCap == 0 && v == p {
+								t.Fatalf("self receive")
+							}
+						}
+					} else {
+						select {
+						case v := <-c:
+							if chanCap == 0 && v == p {
+								t.Fatalf("self receive")
+							}
+						case c <- p:
+						}
+					}
+				}
+			}()
+		}
+		wg.Wait()
+	}
+}
+
+func TestSelectStress(t *testing.T) {
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(10))
+	var c [4]chan int
+	c[0] = make(chan int)
+	c[1] = make(chan int)
+	c[2] = make(chan int, 2)
+	c[3] = make(chan int, 3)
+	N := int(1e5)
+	if testing.Short() {
+		N /= 10
+	}
+	// There are 4 goroutines that send N values on each of the chans,
+	// + 4 goroutines that receive N values on each of the chans,
+	// + 1 goroutine that sends N values on each of the chans in a single select,
+	// + 1 goroutine that receives N values on each of the chans in a single select.
+	// All these sends, receives and selects interact chaotically at runtime,
+	// but we are careful that this whole construct does not deadlock.
+	var wg sync.WaitGroup
+	wg.Add(10)
+	for k := 0; k < 4; k++ {
+		k := k
+		go func() {
+			for i := 0; i < N; i++ {
+				c[k] <- 0
+			}
+			wg.Done()
+		}()
+		go func() {
+			for i := 0; i < N; i++ {
+				<-c[k]
+			}
+			wg.Done()
+		}()
+	}
+	go func() {
+		var n [4]int
+		c1 := c
+		for i := 0; i < 4*N; i++ {
+			select {
+			case c1[3] <- 0:
+				n[3]++
+				if n[3] == N {
+					c1[3] = nil
+				}
+			case c1[2] <- 0:
+				n[2]++
+				if n[2] == N {
+					c1[2] = nil
+				}
+			case c1[0] <- 0:
+				n[0]++
+				if n[0] == N {
+					c1[0] = nil
+				}
+			case c1[1] <- 0:
+				n[1]++
+				if n[1] == N {
+					c1[1] = nil
+				}
+			}
+		}
+		wg.Done()
+	}()
+	go func() {
+		var n [4]int
+		c1 := c
+		for i := 0; i < 4*N; i++ {
+			select {
+			case <-c1[0]:
+				n[0]++
+				if n[0] == N {
+					c1[0] = nil
+				}
+			case <-c1[1]:
+				n[1]++
+				if n[1] == N {
+					c1[1] = nil
+				}
+			case <-c1[2]:
+				n[2]++
+				if n[2] == N {
+					c1[2] = nil
+				}
+			case <-c1[3]:
+				n[3]++
+				if n[3] == N {
+					c1[3] = nil
+				}
+			}
+		}
+		wg.Done()
+	}()
+	wg.Wait()
+}
+
 func TestChanSendInterface(t *testing.T) {
 	type mt struct{}
 	m := &mt{}
@@ -29,34 +348,35 @@ func TestChanSendInterface(t *testing.T) {
 
 func TestPseudoRandomSend(t *testing.T) {
 	n := 100
-	c := make(chan int)
-	l := make([]int, n)
-	var m sync.Mutex
-	m.Lock()
-	go func() {
+	for _, chanCap := range []int{0, n} {
+		c := make(chan int, chanCap)
+		l := make([]int, n)
+		var m sync.Mutex
+		m.Lock()
+		go func() {
+			for i := 0; i < n; i++ {
+				runtime.Gosched()
+				l[i] = <-c
+			}
+			m.Unlock()
+		}()
 		for i := 0; i < n; i++ {
-			runtime.Gosched()
-			l[i] = <-c
+			select {
+			case c <- 1:
+			case c <- 0:
+			}
 		}
-		m.Unlock()
-	}()
-	for i := 0; i < n; i++ {
-		select {
-		case c <- 0:
-		case c <- 1:
+		m.Lock() // wait
+		n0 := 0
+		n1 := 0
+		for _, i := range l {
+			n0 += (i + 1) % 2
+			n1 += i
 		}
-	}
-	m.Lock() // wait
-	n0 := 0
-	n1 := 0
-	for _, i := range l {
-		n0 += (i + 1) % 2
-		n1 += i
-		if n0 > n/10 && n1 > n/10 {
-			return
+		if n0 <= n/10 || n1 <= n/10 {
+			t.Errorf("Want pseudorandom, got %d zeros and %d ones (chan cap %d)", n0, n1, chanCap)
 		}
 	}
-	t.Errorf("Want pseudo random, got %d zeros and %d ones", n0, n1)
 }
 
 func TestMultiConsumer(t *testing.T) {
@@ -110,147 +430,106 @@ func TestMultiConsumer(t *testing.T) {
 	}
 }
 
+func BenchmarkChanNonblocking(b *testing.B) {
+	myc := make(chan int)
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			select {
+			case <-myc:
+			default:
+			}
+		}
+	})
+}
+
 func BenchmarkSelectUncontended(b *testing.B) {
-	const CallsPerSched = 1000
-	procs := runtime.GOMAXPROCS(-1)
-	N := int32(b.N / CallsPerSched)
-	c := make(chan bool, procs)
-	for p := 0; p < procs; p++ {
-		go func() {
-			myc1 := make(chan int, 1)
-			myc2 := make(chan int, 1)
-			myc1 <- 0
-			for atomic.AddInt32(&N, -1) >= 0 {
-				for g := 0; g < CallsPerSched; g++ {
-					select {
-					case <-myc1:
-						myc2 <- 0
-					case <-myc2:
-						myc1 <- 0
-					}
-				}
+	b.RunParallel(func(pb *testing.PB) {
+		myc1 := make(chan int, 1)
+		myc2 := make(chan int, 1)
+		myc1 <- 0
+		for pb.Next() {
+			select {
+			case <-myc1:
+				myc2 <- 0
+			case <-myc2:
+				myc1 <- 0
 			}
-			c <- true
-		}()
-	}
-	for p := 0; p < procs; p++ {
-		<-c
-	}
+		}
+	})
 }
 
 func BenchmarkSelectContended(b *testing.B) {
-	const CallsPerSched = 1000
-	procs := runtime.GOMAXPROCS(-1)
-	N := int32(b.N / CallsPerSched)
-	c := make(chan bool, procs)
+	procs := runtime.GOMAXPROCS(0)
 	myc1 := make(chan int, procs)
 	myc2 := make(chan int, procs)
-	for p := 0; p < procs; p++ {
+	b.RunParallel(func(pb *testing.PB) {
 		myc1 <- 0
-		go func() {
-			for atomic.AddInt32(&N, -1) >= 0 {
-				for g := 0; g < CallsPerSched; g++ {
-					select {
-					case <-myc1:
-						myc2 <- 0
-					case <-myc2:
-						myc1 <- 0
-					}
-				}
+		for pb.Next() {
+			select {
+			case <-myc1:
+				myc2 <- 0
+			case <-myc2:
+				myc1 <- 0
 			}
-			c <- true
-		}()
-	}
-	for p := 0; p < procs; p++ {
-		<-c
-	}
+		}
+	})
 }
 
 func BenchmarkSelectNonblock(b *testing.B) {
-	const CallsPerSched = 1000
-	procs := runtime.GOMAXPROCS(-1)
-	N := int32(b.N / CallsPerSched)
-	c := make(chan bool, procs)
-	for p := 0; p < procs; p++ {
-		go func() {
-			myc1 := make(chan int)
-			myc2 := make(chan int)
-			myc3 := make(chan int, 1)
-			myc4 := make(chan int, 1)
-			for atomic.AddInt32(&N, -1) >= 0 {
-				for g := 0; g < CallsPerSched; g++ {
-					select {
-					case <-myc1:
-					default:
-					}
-					select {
-					case myc2 <- 0:
-					default:
-					}
-					select {
-					case <-myc3:
-					default:
-					}
-					select {
-					case myc4 <- 0:
-					default:
-					}
-				}
+	b.RunParallel(func(pb *testing.PB) {
+		myc1 := make(chan int)
+		myc2 := make(chan int)
+		myc3 := make(chan int, 1)
+		myc4 := make(chan int, 1)
+		for pb.Next() {
+			select {
+			case <-myc1:
+			default:
 			}
-			c <- true
-		}()
-	}
-	for p := 0; p < procs; p++ {
-		<-c
-	}
+			select {
+			case myc2 <- 0:
+			default:
+			}
+			select {
+			case <-myc3:
+			default:
+			}
+			select {
+			case myc4 <- 0:
+			default:
+			}
+		}
+	})
 }
 
 func BenchmarkChanUncontended(b *testing.B) {
-	const CallsPerSched = 1000
-	procs := runtime.GOMAXPROCS(-1)
-	N := int32(b.N / CallsPerSched)
-	c := make(chan bool, procs)
-	for p := 0; p < procs; p++ {
-		go func() {
-			myc := make(chan int, CallsPerSched)
-			for atomic.AddInt32(&N, -1) >= 0 {
-				for g := 0; g < CallsPerSched; g++ {
-					myc <- 0
-				}
-				for g := 0; g < CallsPerSched; g++ {
-					<-myc
-				}
+	const C = 100
+	b.RunParallel(func(pb *testing.PB) {
+		myc := make(chan int, C)
+		for pb.Next() {
+			for i := 0; i < C; i++ {
+				myc <- 0
 			}
-			c <- true
-		}()
-	}
-	for p := 0; p < procs; p++ {
-		<-c
-	}
+			for i := 0; i < C; i++ {
+				<-myc
+			}
+		}
+	})
 }
 
 func BenchmarkChanContended(b *testing.B) {
-	const CallsPerSched = 1000
-	procs := runtime.GOMAXPROCS(-1)
-	N := int32(b.N / CallsPerSched)
-	c := make(chan bool, procs)
-	myc := make(chan int, procs*CallsPerSched)
-	for p := 0; p < procs; p++ {
-		go func() {
-			for atomic.AddInt32(&N, -1) >= 0 {
-				for g := 0; g < CallsPerSched; g++ {
-					myc <- 0
-				}
-				for g := 0; g < CallsPerSched; g++ {
-					<-myc
-				}
+	const C = 100
+	myc := make(chan int, C*runtime.GOMAXPROCS(0))
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			for i := 0; i < C; i++ {
+				myc <- 0
 			}
-			c <- true
-		}()
-	}
-	for p := 0; p < procs; p++ {
-		<-c
-	}
+			for i := 0; i < C; i++ {
+				<-myc
+			}
+		}
+	})
 }
 
 func BenchmarkChanSync(b *testing.B) {
@@ -350,33 +629,83 @@ func BenchmarkChanProdConsWork100(b *testing.B) {
 	benchmarkChanProdCons(b, 100, 100)
 }
 
-func BenchmarkChanCreation(b *testing.B) {
+func BenchmarkSelectProdCons(b *testing.B) {
 	const CallsPerSched = 1000
 	procs := runtime.GOMAXPROCS(-1)
 	N := int32(b.N / CallsPerSched)
-	c := make(chan bool, procs)
+	c := make(chan bool, 2*procs)
+	myc := make(chan int, 128)
+	myclose := make(chan bool)
 	for p := 0; p < procs; p++ {
 		go func() {
+			// Producer: sends to myc.
+			foo := 0
+			// Intended to not fire during benchmarking.
+			mytimer := time.After(time.Hour)
 			for atomic.AddInt32(&N, -1) >= 0 {
 				for g := 0; g < CallsPerSched; g++ {
-					myc := make(chan int, 1)
-					myc <- 0
-					<-myc
+					// Model some local work.
+					for i := 0; i < 100; i++ {
+						foo *= 2
+						foo /= 2
+					}
+					select {
+					case myc <- 1:
+					case <-mytimer:
+					case <-myclose:
+					}
 				}
 			}
-			c <- true
+			myc <- 0
+			c <- foo == 42
+		}()
+		go func() {
+			// Consumer: receives from myc.
+			foo := 0
+			// Intended to not fire during benchmarking.
+			mytimer := time.After(time.Hour)
+		loop:
+			for {
+				select {
+				case v := <-myc:
+					if v == 0 {
+						break loop
+					}
+				case <-mytimer:
+				case <-myclose:
+				}
+				// Model some local work.
+				for i := 0; i < 100; i++ {
+					foo *= 2
+					foo /= 2
+				}
+			}
+			c <- foo == 42
 		}()
 	}
 	for p := 0; p < procs; p++ {
 		<-c
+		<-c
 	}
 }
 
+func BenchmarkChanCreation(b *testing.B) {
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			myc := make(chan int, 1)
+			myc <- 0
+			<-myc
+		}
+	})
+}
+
 func BenchmarkChanSem(b *testing.B) {
 	type Empty struct{}
-	c := make(chan Empty, 1)
-	for i := 0; i < b.N; i++ {
-		c <- Empty{}
-		<-c
-	}
+	myc := make(chan Empty, runtime.GOMAXPROCS(0))
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			myc <- Empty{}
+			<-myc
+		}
+	})
 }
diff --git a/src/pkg/runtime/complex.c b/src/pkg/runtime/complex.c
deleted file mode 100644
index 395e70f..0000000
--- a/src/pkg/runtime/complex.c
+++ /dev/null
@@ -1,62 +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.
-
-#include "runtime.h"
-
-typedef struct Complex128 Complex128;
-
-void
-runtime·complex128div(Complex128 n, Complex128 d, Complex128 q)
-{
-	int32 ninf, dinf, nnan, dnan;
-	float64 a, b, ratio, denom;
-
-	// Special cases as in C99.
-	ninf = n.real == runtime·posinf || n.real == runtime·neginf ||
-	       n.imag == runtime·posinf || n.imag == runtime·neginf;
-	dinf = d.real == runtime·posinf || d.real == runtime·neginf ||
-	       d.imag == runtime·posinf || d.imag == runtime·neginf;
-
-	nnan = !ninf && (ISNAN(n.real) || ISNAN(n.imag));
-	dnan = !dinf && (ISNAN(d.real) || ISNAN(d.imag));
-
-	if(nnan || dnan) {
-		q.real = runtime·nan;
-		q.imag = runtime·nan;
-	} else if(ninf && !dinf) {
-		q.real = runtime·posinf;
-		q.imag = runtime·posinf;
-	} else if(!ninf && dinf) {
-		q.real = 0;
-		q.imag = 0;
-	} else if(d.real == 0 && d.imag == 0) {
-		if(n.real == 0 && n.imag == 0) {
-			q.real = runtime·nan;
-			q.imag = runtime·nan;
-		} else {
-			q.real = runtime·posinf;
-			q.imag = runtime·posinf;
-		}
-	} else {
-		// Standard complex arithmetic, factored to avoid unnecessary overflow.
-		a = d.real;
-		if(a < 0)
-			a = -a;
-		b = d.imag;
-		if(b < 0)
-			b = -b;
-		if(a <= b) {
-			ratio = d.real/d.imag;
-			denom = d.real*ratio + d.imag;
-			q.real = (n.real*ratio + n.imag) / denom;
-			q.imag = (n.imag*ratio - n.real) / denom;
-		} else {
-			ratio = d.imag/d.real;
-			denom = d.imag*ratio + d.real;
-			q.real = (n.imag*ratio + n.real) / denom;
-			q.imag = (n.imag - n.real*ratio) / denom;
-		}
-	}
-	FLUSH(&q);
-}
diff --git a/src/pkg/runtime/complex.goc b/src/pkg/runtime/complex.goc
new file mode 100644
index 0000000..40935cf
--- /dev/null
+++ b/src/pkg/runtime/complex.goc
@@ -0,0 +1,58 @@
+// 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 runtime
+#include "runtime.h"
+
+func complex128div(n Complex128, d Complex128) (q Complex128) {
+	int32 ninf, dinf, nnan, dnan;
+	float64 a, b, ratio, denom;
+
+	// Special cases as in C99.
+	ninf = n.real == runtime·posinf || n.real == runtime·neginf ||
+	       n.imag == runtime·posinf || n.imag == runtime·neginf;
+	dinf = d.real == runtime·posinf || d.real == runtime·neginf ||
+	       d.imag == runtime·posinf || d.imag == runtime·neginf;
+
+	nnan = !ninf && (ISNAN(n.real) || ISNAN(n.imag));
+	dnan = !dinf && (ISNAN(d.real) || ISNAN(d.imag));
+
+	if(nnan || dnan) {
+		q.real = runtime·nan;
+		q.imag = runtime·nan;
+	} else if(ninf && !dinf) {
+		q.real = runtime·posinf;
+		q.imag = runtime·posinf;
+	} else if(!ninf && dinf) {
+		q.real = 0;
+		q.imag = 0;
+	} else if(d.real == 0 && d.imag == 0) {
+		if(n.real == 0 && n.imag == 0) {
+			q.real = runtime·nan;
+			q.imag = runtime·nan;
+		} else {
+			q.real = runtime·posinf;
+			q.imag = runtime·posinf;
+		}
+	} else {
+		// Standard complex arithmetic, factored to avoid unnecessary overflow.
+		a = d.real;
+		if(a < 0)
+			a = -a;
+		b = d.imag;
+		if(b < 0)
+			b = -b;
+		if(a <= b) {
+			ratio = d.real/d.imag;
+			denom = d.real*ratio + d.imag;
+			q.real = (n.real*ratio + n.imag) / denom;
+			q.imag = (n.imag*ratio - n.real) / denom;
+		} else {
+			ratio = d.imag/d.real;
+			denom = d.imag*ratio + d.real;
+			q.real = (n.imag*ratio + n.real) / denom;
+			q.imag = (n.imag - n.real*ratio) / denom;
+		}
+	}
+}
diff --git a/src/pkg/runtime/cpuprof.c b/src/pkg/runtime/cpuprof.c
deleted file mode 100644
index 1c34b9e..0000000
--- a/src/pkg/runtime/cpuprof.c
+++ /dev/null
@@ -1,436 +0,0 @@
-// 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.
-
-// CPU profiling.
-// Based on algorithms and data structures used in
-// http://code.google.com/p/google-perftools/.
-//
-// The main difference between this code and the google-perftools
-// code is that this code is written to allow copying the profile data
-// to an arbitrary io.Writer, while the google-perftools code always
-// writes to an operating system file.
-//
-// The signal handler for the profiling clock tick adds a new stack trace
-// to a hash table tracking counts for recent traces.  Most clock ticks
-// hit in the cache.  In the event of a cache miss, an entry must be 
-// evicted from the hash table, copied to a log that will eventually be
-// written as profile data.  The google-perftools code flushed the
-// log itself during the signal handler.  This code cannot do that, because
-// the io.Writer might block or need system calls or locks that are not
-// safe to use from within the signal handler.  Instead, we split the log
-// into two halves and let the signal handler fill one half while a goroutine
-// is writing out the other half.  When the signal handler fills its half, it
-// offers to swap with the goroutine.  If the writer is not done with its half,
-// we lose the stack trace for this clock tick (and record that loss).
-// The goroutine interacts with the signal handler by calling getprofile() to
-// get the next log piece to write, implicitly handing back the last log
-// piece it obtained.
-//
-// The state of this dance between the signal handler and the goroutine
-// is encoded in the Profile.handoff field.  If handoff == 0, then the goroutine
-// is not using either log half and is waiting (or will soon be waiting) for
-// a new piece by calling notesleep(&p->wait).  If the signal handler
-// changes handoff from 0 to non-zero, it must call notewakeup(&p->wait)
-// to wake the goroutine.  The value indicates the number of entries in the
-// log half being handed off.  The goroutine leaves the non-zero value in
-// place until it has finished processing the log half and then flips the number
-// back to zero.  Setting the high bit in handoff means that the profiling is over, 
-// and the goroutine is now in charge of flushing the data left in the hash table
-// to the log and returning that data.  
-//
-// The handoff field is manipulated using atomic operations.
-// For the most part, the manipulation of handoff is orderly: if handoff == 0
-// then the signal handler owns it and can change it to non-zero.  
-// If handoff != 0 then the goroutine owns it and can change it to zero.
-// If that were the end of the story then we would not need to manipulate
-// handoff using atomic operations.  The operations are needed, however,
-// in order to let the log closer set the high bit to indicate "EOF" safely
-// in the situation when normally the goroutine "owns" handoff.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-
-enum
-{
-	HashSize = 1<<10,
-	LogSize = 1<<17,
-	Assoc = 4,
-	MaxStack = 64,
-};
-
-typedef struct Profile Profile;
-typedef struct Bucket Bucket;
-typedef struct Entry Entry;
-
-struct Entry {
-	uintptr count;
-	uintptr depth;
-	uintptr stack[MaxStack];
-};
-
-struct Bucket {
-	Entry entry[Assoc];
-};
-
-struct Profile {
-	bool on;		// profiling is on
-	Note wait;		// goroutine waits here
-	uintptr count;		// tick count
-	uintptr evicts;		// eviction count
-	uintptr lost;		// lost ticks that need to be logged
-	uintptr totallost;	// total lost ticks
-
-	// Active recent stack traces.
-	Bucket hash[HashSize];
-
-	// Log of traces evicted from hash.
-	// Signal handler has filled log[toggle][:nlog].
-	// Goroutine is writing log[1-toggle][:handoff].
-	uintptr log[2][LogSize/2];
-	uintptr nlog;
-	int32 toggle;
-	uint32 handoff;
-	
-	// Writer state.
-	// Writer maintains its own toggle to avoid races
-	// looking at signal handler's toggle.
-	uint32 wtoggle;
-	bool wholding;	// holding & need to release a log half
-	bool flushing;	// flushing hash table - profile is over
-	bool eod_sent;  // special end-of-data record sent; => flushing
-};
-
-static Lock lk;
-static Profile *prof;
-
-static void tick(uintptr*, int32);
-static void add(Profile*, uintptr*, int32);
-static bool evict(Profile*, Entry*);
-static bool flushlog(Profile*);
-
-static uintptr eod[3] = {0, 1, 0};
-
-// LostProfileData is a no-op function used in profiles
-// to mark the number of profiling stack traces that were
-// discarded due to slow data writers.
-static void
-LostProfileData(void)
-{
-}
-
-// SetCPUProfileRate sets the CPU profiling rate.
-// The user documentation is in debug.go.
-void
-runtime·SetCPUProfileRate(intgo hz)
-{
-	uintptr *p;
-	uintptr n;
-
-	// Clamp hz to something reasonable.
-	if(hz < 0)
-		hz = 0;
-	if(hz > 1000000)
-		hz = 1000000;
-
-	runtime·lock(&lk);
-	if(hz > 0) {
-		if(prof == nil) {
-			prof = runtime·SysAlloc(sizeof *prof, &mstats.other_sys);
-			if(prof == nil) {
-				runtime·printf("runtime: cpu profiling cannot allocate memory\n");
-				runtime·unlock(&lk);
-				return;
-			}
-		}
-		if(prof->on || prof->handoff != 0) {
-			runtime·printf("runtime: cannot set cpu profile rate until previous profile has finished.\n");
-			runtime·unlock(&lk);
-			return;
-		}
-
-		prof->on = true;
-		p = prof->log[0];
-		// pprof binary header format.
-		// http://code.google.com/p/google-perftools/source/browse/trunk/src/profiledata.cc#117
-		*p++ = 0;  // count for header
-		*p++ = 3;  // depth for header
-		*p++ = 0;  // version number
-		*p++ = 1000000 / hz;  // period (microseconds)
-		*p++ = 0;
-		prof->nlog = p - prof->log[0];
-		prof->toggle = 0;
-		prof->wholding = false;
-		prof->wtoggle = 0;
-		prof->flushing = false;
-		prof->eod_sent = false;
-		runtime·noteclear(&prof->wait);
-
-		runtime·setcpuprofilerate(tick, hz);
-	} else if(prof->on) {
-		runtime·setcpuprofilerate(nil, 0);
-		prof->on = false;
-
-		// Now add is not running anymore, and getprofile owns the entire log.
-		// Set the high bit in prof->handoff to tell getprofile.
-		for(;;) {
-			n = prof->handoff;
-			if(n&0x80000000)
-				runtime·printf("runtime: setcpuprofile(off) twice");
-			if(runtime·cas(&prof->handoff, n, n|0x80000000))
-				break;
-		}
-		if(n == 0) {
-			// we did the transition from 0 -> nonzero so we wake getprofile
-			runtime·notewakeup(&prof->wait);
-		}
-	}
-	runtime·unlock(&lk);
-}
-
-static void
-tick(uintptr *pc, int32 n)
-{
-	add(prof, pc, n);
-}
-
-// add adds the stack trace to the profile.
-// It is called from signal handlers and other limited environments
-// and cannot allocate memory or acquire locks that might be
-// held at the time of the signal, nor can it use substantial amounts
-// of stack.  It is allowed to call evict.
-static void
-add(Profile *p, uintptr *pc, int32 n)
-{
-	int32 i, j;
-	uintptr h, x;
-	Bucket *b;
-	Entry *e;
-
-	if(n > MaxStack)
-		n = MaxStack;
-	
-	// Compute hash.
-	h = 0;
-	for(i=0; i<n; i++) {
-		h = h<<8 | (h>>(8*(sizeof(h)-1)));
-		x = pc[i];
-		h += x*31 + x*7 + x*3;
-	}
-	p->count++;
-
-	// Add to entry count if already present in table.
-	b = &p->hash[h%HashSize];
-	for(i=0; i<Assoc; i++) {
-		e = &b->entry[i];
-		if(e->depth != n)	
-			continue;
-		for(j=0; j<n; j++)
-			if(e->stack[j] != pc[j])
-				goto ContinueAssoc;
-		e->count++;
-		return;
-	ContinueAssoc:;
-	}
-
-	// Evict entry with smallest count.
-	e = &b->entry[0];
-	for(i=1; i<Assoc; i++)
-		if(b->entry[i].count < e->count)
-			e = &b->entry[i];
-	if(e->count > 0) {
-		if(!evict(p, e)) {
-			// Could not evict entry.  Record lost stack.
-			p->lost++;
-			p->totallost++;
-			return;
-		}
-		p->evicts++;
-	}
-	
-	// Reuse the newly evicted entry.
-	e->depth = n;
-	e->count = 1;
-	for(i=0; i<n; i++)
-		e->stack[i] = pc[i];
-}
-
-// evict copies the given entry's data into the log, so that
-// the entry can be reused.  evict is called from add, which
-// is called from the profiling signal handler, so it must not
-// allocate memory or block.  It is safe to call flushLog.
-// evict returns true if the entry was copied to the log,
-// false if there was no room available.
-static bool
-evict(Profile *p, Entry *e)
-{
-	int32 i, d, nslot;
-	uintptr *log, *q;
-	
-	d = e->depth;
-	nslot = d+2;
-	log = p->log[p->toggle];
-	if(p->nlog+nslot > nelem(p->log[0])) {
-		if(!flushlog(p))
-			return false;
-		log = p->log[p->toggle];
-	}
-	
-	q = log+p->nlog;
-	*q++ = e->count;
-	*q++ = d;
-	for(i=0; i<d; i++)
-		*q++ = e->stack[i];
-	p->nlog = q - log;
-	e->count = 0;
-	return true;
-}
-
-// flushlog tries to flush the current log and switch to the other one.
-// flushlog is called from evict, called from add, called from the signal handler,
-// so it cannot allocate memory or block.  It can try to swap logs with
-// the writing goroutine, as explained in the comment at the top of this file.
-static bool
-flushlog(Profile *p)
-{
-	uintptr *log, *q;
-
-	if(!runtime·cas(&p->handoff, 0, p->nlog))
-		return false;
-	runtime·notewakeup(&p->wait);
-
-	p->toggle = 1 - p->toggle;
-	log = p->log[p->toggle];
-	q = log;
-	if(p->lost > 0) {
-		*q++ = p->lost;
-		*q++ = 1;
-		*q++ = (uintptr)LostProfileData;
-	}
-	p->nlog = q - log;
-	return true;
-}
-
-// getprofile blocks until the next block of profiling data is available
-// and returns it as a []byte.  It is called from the writing goroutine.
-Slice
-getprofile(Profile *p)
-{
-	uint32 i, j, n;
-	Slice ret;
-	Bucket *b;
-	Entry *e;
-
-	ret.array = nil;
-	ret.len = 0;
-	ret.cap = 0;
-	
-	if(p == nil)	
-		return ret;
-
-	if(p->wholding) {
-		// Release previous log to signal handling side.
-		// Loop because we are racing against SetCPUProfileRate(0).
-		for(;;) {
-			n = p->handoff;
-			if(n == 0) {
-				runtime·printf("runtime: phase error during cpu profile handoff\n");
-				return ret;
-			}
-			if(n & 0x80000000) {
-				p->wtoggle = 1 - p->wtoggle;
-				p->wholding = false;
-				p->flushing = true;
-				goto flush;
-			}
-			if(runtime·cas(&p->handoff, n, 0))
-				break;
-		}
-		p->wtoggle = 1 - p->wtoggle;
-		p->wholding = false;
-	}
-	
-	if(p->flushing)
-		goto flush;
-	
-	if(!p->on && p->handoff == 0)
-		return ret;
-
-	// Wait for new log.
-	runtime·notetsleepg(&p->wait, -1);
-	runtime·noteclear(&p->wait);
-
-	n = p->handoff;
-	if(n == 0) {
-		runtime·printf("runtime: phase error during cpu profile wait\n");
-		return ret;
-	}
-	if(n == 0x80000000) {
-		p->flushing = true;
-		goto flush;
-	}
-	n &= ~0x80000000;
-
-	// Return new log to caller.
-	p->wholding = true;
-
-	ret.array = (byte*)p->log[p->wtoggle];
-	ret.len = n*sizeof(uintptr);
-	ret.cap = ret.len;
-	return ret;
-
-flush:
-	// In flush mode.
-	// Add is no longer being called.  We own the log.
-	// Also, p->handoff is non-zero, so flushlog will return false.
-	// Evict the hash table into the log and return it.
-	for(i=0; i<HashSize; i++) {
-		b = &p->hash[i];
-		for(j=0; j<Assoc; j++) {
-			e = &b->entry[j];
-			if(e->count > 0 && !evict(p, e)) {
-				// Filled the log.  Stop the loop and return what we've got.
-				goto breakflush;
-			}
-		}
-	}
-breakflush:
-
-	// Return pending log data.
-	if(p->nlog > 0) {
-		// Note that we're using toggle now, not wtoggle,
-		// because we're working on the log directly.
-		ret.array = (byte*)p->log[p->toggle];
-		ret.len = p->nlog*sizeof(uintptr);
-		ret.cap = ret.len;
-		p->nlog = 0;
-		return ret;
-	}
-
-	// Made it through the table without finding anything to log.
-	if(!p->eod_sent) {
-		// We may not have space to append this to the partial log buf,
-		// so we always return a new slice for the end-of-data marker.
-		p->eod_sent = true;
-		ret.array = (byte*)eod;
-		ret.len = sizeof eod;
-		ret.cap = ret.len;
-		return ret;
-	}
-
-	// Finally done.  Clean up and return nil.
-	p->flushing = false;
-	if(!runtime·cas(&p->handoff, p->handoff, 0))
-		runtime·printf("runtime: profile flush racing with something\n");
-	return ret;  // set to nil at top of function
-}
-
-// CPUProfile returns the next cpu profile block as a []byte.
-// The user documentation is in debug.go.
-void
-runtime·CPUProfile(Slice ret)
-{
-	ret = getprofile(prof);
-	FLUSH(&ret);
-}
diff --git a/src/pkg/runtime/cpuprof.goc b/src/pkg/runtime/cpuprof.goc
new file mode 100644
index 0000000..faaea29
--- /dev/null
+++ b/src/pkg/runtime/cpuprof.goc
@@ -0,0 +1,433 @@
+// 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.
+
+// CPU profiling.
+// Based on algorithms and data structures used in
+// http://code.google.com/p/google-perftools/.
+//
+// The main difference between this code and the google-perftools
+// code is that this code is written to allow copying the profile data
+// to an arbitrary io.Writer, while the google-perftools code always
+// writes to an operating system file.
+//
+// The signal handler for the profiling clock tick adds a new stack trace
+// to a hash table tracking counts for recent traces.  Most clock ticks
+// hit in the cache.  In the event of a cache miss, an entry must be 
+// evicted from the hash table, copied to a log that will eventually be
+// written as profile data.  The google-perftools code flushed the
+// log itself during the signal handler.  This code cannot do that, because
+// the io.Writer might block or need system calls or locks that are not
+// safe to use from within the signal handler.  Instead, we split the log
+// into two halves and let the signal handler fill one half while a goroutine
+// is writing out the other half.  When the signal handler fills its half, it
+// offers to swap with the goroutine.  If the writer is not done with its half,
+// we lose the stack trace for this clock tick (and record that loss).
+// The goroutine interacts with the signal handler by calling getprofile() to
+// get the next log piece to write, implicitly handing back the last log
+// piece it obtained.
+//
+// The state of this dance between the signal handler and the goroutine
+// is encoded in the Profile.handoff field.  If handoff == 0, then the goroutine
+// is not using either log half and is waiting (or will soon be waiting) for
+// a new piece by calling notesleep(&p->wait).  If the signal handler
+// changes handoff from 0 to non-zero, it must call notewakeup(&p->wait)
+// to wake the goroutine.  The value indicates the number of entries in the
+// log half being handed off.  The goroutine leaves the non-zero value in
+// place until it has finished processing the log half and then flips the number
+// back to zero.  Setting the high bit in handoff means that the profiling is over, 
+// and the goroutine is now in charge of flushing the data left in the hash table
+// to the log and returning that data.  
+//
+// The handoff field is manipulated using atomic operations.
+// For the most part, the manipulation of handoff is orderly: if handoff == 0
+// then the signal handler owns it and can change it to non-zero.  
+// If handoff != 0 then the goroutine owns it and can change it to zero.
+// If that were the end of the story then we would not need to manipulate
+// handoff using atomic operations.  The operations are needed, however,
+// in order to let the log closer set the high bit to indicate "EOF" safely
+// in the situation when normally the goroutine "owns" handoff.
+
+package runtime
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+
+enum
+{
+	HashSize = 1<<10,
+	LogSize = 1<<17,
+	Assoc = 4,
+	MaxStack = 64,
+};
+
+typedef struct Profile Profile;
+typedef struct Bucket Bucket;
+typedef struct Entry Entry;
+
+struct Entry {
+	uintptr count;
+	uintptr depth;
+	uintptr stack[MaxStack];
+};
+
+struct Bucket {
+	Entry entry[Assoc];
+};
+
+struct Profile {
+	bool on;		// profiling is on
+	Note wait;		// goroutine waits here
+	uintptr count;		// tick count
+	uintptr evicts;		// eviction count
+	uintptr lost;		// lost ticks that need to be logged
+
+	// Active recent stack traces.
+	Bucket hash[HashSize];
+
+	// Log of traces evicted from hash.
+	// Signal handler has filled log[toggle][:nlog].
+	// Goroutine is writing log[1-toggle][:handoff].
+	uintptr log[2][LogSize/2];
+	uintptr nlog;
+	int32 toggle;
+	uint32 handoff;
+	
+	// Writer state.
+	// Writer maintains its own toggle to avoid races
+	// looking at signal handler's toggle.
+	uint32 wtoggle;
+	bool wholding;	// holding & need to release a log half
+	bool flushing;	// flushing hash table - profile is over
+	bool eod_sent;  // special end-of-data record sent; => flushing
+};
+
+static Lock lk;
+static Profile *prof;
+
+static void tick(uintptr*, int32);
+static void add(Profile*, uintptr*, int32);
+static bool evict(Profile*, Entry*);
+static bool flushlog(Profile*);
+
+static uintptr eod[3] = {0, 1, 0};
+
+// LostProfileData is a no-op function used in profiles
+// to mark the number of profiling stack traces that were
+// discarded due to slow data writers.
+static void
+LostProfileData(void)
+{
+}
+
+// SetCPUProfileRate sets the CPU profiling rate.
+// The user documentation is in debug.go.
+void
+runtime·SetCPUProfileRate(intgo hz)
+{
+	uintptr *p;
+	uintptr n;
+
+	// Clamp hz to something reasonable.
+	if(hz < 0)
+		hz = 0;
+	if(hz > 1000000)
+		hz = 1000000;
+
+	runtime·lock(&lk);
+	if(hz > 0) {
+		if(prof == nil) {
+			prof = runtime·SysAlloc(sizeof *prof, &mstats.other_sys);
+			if(prof == nil) {
+				runtime·printf("runtime: cpu profiling cannot allocate memory\n");
+				runtime·unlock(&lk);
+				return;
+			}
+		}
+		if(prof->on || prof->handoff != 0) {
+			runtime·printf("runtime: cannot set cpu profile rate until previous profile has finished.\n");
+			runtime·unlock(&lk);
+			return;
+		}
+
+		prof->on = true;
+		p = prof->log[0];
+		// pprof binary header format.
+		// http://code.google.com/p/google-perftools/source/browse/trunk/src/profiledata.cc#117
+		*p++ = 0;  // count for header
+		*p++ = 3;  // depth for header
+		*p++ = 0;  // version number
+		*p++ = 1000000 / hz;  // period (microseconds)
+		*p++ = 0;
+		prof->nlog = p - prof->log[0];
+		prof->toggle = 0;
+		prof->wholding = false;
+		prof->wtoggle = 0;
+		prof->flushing = false;
+		prof->eod_sent = false;
+		runtime·noteclear(&prof->wait);
+
+		runtime·setcpuprofilerate(tick, hz);
+	} else if(prof != nil && prof->on) {
+		runtime·setcpuprofilerate(nil, 0);
+		prof->on = false;
+
+		// Now add is not running anymore, and getprofile owns the entire log.
+		// Set the high bit in prof->handoff to tell getprofile.
+		for(;;) {
+			n = prof->handoff;
+			if(n&0x80000000)
+				runtime·printf("runtime: setcpuprofile(off) twice");
+			if(runtime·cas(&prof->handoff, n, n|0x80000000))
+				break;
+		}
+		if(n == 0) {
+			// we did the transition from 0 -> nonzero so we wake getprofile
+			runtime·notewakeup(&prof->wait);
+		}
+	}
+	runtime·unlock(&lk);
+}
+
+static void
+tick(uintptr *pc, int32 n)
+{
+	add(prof, pc, n);
+}
+
+// add adds the stack trace to the profile.
+// It is called from signal handlers and other limited environments
+// and cannot allocate memory or acquire locks that might be
+// held at the time of the signal, nor can it use substantial amounts
+// of stack.  It is allowed to call evict.
+static void
+add(Profile *p, uintptr *pc, int32 n)
+{
+	int32 i, j;
+	uintptr h, x;
+	Bucket *b;
+	Entry *e;
+
+	if(n > MaxStack)
+		n = MaxStack;
+	
+	// Compute hash.
+	h = 0;
+	for(i=0; i<n; i++) {
+		h = h<<8 | (h>>(8*(sizeof(h)-1)));
+		x = pc[i];
+		h += x*31 + x*7 + x*3;
+	}
+	p->count++;
+
+	// Add to entry count if already present in table.
+	b = &p->hash[h%HashSize];
+	for(i=0; i<Assoc; i++) {
+		e = &b->entry[i];
+		if(e->depth != n)	
+			continue;
+		for(j=0; j<n; j++)
+			if(e->stack[j] != pc[j])
+				goto ContinueAssoc;
+		e->count++;
+		return;
+	ContinueAssoc:;
+	}
+
+	// Evict entry with smallest count.
+	e = &b->entry[0];
+	for(i=1; i<Assoc; i++)
+		if(b->entry[i].count < e->count)
+			e = &b->entry[i];
+	if(e->count > 0) {
+		if(!evict(p, e)) {
+			// Could not evict entry.  Record lost stack.
+			p->lost++;
+			return;
+		}
+		p->evicts++;
+	}
+	
+	// Reuse the newly evicted entry.
+	e->depth = n;
+	e->count = 1;
+	for(i=0; i<n; i++)
+		e->stack[i] = pc[i];
+}
+
+// evict copies the given entry's data into the log, so that
+// the entry can be reused.  evict is called from add, which
+// is called from the profiling signal handler, so it must not
+// allocate memory or block.  It is safe to call flushLog.
+// evict returns true if the entry was copied to the log,
+// false if there was no room available.
+static bool
+evict(Profile *p, Entry *e)
+{
+	int32 i, d, nslot;
+	uintptr *log, *q;
+	
+	d = e->depth;
+	nslot = d+2;
+	log = p->log[p->toggle];
+	if(p->nlog+nslot > nelem(p->log[0])) {
+		if(!flushlog(p))
+			return false;
+		log = p->log[p->toggle];
+	}
+	
+	q = log+p->nlog;
+	*q++ = e->count;
+	*q++ = d;
+	for(i=0; i<d; i++)
+		*q++ = e->stack[i];
+	p->nlog = q - log;
+	e->count = 0;
+	return true;
+}
+
+// flushlog tries to flush the current log and switch to the other one.
+// flushlog is called from evict, called from add, called from the signal handler,
+// so it cannot allocate memory or block.  It can try to swap logs with
+// the writing goroutine, as explained in the comment at the top of this file.
+static bool
+flushlog(Profile *p)
+{
+	uintptr *log, *q;
+
+	if(!runtime·cas(&p->handoff, 0, p->nlog))
+		return false;
+	runtime·notewakeup(&p->wait);
+
+	p->toggle = 1 - p->toggle;
+	log = p->log[p->toggle];
+	q = log;
+	if(p->lost > 0) {
+		*q++ = p->lost;
+		*q++ = 1;
+		*q++ = (uintptr)LostProfileData;
+		p->lost = 0;
+	}
+	p->nlog = q - log;
+	return true;
+}
+
+// getprofile blocks until the next block of profiling data is available
+// and returns it as a []byte.  It is called from the writing goroutine.
+Slice
+getprofile(Profile *p)
+{
+	uint32 i, j, n;
+	Slice ret;
+	Bucket *b;
+	Entry *e;
+
+	ret.array = nil;
+	ret.len = 0;
+	ret.cap = 0;
+	
+	if(p == nil)	
+		return ret;
+
+	if(p->wholding) {
+		// Release previous log to signal handling side.
+		// Loop because we are racing against SetCPUProfileRate(0).
+		for(;;) {
+			n = p->handoff;
+			if(n == 0) {
+				runtime·printf("runtime: phase error during cpu profile handoff\n");
+				return ret;
+			}
+			if(n & 0x80000000) {
+				p->wtoggle = 1 - p->wtoggle;
+				p->wholding = false;
+				p->flushing = true;
+				goto flush;
+			}
+			if(runtime·cas(&p->handoff, n, 0))
+				break;
+		}
+		p->wtoggle = 1 - p->wtoggle;
+		p->wholding = false;
+	}
+	
+	if(p->flushing)
+		goto flush;
+	
+	if(!p->on && p->handoff == 0)
+		return ret;
+
+	// Wait for new log.
+	runtime·notetsleepg(&p->wait, -1);
+	runtime·noteclear(&p->wait);
+
+	n = p->handoff;
+	if(n == 0) {
+		runtime·printf("runtime: phase error during cpu profile wait\n");
+		return ret;
+	}
+	if(n == 0x80000000) {
+		p->flushing = true;
+		goto flush;
+	}
+	n &= ~0x80000000;
+
+	// Return new log to caller.
+	p->wholding = true;
+
+	ret.array = (byte*)p->log[p->wtoggle];
+	ret.len = n*sizeof(uintptr);
+	ret.cap = ret.len;
+	return ret;
+
+flush:
+	// In flush mode.
+	// Add is no longer being called.  We own the log.
+	// Also, p->handoff is non-zero, so flushlog will return false.
+	// Evict the hash table into the log and return it.
+	for(i=0; i<HashSize; i++) {
+		b = &p->hash[i];
+		for(j=0; j<Assoc; j++) {
+			e = &b->entry[j];
+			if(e->count > 0 && !evict(p, e)) {
+				// Filled the log.  Stop the loop and return what we've got.
+				goto breakflush;
+			}
+		}
+	}
+breakflush:
+
+	// Return pending log data.
+	if(p->nlog > 0) {
+		// Note that we're using toggle now, not wtoggle,
+		// because we're working on the log directly.
+		ret.array = (byte*)p->log[p->toggle];
+		ret.len = p->nlog*sizeof(uintptr);
+		ret.cap = ret.len;
+		p->nlog = 0;
+		return ret;
+	}
+
+	// Made it through the table without finding anything to log.
+	if(!p->eod_sent) {
+		// We may not have space to append this to the partial log buf,
+		// so we always return a new slice for the end-of-data marker.
+		p->eod_sent = true;
+		ret.array = (byte*)eod;
+		ret.len = sizeof eod;
+		ret.cap = ret.len;
+		return ret;
+	}
+
+	// Finally done.  Clean up and return nil.
+	p->flushing = false;
+	if(!runtime·cas(&p->handoff, p->handoff, 0))
+		runtime·printf("runtime: profile flush racing with something\n");
+	return ret;  // set to nil at top of function
+}
+
+// CPUProfile returns the next cpu profile block as a []byte.
+// The user documentation is in debug.go.
+func CPUProfile() (ret Slice) {
+	ret = getprofile(prof);
+}
diff --git a/src/pkg/runtime/crash_test.go b/src/pkg/runtime/crash_test.go
index 5476924..b0277f2 100644
--- a/src/pkg/runtime/crash_test.go
+++ b/src/pkg/runtime/crash_test.go
@@ -9,6 +9,7 @@ import (
 	"os"
 	"os/exec"
 	"path/filepath"
+	"runtime"
 	"strings"
 	"testing"
 	"text/template"
@@ -31,6 +32,10 @@ func testEnv(cmd *exec.Cmd) *exec.Cmd {
 }
 
 func executeTest(t *testing.T, templ string, data interface{}) string {
+	if runtime.GOOS == "nacl" {
+		t.Skip("skipping on nacl")
+	}
+
 	checkStaleRuntime(t)
 
 	st := template.Must(template.New("crashSource").Parse(templ))
@@ -111,8 +116,9 @@ func TestLockedDeadlock2(t *testing.T) {
 
 func TestGoexitDeadlock(t *testing.T) {
 	output := executeTest(t, goexitDeadlockSource, nil)
-	if output != "" {
-		t.Fatalf("expected no output, got:\n%s", output)
+	want := "no goroutines (main called runtime.Goexit) - deadlock!"
+	if !strings.Contains(output, want) {
+		t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
 	}
 }
 
@@ -132,6 +138,34 @@ func TestThreadExhaustion(t *testing.T) {
 	}
 }
 
+func TestRecursivePanic(t *testing.T) {
+	output := executeTest(t, recursivePanicSource, nil)
+	want := `wrap: bad
+panic: again
+
+`
+	if !strings.HasPrefix(output, want) {
+		t.Fatalf("output does not start with %q:\n%s", want, output)
+	}
+
+}
+
+func TestGoexitCrash(t *testing.T) {
+	output := executeTest(t, goexitExitSource, nil)
+	want := "no goroutines (main called runtime.Goexit) - deadlock!"
+	if !strings.Contains(output, want) {
+		t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
+	}
+}
+
+func TestGoNil(t *testing.T) {
+	output := executeTest(t, goNilSource, nil)
+	want := "go of nil func value"
+	if !strings.Contains(output, want) {
+		t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
+	}
+}
+
 const crashSource = `
 package main
 
@@ -272,3 +306,61 @@ func main() {
 	}
 }
 `
+
+const recursivePanicSource = `
+package main
+
+import (
+	"fmt"
+)
+
+func main() {
+	func() {
+		defer func() {
+			fmt.Println(recover())
+		}()
+		var x [8192]byte
+		func(x [8192]byte) {
+			defer func() {
+				if err := recover(); err != nil {
+					panic("wrap: " + err.(string))
+				}
+			}()
+			panic("bad")
+		}(x)
+	}()
+	panic("again")
+}
+`
+
+const goexitExitSource = `
+package main
+
+import (
+	"runtime"
+	"time"
+)
+
+func main() {
+	go func() {
+		time.Sleep(time.Millisecond)
+	}()
+	i := 0
+	runtime.SetFinalizer(&i, func(p *int) {})
+	runtime.GC()
+	runtime.Goexit()
+}
+`
+
+const goNilSource = `
+package main
+
+func main() {
+	defer func() {
+		recover()
+	}()
+	var f func()
+	go f()
+	select{}
+}
+`
diff --git a/src/pkg/runtime/debug/garbage.go b/src/pkg/runtime/debug/garbage.go
index 8337d5d..edb3643 100644
--- a/src/pkg/runtime/debug/garbage.go
+++ b/src/pkg/runtime/debug/garbage.go
@@ -91,7 +91,9 @@ func (x byDuration) Less(i, j int) bool { return x[i] < x[j] }
 // at startup, or 100 if the variable is not set.
 // A negative percentage disables garbage collection.
 func SetGCPercent(percent int) int {
-	return setGCPercent(percent)
+	old := setGCPercent(percent)
+	runtime.GC()
+	return old
 }
 
 // FreeOSMemory forces a garbage collection followed by an
@@ -133,3 +135,19 @@ func SetMaxStack(bytes int) int {
 func SetMaxThreads(threads int) int {
 	return setMaxThreads(threads)
 }
+
+// SetPanicOnFault controls the runtime's behavior when a program faults
+// at an unexpected (non-nil) address. Such faults are typically caused by
+// bugs such as runtime memory corruption, so the default response is to crash
+// the program. Programs working with memory-mapped files or unsafe
+// manipulation of memory may cause faults at non-nil addresses in less
+// dramatic situations; SetPanicOnFault allows such programs to request
+// that the runtime trigger only a panic, not a crash.
+// SetPanicOnFault applies only to the current goroutine.
+// It returns the previous setting.
+func SetPanicOnFault(enabled bool) bool
+
+// WriteHeapDump writes a description of the heap and the objects in
+// it to the given file descriptor.
+// The heap dump format is defined at http://golang.org/s/go13heapdump.
+func WriteHeapDump(fd uintptr)
diff --git a/src/pkg/runtime/debug/heapdump_test.go b/src/pkg/runtime/debug/heapdump_test.go
new file mode 100644
index 0000000..9201901
--- /dev/null
+++ b/src/pkg/runtime/debug/heapdump_test.go
@@ -0,0 +1,33 @@
+// 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 debug
+
+import (
+	"io/ioutil"
+	"os"
+	"runtime"
+	"testing"
+)
+
+func TestWriteHeapDumpNonempty(t *testing.T) {
+	if runtime.GOOS == "nacl" {
+		t.Skip("WriteHeapDump is not available on NaCl.")
+	}
+	f, err := ioutil.TempFile("", "heapdumptest")
+	if err != nil {
+		t.Fatalf("TempFile failed: %v", err)
+	}
+	defer os.Remove(f.Name())
+	defer f.Close()
+	WriteHeapDump(f.Fd())
+	fi, err := f.Stat()
+	if err != nil {
+		t.Fatalf("Stat failed: %v", err)
+	}
+	const minSize = 1
+	if size := fi.Size(); size < minSize {
+		t.Fatalf("Heap dump size %d bytes, expected at least %d bytes", size, minSize)
+	}
+}
diff --git a/src/pkg/runtime/debug/stack.go b/src/pkg/runtime/debug/stack.go
index 2896b21..c29b0a2 100644
--- a/src/pkg/runtime/debug/stack.go
+++ b/src/pkg/runtime/debug/stack.go
@@ -18,6 +18,7 @@ var (
 	dunno     = []byte("???")
 	centerDot = []byte("·")
 	dot       = []byte(".")
+	slash     = []byte("/")
 )
 
 // PrintStack prints to standard error the stack trace returned by Stack.
@@ -84,6 +85,11 @@ func function(pc uintptr) []byte {
 	//	runtime/debug.*T·ptrmethod
 	// and want
 	//	*T.ptrmethod
+	// Since the package path might contains dots (e.g. code.google.com/...),
+	// we first remove the path prefix if there is one.
+	if lastslash := bytes.LastIndex(name, slash); lastslash >= 0 {
+		name = name[lastslash+1:]
+	}
 	if period := bytes.Index(name, dot); period >= 0 {
 		name = name[period+1:]
 	}
diff --git a/src/pkg/runtime/defs.c b/src/pkg/runtime/defs.c
new file mode 100644
index 0000000..1c76198
--- /dev/null
+++ b/src/pkg/runtime/defs.c
@@ -0,0 +1,14 @@
+// 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.
+
+// This file is compiled by cmd/dist to obtain debug information
+// about the given header files.
+
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+#include "type.h"
+#include "race.h"
+#include "hashmap.h"
+#include "chan.h"
diff --git a/src/pkg/runtime/defs_freebsd.go b/src/pkg/runtime/defs_freebsd.go
index dad20f1..2832583 100644
--- a/src/pkg/runtime/defs_freebsd.go
+++ b/src/pkg/runtime/defs_freebsd.go
@@ -49,8 +49,10 @@ const (
 	SA_RESTART = C.SA_RESTART
 	SA_ONSTACK = C.SA_ONSTACK
 
-	UMTX_OP_WAIT_UINT = C.UMTX_OP_WAIT_UINT
-	UMTX_OP_WAKE      = C.UMTX_OP_WAKE
+	UMTX_OP_WAIT_UINT         = C.UMTX_OP_WAIT_UINT
+	UMTX_OP_WAIT_UINT_PRIVATE = C.UMTX_OP_WAIT_UINT_PRIVATE
+	UMTX_OP_WAKE              = C.UMTX_OP_WAKE
+	UMTX_OP_WAKE_PRIVATE      = C.UMTX_OP_WAKE_PRIVATE
 
 	SIGHUP    = C.SIGHUP
 	SIGINT    = C.SIGINT
diff --git a/src/pkg/runtime/defs_freebsd_386.h b/src/pkg/runtime/defs_freebsd_386.h
index cf9c76e..fab9385 100644
--- a/src/pkg/runtime/defs_freebsd_386.h
+++ b/src/pkg/runtime/defs_freebsd_386.h
@@ -21,8 +21,10 @@ enum {
 	SA_RESTART	= 0x2,
 	SA_ONSTACK	= 0x1,
 
-	UMTX_OP_WAIT_UINT	= 0xb,
-	UMTX_OP_WAKE		= 0x3,
+	UMTX_OP_WAIT_UINT		= 0xb,
+	UMTX_OP_WAIT_UINT_PRIVATE	= 0xf,
+	UMTX_OP_WAKE			= 0x3,
+	UMTX_OP_WAKE_PRIVATE		= 0x10,
 
 	SIGHUP		= 0x1,
 	SIGINT		= 0x2,
diff --git a/src/pkg/runtime/defs_freebsd_amd64.h b/src/pkg/runtime/defs_freebsd_amd64.h
index 3fb33f3..c1db918 100644
--- a/src/pkg/runtime/defs_freebsd_amd64.h
+++ b/src/pkg/runtime/defs_freebsd_amd64.h
@@ -21,8 +21,10 @@ enum {
 	SA_RESTART	= 0x2,
 	SA_ONSTACK	= 0x1,
 
-	UMTX_OP_WAIT_UINT	= 0xb,
-	UMTX_OP_WAKE		= 0x3,
+	UMTX_OP_WAIT_UINT		= 0xb,
+	UMTX_OP_WAIT_UINT_PRIVATE	= 0xf,
+	UMTX_OP_WAKE			= 0x3,
+	UMTX_OP_WAKE_PRIVATE		= 0x10,
 
 	SIGHUP		= 0x1,
 	SIGINT		= 0x2,
diff --git a/src/pkg/runtime/defs_freebsd_arm.h b/src/pkg/runtime/defs_freebsd_arm.h
index d321f42..4fc452e 100644
--- a/src/pkg/runtime/defs_freebsd_arm.h
+++ b/src/pkg/runtime/defs_freebsd_arm.h
@@ -4,7 +4,7 @@
 
 enum {
 	EINTR	= 0x4,
-	EFAULT  = 0xe,
+	EFAULT	= 0xe,
 
 	PROT_NONE	= 0x0,
 	PROT_READ	= 0x1,
@@ -21,8 +21,10 @@ enum {
 	SA_RESTART	= 0x2,
 	SA_ONSTACK	= 0x1,
 
-	UMTX_OP_WAIT_UINT	= 0xb,
-	UMTX_OP_WAKE		= 0x3,
+	UMTX_OP_WAIT_UINT		= 0xb,
+	UMTX_OP_WAIT_UINT_PRIVATE	= 0xf,
+	UMTX_OP_WAKE			= 0x3,
+	UMTX_OP_WAKE_PRIVATE		= 0x10,
 
 	SIGHUP		= 0x1,
 	SIGINT		= 0x2,
@@ -76,13 +78,13 @@ enum {
 	ITIMER_VIRTUAL	= 0x1,
 	ITIMER_PROF	= 0x2,
 
-	EV_ADD          = 0x1,
-	EV_DELETE       = 0x2,
-	EV_CLEAR        = 0x20,
-	EV_RECEIPT      = 0x40,
-	EV_ERROR        = 0x4000,
-	EVFILT_READ     = -0x1,
-	EVFILT_WRITE    = -0x2,
+	EV_ADD		= 0x1,
+	EV_DELETE	= 0x2,
+	EV_CLEAR	= 0x20,
+	EV_RECEIPT	= 0x40,
+	EV_ERROR	= 0x4000,
+	EVFILT_READ	= -0x1,
+	EVFILT_WRITE	= -0x2,
 };
 
 typedef struct Rtprio Rtprio;
@@ -159,10 +161,12 @@ struct Ucontext {
 struct Timespec {
 	int64	tv_sec;
 	int32	tv_nsec;
+	byte	Pad_cgo_0[4];
 };
 struct Timeval {
 	int64	tv_sec;
 	int32	tv_usec;
+	byte	Pad_cgo_0[4];
 };
 struct Itimerval {
 	Timeval	it_interval;
@@ -170,12 +174,12 @@ struct Itimerval {
 };
 
 struct Kevent {
-	uint32  ident;
-	int16   filter;
-	uint16  flags;
-	uint32  fflags;
-	int32   data;
-	byte    *udata;
+	uint32	ident;
+	int16	filter;
+	uint16	flags;
+	uint32	fflags;
+	int32	data;
+	byte	*udata;
 };
 
 
diff --git a/src/pkg/runtime/defs_nacl_386.h b/src/pkg/runtime/defs_nacl_386.h
new file mode 100644
index 0000000..e8fbb38
--- /dev/null
+++ b/src/pkg/runtime/defs_nacl_386.h
@@ -0,0 +1,63 @@
+// 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.
+
+// Created by hand, not machine generated.
+
+enum
+{
+	// These values are referred to in the source code
+	// but really don't matter. Even so, use the standard numbers.
+	SIGSEGV = 11,
+	SIGPROF = 27,
+};
+
+typedef struct Siginfo Siginfo;
+
+// native_client/src/trusted/service_runtime/include/machine/_types.h
+typedef struct Timespec Timespec;
+
+struct Timespec
+{
+	int64 tv_sec;
+	int32 tv_nsec;
+};
+
+// native_client/src/trusted/service_runtime/nacl_exception.h
+// native_client/src/include/nacl/nacl_exception.h
+
+typedef struct ExcContext ExcContext;
+typedef struct ExcPortable ExcPortable;
+typedef struct ExcRegs386 ExcRegs386;
+
+struct ExcRegs386
+{
+	uint32	eax;
+	uint32	ecx;
+	uint32	edx;
+	uint32	ebx;
+	uint32	esp;
+	uint32	ebp;
+	uint32	esi;
+	uint32	edi;
+	uint32	eip;
+	uint32	eflags;
+};
+
+struct ExcContext
+{
+	uint32	size;
+	uint32	portable_context_offset;
+	uint32	portable_context_size;
+	uint32	arch;
+	uint32	regs_size;
+	uint32	reserved[11];
+	ExcRegs386	regs;
+};
+
+struct ExcPortableContext
+{
+	uint32	pc;
+	uint32	sp;
+	uint32	fp;
+};
diff --git a/src/pkg/runtime/defs_nacl_amd64p32.h b/src/pkg/runtime/defs_nacl_amd64p32.h
new file mode 100644
index 0000000..8d3068b
--- /dev/null
+++ b/src/pkg/runtime/defs_nacl_amd64p32.h
@@ -0,0 +1,90 @@
+// 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.
+
+// Created by hand, not machine generated.
+
+enum
+{
+	// These values are referred to in the source code
+	// but really don't matter. Even so, use the standard numbers.
+	SIGSEGV = 11,
+	SIGPROF = 27,
+};
+
+typedef struct Siginfo Siginfo;
+
+
+// native_client/src/trusted/service_runtime/include/machine/_types.h
+typedef struct Timespec Timespec;
+
+struct Timespec
+{
+	int64 tv_sec;
+	int32 tv_nsec;
+};
+
+// native_client/src/trusted/service_runtime/nacl_exception.h
+// native_client/src/include/nacl/nacl_exception.h
+
+typedef struct ExcContext ExcContext;
+typedef struct ExcPortable ExcPortable;
+typedef struct ExcRegs386 ExcRegs386;
+typedef struct ExcRegsAmd64 ExcRegsAmd64;
+
+struct ExcRegs386
+{
+	uint32	eax;
+	uint32	ecx;
+	uint32	edx;
+	uint32	ebx;
+	uint32	esp;
+	uint32	ebp;
+	uint32	esi;
+	uint32	edi;
+	uint32	eip;
+	uint32	eflags;
+};
+
+struct ExcRegsAmd64
+{
+	uint64	rax;
+	uint64	rcx;
+	uint64	rdx;
+	uint64	rbx;
+	uint64	rsp;
+	uint64	rbp;
+	uint64	rsi;
+	uint64	rdi;
+	uint64	r8;
+	uint64	r9;
+	uint64	r10;
+	uint64	r11;
+	uint64	r12;
+	uint64	r13;
+	uint64	r14;
+	uint64	r15;
+	uint64	rip;
+	uint32	rflags;
+};
+
+struct ExcContext
+{
+	uint32	size;
+	uint32	portable_context_offset;
+	uint32	portable_context_size;
+	uint32	arch;
+	uint32	regs_size;
+	uint32	reserved[11];
+	union {
+		ExcRegs386	regs;
+		ExcRegsAmd64	regs64;
+	};
+};
+
+struct ExcPortableContext
+{
+	uint32	pc;
+	uint32	sp;
+	uint32	fp;
+};
diff --git a/src/pkg/runtime/defs_openbsd_386.h b/src/pkg/runtime/defs_openbsd_386.h
index a5b7f04..b8f993e 100644
--- a/src/pkg/runtime/defs_openbsd_386.h
+++ b/src/pkg/runtime/defs_openbsd_386.h
@@ -121,7 +121,7 @@ struct Sigcontext {
 	int32	sc_eflags;
 	int32	sc_esp;
 	int32	sc_ss;
-	int32	sc_onstack;
+	int32	__sc_unused;
 	int32	sc_mask;
 	int32	sc_trapno;
 	int32	sc_err;
@@ -143,11 +143,11 @@ struct StackT {
 };
 
 struct Timespec {
-	int32	tv_sec;
+	int64	tv_sec;
 	int32	tv_nsec;
 };
 struct Timeval {
-	int32	tv_sec;
+	int64	tv_sec;
 	int32	tv_usec;
 };
 struct Itimerval {
@@ -160,7 +160,7 @@ struct Kevent {
 	int16	filter;
 	uint16	flags;
 	uint32	fflags;
-	int32	data;
+	int64	data;
 	byte	*udata;
 };
 
diff --git a/src/pkg/runtime/defs_openbsd_amd64.h b/src/pkg/runtime/defs_openbsd_amd64.h
index eb47ec8..a1ae2ef 100644
--- a/src/pkg/runtime/defs_openbsd_amd64.h
+++ b/src/pkg/runtime/defs_openbsd_amd64.h
@@ -133,7 +133,7 @@ struct Sigcontext {
 	int64	sc_rsp;
 	int64	sc_ss;
 	void	*sc_fpstate;
-	int32	sc_onstack;
+	int32	__sc_unused;
 	int32	sc_mask;
 };
 struct Siginfo {
@@ -154,8 +154,7 @@ struct StackT {
 };
 
 struct Timespec {
-	int32	tv_sec;
-	byte	Pad_cgo_0[4];
+	int64	tv_sec;
 	int64	tv_nsec;
 };
 struct Timeval {
@@ -168,11 +167,11 @@ struct Itimerval {
 };
 
 struct Kevent {
-	uint32	ident;
+	uint64	ident;
 	int16	filter;
 	uint16	flags;
 	uint32	fflags;
-	int32	data;
+	int64	data;
 	byte	*udata;
 };
 
diff --git a/src/pkg/runtime/defs_solaris.go b/src/pkg/runtime/defs_solaris.go
new file mode 100644
index 0000000..8dcbb08
--- /dev/null
+++ b/src/pkg/runtime/defs_solaris.go
@@ -0,0 +1,156 @@
+// 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.
+
+// +build ignore
+
+/*
+Input to cgo.
+
+GOARCH=amd64 go tool cgo -cdefs defs_solaris.go >defs_solaris_amd64.h
+*/
+
+package runtime
+
+/*
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/select.h>
+#include <sys/siginfo.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/ucontext.h>
+#include <sys/regset.h>
+#include <sys/unistd.h>
+#include <sys/fork.h>
+#include <sys/port.h>
+#include <semaphore.h>
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include <netdb.h>
+*/
+import "C"
+
+const (
+	EINTR       = C.EINTR
+	EBADF       = C.EBADF
+	EFAULT      = C.EFAULT
+	EAGAIN      = C.EAGAIN
+	ETIMEDOUT   = C.ETIMEDOUT
+	EWOULDBLOCK = C.EWOULDBLOCK
+	EINPROGRESS = C.EINPROGRESS
+
+	PROT_NONE  = C.PROT_NONE
+	PROT_READ  = C.PROT_READ
+	PROT_WRITE = C.PROT_WRITE
+	PROT_EXEC  = C.PROT_EXEC
+
+	MAP_ANON    = C.MAP_ANON
+	MAP_PRIVATE = C.MAP_PRIVATE
+	MAP_FIXED   = C.MAP_FIXED
+
+	MADV_FREE = C.MADV_FREE
+
+	SA_SIGINFO = C.SA_SIGINFO
+	SA_RESTART = C.SA_RESTART
+	SA_ONSTACK = C.SA_ONSTACK
+
+	SIGHUP    = C.SIGHUP
+	SIGINT    = C.SIGINT
+	SIGQUIT   = C.SIGQUIT
+	SIGILL    = C.SIGILL
+	SIGTRAP   = C.SIGTRAP
+	SIGABRT   = C.SIGABRT
+	SIGEMT    = C.SIGEMT
+	SIGFPE    = C.SIGFPE
+	SIGKILL   = C.SIGKILL
+	SIGBUS    = C.SIGBUS
+	SIGSEGV   = C.SIGSEGV
+	SIGSYS    = C.SIGSYS
+	SIGPIPE   = C.SIGPIPE
+	SIGALRM   = C.SIGALRM
+	SIGTERM   = C.SIGTERM
+	SIGURG    = C.SIGURG
+	SIGSTOP   = C.SIGSTOP
+	SIGTSTP   = C.SIGTSTP
+	SIGCONT   = C.SIGCONT
+	SIGCHLD   = C.SIGCHLD
+	SIGTTIN   = C.SIGTTIN
+	SIGTTOU   = C.SIGTTOU
+	SIGIO     = C.SIGIO
+	SIGXCPU   = C.SIGXCPU
+	SIGXFSZ   = C.SIGXFSZ
+	SIGVTALRM = C.SIGVTALRM
+	SIGPROF   = C.SIGPROF
+	SIGWINCH  = C.SIGWINCH
+	SIGUSR1   = C.SIGUSR1
+	SIGUSR2   = C.SIGUSR2
+
+	FPE_INTDIV = C.FPE_INTDIV
+	FPE_INTOVF = C.FPE_INTOVF
+	FPE_FLTDIV = C.FPE_FLTDIV
+	FPE_FLTOVF = C.FPE_FLTOVF
+	FPE_FLTUND = C.FPE_FLTUND
+	FPE_FLTRES = C.FPE_FLTRES
+	FPE_FLTINV = C.FPE_FLTINV
+	FPE_FLTSUB = C.FPE_FLTSUB
+
+	BUS_ADRALN = C.BUS_ADRALN
+	BUS_ADRERR = C.BUS_ADRERR
+	BUS_OBJERR = C.BUS_OBJERR
+
+	SEGV_MAPERR = C.SEGV_MAPERR
+	SEGV_ACCERR = C.SEGV_ACCERR
+
+	ITIMER_REAL    = C.ITIMER_REAL
+	ITIMER_VIRTUAL = C.ITIMER_VIRTUAL
+	ITIMER_PROF    = C.ITIMER_PROF
+
+	_SC_NPROCESSORS_ONLN = C._SC_NPROCESSORS_ONLN
+
+	PTHREAD_CREATE_DETACHED = C.PTHREAD_CREATE_DETACHED
+
+	FORK_NOSIGCHLD = C.FORK_NOSIGCHLD
+	FORK_WAITPID   = C.FORK_WAITPID
+
+	MAXHOSTNAMELEN = C.MAXHOSTNAMELEN
+
+	O_NONBLOCK = C.O_NONBLOCK
+	FD_CLOEXEC = C.FD_CLOEXEC
+	F_GETFL    = C.F_GETFL
+	F_SETFL    = C.F_SETFL
+	F_SETFD    = C.F_SETFD
+
+	POLLIN  = C.POLLIN
+	POLLOUT = C.POLLOUT
+	POLLHUP = C.POLLHUP
+	POLLERR = C.POLLERR
+
+	PORT_SOURCE_FD = C.PORT_SOURCE_FD
+)
+
+type SemT C.sem_t
+
+type Sigaltstack C.struct_sigaltstack
+type Sigset C.sigset_t
+type StackT C.stack_t
+
+type Siginfo C.siginfo_t
+type Sigaction C.struct_sigaction
+
+type Fpregset C.fpregset_t
+type Mcontext C.mcontext_t
+type Ucontext C.ucontext_t
+
+type Timespec C.struct_timespec
+type Timeval C.struct_timeval
+type Itimerval C.struct_itimerval
+
+type PortEvent C.port_event_t
+type Pthread C.pthread_t
+type PthreadAttr C.pthread_attr_t
+
+// depends on Timespec, must appear below
+type Stat C.struct_stat
diff --git a/src/pkg/runtime/defs_solaris_amd64.go b/src/pkg/runtime/defs_solaris_amd64.go
new file mode 100644
index 0000000..0493178
--- /dev/null
+++ b/src/pkg/runtime/defs_solaris_amd64.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.
+
+// +build ignore
+
+/*
+Input to cgo.
+
+GOARCH=amd64 go tool cgo -cdefs defs_solaris.go defs_solaris_amd64.go >defs_solaris_amd64.h
+*/
+
+package runtime
+
+/*
+#include <sys/types.h>
+#include <sys/regset.h>
+*/
+import "C"
+
+const (
+	REG_RDI    = C.REG_RDI
+	REG_RSI    = C.REG_RSI
+	REG_RDX    = C.REG_RDX
+	REG_RCX    = C.REG_RCX
+	REG_R8     = C.REG_R8
+	REG_R9     = C.REG_R9
+	REG_R10    = C.REG_R10
+	REG_R11    = C.REG_R11
+	REG_R12    = C.REG_R12
+	REG_R13    = C.REG_R13
+	REG_R14    = C.REG_R14
+	REG_R15    = C.REG_R15
+	REG_RBP    = C.REG_RBP
+	REG_RBX    = C.REG_RBX
+	REG_RAX    = C.REG_RAX
+	REG_GS     = C.REG_GS
+	REG_FS     = C.REG_FS
+	REG_ES     = C.REG_ES
+	REG_DS     = C.REG_DS
+	REG_TRAPNO = C.REG_TRAPNO
+	REG_ERR    = C.REG_ERR
+	REG_RIP    = C.REG_RIP
+	REG_CS     = C.REG_CS
+	REG_RFLAGS = C.REG_RFL
+	REG_RSP    = C.REG_RSP
+	REG_SS     = C.REG_SS
+)
diff --git a/src/pkg/runtime/defs_solaris_amd64.h b/src/pkg/runtime/defs_solaris_amd64.h
new file mode 100644
index 0000000..799724f
--- /dev/null
+++ b/src/pkg/runtime/defs_solaris_amd64.h
@@ -0,0 +1,254 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_solaris.go defs_solaris_amd64.go
+
+
+enum {
+	EINTR		= 0x4,
+	EBADF		= 0x9,
+	EFAULT		= 0xe,
+	EAGAIN		= 0xb,
+	ETIMEDOUT	= 0x91,
+	EWOULDBLOCK	= 0xb,
+	EINPROGRESS	= 0x96,
+
+	PROT_NONE	= 0x0,
+	PROT_READ	= 0x1,
+	PROT_WRITE	= 0x2,
+	PROT_EXEC	= 0x4,
+
+	MAP_ANON	= 0x100,
+	MAP_PRIVATE	= 0x2,
+	MAP_FIXED	= 0x10,
+
+	MADV_FREE	= 0x5,
+
+	SA_SIGINFO	= 0x8,
+	SA_RESTART	= 0x4,
+	SA_ONSTACK	= 0x1,
+
+	SIGHUP		= 0x1,
+	SIGINT		= 0x2,
+	SIGQUIT		= 0x3,
+	SIGILL		= 0x4,
+	SIGTRAP		= 0x5,
+	SIGABRT		= 0x6,
+	SIGEMT		= 0x7,
+	SIGFPE		= 0x8,
+	SIGKILL		= 0x9,
+	SIGBUS		= 0xa,
+	SIGSEGV		= 0xb,
+	SIGSYS		= 0xc,
+	SIGPIPE		= 0xd,
+	SIGALRM		= 0xe,
+	SIGTERM		= 0xf,
+	SIGURG		= 0x15,
+	SIGSTOP		= 0x17,
+	SIGTSTP		= 0x18,
+	SIGCONT		= 0x19,
+	SIGCHLD		= 0x12,
+	SIGTTIN		= 0x1a,
+	SIGTTOU		= 0x1b,
+	SIGIO		= 0x16,
+	SIGXCPU		= 0x1e,
+	SIGXFSZ		= 0x1f,
+	SIGVTALRM	= 0x1c,
+	SIGPROF		= 0x1d,
+	SIGWINCH	= 0x14,
+	SIGUSR1		= 0x10,
+	SIGUSR2		= 0x11,
+
+	FPE_INTDIV	= 0x1,
+	FPE_INTOVF	= 0x2,
+	FPE_FLTDIV	= 0x3,
+	FPE_FLTOVF	= 0x4,
+	FPE_FLTUND	= 0x5,
+	FPE_FLTRES	= 0x6,
+	FPE_FLTINV	= 0x7,
+	FPE_FLTSUB	= 0x8,
+
+	BUS_ADRALN	= 0x1,
+	BUS_ADRERR	= 0x2,
+	BUS_OBJERR	= 0x3,
+
+	SEGV_MAPERR	= 0x1,
+	SEGV_ACCERR	= 0x2,
+
+	ITIMER_REAL	= 0x0,
+	ITIMER_VIRTUAL	= 0x1,
+	ITIMER_PROF	= 0x2,
+
+	_SC_NPROCESSORS_ONLN	= 0xf,
+
+	PTHREAD_CREATE_DETACHED	= 0x40,
+
+	FORK_NOSIGCHLD	= 0x1,
+	FORK_WAITPID	= 0x2,
+
+	MAXHOSTNAMELEN	= 0x100,
+
+	O_NONBLOCK	= 0x80,
+	FD_CLOEXEC	= 0x1,
+	F_GETFL		= 0x3,
+	F_SETFL		= 0x4,
+	F_SETFD		= 0x2,
+
+	POLLIN	= 0x1,
+	POLLOUT	= 0x4,
+	POLLHUP	= 0x10,
+	POLLERR	= 0x8,
+
+	PORT_SOURCE_FD	= 0x4,
+};
+
+typedef struct SemT SemT;
+typedef struct Sigaltstack Sigaltstack;
+typedef struct Sigset Sigset;
+typedef struct StackT StackT;
+typedef struct Siginfo Siginfo;
+typedef struct Sigaction Sigaction;
+typedef struct Fpregset Fpregset;
+typedef struct Mcontext Mcontext;
+typedef struct Ucontext Ucontext;
+typedef struct Timespec Timespec;
+typedef struct Timeval Timeval;
+typedef struct Itimerval Itimerval;
+typedef struct PortEvent PortEvent;
+typedef struct PthreadAttr PthreadAttr;
+typedef struct Stat Stat;
+
+#pragma pack on
+
+struct SemT {
+	uint32	sem_count;
+	uint16	sem_type;
+	uint16	sem_magic;
+	uint64	sem_pad1[3];
+	uint64	sem_pad2[2];
+};
+
+struct Sigaltstack {
+	byte	*ss_sp;
+	uint64	ss_size;
+	int32	ss_flags;
+	byte	Pad_cgo_0[4];
+};
+struct Sigset {
+	uint32	__sigbits[4];
+};
+struct StackT {
+	byte	*ss_sp;
+	uint64	ss_size;
+	int32	ss_flags;
+	byte	Pad_cgo_0[4];
+};
+
+struct Siginfo {
+	int32	si_signo;
+	int32	si_code;
+	int32	si_errno;
+	int32	si_pad;
+	byte	__data[240];
+};
+struct Sigaction {
+	int32	sa_flags;
+	byte	Pad_cgo_0[4];
+	byte	_funcptr[8];
+	Sigset	sa_mask;
+};
+
+struct Fpregset {
+	byte	fp_reg_set[528];
+};
+struct Mcontext {
+	int64	gregs[28];
+	Fpregset	fpregs;
+};
+struct Ucontext {
+	uint64	uc_flags;
+	Ucontext	*uc_link;
+	Sigset	uc_sigmask;
+	StackT	uc_stack;
+	byte	Pad_cgo_0[8];
+	Mcontext	uc_mcontext;
+	int64	uc_filler[5];
+	byte	Pad_cgo_1[8];
+};
+
+struct Timespec {
+	int64	tv_sec;
+	int64	tv_nsec;
+};
+struct Timeval {
+	int64	tv_sec;
+	int64	tv_usec;
+};
+struct Itimerval {
+	Timeval	it_interval;
+	Timeval	it_value;
+};
+
+struct PortEvent {
+	int32	portev_events;
+	uint16	portev_source;
+	uint16	portev_pad;
+	uint64	portev_object;
+	byte	*portev_user;
+};
+typedef	uint32	Pthread;
+struct PthreadAttr {
+	byte	*__pthread_attrp;
+};
+
+struct Stat {
+	uint64	st_dev;
+	uint64	st_ino;
+	uint32	st_mode;
+	uint32	st_nlink;
+	uint32	st_uid;
+	uint32	st_gid;
+	uint64	st_rdev;
+	int64	st_size;
+	Timespec	st_atim;
+	Timespec	st_mtim;
+	Timespec	st_ctim;
+	int32	st_blksize;
+	byte	Pad_cgo_0[4];
+	int64	st_blocks;
+	int8	st_fstype[16];
+};
+
+
+#pragma pack off
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_solaris.go defs_solaris_amd64.go
+
+
+enum {
+	REG_RDI		= 0x8,
+	REG_RSI		= 0x9,
+	REG_RDX		= 0xc,
+	REG_RCX		= 0xd,
+	REG_R8		= 0x7,
+	REG_R9		= 0x6,
+	REG_R10		= 0x5,
+	REG_R11		= 0x4,
+	REG_R12		= 0x3,
+	REG_R13		= 0x2,
+	REG_R14		= 0x1,
+	REG_R15		= 0x0,
+	REG_RBP		= 0xa,
+	REG_RBX		= 0xb,
+	REG_RAX		= 0xe,
+	REG_GS		= 0x17,
+	REG_FS		= 0x16,
+	REG_ES		= 0x18,
+	REG_DS		= 0x19,
+	REG_TRAPNO	= 0xf,
+	REG_ERR		= 0x10,
+	REG_RIP		= 0x11,
+	REG_CS		= 0x12,
+	REG_RFLAGS	= 0x13,
+	REG_RSP		= 0x14,
+	REG_SS		= 0x15,
+};
+
diff --git a/src/pkg/runtime/env_plan9.c b/src/pkg/runtime/env_plan9.c
index 599319c..f732c9f 100644
--- a/src/pkg/runtime/env_plan9.c
+++ b/src/pkg/runtime/env_plan9.c
@@ -12,6 +12,7 @@ runtime·getenv(int8 *s)
 	intgo len;
 	byte file[128];
 	byte *p;
+	static byte b[128];
 
 	len = runtime·findnull((byte*)s);
 	if(len > sizeof file-6)
@@ -25,7 +26,14 @@ runtime·getenv(int8 *s)
 	if(fd < 0)
 		return nil;
 	n = runtime·seek(fd, 0, 2);
-	p = runtime·malloc(n+1);
+	if(runtime·strcmp((byte*)s, (byte*)"GOTRACEBACK") == 0){
+		// should not call malloc
+		if(n >= sizeof b)
+			return nil;
+		runtime·memclr(b, sizeof b);
+		p = b;
+	}else
+		p = runtime·malloc(n+1);
 	r = runtime·pread(fd, p, n, 0);
 	runtime·close(fd);
 	if(r < 0)
diff --git a/src/pkg/runtime/env_posix.c b/src/pkg/runtime/env_posix.c
index 00ce577..4c8288f 100644
--- a/src/pkg/runtime/env_posix.c
+++ b/src/pkg/runtime/env_posix.c
@@ -2,9 +2,11 @@
 // 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 windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 #include "runtime.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
 
 Slice syscall·envs;
 
@@ -44,15 +46,24 @@ void
 syscall·setenv_c(String k, String v)
 {
 	byte *arg[2];
+	uintptr len;
 
 	if(_cgo_setenv == nil)
 		return;
 
-	arg[0] = runtime·malloc(k.len + 1);
+	// Objects that are explicitly freed must be at least 16 bytes in size,
+	// so that they are not allocated using tiny alloc.
+	len = k.len + 1;
+	if(len < TinySize)
+		len = TinySize;
+	arg[0] = runtime·malloc(len);
 	runtime·memmove(arg[0], k.str, k.len);
 	arg[0][k.len] = 0;
 
-	arg[1] = runtime·malloc(v.len + 1);
+	len = v.len + 1;
+	if(len < TinySize)
+		len = TinySize;
+	arg[1] = runtime·malloc(len);
 	runtime·memmove(arg[1], v.str, v.len);
 	arg[1][v.len] = 0;
 
diff --git a/src/pkg/runtime/error.go b/src/pkg/runtime/error.go
index bd70908..e704ff8 100644
--- a/src/pkg/runtime/error.go
+++ b/src/pkg/runtime/error.go
@@ -75,19 +75,20 @@ func newErrorString(s string, ret *interface{}) {
 }
 
 // An errorCString represents a runtime error described by a single C string.
-type errorCString uintptr
+// Not "type errorCString uintptr" because of http://golang.org/issue/7084.
+type errorCString struct{ cstr uintptr }
 
 func (e errorCString) RuntimeError() {}
 
 func cstringToGo(uintptr) string
 
 func (e errorCString) Error() string {
-	return "runtime error: " + cstringToGo(uintptr(e))
+	return "runtime error: " + cstringToGo(e.cstr)
 }
 
 // For calling from C.
 func newErrorCString(s uintptr, ret *interface{}) {
-	*ret = errorCString(s)
+	*ret = errorCString{s}
 }
 
 type stringer interface {
diff --git a/src/pkg/runtime/export_test.c b/src/pkg/runtime/export_test.c
deleted file mode 100644
index 5ad1a70..0000000
--- a/src/pkg/runtime/export_test.c
+++ /dev/null
@@ -1,13 +0,0 @@
-// 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 "runtime.h"
-#include "arch_GOARCH.h"
-
-void
-·GogoBytes(int32 x)
-{
-	x = RuntimeGogoBytes;
-	FLUSH(&x);
-}
diff --git a/src/pkg/runtime/export_test.go b/src/pkg/runtime/export_test.go
index d170fa7..7a31b63 100644
--- a/src/pkg/runtime/export_test.go
+++ b/src/pkg/runtime/export_test.go
@@ -31,11 +31,11 @@ type LFNode struct {
 	Pushcnt uintptr
 }
 
-func lfstackpush(head *uint64, node *LFNode)
-func lfstackpop2(head *uint64) *LFNode
+func lfstackpush_go(head *uint64, node *LFNode)
+func lfstackpop_go(head *uint64) *LFNode
 
-var LFStackPush = lfstackpush
-var LFStackPop = lfstackpop2
+var LFStackPush = lfstackpush_go
+var LFStackPop = lfstackpop_go
 
 type ParFor struct {
 	body    *byte
@@ -48,17 +48,17 @@ type ParFor struct {
 	wait    bool
 }
 
-func parforalloc2(nthrmax uint32) *ParFor
-func parforsetup2(desc *ParFor, nthr, n uint32, ctx *byte, wait bool, body func(*ParFor, uint32))
-func parfordo(desc *ParFor)
-func parforiters(desc *ParFor, tid uintptr) (uintptr, uintptr)
+func newParFor(nthrmax uint32) *ParFor
+func parForSetup(desc *ParFor, nthr, n uint32, ctx *byte, wait bool, body func(*ParFor, uint32))
+func parForDo(desc *ParFor)
+func parForIters(desc *ParFor, tid uintptr) (uintptr, uintptr)
 
-var NewParFor = parforalloc2
-var ParForSetup = parforsetup2
-var ParForDo = parfordo
+var NewParFor = newParFor
+var ParForSetup = parForSetup
+var ParForDo = parForDo
 
 func ParForIters(desc *ParFor, tid uint32) (uint32, uint32) {
-	begin, end := parforiters(desc, uintptr(tid))
+	begin, end := parForIters(desc, uintptr(tid))
 	return uint32(begin), uint32(end)
 }
 
@@ -80,7 +80,13 @@ var BytesHash = bytesHash
 var Int32Hash = int32Hash
 var Int64Hash = int64Hash
 
-func GogoBytes() int32
-
 var hashLoad float64 // declared in hashmap.c
 var HashLoad = &hashLoad
+
+func memclrBytes(b []byte)
+
+var MemclrBytes = memclrBytes
+
+func gogoBytes() int32
+
+var GogoBytes = gogoBytes
diff --git a/src/pkg/runtime/extern.go b/src/pkg/runtime/extern.go
index 527e9cd..053dc10 100644
--- a/src/pkg/runtime/extern.go
+++ b/src/pkg/runtime/extern.go
@@ -24,18 +24,28 @@ percentage at run time. See http://golang.org/pkg/runtime/debug/#SetGCPercent.
 The GODEBUG variable controls debug output from the runtime. GODEBUG value is
 a comma-separated list of name=val pairs. Supported names are:
 
+	allocfreetrace: setting allocfreetrace=1 causes every allocation to be
+	profiled and a stack trace printed on each object's allocation and free.
+
+	efence: setting efence=1 causes the allocator to run in a mode
+	where each object is allocated on a unique page and addresses are
+	never recycled.
+
 	gctrace: setting gctrace=1 causes the garbage collector to emit a single line to standard
 	error at each collection, summarizing the amount of memory collected and the
 	length of the pause. Setting gctrace=2 emits the same summary but also
 	repeats each collection.
 
-	schedtrace: setting schedtrace=X causes the scheduler to emit a single line to standard
-	error every X milliseconds, summarizing the scheduler state.
+	gcdead: setting gcdead=1 causes the garbage collector to clobber all stack slots
+	that it thinks are dead.
 
 	scheddetail: setting schedtrace=X and scheddetail=1 causes the scheduler to emit
 	detailed multiline info every X milliseconds, describing state of the scheduler,
 	processors, threads and goroutines.
 
+	schedtrace: setting schedtrace=X causes the scheduler to emit a single line to standard
+	error every X milliseconds, summarizing the scheduler state.
+
 The GOMAXPROCS variable limits the number of operating system threads that
 can execute user-level Go code simultaneously. There is no limit to the number of threads
 that can be blocked in system calls on behalf of Go code; those do not count against
@@ -69,6 +79,11 @@ func Gosched()
 
 // Goexit terminates the goroutine that calls it.  No other goroutine is affected.
 // Goexit runs all deferred calls before terminating the goroutine.
+//
+// Calling Goexit from the main goroutine terminates that goroutine
+// without func main returning. Since func main has not returned,
+// the program continues execution of other goroutines.
+// If all other goroutines exit, the program crashes.
 func Goexit()
 
 // Caller reports file and line number information about function invocations on
@@ -153,6 +168,9 @@ func funcentry_go(*Func) uintptr
 // to depend on a finalizer to flush an in-memory I/O buffer such as a
 // bufio.Writer, because the buffer would not be flushed at program exit.
 //
+// It is not guaranteed that a finalizer will run if the size of *x is
+// zero bytes.
+//
 // A single goroutine runs all finalizers for a program, sequentially.
 // If a finalizer must run for a long time, it should do so by starting
 // a new goroutine.
@@ -172,10 +190,8 @@ func GOROOT() string {
 }
 
 // Version returns the Go tree's version string.
-// It is either a sequence number or, when possible,
-// a release tag like "release.2010-03-04".
-// A trailing + indicates that the tree had local modifications
-// at the time of the build.
+// It is either the commit hash and date at the time of the build or,
+// when possible, a release tag like "go1.3".
 func Version() string {
 	return theVersion
 }
diff --git a/src/pkg/runtime/funcdata.h b/src/pkg/runtime/funcdata.h
index 166263e..e20b6ae 100644
--- a/src/pkg/runtime/funcdata.h
+++ b/src/pkg/runtime/funcdata.h
@@ -8,9 +8,11 @@
 // as well as the compilers.
 
 #define PCDATA_ArgSize 0 /* argument size at CALL instruction */
+#define PCDATA_StackMapIndex 1
 
-#define FUNCDATA_GCArgs 0 /* garbage collector blocks */
-#define FUNCDATA_GCLocals 1
+#define FUNCDATA_ArgsPointerMaps 2 /* garbage collector blocks */
+#define FUNCDATA_LocalsPointerMaps 3
+#define FUNCDATA_DeadValueMaps 4
 
 // To be used in assembly.
 #define ARGSIZE(n) PCDATA $PCDATA_ArgSize, $n
diff --git a/src/pkg/runtime/futex_test.go b/src/pkg/runtime/futex_test.go
index f4054b7..f57fc52 100644
--- a/src/pkg/runtime/futex_test.go
+++ b/src/pkg/runtime/futex_test.go
@@ -2,33 +2,76 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Futex is only available on Dragonfly, FreeBSD and Linux.
-// The race detector emits calls to split stack functions so it breaks the test.
+// Futex is only available on DragonFly BSD, FreeBSD and Linux.
+// The race detector emits calls to split stack functions so it breaks
+// the test.
+
 // +build dragonfly freebsd linux
 // +build !race
 
 package runtime_test
 
 import (
-	. "runtime"
+	"runtime"
 	"testing"
 	"time"
 )
 
+type futexsleepTest struct {
+	mtx uint32
+	ns  int64
+	msg string
+	ch  chan futexsleepTest
+}
+
+var futexsleepTests = []futexsleepTest{
+	beforeY2038: {mtx: 0, ns: 86400 * 1e9, msg: "before the year 2038", ch: make(chan futexsleepTest, 1)},
+	afterY2038:  {mtx: 0, ns: (1<<31 + 100) * 1e9, msg: "after the year 2038", ch: make(chan futexsleepTest, 1)},
+}
+
+const (
+	beforeY2038 = iota
+	afterY2038
+)
+
 func TestFutexsleep(t *testing.T) {
-	ch := make(chan bool, 1)
-	var dummy uint32
+	if runtime.GOMAXPROCS(0) > 1 {
+		// futexsleep doesn't handle EINTR or other signals,
+		// so spurious wakeups may happen.
+		t.Skip("skipping; GOMAXPROCS>1")
+	}
+
 	start := time.Now()
-	go func() {
-		Entersyscall()
-		Futexsleep(&dummy, 0, (1<<31+100)*1e9)
-		Exitsyscall()
-		ch <- true
-	}()
-	select {
-	case <-ch:
-		t.Errorf("futexsleep finished early after %s!", time.Since(start))
-	case <-time.After(time.Second):
-		Futexwakeup(&dummy, 1)
+	for _, tt := range futexsleepTests {
+		go func(tt futexsleepTest) {
+			runtime.Entersyscall()
+			runtime.Futexsleep(&tt.mtx, tt.mtx, tt.ns)
+			runtime.Exitsyscall()
+			tt.ch <- tt
+		}(tt)
+	}
+loop:
+	for {
+		select {
+		case tt := <-futexsleepTests[beforeY2038].ch:
+			t.Errorf("futexsleep test %q finished early after %s", tt.msg, time.Since(start))
+			break loop
+		case tt := <-futexsleepTests[afterY2038].ch:
+			// Looks like FreeBSD 10 kernel has changed
+			// the semantics of timedwait on userspace
+			// mutex to make broken stuff look broken.
+			switch {
+			case runtime.GOOS == "freebsd" && runtime.GOARCH == "386":
+				t.Log("freebsd/386 may not work correctly after the year 2038, see golang.org/issue/7194")
+			default:
+				t.Errorf("futexsleep test %q finished early after %s", tt.msg, time.Since(start))
+				break loop
+			}
+		case <-time.After(time.Second):
+			break loop
+		}
+	}
+	for _, tt := range futexsleepTests {
+		runtime.Futexwakeup(&tt.mtx, 1)
 	}
 }
diff --git a/src/pkg/runtime/gc_test.go b/src/pkg/runtime/gc_test.go
index dbd68c1..58717ec 100644
--- a/src/pkg/runtime/gc_test.go
+++ b/src/pkg/runtime/gc_test.go
@@ -9,6 +9,7 @@ import (
 	"runtime"
 	"runtime/debug"
 	"testing"
+	"time"
 )
 
 func TestGcSys(t *testing.T) {
@@ -151,3 +152,85 @@ func TestGcRescan(t *testing.T) {
 		}
 	}
 }
+
+func TestGcLastTime(t *testing.T) {
+	ms := new(runtime.MemStats)
+	t0 := time.Now().UnixNano()
+	runtime.GC()
+	t1 := time.Now().UnixNano()
+	runtime.ReadMemStats(ms)
+	last := int64(ms.LastGC)
+	if t0 > last || last > t1 {
+		t.Fatalf("bad last GC time: got %v, want [%v, %v]", last, t0, t1)
+	}
+}
+
+func BenchmarkSetTypeNoPtr1(b *testing.B) {
+	type NoPtr1 struct {
+		p uintptr
+	}
+	var p *NoPtr1
+	for i := 0; i < b.N; i++ {
+		p = &NoPtr1{}
+	}
+	_ = p
+}
+func BenchmarkSetTypeNoPtr2(b *testing.B) {
+	type NoPtr2 struct {
+		p, q uintptr
+	}
+	var p *NoPtr2
+	for i := 0; i < b.N; i++ {
+		p = &NoPtr2{}
+	}
+	_ = p
+}
+func BenchmarkSetTypePtr1(b *testing.B) {
+	type Ptr1 struct {
+		p *byte
+	}
+	var p *Ptr1
+	for i := 0; i < b.N; i++ {
+		p = &Ptr1{}
+	}
+	_ = p
+}
+func BenchmarkSetTypePtr2(b *testing.B) {
+	type Ptr2 struct {
+		p, q *byte
+	}
+	var p *Ptr2
+	for i := 0; i < b.N; i++ {
+		p = &Ptr2{}
+	}
+	_ = p
+}
+
+func BenchmarkAllocation(b *testing.B) {
+	type T struct {
+		x, y *byte
+	}
+	ngo := runtime.GOMAXPROCS(0)
+	work := make(chan bool, b.N+ngo)
+	result := make(chan *T)
+	for i := 0; i < b.N; i++ {
+		work <- true
+	}
+	for i := 0; i < ngo; i++ {
+		work <- false
+	}
+	for i := 0; i < ngo; i++ {
+		go func() {
+			var x *T
+			for <-work {
+				for i := 0; i < 1000; i++ {
+					x = &T{}
+				}
+			}
+			result <- x
+		}()
+	}
+	for i := 0; i < ngo; i++ {
+		<-result
+	}
+}
diff --git a/src/pkg/runtime/hash_test.go b/src/pkg/runtime/hash_test.go
index 312c4be..1c11e05 100644
--- a/src/pkg/runtime/hash_test.go
+++ b/src/pkg/runtime/hash_test.go
@@ -397,10 +397,10 @@ func avalancheTest1(t *testing.T, k Key) {
 	// all sums inside those bounds with 99% probability.
 	N := n * hashSize
 	var c float64
-	// find c such that Prob(mean-c*stddev < x < mean+c*stddev)^N > .99
-	for c = 0.0; math.Pow(math.Erf(c/math.Sqrt(2)), float64(N)) < .99; c += .1 {
+	// find c such that Prob(mean-c*stddev < x < mean+c*stddev)^N > .9999
+	for c = 0.0; math.Pow(math.Erf(c/math.Sqrt(2)), float64(N)) < .9999; c += .1 {
 	}
-	c *= 2.0 // allowed slack - we don't need to be perfectly random
+	c *= 4.0 // allowed slack - we don't need to be perfectly random
 	mean := .5 * REP
 	stddev := .5 * math.Sqrt(REP)
 	low := int(mean - c*stddev)
diff --git a/src/pkg/runtime/hashmap.c b/src/pkg/runtime/hashmap.c
deleted file mode 100644
index 6d2ab21..0000000
--- a/src/pkg/runtime/hashmap.c
+++ /dev/null
@@ -1,1367 +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 "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "type.h"
-#include "race.h"
-#include "../../cmd/ld/textflag.h"
-
-// This file contains the implementation of Go's map type.
-//
-// The map is just a hash table.  The data is arranged
-// into an array of buckets.  Each bucket contains up to
-// 8 key/value pairs.  The low-order bits of the hash are
-// used to select a bucket.  Each bucket contains a few
-// high-order bits of each hash to distinguish the entries
-// within a single bucket.
-//
-// If more than 8 keys hash to a bucket, we chain on
-// extra buckets.
-//
-// When the hashtable grows, we allocate a new array
-// of buckets twice as big.  Buckets are incrementally
-// copied from the old bucket array to the new bucket array.
-//
-// Map iterators walk through the array of buckets and
-// return the keys in walk order (bucket #, then overflow
-// chain order, then bucket index).  To maintain iteration
-// semantics, we never move keys within their bucket (if
-// we did, keys might be returned 0 or 2 times).  When
-// growing the table, iterators remain iterating through the
-// old table and must check the new table if the bucket
-// they are iterating through has been moved ("evacuated")
-// to the new table.
-
-// Maximum number of key/value pairs a bucket can hold.
-#define BUCKETSIZE 8
-
-// Maximum average load of a bucket that triggers growth.
-#define LOAD 6.5
-
-// Picking LOAD: too large and we have lots of overflow
-// buckets, too small and we waste a lot of space.  I wrote
-// a simple program to check some stats for different loads:
-// (64-bit, 8 byte keys and values)
-//        LOAD    %overflow  bytes/entry     hitprobe    missprobe
-//        4.00         2.13        20.77         3.00         4.00
-//        4.50         4.05        17.30         3.25         4.50
-//        5.00         6.85        14.77         3.50         5.00
-//        5.50        10.55        12.94         3.75         5.50
-//        6.00        15.27        11.67         4.00         6.00
-//        6.50        20.90        10.79         4.25         6.50
-//        7.00        27.14        10.15         4.50         7.00
-//        7.50        34.03         9.73         4.75         7.50
-//        8.00        41.10         9.40         5.00         8.00
-//
-// %overflow   = percentage of buckets which have an overflow bucket
-// bytes/entry = overhead bytes used per key/value pair
-// hitprobe    = # of entries to check when looking up a present key
-// missprobe   = # of entries to check when looking up an absent key
-//
-// Keep in mind this data is for maximally loaded tables, i.e. just
-// before the table grows.  Typical tables will be somewhat less loaded.
-
-// Maximum key or value size to keep inline (instead of mallocing per element).
-// Must fit in a uint8.
-// Fast versions cannot handle big values - the cutoff size for
-// fast versions in ../../cmd/gc/walk.c must be at most this value.
-#define MAXKEYSIZE 128
-#define MAXVALUESIZE 128
-
-typedef struct Bucket Bucket;
-struct Bucket
-{
-	// Note: the format of the Bucket is encoded in ../../cmd/gc/reflect.c and
-	// ../reflect/type.go.  Don't change this structure without also changing that code!
-	uint8  tophash[BUCKETSIZE]; // top 8 bits of hash of each entry (0 = empty)
-	Bucket *overflow;           // overflow bucket, if any
-	byte   data[1];             // BUCKETSIZE keys followed by BUCKETSIZE values
-};
-// NOTE: packing all the keys together and then all the values together makes the
-// code a bit more complicated than alternating key/value/key/value/... but it allows
-// us to eliminate padding which would be needed for, e.g., map[int64]int8.
-
-// Low-order bit of overflow field is used to mark a bucket as already evacuated
-// without destroying the overflow pointer.
-// Only buckets in oldbuckets will be marked as evacuated.
-// Evacuated bit will be set identically on the base bucket and any overflow buckets.
-#define evacuated(b) (((uintptr)(b)->overflow & 1) != 0)
-#define overflowptr(b) ((Bucket*)((uintptr)(b)->overflow & ~(uintptr)1))
-
-struct Hmap
-{
-	// Note: the format of the Hmap is encoded in ../../cmd/gc/reflect.c and
-	// ../reflect/type.go.  Don't change this structure without also changing that code!
-	uintgo  count;        // # live cells == size of map.  Must be first (used by len() builtin)
-	uint32  flags;
-	uint32  hash0;        // hash seed
-	uint8   B;            // log_2 of # of buckets (can hold up to LOAD * 2^B items)
-	uint8   keysize;      // key size in bytes
-	uint8   valuesize;    // value size in bytes
-	uint16  bucketsize;   // bucket size in bytes
-
-	byte    *buckets;     // array of 2^B Buckets. may be nil if count==0.
-	byte    *oldbuckets;  // previous bucket array of half the size, non-nil only when growing
-	uintptr nevacuate;    // progress counter for evacuation (buckets less than this have been evacuated)
-};
-
-// possible flags
-enum
-{
-	IndirectKey = 1,    // storing pointers to keys
-	IndirectValue = 2,  // storing pointers to values
-	Iterator = 4,       // there may be an iterator using buckets
-	OldIterator = 8,    // there may be an iterator using oldbuckets
-};
-
-// Macros for dereferencing indirect keys
-#define IK(h, p) (((h)->flags & IndirectKey) != 0 ? *(byte**)(p) : (p))
-#define IV(h, p) (((h)->flags & IndirectValue) != 0 ? *(byte**)(p) : (p))
-
-enum
-{
-	docheck = 0,  // check invariants before and after every op.  Slow!!!
-	debug = 0,    // print every operation
-	checkgc = 0 || docheck,  // check interaction of mallocgc() with the garbage collector
-};
-static void
-check(MapType *t, Hmap *h)
-{
-	uintptr bucket, oldbucket;
-	Bucket *b;
-	uintptr i;
-	uintptr hash;
-	uintgo cnt;
-	uint8 top;
-	bool eq;
-	byte *k, *v;
-
-	cnt = 0;
-
-	// check buckets
-	for(bucket = 0; bucket < (uintptr)1 << h->B; bucket++) {
-		if(h->oldbuckets != nil) {
-			oldbucket = bucket & (((uintptr)1 << (h->B - 1)) - 1);
-			b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
-			if(!evacuated(b))
-				continue; // b is still uninitialized
-		}
-		for(b = (Bucket*)(h->buckets + bucket * h->bucketsize); b != nil; b = b->overflow) {
-			for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
-				if(b->tophash[i] == 0)
-					continue;
-				cnt++;
-				t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
-				if(!eq)
-					continue; // NaN!
-				hash = h->hash0;
-				t->key->alg->hash(&hash, t->key->size, IK(h, k));
-				top = hash >> (8*sizeof(uintptr) - 8);
-				if(top == 0)
-					top = 1;
-				if(top != b->tophash[i])
-					runtime·throw("bad hash");
-			}
-		}
-	}
-
-	// check oldbuckets
-	if(h->oldbuckets != nil) {
-		for(oldbucket = 0; oldbucket < (uintptr)1 << (h->B - 1); oldbucket++) {
-			b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
-			if(evacuated(b))
-				continue;
-			if(oldbucket < h->nevacuate)
-				runtime·throw("bucket became unevacuated");
-			for(; b != nil; b = overflowptr(b)) {
-				for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
-					if(b->tophash[i] == 0)
-						continue;
-					cnt++;
-					t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
-					if(!eq)
-						continue; // NaN!
-					hash = h->hash0;
-					t->key->alg->hash(&hash, t->key->size, IK(h, k));
-					top = hash >> (8*sizeof(uintptr) - 8);
-					if(top == 0)
-						top = 1;
-					if(top != b->tophash[i])
-						runtime·throw("bad hash (old)");
-				}
-			}
-		}
-	}
-
-	if(cnt != h->count) {
-		runtime·printf("%D %D\n", (uint64)cnt, (uint64)h->count);
-		runtime·throw("entries missing");
-	}
-}
-
-static void
-hash_init(MapType *t, Hmap *h, uint32 hint)
-{
-	uint8 B;
-	byte *buckets;
-	uintptr keysize, valuesize, bucketsize;
-	uint8 flags;
-
-	flags = 0;
-
-	// figure out how big we have to make everything
-	keysize = t->key->size;
-	if(keysize > MAXKEYSIZE) {
-		flags |= IndirectKey;
-		keysize = sizeof(byte*);
-	}
-	valuesize = t->elem->size;
-	if(valuesize > MAXVALUESIZE) {
-		flags |= IndirectValue;
-		valuesize = sizeof(byte*);
-	}
-	bucketsize = offsetof(Bucket, data[0]) + (keysize + valuesize) * BUCKETSIZE;
-
-	// invariants we depend on.  We should probably check these at compile time
-	// somewhere, but for now we'll do it here.
-	if(t->key->align > BUCKETSIZE)
-		runtime·throw("key align too big");
-	if(t->elem->align > BUCKETSIZE)
-		runtime·throw("value align too big");
-	if(t->key->size % t->key->align != 0)
-		runtime·throw("key size not a multiple of key align");
-	if(t->elem->size % t->elem->align != 0)
-		runtime·throw("value size not a multiple of value align");
-	if(BUCKETSIZE < 8)
-		runtime·throw("bucketsize too small for proper alignment");
-	if(sizeof(void*) == 4 && t->key->align > 4)
-		runtime·throw("need padding in bucket (key)");
-	if(sizeof(void*) == 4 && t->elem->align > 4)
-		runtime·throw("need padding in bucket (value)");
-
-	// find size parameter which will hold the requested # of elements
-	B = 0;
-	while(hint > BUCKETSIZE && hint > LOAD * ((uintptr)1 << B))
-		B++;
-
-	// allocate initial hash table
-	// If hint is large zeroing this memory could take a while.
-	if(checkgc) mstats.next_gc = mstats.heap_alloc;
-	if(B == 0) {
-		// done lazily later.
-		buckets = nil;
-	} else {
-		buckets = runtime·cnewarray(t->bucket, (uintptr)1 << B);
-	}
-
-	// initialize Hmap
-	h->count = 0;
-	h->B = B;
-	h->flags = flags;
-	h->keysize = keysize;
-	h->valuesize = valuesize;
-	h->bucketsize = bucketsize;
-	h->hash0 = runtime·fastrand1();
-	h->buckets = buckets;
-	h->oldbuckets = nil;
-	h->nevacuate = 0;
-	if(docheck)
-		check(t, h);
-}
-
-// Moves entries in oldbuckets[i] to buckets[i] and buckets[i+2^k].
-// We leave the original bucket intact, except for the evacuated marks, so that
-// iterators can still iterate through the old buckets.
-static void
-evacuate(MapType *t, Hmap *h, uintptr oldbucket)
-{
-	Bucket *b;
-	Bucket *nextb;
-	Bucket *x, *y;
-	Bucket *newx, *newy;
-	uintptr xi, yi;
-	uintptr newbit;
-	uintptr hash;
-	uintptr i;
-	byte *k, *v;
-	byte *xk, *yk, *xv, *yv;
-	uint8 top;
-	bool eq;
-
-	b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
-	newbit = (uintptr)1 << (h->B - 1);
-
-	if(!evacuated(b)) {
-		// TODO: reuse overflow buckets instead of using new ones, if there
-		// is no iterator using the old buckets.  (If !OldIterator.)
-
-		x = (Bucket*)(h->buckets + oldbucket * h->bucketsize);
-		y = (Bucket*)(h->buckets + (oldbucket + newbit) * h->bucketsize);
-		xi = 0;
-		yi = 0;
-		xk = x->data;
-		yk = y->data;
-		xv = xk + h->keysize * BUCKETSIZE;
-		yv = yk + h->keysize * BUCKETSIZE;
-		do {
-			for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
-				top = b->tophash[i];
-				if(top == 0)
-					continue;
-
-				// Compute hash to make our evacuation decision (whether we need
-				// to send this key/value to bucket x or bucket y).
-				hash = h->hash0;
-				t->key->alg->hash(&hash, t->key->size, IK(h, k));
-				if((h->flags & Iterator) != 0) {
-					t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
-					if(!eq) {
-						// If key != key (NaNs), then the hash could be (and probably
-						// will be) entirely different from the old hash.  Moreover,
-						// it isn't reproducible.  Reproducibility is required in the
-						// presence of iterators, as our evacuation decision must
-						// match whatever decision the iterator made.
-						// Fortunately, we have the freedom to send these keys either
-						// way.  Also, tophash is meaningless for these kinds of keys.
-						// We let the low bit of tophash drive the evacuation decision.
-						// We recompute a new random tophash for the next level so
-						// these keys will get evenly distributed across all buckets
-						// after multiple grows.
-						if((top & 1) != 0)
-							hash |= newbit;
-						else
-							hash &= ~newbit;
-						top = hash >> (8*sizeof(uintptr)-8);
-						if(top == 0)
-							top = 1;
-					}
-				}
-
-				if((hash & newbit) == 0) {
-					if(xi == BUCKETSIZE) {
-						if(checkgc) mstats.next_gc = mstats.heap_alloc;
-						newx = runtime·cnew(t->bucket);
-						x->overflow = newx;
-						x = newx;
-						xi = 0;
-						xk = x->data;
-						xv = xk + h->keysize * BUCKETSIZE;
-					}
-					x->tophash[xi] = top;
-					if((h->flags & IndirectKey) != 0) {
-						*(byte**)xk = *(byte**)k;               // copy pointer
-					} else {
-						t->key->alg->copy(t->key->size, xk, k); // copy value
-					}
-					if((h->flags & IndirectValue) != 0) {
-						*(byte**)xv = *(byte**)v;
-					} else {
-						t->elem->alg->copy(t->elem->size, xv, v);
-					}
-					xi++;
-					xk += h->keysize;
-					xv += h->valuesize;
-				} else {
-					if(yi == BUCKETSIZE) {
-						if(checkgc) mstats.next_gc = mstats.heap_alloc;
-						newy = runtime·cnew(t->bucket);
-						y->overflow = newy;
-						y = newy;
-						yi = 0;
-						yk = y->data;
-						yv = yk + h->keysize * BUCKETSIZE;
-					}
-					y->tophash[yi] = top;
-					if((h->flags & IndirectKey) != 0) {
-						*(byte**)yk = *(byte**)k;
-					} else {
-						t->key->alg->copy(t->key->size, yk, k);
-					}
-					if((h->flags & IndirectValue) != 0) {
-						*(byte**)yv = *(byte**)v;
-					} else {
-						t->elem->alg->copy(t->elem->size, yv, v);
-					}
-					yi++;
-					yk += h->keysize;
-					yv += h->valuesize;
-				}
-			}
-
-			// mark as evacuated so we don't do it again.
-			// this also tells any iterators that this data isn't golden anymore.
-			nextb = b->overflow;
-			b->overflow = (Bucket*)((uintptr)nextb + 1);
-
-			b = nextb;
-		} while(b != nil);
-
-		// Unlink the overflow buckets to help GC.
-		b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
-		if((h->flags & OldIterator) == 0)
-			b->overflow = (Bucket*)1;
-	}
-
-	// advance evacuation mark
-	if(oldbucket == h->nevacuate) {
-		h->nevacuate = oldbucket + 1;
-		if(oldbucket + 1 == newbit) // newbit == # of oldbuckets
-			// free main bucket array
-			h->oldbuckets = nil;
-	}
-	if(docheck)
-		check(t, h);
-}
-
-static void
-grow_work(MapType *t, Hmap *h, uintptr bucket)
-{
-	uintptr noldbuckets;
-
-	noldbuckets = (uintptr)1 << (h->B - 1);
-
-	// make sure we evacuate the oldbucket corresponding
-	// to the bucket we're about to use
-	evacuate(t, h, bucket & (noldbuckets - 1));
-
-	// evacuate one more oldbucket to make progress on growing
-	if(h->oldbuckets != nil)
-		evacuate(t, h, h->nevacuate);
-}
-
-static void
-hash_grow(MapType *t, Hmap *h)
-{
-	byte *old_buckets;
-	byte *new_buckets;
-	uint8 flags;
-
-	// allocate a bigger hash table
-	if(h->oldbuckets != nil)
-		runtime·throw("evacuation not done in time");
-	old_buckets = h->buckets;
-	// NOTE: this could be a big malloc, but since we don't need zeroing it is probably fast.
-	if(checkgc) mstats.next_gc = mstats.heap_alloc;
-	new_buckets = runtime·cnewarray(t->bucket, (uintptr)1 << (h->B + 1));
-	flags = (h->flags & ~(Iterator | OldIterator));
-	if((h->flags & Iterator) != 0)
-		flags |= OldIterator;
-
-	// commit the grow (atomic wrt gc)
-	h->B++;
-	h->flags = flags;
-	h->oldbuckets = old_buckets;
-	h->buckets = new_buckets;
-	h->nevacuate = 0;
-
-	// the actual copying of the hash table data is done incrementally
-	// by grow_work() and evacuate().
-	if(docheck)
-		check(t, h);
-}
-
-// returns ptr to value associated with key *keyp, or nil if none.
-// if it returns non-nil, updates *keyp to point to the currently stored key.
-static byte*
-hash_lookup(MapType *t, Hmap *h, byte **keyp)
-{
-	void *key;
-	uintptr hash;
-	uintptr bucket, oldbucket;
-	Bucket *b;
-	uint8 top;
-	uintptr i;
-	bool eq;
-	byte *k, *k2, *v;
-
-	key = *keyp;
-	if(docheck)
-		check(t, h);
-	if(h->count == 0)
-		return nil;
-	hash = h->hash0;
-	t->key->alg->hash(&hash, t->key->size, key);
-	bucket = hash & (((uintptr)1 << h->B) - 1);
-	if(h->oldbuckets != nil) {
-		oldbucket = bucket & (((uintptr)1 << (h->B - 1)) - 1);
-		b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
-		if(evacuated(b)) {
-			b = (Bucket*)(h->buckets + bucket * h->bucketsize);
-		}
-	} else {
-		b = (Bucket*)(h->buckets + bucket * h->bucketsize);
-	}
-	top = hash >> (sizeof(uintptr)*8 - 8);
-	if(top == 0)
-		top = 1;
-	do {
-		for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
-			if(b->tophash[i] == top) {
-				k2 = IK(h, k);
-				t->key->alg->equal(&eq, t->key->size, key, k2);
-				if(eq) {
-					*keyp = k2;
-					return IV(h, v);
-				}
-			}
-		}
-		b = b->overflow;
-	} while(b != nil);
-	return nil;
-}
-
-// When an item is not found, fast versions return a pointer to this zeroed memory.
-#pragma dataflag RODATA
-static uint8 empty_value[MAXVALUESIZE];
-
-// Specialized versions of mapaccess1 for specific types.
-// See ./hashmap_fast.c and ../../cmd/gc/walk.c.
-#define HASH_LOOKUP1 runtime·mapaccess1_fast32
-#define HASH_LOOKUP2 runtime·mapaccess2_fast32
-#define KEYTYPE uint32
-#define HASHFUNC runtime·algarray[AMEM32].hash
-#define FASTKEY(x) true
-#define QUICK_NE(x,y) ((x) != (y))
-#define QUICK_EQ(x,y) true
-#define SLOW_EQ(x,y) true
-#define MAYBE_EQ(x,y) true
-#include "hashmap_fast.c"
-
-#undef HASH_LOOKUP1
-#undef HASH_LOOKUP2
-#undef KEYTYPE
-#undef HASHFUNC
-#undef FASTKEY
-#undef QUICK_NE
-#undef QUICK_EQ
-#undef SLOW_EQ
-#undef MAYBE_EQ
-
-#define HASH_LOOKUP1 runtime·mapaccess1_fast64
-#define HASH_LOOKUP2 runtime·mapaccess2_fast64
-#define KEYTYPE uint64
-#define HASHFUNC runtime·algarray[AMEM64].hash
-#define FASTKEY(x) true
-#define QUICK_NE(x,y) ((x) != (y))
-#define QUICK_EQ(x,y) true
-#define SLOW_EQ(x,y) true
-#define MAYBE_EQ(x,y) true
-#include "hashmap_fast.c"
-
-#undef HASH_LOOKUP1
-#undef HASH_LOOKUP2
-#undef KEYTYPE
-#undef HASHFUNC
-#undef FASTKEY
-#undef QUICK_NE
-#undef QUICK_EQ
-#undef SLOW_EQ
-#undef MAYBE_EQ
-
-#ifdef GOARCH_amd64
-#define CHECKTYPE uint64
-#endif
-#ifdef GOARCH_386
-#define CHECKTYPE uint32
-#endif
-#ifdef GOARCH_arm
-// can't use uint32 on arm because our loads aren't aligned.
-// TODO: use uint32 for arm v6+?
-#define CHECKTYPE uint8
-#endif
-
-#define HASH_LOOKUP1 runtime·mapaccess1_faststr
-#define HASH_LOOKUP2 runtime·mapaccess2_faststr
-#define KEYTYPE String
-#define HASHFUNC runtime·algarray[ASTRING].hash
-#define FASTKEY(x) ((x).len < 32)
-#define QUICK_NE(x,y) ((x).len != (y).len)
-#define QUICK_EQ(x,y) ((x).str == (y).str)
-#define SLOW_EQ(x,y) runtime·memeq((x).str, (y).str, (x).len)
-#define MAYBE_EQ(x,y) (*(CHECKTYPE*)(x).str == *(CHECKTYPE*)(y).str && *(CHECKTYPE*)((x).str + (x).len - sizeof(CHECKTYPE)) == *(CHECKTYPE*)((y).str + (x).len - sizeof(CHECKTYPE)))
-#include "hashmap_fast.c"
-
-static void
-hash_insert(MapType *t, Hmap *h, void *key, void *value)
-{
-	uintptr hash;
-	uintptr bucket;
-	uintptr i;
-	bool eq;
-	Bucket *b;
-	Bucket *newb;
-	uint8 *inserti;
-	byte *insertk, *insertv;
-	uint8 top;
-	byte *k, *v;
-	byte *kmem, *vmem;
-
-	if(docheck)
-		check(t, h);
-	hash = h->hash0;
-	t->key->alg->hash(&hash, t->key->size, key);
-	if(h->buckets == nil)
-		h->buckets = runtime·cnewarray(t->bucket, 1);
-
- again:
-	bucket = hash & (((uintptr)1 << h->B) - 1);
-	if(h->oldbuckets != nil)
-		grow_work(t, h, bucket);
-	b = (Bucket*)(h->buckets + bucket * h->bucketsize);
-	top = hash >> (sizeof(uintptr)*8 - 8);
-	if(top == 0)
-		top = 1;
-	inserti = nil;
-	insertk = nil;
-	insertv = nil;
-	while(true) {
-		for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
-			if(b->tophash[i] != top) {
-				if(b->tophash[i] == 0 && inserti == nil) {
-					inserti = &b->tophash[i];
-					insertk = k;
-					insertv = v;
-				}
-				continue;
-			}
-			t->key->alg->equal(&eq, t->key->size, key, IK(h, k));
-			if(!eq)
-				continue;
-			// already have a mapping for key.  Update it.
-			t->key->alg->copy(t->key->size, IK(h, k), key); // Need to update key for keys which are distinct but equal (e.g. +0.0 and -0.0)
-			t->elem->alg->copy(t->elem->size, IV(h, v), value);
-			if(docheck)
-				check(t, h);
-			return;
-		}
-		if(b->overflow == nil)
-			break;
-		b = b->overflow;
-	}
-
-	// did not find mapping for key.  Allocate new cell & add entry.
-	if(h->count >= LOAD * ((uintptr)1 << h->B) && h->count >= BUCKETSIZE) {
-		hash_grow(t, h);
-		goto again; // Growing the table invalidates everything, so try again
-	}
-
-	if(inserti == nil) {
-		// all current buckets are full, allocate a new one.
-		if(checkgc) mstats.next_gc = mstats.heap_alloc;
-		newb = runtime·cnew(t->bucket);
-		b->overflow = newb;
-		inserti = newb->tophash;
-		insertk = newb->data;
-		insertv = insertk + h->keysize * BUCKETSIZE;
-	}
-
-	// store new key/value at insert position
-	if((h->flags & IndirectKey) != 0) {
-		if(checkgc) mstats.next_gc = mstats.heap_alloc;
-		kmem = runtime·cnew(t->key);
-		*(byte**)insertk = kmem;
-		insertk = kmem;
-	}
-	if((h->flags & IndirectValue) != 0) {
-		if(checkgc) mstats.next_gc = mstats.heap_alloc;
-		vmem = runtime·cnew(t->elem);
-		*(byte**)insertv = vmem;
-		insertv = vmem;
-	}
-	t->key->alg->copy(t->key->size, insertk, key);
-	t->elem->alg->copy(t->elem->size, insertv, value);
-	*inserti = top;
-	h->count++;
-	if(docheck)
-		check(t, h);
-}
-
-static void
-hash_remove(MapType *t, Hmap *h, void *key)
-{
-	uintptr hash;
-	uintptr bucket;
-	Bucket *b;
-	uint8 top;
-	uintptr i;
-	byte *k, *v;
-	bool eq;
-	
-	if(docheck)
-		check(t, h);
-	if(h->count == 0)
-		return;
-	hash = h->hash0;
-	t->key->alg->hash(&hash, t->key->size, key);
-	bucket = hash & (((uintptr)1 << h->B) - 1);
-	if(h->oldbuckets != nil)
-		grow_work(t, h, bucket);
-	b = (Bucket*)(h->buckets + bucket * h->bucketsize);
-	top = hash >> (sizeof(uintptr)*8 - 8);
-	if(top == 0)
-		top = 1;
-	do {
-		for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
-			if(b->tophash[i] != top)
-				continue;
-			t->key->alg->equal(&eq, t->key->size, key, IK(h, k));
-			if(!eq)
-				continue;
-
-			if((h->flags & IndirectKey) != 0) {
-				*(byte**)k = nil;
-			} else {
-				t->key->alg->copy(t->key->size, k, nil);
-			}
-			if((h->flags & IndirectValue) != 0) {
-				*(byte**)v = nil;
-			} else {
-				t->elem->alg->copy(t->elem->size, v, nil);
-			}
-
-			b->tophash[i] = 0;
-			h->count--;
-			
-			// TODO: consolidate buckets if they are mostly empty
-			// can only consolidate if there are no live iterators at this size.
-			if(docheck)
-				check(t, h);
-			return;
-		}
-		b = b->overflow;
-	} while(b != nil);
-}
-
-// TODO: shrink the map, the same way we grow it.
-
-// If you modify hash_iter, also change cmd/gc/range.c to indicate
-// the size of this structure.
-struct hash_iter
-{
-	uint8* key; // Must be in first position.  Write nil to indicate iteration end (see cmd/gc/range.c).
-	uint8* value;
-
-	MapType *t;
-	Hmap *h;
-
-	// end point for iteration
-	uintptr endbucket;
-	bool wrapped;
-
-	// state of table at time iterator is initialized
-	uint8 B;
-	byte *buckets;
-
-	// iter state
-	uintptr bucket;
-	struct Bucket *bptr;
-	uintptr i;
-	intptr check_bucket;
-};
-
-// iterator state:
-// bucket: the current bucket ID
-// b: the current Bucket in the chain
-// i: the next offset to check in the current bucket
-static void
-hash_iter_init(MapType *t, Hmap *h, struct hash_iter *it)
-{
-	uint32 old;
-
-	if(sizeof(struct hash_iter) / sizeof(uintptr) != 11) {
-		runtime·throw("hash_iter size incorrect"); // see ../../cmd/gc/range.c
-	}
-	it->t = t;
-	it->h = h;
-
-	// grab snapshot of bucket state
-	it->B = h->B;
-	it->buckets = h->buckets;
-
-	// iterator state
-	it->bucket = it->endbucket = runtime·fastrand1() & (((uintptr)1 << h->B) - 1);
-	it->wrapped = false;
-	it->bptr = nil;
-
-	// Remember we have an iterator.
-	// Can run concurrently with another hash_iter_init().
-	for(;;) {
-		old = h->flags;
-		if((old&(Iterator|OldIterator)) == (Iterator|OldIterator))
-			break;
-		if(runtime·cas(&h->flags, old, old|Iterator|OldIterator))
-			break;
-	}
-
-	if(h->buckets == nil) {
-		// Empty map. Force next hash_next to exit without
-		// evalulating h->bucket.
-		it->wrapped = true;
-	}
-}
-
-// initializes it->key and it->value to the next key/value pair
-// in the iteration, or nil if we've reached the end.
-static void
-hash_next(struct hash_iter *it)
-{
-	Hmap *h;
-	MapType *t;
-	uintptr bucket, oldbucket;
-	uintptr hash;
-	Bucket *b;
-	uintptr i;
-	intptr check_bucket;
-	bool eq;
-	byte *k, *v;
-	byte *rk, *rv;
-
-	h = it->h;
-	t = it->t;
-	bucket = it->bucket;
-	b = it->bptr;
-	i = it->i;
-	check_bucket = it->check_bucket;
-
-next:
-	if(b == nil) {
-		if(bucket == it->endbucket && it->wrapped) {
-			// end of iteration
-			it->key = nil;
-			it->value = nil;
-			return;
-		}
-		if(h->oldbuckets != nil && it->B == h->B) {
-			// Iterator was started in the middle of a grow, and the grow isn't done yet.
-			// If the bucket we're looking at hasn't been filled in yet (i.e. the old
-			// bucket hasn't been evacuated) then we need to iterate through the old
-			// bucket and only return the ones that will be migrated to this bucket.
-			oldbucket = bucket & (((uintptr)1 << (it->B - 1)) - 1);
-			b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
-			if(!evacuated(b)) {
-				check_bucket = bucket;
-			} else {
-				b = (Bucket*)(it->buckets + bucket * h->bucketsize);
-				check_bucket = -1;
-			}
-		} else {
-			b = (Bucket*)(it->buckets + bucket * h->bucketsize);
-			check_bucket = -1;
-		}
-		bucket++;
-		if(bucket == ((uintptr)1 << it->B)) {
-			bucket = 0;
-			it->wrapped = true;
-		}
-		i = 0;
-	}
-	k = b->data + h->keysize * i;
-	v = b->data + h->keysize * BUCKETSIZE + h->valuesize * i;
-	for(; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
-		if(b->tophash[i] != 0) {
-			if(check_bucket >= 0) {
-				// Special case: iterator was started during a grow and the
-				// grow is not done yet.  We're working on a bucket whose
-				// oldbucket has not been evacuated yet.  So we're iterating
-				// through the oldbucket, skipping any keys that will go
-				// to the other new bucket (each oldbucket expands to two
-				// buckets during a grow).
-				t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
-				if(eq) {
-					// If the item in the oldbucket is not destined for
-					// the current new bucket in the iteration, skip it.
-					hash = h->hash0;
-					t->key->alg->hash(&hash, t->key->size, IK(h, k));
-					if((hash & (((uintptr)1 << it->B) - 1)) != check_bucket) {
-						continue;
-					}
-				} else {
-					// Hash isn't repeatable if k != k (NaNs).  We need a
-					// repeatable and randomish choice of which direction
-					// to send NaNs during evacuation.  We'll use the low
-					// bit of tophash to decide which way NaNs go.
-					if(check_bucket >> (it->B - 1) != (b->tophash[i] & 1)) {
-						continue;
-					}
-				}
-			}
-			if(!evacuated(b)) {
-				// this is the golden data, we can return it.
-				it->key = IK(h, k);
-				it->value = IV(h, v);
-			} else {
-				// The hash table has grown since the iterator was started.
-				// The golden data for this key is now somewhere else.
-				t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
-				if(eq) {
-					// Check the current hash table for the data.
-					// This code handles the case where the key
-					// has been deleted, updated, or deleted and reinserted.
-					// NOTE: we need to regrab the key as it has potentially been
-					// updated to an equal() but not identical key (e.g. +0.0 vs -0.0).
-					rk = IK(h, k);
-					rv = hash_lookup(t, it->h, &rk);
-					if(rv == nil)
-						continue; // key has been deleted
-					it->key = rk;
-					it->value = rv;
-				} else {
-					// if key!=key then the entry can't be deleted or
-					// updated, so we can just return it.  That's lucky for
-					// us because when key!=key we can't look it up
-					// successfully in the current table.
-					it->key = IK(h, k);
-					it->value = IV(h, v);
-				}
-			}
-			it->bucket = bucket;
-			it->bptr = b;
-			it->i = i + 1;
-			it->check_bucket = check_bucket;
-			return;
-		}
-	}
-	b = overflowptr(b);
-	i = 0;
-	goto next;
-}
-
-//
-/// interfaces to go runtime
-//
-
-void
-reflect·ismapkey(Type *typ, bool ret)
-{
-	ret = typ != nil && typ->alg->hash != runtime·nohash;
-	FLUSH(&ret);
-}
-
-Hmap*
-runtime·makemap_c(MapType *typ, int64 hint)
-{
-	Hmap *h;
-	Type *key;
-
-	key = typ->key;
-	
-	if(sizeof(Hmap) > 48)
-		runtime·panicstring("hmap too large");
-
-	if(hint < 0 || (int32)hint != hint)
-		runtime·panicstring("makemap: size out of range");
-
-	if(key->alg->hash == runtime·nohash)
-		runtime·throw("runtime.makemap: unsupported map key type");
-
-	h = runtime·cnew(typ->hmap);
-	hash_init(typ, h, hint);
-
-	// these calculations are compiler dependent.
-	// figure out offsets of map call arguments.
-
-	if(debug) {
-		runtime·printf("makemap: map=%p; keysize=%p; valsize=%p; keyalg=%p; valalg=%p\n",
-			       h, key->size, typ->elem->size, key->alg, typ->elem->alg);
-	}
-
-	return h;
-}
-
-// makemap(key, val *Type, hint int64) (hmap *map[any]any);
-void
-runtime·makemap(MapType *typ, int64 hint, Hmap *ret)
-{
-	ret = runtime·makemap_c(typ, hint);
-	FLUSH(&ret);
-}
-
-// For reflect:
-//	func makemap(Type *mapType) (hmap *map)
-void
-reflect·makemap(MapType *t, Hmap *ret)
-{
-	ret = runtime·makemap_c(t, 0);
-	FLUSH(&ret);
-}
-
-void
-runtime·mapaccess(MapType *t, Hmap *h, byte *ak, byte *av, bool *pres)
-{
-	byte *res;
-	Type *elem;
-
-	elem = t->elem;
-	if(h == nil || h->count == 0) {
-		elem->alg->copy(elem->size, av, nil);
-		*pres = false;
-		return;
-	}
-
-	res = hash_lookup(t, h, &ak);
-
-	if(res != nil) {
-		*pres = true;
-		elem->alg->copy(elem->size, av, res);
-	} else {
-		*pres = false;
-		elem->alg->copy(elem->size, av, nil);
-	}
-}
-
-// mapaccess1(hmap *map[any]any, key any) (val any);
-#pragma textflag NOSPLIT
-void
-runtime·mapaccess1(MapType *t, Hmap *h, ...)
-{
-	byte *ak, *av;
-	byte *res;
-
-	if(raceenabled && h != nil)
-		runtime·racereadpc(h, runtime·getcallerpc(&t), runtime·mapaccess1);
-
-	ak = (byte*)(&h + 1);
-	av = ak + ROUND(t->key->size, Structrnd);
-
-	if(h == nil || h->count == 0) {
-		t->elem->alg->copy(t->elem->size, av, nil);
-	} else {
-		res = hash_lookup(t, h, &ak);
-		t->elem->alg->copy(t->elem->size, av, res);
-	}
-
-	if(debug) {
-		runtime·prints("runtime.mapaccess1: map=");
-		runtime·printpointer(h);
-		runtime·prints("; key=");
-		t->key->alg->print(t->key->size, ak);
-		runtime·prints("; val=");
-		t->elem->alg->print(t->elem->size, av);
-		runtime·prints("\n");
-	}
-}
-
-// mapaccess2(hmap *map[any]any, key any) (val any, pres bool);
-#pragma textflag NOSPLIT
-void
-runtime·mapaccess2(MapType *t, Hmap *h, ...)
-{
-	byte *ak, *av, *ap;
-
-	if(raceenabled && h != nil)
-		runtime·racereadpc(h, runtime·getcallerpc(&t), runtime·mapaccess2);
-
-	ak = (byte*)(&h + 1);
-	av = ak + ROUND(t->key->size, Structrnd);
-	ap = av + t->elem->size;
-
-	runtime·mapaccess(t, h, ak, av, ap);
-
-	if(debug) {
-		runtime·prints("runtime.mapaccess2: map=");
-		runtime·printpointer(h);
-		runtime·prints("; key=");
-		t->key->alg->print(t->key->size, ak);
-		runtime·prints("; val=");
-		t->elem->alg->print(t->elem->size, av);
-		runtime·prints("; pres=");
-		runtime·printbool(*ap);
-		runtime·prints("\n");
-	}
-}
-
-// For reflect:
-//	func mapaccess(t type, h map, key iword) (val iword, pres bool)
-// where an iword is the same word an interface value would use:
-// the actual data if it fits, or else a pointer to the data.
-void
-reflect·mapaccess(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
-{
-	byte *ak, *av;
-
-	if(raceenabled && h != nil)
-		runtime·racereadpc(h, runtime·getcallerpc(&t), reflect·mapaccess);
-
-	if(t->key->size <= sizeof(key))
-		ak = (byte*)&key;
-	else
-		ak = (byte*)key;
-	val = 0;
-	pres = false;
-	if(t->elem->size <= sizeof(val))
-		av = (byte*)&val;
-	else {
-		av = runtime·mal(t->elem->size);
-		val = (uintptr)av;
-	}
-	runtime·mapaccess(t, h, ak, av, &pres);
-	FLUSH(&val);
-	FLUSH(&pres);
-}
-
-void
-runtime·mapassign(MapType *t, Hmap *h, byte *ak, byte *av)
-{
-	if(h == nil)
-		runtime·panicstring("assignment to entry in nil map");
-
-	if(av == nil) {
-		hash_remove(t, h, ak);
-	} else {
-		hash_insert(t, h, ak, av);
-	}
-
-	if(debug) {
-		runtime·prints("mapassign: map=");
-		runtime·printpointer(h);
-		runtime·prints("; key=");
-		t->key->alg->print(t->key->size, ak);
-		runtime·prints("; val=");
-		if(av)
-			t->elem->alg->print(t->elem->size, av);
-		else
-			runtime·prints("nil");
-		runtime·prints("\n");
-	}
-}
-
-// mapassign1(mapType *type, hmap *map[any]any, key any, val any);
-#pragma textflag NOSPLIT
-void
-runtime·mapassign1(MapType *t, Hmap *h, ...)
-{
-	byte *ak, *av;
-
-	if(h == nil)
-		runtime·panicstring("assignment to entry in nil map");
-
-	if(raceenabled)
-		runtime·racewritepc(h, runtime·getcallerpc(&t), runtime·mapassign1);
-	ak = (byte*)(&h + 1);
-	av = ak + ROUND(t->key->size, t->elem->align);
-
-	runtime·mapassign(t, h, ak, av);
-}
-
-// mapdelete(mapType *type, hmap *map[any]any, key any)
-#pragma textflag NOSPLIT
-void
-runtime·mapdelete(MapType *t, Hmap *h, ...)
-{
-	byte *ak;
-
-	if(h == nil)
-		return;
-
-	if(raceenabled)
-		runtime·racewritepc(h, runtime·getcallerpc(&t), runtime·mapdelete);
-	ak = (byte*)(&h + 1);
-	runtime·mapassign(t, h, ak, nil);
-
-	if(debug) {
-		runtime·prints("mapdelete: map=");
-		runtime·printpointer(h);
-		runtime·prints("; key=");
-		t->key->alg->print(t->key->size, ak);
-		runtime·prints("\n");
-	}
-}
-
-// For reflect:
-//	func mapassign(t type h map, key, val iword, pres bool)
-// where an iword is the same word an interface value would use:
-// the actual data if it fits, or else a pointer to the data.
-void
-reflect·mapassign(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
-{
-	byte *ak, *av;
-
-	if(h == nil)
-		runtime·panicstring("assignment to entry in nil map");
-	if(raceenabled)
-		runtime·racewritepc(h, runtime·getcallerpc(&t), reflect·mapassign);
-	if(t->key->size <= sizeof(key))
-		ak = (byte*)&key;
-	else
-		ak = (byte*)key;
-	if(t->elem->size <= sizeof(val))
-		av = (byte*)&val;
-	else
-		av = (byte*)val;
-	if(!pres)
-		av = nil;
-	runtime·mapassign(t, h, ak, av);
-}
-
-// mapiterinit(mapType *type, hmap *map[any]any, hiter *any);
-void
-runtime·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it)
-{
-	if(h == nil || h->count == 0) {
-		it->key = nil;
-		return;
-	}
-	if(raceenabled)
-		runtime·racereadpc(h, runtime·getcallerpc(&t), runtime·mapiterinit);
-	hash_iter_init(t, h, it);
-	hash_next(it);
-	if(debug) {
-		runtime·prints("runtime.mapiterinit: map=");
-		runtime·printpointer(h);
-		runtime·prints("; iter=");
-		runtime·printpointer(it);
-		runtime·prints("; key=");
-		runtime·printpointer(it->key);
-		runtime·prints("\n");
-	}
-}
-
-// For reflect:
-//	func mapiterinit(h map) (it iter)
-void
-reflect·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it)
-{
-	it = runtime·mal(sizeof *it);
-	FLUSH(&it);
-	runtime·mapiterinit(t, h, it);
-}
-
-// mapiternext(hiter *any);
-void
-runtime·mapiternext(struct hash_iter *it)
-{
-	if(raceenabled)
-		runtime·racereadpc(it->h, runtime·getcallerpc(&it), runtime·mapiternext);
-
-	hash_next(it);
-	if(debug) {
-		runtime·prints("runtime.mapiternext: iter=");
-		runtime·printpointer(it);
-		runtime·prints("; key=");
-		runtime·printpointer(it->key);
-		runtime·prints("\n");
-	}
-}
-
-// For reflect:
-//	func mapiternext(it iter)
-void
-reflect·mapiternext(struct hash_iter *it)
-{
-	runtime·mapiternext(it);
-}
-
-// mapiter1(hiter *any) (key any);
-#pragma textflag NOSPLIT
-void
-runtime·mapiter1(struct hash_iter *it, ...)
-{
-	byte *ak, *res;
-	Type *key;
-
-	ak = (byte*)(&it + 1);
-
-	res = it->key;
-	if(res == nil)
-		runtime·throw("runtime.mapiter1: key:val nil pointer");
-
-	key = it->t->key;
-	key->alg->copy(key->size, ak, res);
-
-	if(debug) {
-		runtime·prints("mapiter1: iter=");
-		runtime·printpointer(it);
-		runtime·prints("; map=");
-		runtime·printpointer(it->h);
-		runtime·prints("\n");
-	}
-}
-
-bool
-runtime·mapiterkey(struct hash_iter *it, void *ak)
-{
-	byte *res;
-	Type *key;
-
-	res = it->key;
-	if(res == nil)
-		return false;
-	key = it->t->key;
-	key->alg->copy(key->size, ak, res);
-	return true;
-}
-
-// For reflect:
-//	func mapiterkey(h map) (key iword, ok bool)
-// where an iword is the same word an interface value would use:
-// the actual data if it fits, or else a pointer to the data.
-void
-reflect·mapiterkey(struct hash_iter *it, uintptr key, bool ok)
-{
-	byte *res;
-	Type *tkey;
-
-	key = 0;
-	ok = false;
-	res = it->key;
-	if(res != nil) {
-		tkey = it->t->key;
-		if(tkey->size <= sizeof(key))
-			tkey->alg->copy(tkey->size, (byte*)&key, res);
-		else
-			key = (uintptr)res;
-		ok = true;
-	}
-	FLUSH(&key);
-	FLUSH(&ok);
-}
-
-// For reflect:
-//	func maplen(h map) (len int)
-// Like len(m) in the actual language, we treat the nil map as length 0.
-void
-reflect·maplen(Hmap *h, intgo len)
-{
-	if(h == nil)
-		len = 0;
-	else {
-		len = h->count;
-		if(raceenabled)
-			runtime·racereadpc(h, runtime·getcallerpc(&h), reflect·maplen);
-	}
-	FLUSH(&len);
-}
-
-// mapiter2(hiter *any) (key any, val any);
-#pragma textflag NOSPLIT
-void
-runtime·mapiter2(struct hash_iter *it, ...)
-{
-	byte *ak, *av, *res;
-	MapType *t;
-
-	t = it->t;
-	ak = (byte*)(&it + 1);
-	av = ak + ROUND(t->key->size, t->elem->align);
-
-	res = it->key;
-	if(res == nil)
-		runtime·throw("runtime.mapiter2: key:val nil pointer");
-
-	t->key->alg->copy(t->key->size, ak, res);
-	t->elem->alg->copy(t->elem->size, av, it->value);
-
-	if(debug) {
-		runtime·prints("mapiter2: iter=");
-		runtime·printpointer(it);
-		runtime·prints("; map=");
-		runtime·printpointer(it->h);
-		runtime·prints("\n");
-	}
-}
-
-// exported value for testing
-float64 runtime·hashLoad = LOAD;
diff --git a/src/pkg/runtime/hashmap.goc b/src/pkg/runtime/hashmap.goc
new file mode 100644
index 0000000..3327bed
--- /dev/null
+++ b/src/pkg/runtime/hashmap.goc
@@ -0,0 +1,1078 @@
+// 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.
+
+package runtime
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+#include "type.h"
+#include "race.h"
+#include "hashmap.h"
+#include "typekind.h"
+#include "../../cmd/ld/textflag.h"
+
+enum
+{
+	docheck = 0,  // check invariants before and after every op.  Slow!!!
+	debug = 0,    // print every operation
+	checkgc = 0 || docheck,  // check interaction of mallocgc() with the garbage collector
+};
+static void
+check(MapType *t, Hmap *h)
+{
+	uintptr bucket, oldbucket;
+	Bucket *b;
+	uintptr i;
+	uintptr hash;
+	uintgo cnt;
+	uint8 top;
+	bool eq;
+	byte *k, *v;
+
+	cnt = 0;
+
+	// check buckets
+	for(bucket = 0; bucket < (uintptr)1 << h->B; bucket++) {
+		for(b = (Bucket*)(h->buckets + bucket * h->bucketsize); b != nil; b = b->overflow) {
+			for(i = 0, k = (byte*)b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+				if(b->tophash[i] == Empty)
+					continue;
+				if(b->tophash[i] > Empty && b->tophash[i] < MinTopHash)
+					runtime·throw("evacuated cell in buckets");
+				cnt++;
+				t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
+				if(!eq)
+					continue; // NaN!
+				hash = h->hash0;
+				t->key->alg->hash(&hash, t->key->size, IK(h, k));
+				top = hash >> (8*sizeof(uintptr) - 8);
+				if(top < MinTopHash)
+					top += MinTopHash;
+				if(top != b->tophash[i])
+					runtime·throw("bad hash");
+			}
+		}
+	}
+
+	// check oldbuckets
+	if(h->oldbuckets != nil) {
+		for(oldbucket = 0; oldbucket < (uintptr)1 << (h->B - 1); oldbucket++) {
+			b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
+			for(; b != nil; b = b->overflow) {
+				for(i = 0, k = (byte*)b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+					if(b->tophash[i] < MinTopHash)
+						continue;
+					if(oldbucket < h->nevacuate)
+						runtime·throw("unevacuated entry in an evacuated bucket");
+					cnt++;
+					t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
+					if(!eq)
+						continue; // NaN!
+					hash = h->hash0;
+					t->key->alg->hash(&hash, t->key->size, IK(h, k));
+					top = hash >> (8*sizeof(uintptr) - 8);
+					if(top < MinTopHash)
+						top += MinTopHash;
+					if(top != b->tophash[i])
+						runtime·throw("bad hash (old)");
+				}
+			}
+		}
+	}
+
+	if(cnt != h->count) {
+		runtime·printf("%D %D\n", (uint64)cnt, (uint64)h->count);
+		runtime·throw("entries missing");
+	}
+}
+
+static void
+hash_init(MapType *t, Hmap *h, uint32 hint)
+{
+	uint8 B;
+	byte *buckets;
+	uintptr keysize, valuesize, bucketsize;
+	uint8 flags;
+
+	flags = 0;
+
+	// figure out how big we have to make everything
+	keysize = t->key->size;
+	if(keysize > MAXKEYSIZE) {
+		flags |= IndirectKey;
+		keysize = sizeof(byte*);
+	}
+	valuesize = t->elem->size;
+	if(valuesize > MAXVALUESIZE) {
+		flags |= IndirectValue;
+		valuesize = sizeof(byte*);
+	}
+	bucketsize = offsetof(Bucket, data[0]) + (keysize + valuesize) * BUCKETSIZE;
+	if(bucketsize != t->bucket->size) {
+		runtime·printf("runtime: bucketsize=%p but t->bucket->size=%p; t=%S\n", bucketsize, t->bucket->size, *t->string);
+		runtime·throw("bucketsize wrong");
+	}
+
+	// invariants we depend on.  We should probably check these at compile time
+	// somewhere, but for now we'll do it here.
+	if(t->key->align > BUCKETSIZE)
+		runtime·throw("key align too big");
+	if(t->elem->align > BUCKETSIZE)
+		runtime·throw("value align too big");
+	if(t->key->size % t->key->align != 0)
+		runtime·throw("key size not a multiple of key align");
+	if(t->elem->size % t->elem->align != 0)
+		runtime·throw("value size not a multiple of value align");
+	if(BUCKETSIZE < 8)
+		runtime·throw("bucketsize too small for proper alignment");
+	if((offsetof(Bucket, data[0]) & (t->key->align-1)) != 0)
+		runtime·throw("need padding in bucket (key)");
+	if((offsetof(Bucket, data[0]) & (t->elem->align-1)) != 0)
+		runtime·throw("need padding in bucket (value)");
+
+	// find size parameter which will hold the requested # of elements
+	B = 0;
+	while(hint > BUCKETSIZE && hint > LOAD * ((uintptr)1 << B))
+		B++;
+
+	// allocate initial hash table
+	// If hint is large zeroing this memory could take a while.
+	if(checkgc) mstats.next_gc = mstats.heap_alloc;
+	if(B == 0) {
+		// done lazily later.
+		buckets = nil;
+	} else {
+		buckets = runtime·cnewarray(t->bucket, (uintptr)1 << B);
+	}
+
+	// initialize Hmap
+	h->count = 0;
+	h->B = B;
+	h->flags = flags;
+	h->keysize = keysize;
+	h->valuesize = valuesize;
+	h->bucketsize = bucketsize;
+	h->hash0 = runtime·fastrand1();
+	h->buckets = buckets;
+	h->oldbuckets = nil;
+	h->nevacuate = 0;
+	if(docheck)
+		check(t, h);
+}
+
+// Moves entries in oldbuckets[i] to buckets[i] and buckets[i+2^k].
+// We leave the original bucket intact, except for marking the topbits
+// entries as evacuated, so that iterators can still iterate through the old buckets.
+static void
+evacuate(MapType *t, Hmap *h, uintptr oldbucket)
+{
+	Bucket *b;
+	Bucket *x, *y;
+	Bucket *newx, *newy;
+	uintptr xi, yi;
+	uintptr newbit;
+	uintptr hash;
+	uintptr i;
+	byte *k, *v;
+	byte *xk, *yk, *xv, *yv;
+	uint8 top;
+	bool eq;
+
+	b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
+	newbit = (uintptr)1 << (h->B - 1);
+
+	if(!evacuated(b)) {
+		// TODO: reuse overflow buckets instead of using new ones, if there
+		// is no iterator using the old buckets.  (If !OldIterator.)
+
+		x = (Bucket*)(h->buckets + oldbucket * h->bucketsize);
+		y = (Bucket*)(h->buckets + (oldbucket + newbit) * h->bucketsize);
+		xi = 0;
+		yi = 0;
+		xk = (byte*)x->data;
+		yk = (byte*)y->data;
+		xv = xk + h->keysize * BUCKETSIZE;
+		yv = yk + h->keysize * BUCKETSIZE;
+		for(; b != nil; b = b->overflow) {
+			for(i = 0, k = (byte*)b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+				top = b->tophash[i];
+				if(top == Empty) {
+					b->tophash[i] = EvacuatedEmpty;
+					continue;
+				}
+				if(top < MinTopHash)
+					runtime·throw("bad state");
+
+				// Compute hash to make our evacuation decision (whether we need
+				// to send this key/value to bucket x or bucket y).
+				hash = h->hash0;
+				t->key->alg->hash(&hash, t->key->size, IK(h, k));
+				if((h->flags & Iterator) != 0) {
+					t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
+					if(!eq) {
+						// If key != key (NaNs), then the hash could be (and probably
+						// will be) entirely different from the old hash.  Moreover,
+						// it isn't reproducible.  Reproducibility is required in the
+						// presence of iterators, as our evacuation decision must
+						// match whatever decision the iterator made.
+						// Fortunately, we have the freedom to send these keys either
+						// way.  Also, tophash is meaningless for these kinds of keys.
+						// We let the low bit of tophash drive the evacuation decision.
+						// We recompute a new random tophash for the next level so
+						// these keys will get evenly distributed across all buckets
+						// after multiple grows.
+						if((top & 1) != 0)
+							hash |= newbit;
+						else
+							hash &= ~newbit;
+						top = hash >> (8*sizeof(uintptr)-8);
+						if(top < MinTopHash)
+							top += MinTopHash;
+					}
+				}
+
+				if((hash & newbit) == 0) {
+					b->tophash[i] = EvacuatedX;
+					if(xi == BUCKETSIZE) {
+						if(checkgc) mstats.next_gc = mstats.heap_alloc;
+						newx = runtime·cnew(t->bucket);
+						x->overflow = newx;
+						x = newx;
+						xi = 0;
+						xk = (byte*)x->data;
+						xv = xk + h->keysize * BUCKETSIZE;
+					}
+					x->tophash[xi] = top;
+					if((h->flags & IndirectKey) != 0) {
+						*(byte**)xk = *(byte**)k;               // copy pointer
+					} else {
+						t->key->alg->copy(t->key->size, xk, k); // copy value
+					}
+					if((h->flags & IndirectValue) != 0) {
+						*(byte**)xv = *(byte**)v;
+					} else {
+						t->elem->alg->copy(t->elem->size, xv, v);
+					}
+					xi++;
+					xk += h->keysize;
+					xv += h->valuesize;
+				} else {
+					b->tophash[i] = EvacuatedY;
+					if(yi == BUCKETSIZE) {
+						if(checkgc) mstats.next_gc = mstats.heap_alloc;
+						newy = runtime·cnew(t->bucket);
+						y->overflow = newy;
+						y = newy;
+						yi = 0;
+						yk = (byte*)y->data;
+						yv = yk + h->keysize * BUCKETSIZE;
+					}
+					y->tophash[yi] = top;
+					if((h->flags & IndirectKey) != 0) {
+						*(byte**)yk = *(byte**)k;
+					} else {
+						t->key->alg->copy(t->key->size, yk, k);
+					}
+					if((h->flags & IndirectValue) != 0) {
+						*(byte**)yv = *(byte**)v;
+					} else {
+						t->elem->alg->copy(t->elem->size, yv, v);
+					}
+					yi++;
+					yk += h->keysize;
+					yv += h->valuesize;
+				}
+			}
+		}
+
+		// Unlink the overflow buckets & clear key/value to help GC.
+		if((h->flags & OldIterator) == 0) {
+			b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
+			b->overflow = nil;
+			runtime·memclr((byte*)b->data, h->bucketsize - offsetof(Bucket, data[0]));
+		}
+	}
+
+	// Advance evacuation mark
+	if(oldbucket == h->nevacuate) {
+		h->nevacuate = oldbucket + 1;
+		if(oldbucket + 1 == newbit) // newbit == # of oldbuckets
+			// Growing is all done.  Free old main bucket array.
+			h->oldbuckets = nil;
+	}
+	if(docheck)
+		check(t, h);
+}
+
+static void
+grow_work(MapType *t, Hmap *h, uintptr bucket)
+{
+	uintptr noldbuckets;
+
+	noldbuckets = (uintptr)1 << (h->B - 1);
+
+	// make sure we evacuate the oldbucket corresponding
+	// to the bucket we're about to use
+	evacuate(t, h, bucket & (noldbuckets - 1));
+
+	// evacuate one more oldbucket to make progress on growing
+	if(h->oldbuckets != nil)
+		evacuate(t, h, h->nevacuate);
+}
+
+static void
+hash_grow(MapType *t, Hmap *h)
+{
+	byte *old_buckets;
+	byte *new_buckets;
+	uint8 flags;
+
+	// allocate a bigger hash table
+	if(h->oldbuckets != nil)
+		runtime·throw("evacuation not done in time");
+	old_buckets = h->buckets;
+	if(checkgc) mstats.next_gc = mstats.heap_alloc;
+	new_buckets = runtime·cnewarray(t->bucket, (uintptr)1 << (h->B + 1));
+	flags = (h->flags & ~(Iterator | OldIterator));
+	if((h->flags & Iterator) != 0)
+		flags |= OldIterator;
+
+	// commit the grow (atomic wrt gc)
+	h->B++;
+	h->flags = flags;
+	h->oldbuckets = old_buckets;
+	h->buckets = new_buckets;
+	h->nevacuate = 0;
+
+	// the actual copying of the hash table data is done incrementally
+	// by grow_work() and evacuate().
+	if(docheck)
+		check(t, h);
+}
+
+// returns ptr to value associated with key *keyp, or nil if none.
+// if it returns non-nil, updates *keyp to point to the currently stored key.
+static byte*
+hash_lookup(MapType *t, Hmap *h, byte **keyp)
+{
+	void *key;
+	uintptr hash;
+	uintptr bucket, oldbucket;
+	Bucket *b;
+	uint8 top;
+	uintptr i;
+	bool eq;
+	byte *k, *k2, *v;
+
+	key = *keyp;
+	if(docheck)
+		check(t, h);
+	if(h->count == 0)
+		return nil;
+	hash = h->hash0;
+	t->key->alg->hash(&hash, t->key->size, key);
+	bucket = hash & (((uintptr)1 << h->B) - 1);
+	if(h->oldbuckets != nil) {
+		oldbucket = bucket & (((uintptr)1 << (h->B - 1)) - 1);
+		b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
+		if(evacuated(b)) {
+			b = (Bucket*)(h->buckets + bucket * h->bucketsize);
+		}
+	} else {
+		b = (Bucket*)(h->buckets + bucket * h->bucketsize);
+	}
+	top = hash >> (sizeof(uintptr)*8 - 8);
+	if(top < MinTopHash)
+		top += MinTopHash;
+	do {
+		for(i = 0, k = (byte*)b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+			if(b->tophash[i] == top) {
+				k2 = IK(h, k);
+				t->key->alg->equal(&eq, t->key->size, key, k2);
+				if(eq) {
+					*keyp = k2;
+					return IV(h, v);
+				}
+			}
+		}
+		b = b->overflow;
+	} while(b != nil);
+	return nil;
+}
+
+// Specialized versions of mapaccess1 for specific types.
+// See ./hashmap_fast.c and ../../cmd/gc/walk.c.
+#define HASH_LOOKUP1 runtime·mapaccess1_fast32
+#define HASH_LOOKUP2 runtime·mapaccess2_fast32
+#define KEYTYPE uint32
+#define HASHFUNC runtime·algarray[AMEM32].hash
+#define FASTKEY(x) true
+#define QUICK_NE(x,y) ((x) != (y))
+#define QUICK_EQ(x,y) true
+#define SLOW_EQ(x,y) true
+#define MAYBE_EQ(x,y) true
+#include "hashmap_fast.c"
+
+#undef HASH_LOOKUP1
+#undef HASH_LOOKUP2
+#undef KEYTYPE
+#undef HASHFUNC
+#undef FASTKEY
+#undef QUICK_NE
+#undef QUICK_EQ
+#undef SLOW_EQ
+#undef MAYBE_EQ
+
+#define HASH_LOOKUP1 runtime·mapaccess1_fast64
+#define HASH_LOOKUP2 runtime·mapaccess2_fast64
+#define KEYTYPE uint64
+#define HASHFUNC runtime·algarray[AMEM64].hash
+#define FASTKEY(x) true
+#define QUICK_NE(x,y) ((x) != (y))
+#define QUICK_EQ(x,y) true
+#define SLOW_EQ(x,y) true
+#define MAYBE_EQ(x,y) true
+#include "hashmap_fast.c"
+
+#undef HASH_LOOKUP1
+#undef HASH_LOOKUP2
+#undef KEYTYPE
+#undef HASHFUNC
+#undef FASTKEY
+#undef QUICK_NE
+#undef QUICK_EQ
+#undef SLOW_EQ
+#undef MAYBE_EQ
+
+#ifdef GOARCH_amd64
+#define CHECKTYPE uint64
+#endif
+#ifdef GOARCH_amd64p32
+#define CHECKTYPE uint32
+#endif
+#ifdef GOARCH_386
+#define CHECKTYPE uint32
+#endif
+#ifdef GOARCH_arm
+// can't use uint32 on arm because our loads aren't aligned.
+// TODO: use uint32 for arm v6+?
+#define CHECKTYPE uint8
+#endif
+
+#define HASH_LOOKUP1 runtime·mapaccess1_faststr
+#define HASH_LOOKUP2 runtime·mapaccess2_faststr
+#define KEYTYPE String
+#define HASHFUNC runtime·algarray[ASTRING].hash
+#define FASTKEY(x) ((x).len < 32)
+#define QUICK_NE(x,y) ((x).len != (y).len)
+#define QUICK_EQ(x,y) ((x).str == (y).str)
+#define SLOW_EQ(x,y) runtime·memeq((x).str, (y).str, (x).len)
+#define MAYBE_EQ(x,y) (*(CHECKTYPE*)(x).str == *(CHECKTYPE*)(y).str && *(CHECKTYPE*)((x).str + (x).len - sizeof(CHECKTYPE)) == *(CHECKTYPE*)((y).str + (x).len - sizeof(CHECKTYPE)))
+#include "hashmap_fast.c"
+
+static void
+hash_insert(MapType *t, Hmap *h, void *key, void *value)
+{
+	uintptr hash;
+	uintptr bucket;
+	uintptr i;
+	bool eq;
+	Bucket *b;
+	Bucket *newb;
+	uint8 *inserti;
+	byte *insertk, *insertv;
+	uint8 top;
+	byte *k, *v;
+	byte *kmem, *vmem;
+
+	if(docheck)
+		check(t, h);
+	hash = h->hash0;
+	t->key->alg->hash(&hash, t->key->size, key);
+	if(h->buckets == nil)
+		h->buckets = runtime·cnewarray(t->bucket, 1);
+
+ again:
+	bucket = hash & (((uintptr)1 << h->B) - 1);
+	if(h->oldbuckets != nil)
+		grow_work(t, h, bucket);
+	b = (Bucket*)(h->buckets + bucket * h->bucketsize);
+	top = hash >> (sizeof(uintptr)*8 - 8);
+	if(top < MinTopHash)
+		top += MinTopHash;
+	inserti = nil;
+	insertk = nil;
+	insertv = nil;
+	while(true) {
+		for(i = 0, k = (byte*)b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+			if(b->tophash[i] != top) {
+				if(b->tophash[i] == Empty && inserti == nil) {
+					inserti = &b->tophash[i];
+					insertk = k;
+					insertv = v;
+				}
+				continue;
+			}
+			t->key->alg->equal(&eq, t->key->size, key, IK(h, k));
+			if(!eq)
+				continue;
+			// already have a mapping for key.  Update it.
+			t->key->alg->copy(t->key->size, IK(h, k), key); // Need to update key for keys which are distinct but equal (e.g. +0.0 and -0.0)
+			t->elem->alg->copy(t->elem->size, IV(h, v), value);
+			if(docheck)
+				check(t, h);
+			return;
+		}
+		if(b->overflow == nil)
+			break;
+		b = b->overflow;
+	}
+
+	// did not find mapping for key.  Allocate new cell & add entry.
+	if(h->count >= LOAD * ((uintptr)1 << h->B) && h->count >= BUCKETSIZE) {
+		hash_grow(t, h);
+		goto again; // Growing the table invalidates everything, so try again
+	}
+
+	if(inserti == nil) {
+		// all current buckets are full, allocate a new one.
+		if(checkgc) mstats.next_gc = mstats.heap_alloc;
+		newb = runtime·cnew(t->bucket);
+		b->overflow = newb;
+		inserti = newb->tophash;
+		insertk = (byte*)newb->data;
+		insertv = insertk + h->keysize * BUCKETSIZE;
+	}
+
+	// store new key/value at insert position
+	if((h->flags & IndirectKey) != 0) {
+		if(checkgc) mstats.next_gc = mstats.heap_alloc;
+		kmem = runtime·cnew(t->key);
+		*(byte**)insertk = kmem;
+		insertk = kmem;
+	}
+	if((h->flags & IndirectValue) != 0) {
+		if(checkgc) mstats.next_gc = mstats.heap_alloc;
+		vmem = runtime·cnew(t->elem);
+		*(byte**)insertv = vmem;
+		insertv = vmem;
+	}
+	t->key->alg->copy(t->key->size, insertk, key);
+	t->elem->alg->copy(t->elem->size, insertv, value);
+	*inserti = top;
+	h->count++;
+	if(docheck)
+		check(t, h);
+}
+
+static void
+hash_remove(MapType *t, Hmap *h, void *key)
+{
+	uintptr hash;
+	uintptr bucket;
+	Bucket *b;
+	uint8 top;
+	uintptr i;
+	byte *k, *v;
+	bool eq;
+	
+	if(docheck)
+		check(t, h);
+	if(h->count == 0)
+		return;
+	hash = h->hash0;
+	t->key->alg->hash(&hash, t->key->size, key);
+	bucket = hash & (((uintptr)1 << h->B) - 1);
+	if(h->oldbuckets != nil)
+		grow_work(t, h, bucket);
+	b = (Bucket*)(h->buckets + bucket * h->bucketsize);
+	top = hash >> (sizeof(uintptr)*8 - 8);
+	if(top < MinTopHash)
+		top += MinTopHash;
+	do {
+		for(i = 0, k = (byte*)b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+			if(b->tophash[i] != top)
+				continue;
+			t->key->alg->equal(&eq, t->key->size, key, IK(h, k));
+			if(!eq)
+				continue;
+
+			if((h->flags & IndirectKey) != 0) {
+				*(byte**)k = nil;
+			} else {
+				t->key->alg->copy(t->key->size, k, nil);
+			}
+			if((h->flags & IndirectValue) != 0) {
+				*(byte**)v = nil;
+			} else {
+				t->elem->alg->copy(t->elem->size, v, nil);
+			}
+
+			b->tophash[i] = Empty;
+			h->count--;
+			
+			// TODO: consolidate buckets if they are mostly empty
+			// can only consolidate if there are no live iterators at this size.
+			if(docheck)
+				check(t, h);
+			return;
+		}
+		b = b->overflow;
+	} while(b != nil);
+}
+
+// TODO: shrink the map, the same way we grow it.
+
+// iterator state:
+// bucket: the current bucket ID
+// b: the current Bucket in the chain
+// i: the next offset to check in the current bucket
+static void
+hash_iter_init(MapType *t, Hmap *h, Hiter *it)
+{
+	uint32 old;
+
+	if(sizeof(Hiter) / sizeof(uintptr) != 10) {
+		runtime·throw("hash_iter size incorrect"); // see ../../cmd/gc/reflect.c
+	}
+	it->t = t;
+	it->h = h;
+
+	// grab snapshot of bucket state
+	it->B = h->B;
+	it->buckets = h->buckets;
+
+	// iterator state
+	it->bucket = 0;
+	it->offset = runtime·fastrand1() & (BUCKETSIZE - 1);
+	it->done = false;
+	it->bptr = nil;
+
+	// Remember we have an iterator.
+	// Can run concurrently with another hash_iter_init().
+	for(;;) {
+		old = h->flags;
+		if((old&(Iterator|OldIterator)) == (Iterator|OldIterator))
+			break;
+		if(runtime·cas(&h->flags, old, old|Iterator|OldIterator))
+			break;
+	}
+
+	if(h->buckets == nil) {
+		// Empty map. Force next hash_next to exit without
+		// evaluating h->bucket.
+		it->done = true;
+	}
+}
+
+// initializes it->key and it->value to the next key/value pair
+// in the iteration, or nil if we've reached the end.
+static void
+hash_next(Hiter *it)
+{
+	Hmap *h;
+	MapType *t;
+	uintptr bucket, oldbucket;
+	uintptr hash;
+	Bucket *b;
+	uintptr i, offi;
+	intptr check_bucket;
+	bool eq;
+	byte *k, *v;
+	byte *rk, *rv;
+
+	h = it->h;
+	t = it->t;
+	bucket = it->bucket;
+	b = it->bptr;
+	i = it->i;
+	check_bucket = it->check_bucket;
+
+next:
+	if(b == nil) {
+		if(it->done) {
+			// end of iteration
+			it->key = nil;
+			it->value = nil;
+			return;
+		}
+		if(h->oldbuckets != nil && it->B == h->B) {
+			// Iterator was started in the middle of a grow, and the grow isn't done yet.
+			// If the bucket we're looking at hasn't been filled in yet (i.e. the old
+			// bucket hasn't been evacuated) then we need to iterate through the old
+			// bucket and only return the ones that will be migrated to this bucket.
+			oldbucket = bucket & (((uintptr)1 << (it->B - 1)) - 1);
+			b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
+			if(!evacuated(b)) {
+				check_bucket = bucket;
+			} else {
+				b = (Bucket*)(it->buckets + bucket * h->bucketsize);
+				check_bucket = -1;
+			}
+		} else {
+			b = (Bucket*)(it->buckets + bucket * h->bucketsize);
+			check_bucket = -1;
+		}
+		bucket++;
+		if(bucket == ((uintptr)1 << it->B)) {
+			bucket = 0;
+			it->done = true;
+		}
+		i = 0;
+	}
+	for(; i < BUCKETSIZE; i++) {
+		offi = (i + it->offset) & (BUCKETSIZE - 1);
+		k = (byte*)b->data + h->keysize * offi;
+		v = (byte*)b->data + h->keysize * BUCKETSIZE + h->valuesize * offi;
+		if(b->tophash[offi] != Empty && b->tophash[offi] != EvacuatedEmpty) {
+			if(check_bucket >= 0) {
+				// Special case: iterator was started during a grow and the
+				// grow is not done yet.  We're working on a bucket whose
+				// oldbucket has not been evacuated yet.  Or at least, it wasn't
+				// evacuated when we started the bucket.  So we're iterating
+				// through the oldbucket, skipping any keys that will go
+				// to the other new bucket (each oldbucket expands to two
+				// buckets during a grow).
+				t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
+				if(eq) {
+					// If the item in the oldbucket is not destined for
+					// the current new bucket in the iteration, skip it.
+					hash = h->hash0;
+					t->key->alg->hash(&hash, t->key->size, IK(h, k));
+					if((hash & (((uintptr)1 << it->B) - 1)) != check_bucket) {
+						continue;
+					}
+				} else {
+					// Hash isn't repeatable if k != k (NaNs).  We need a
+					// repeatable and randomish choice of which direction
+					// to send NaNs during evacuation.  We'll use the low
+					// bit of tophash to decide which way NaNs go.
+					// NOTE: this case is why we need two evacuate tophash
+					// values, evacuatedX and evacuatedY, that differ in
+					// their low bit.
+					if(check_bucket >> (it->B - 1) != (b->tophash[offi] & 1)) {
+						continue;
+					}
+				}
+			}
+			if(b->tophash[offi] != EvacuatedX && b->tophash[offi] != EvacuatedY) {
+				// this is the golden data, we can return it.
+				it->key = IK(h, k);
+				it->value = IV(h, v);
+			} else {
+				// The hash table has grown since the iterator was started.
+				// The golden data for this key is now somewhere else.
+				t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
+				if(eq) {
+					// Check the current hash table for the data.
+					// This code handles the case where the key
+					// has been deleted, updated, or deleted and reinserted.
+					// NOTE: we need to regrab the key as it has potentially been
+					// updated to an equal() but not identical key (e.g. +0.0 vs -0.0).
+					rk = IK(h, k);
+					rv = hash_lookup(t, it->h, &rk);
+					if(rv == nil)
+						continue; // key has been deleted
+					it->key = rk;
+					it->value = rv;
+				} else {
+					// if key!=key then the entry can't be deleted or
+					// updated, so we can just return it.  That's lucky for
+					// us because when key!=key we can't look it up
+					// successfully in the current table.
+					it->key = IK(h, k);
+					it->value = IV(h, v);
+				}
+			}
+			it->bucket = bucket;
+			it->bptr = b;
+			it->i = i + 1;
+			it->check_bucket = check_bucket;
+			return;
+		}
+	}
+	b = b->overflow;
+	i = 0;
+	goto next;
+}
+
+//
+/// interfaces to go runtime
+//
+
+func reflect·ismapkey(typ *Type) (ret bool) {
+	ret = typ != nil && typ->alg->hash != runtime·nohash;
+}
+
+static Hmap*
+makemap_c(MapType *typ, int64 hint)
+{
+	Hmap *h;
+	Type *key;
+
+	key = typ->key;
+	
+	if(sizeof(Hmap) > 48)
+		runtime·panicstring("hmap too large");
+
+	if(hint < 0 || (int32)hint != hint)
+		runtime·panicstring("makemap: size out of range");
+
+	if(key->alg->hash == runtime·nohash)
+		runtime·throw("runtime.makemap: unsupported map key type");
+
+	h = runtime·cnew(typ->hmap);
+	hash_init(typ, h, hint);
+
+	// these calculations are compiler dependent.
+	// figure out offsets of map call arguments.
+
+	if(debug) {
+		runtime·printf("makemap: map=%p; keysize=%p; valsize=%p; keyalg=%p; valalg=%p\n",
+			       h, key->size, typ->elem->size, key->alg, typ->elem->alg);
+	}
+
+	return h;
+}
+
+func makemap(typ *MapType, hint int64) (ret *Hmap) {
+	ret = makemap_c(typ, hint);
+}
+
+func reflect·makemap(t *MapType) (ret *Hmap) {
+	ret = makemap_c(t, 0);
+}
+
+// NOTE: The returned pointer may keep the whole map live, so don't
+// hold onto it for very long.
+#pragma textflag NOSPLIT
+func mapaccess1(t *MapType, h *Hmap, key *byte) (val *byte) {
+	if(raceenabled && h != nil) {
+		runtime·racereadpc(h, runtime·getcallerpc(&t), runtime·mapaccess1);
+		runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), runtime·mapaccess1);
+	}
+	if(h == nil || h->count == 0) {
+		val = t->elem->zero;
+	} else {
+		val = hash_lookup(t, h, &key);
+		if(val == nil)
+			val = t->elem->zero;
+	}
+
+	if(debug) {
+		runtime·prints("runtime.mapaccess1: map=");
+		runtime·printpointer(h);
+		runtime·prints("; key=");
+		t->key->alg->print(t->key->size, key);
+		runtime·prints("; val=");
+		t->elem->alg->print(t->elem->size, val);
+		runtime·prints("\n");
+	}
+}
+
+// NOTE: The returned pointer keeps the whole map live, so don't
+// hold onto it for very long.
+#pragma textflag NOSPLIT
+func mapaccess2(t *MapType, h *Hmap, key *byte) (val *byte, pres bool) {
+	if(raceenabled && h != nil) {
+		runtime·racereadpc(h, runtime·getcallerpc(&t), runtime·mapaccess2);
+		runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), runtime·mapaccess2);
+	}
+
+	if(h == nil || h->count == 0) {
+		val = t->elem->zero;
+		pres = false;
+	} else {
+		val = hash_lookup(t, h, &key);
+		if(val == nil) {
+			val = t->elem->zero;
+			pres = false;
+		} else {
+			pres = true;
+		}
+	}
+
+	if(debug) {
+		runtime·prints("runtime.mapaccess2: map=");
+		runtime·printpointer(h);
+		runtime·prints("; key=");
+		t->key->alg->print(t->key->size, key);
+		runtime·prints("; val=");
+		t->elem->alg->print(t->elem->size, val);
+		runtime·prints("; pres=");
+		runtime·printbool(pres);
+		runtime·prints("\n");
+	}
+}
+
+#pragma textflag NOSPLIT
+func reflect·mapaccess(t *MapType, h *Hmap, key *byte) (val *byte) {
+	if(h == nil)
+		val = nil;
+	else {
+		if(raceenabled) {
+			runtime·racereadpc(h, runtime·getcallerpc(&t), reflect·mapaccess);
+			runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), reflect·mapaccess);
+		}
+		val = hash_lookup(t, h, &key);
+	}
+}
+
+#pragma textflag NOSPLIT
+func mapassign1(t *MapType, h *Hmap, key *byte, val *byte) {
+	if(h == nil)
+		runtime·panicstring("assignment to entry in nil map");
+
+	if(raceenabled) {
+		runtime·racewritepc(h, runtime·getcallerpc(&t), runtime·mapassign1);
+		runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), runtime·mapassign1);
+		runtime·racereadobjectpc(val, t->elem, runtime·getcallerpc(&t), runtime·mapassign1);
+	}
+
+	hash_insert(t, h, key, val);
+
+	if(debug) {
+		runtime·prints("mapassign1: map=");
+		runtime·printpointer(h);
+		runtime·prints("; key=");
+		t->key->alg->print(t->key->size, key);
+		runtime·prints("; val=");
+		t->elem->alg->print(t->elem->size, val);
+		runtime·prints("\n");
+	}
+}
+
+#pragma textflag NOSPLIT
+func mapdelete(t *MapType, h *Hmap, key *byte) {
+	if(h == nil)
+		return;
+
+	if(raceenabled) {
+		runtime·racewritepc(h, runtime·getcallerpc(&t), runtime·mapdelete);
+		runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), runtime·mapdelete);
+	}
+
+	hash_remove(t, h, key);
+
+	if(debug) {
+		runtime·prints("mapdelete: map=");
+		runtime·printpointer(h);
+		runtime·prints("; key=");
+		t->key->alg->print(t->key->size, key);
+		runtime·prints("\n");
+	}
+}
+
+#pragma textflag NOSPLIT
+func reflect·mapassign(t *MapType, h *Hmap, key *byte, val *byte) {
+	if(h == nil)
+		runtime·panicstring("assignment to entry in nil map");
+	if(raceenabled) {
+		runtime·racewritepc(h, runtime·getcallerpc(&t), reflect·mapassign);
+		runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), reflect·mapassign);
+		runtime·racereadobjectpc(val, t->elem, runtime·getcallerpc(&t), reflect·mapassign);
+	}
+
+	hash_insert(t, h, key, val);
+
+	if(debug) {
+		runtime·prints("mapassign: map=");
+		runtime·printpointer(h);
+		runtime·prints("; key=");
+		t->key->alg->print(t->key->size, key);
+		runtime·prints("; val=");
+		t->elem->alg->print(t->elem->size, val);
+		runtime·prints("\n");
+	}
+}
+
+#pragma textflag NOSPLIT
+func reflect·mapdelete(t *MapType, h *Hmap, key *byte) {
+	if(h == nil)
+		return; // see bug 8051
+	if(raceenabled) {
+		runtime·racewritepc(h, runtime·getcallerpc(&t), reflect·mapdelete);
+		runtime·racereadobjectpc(key, t->key, runtime·getcallerpc(&t), reflect·mapdelete);
+	}
+	hash_remove(t, h, key);
+
+	if(debug) {
+		runtime·prints("mapdelete: map=");
+		runtime·printpointer(h);
+		runtime·prints("; key=");
+		t->key->alg->print(t->key->size, key);
+		runtime·prints("\n");
+	}
+}
+
+#pragma textflag NOSPLIT
+func mapiterinit(t *MapType, h *Hmap, it *Hiter) {
+	// Clear pointer fields so garbage collector does not complain.
+	it->key = nil;
+	it->value = nil;
+	it->t = nil;
+	it->h = nil;
+	it->buckets = nil;
+	it->bptr = nil;
+
+	if(h == nil || h->count == 0) {
+		it->key = nil;
+		return;
+	}
+	if(raceenabled)
+		runtime·racereadpc(h, runtime·getcallerpc(&t), runtime·mapiterinit);
+	hash_iter_init(t, h, it);
+	hash_next(it);
+	if(debug) {
+		runtime·prints("runtime.mapiterinit: map=");
+		runtime·printpointer(h);
+		runtime·prints("; iter=");
+		runtime·printpointer(it);
+		runtime·prints("; key=");
+		runtime·printpointer(it->key);
+		runtime·prints("\n");
+	}
+}
+
+func reflect·mapiterinit(t *MapType, h *Hmap) (it *Hiter) {
+	it = runtime·mal(sizeof *it);
+	runtime·mapiterinit(t, h, it);
+}
+
+#pragma textflag NOSPLIT
+func mapiternext(it *Hiter) {
+	if(raceenabled)
+		runtime·racereadpc(it->h, runtime·getcallerpc(&it), runtime·mapiternext);
+
+	hash_next(it);
+	if(debug) {
+		runtime·prints("runtime.mapiternext: iter=");
+		runtime·printpointer(it);
+		runtime·prints("; key=");
+		runtime·printpointer(it->key);
+		runtime·prints("\n");
+	}
+}
+
+func reflect·mapiternext(it *Hiter) {
+	runtime·mapiternext(it);
+}
+
+func reflect·mapiterkey(it *Hiter) (key *byte) {
+	key = it->key;
+}
+
+#pragma textflag NOSPLIT
+func reflect·maplen(h *Hmap) (len int) {
+	if(h == nil)
+		len = 0;
+	else {
+		len = h->count;
+		if(raceenabled)
+			runtime·racereadpc(h, runtime·getcallerpc(&h), reflect·maplen);
+	}
+}
+
+// exported value for testing
+float64 runtime·hashLoad = LOAD;
diff --git a/src/pkg/runtime/hashmap.h b/src/pkg/runtime/hashmap.h
new file mode 100644
index 0000000..522d1ad
--- /dev/null
+++ b/src/pkg/runtime/hashmap.h
@@ -0,0 +1,147 @@
+// 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.
+
+// This file contains the implementation of Go's map type.
+//
+// The map is just a hash table.  The data is arranged
+// into an array of buckets.  Each bucket contains up to
+// 8 key/value pairs.  The low-order bits of the hash are
+// used to select a bucket.  Each bucket contains a few
+// high-order bits of each hash to distinguish the entries
+// within a single bucket.
+//
+// If more than 8 keys hash to a bucket, we chain on
+// extra buckets.
+//
+// When the hashtable grows, we allocate a new array
+// of buckets twice as big.  Buckets are incrementally
+// copied from the old bucket array to the new bucket array.
+//
+// Map iterators walk through the array of buckets and
+// return the keys in walk order (bucket #, then overflow
+// chain order, then bucket index).  To maintain iteration
+// semantics, we never move keys within their bucket (if
+// we did, keys might be returned 0 or 2 times).  When
+// growing the table, iterators remain iterating through the
+// old table and must check the new table if the bucket
+// they are iterating through has been moved ("evacuated")
+// to the new table.
+
+// Maximum number of key/value pairs a bucket can hold.
+#define BUCKETSIZE 8
+
+// Maximum average load of a bucket that triggers growth.
+#define LOAD 6.5
+
+// Picking LOAD: too large and we have lots of overflow
+// buckets, too small and we waste a lot of space.  I wrote
+// a simple program to check some stats for different loads:
+// (64-bit, 8 byte keys and values)
+//        LOAD    %overflow  bytes/entry     hitprobe    missprobe
+//        4.00         2.13        20.77         3.00         4.00
+//        4.50         4.05        17.30         3.25         4.50
+//        5.00         6.85        14.77         3.50         5.00
+//        5.50        10.55        12.94         3.75         5.50
+//        6.00        15.27        11.67         4.00         6.00
+//        6.50        20.90        10.79         4.25         6.50
+//        7.00        27.14        10.15         4.50         7.00
+//        7.50        34.03         9.73         4.75         7.50
+//        8.00        41.10         9.40         5.00         8.00
+//
+// %overflow   = percentage of buckets which have an overflow bucket
+// bytes/entry = overhead bytes used per key/value pair
+// hitprobe    = # of entries to check when looking up a present key
+// missprobe   = # of entries to check when looking up an absent key
+//
+// Keep in mind this data is for maximally loaded tables, i.e. just
+// before the table grows.  Typical tables will be somewhat less loaded.
+
+// Maximum key or value size to keep inline (instead of mallocing per element).
+// Must fit in a uint8.
+// Fast versions cannot handle big values - the cutoff size for
+// fast versions in ../../cmd/gc/walk.c must be at most this value.
+#define MAXKEYSIZE 128
+#define MAXVALUESIZE 128
+
+typedef struct Bucket Bucket;
+struct Bucket
+{
+	// Note: the format of the Bucket is encoded in ../../cmd/gc/reflect.c and
+	// ../reflect/type.go.  Don't change this structure without also changing that code!
+	uint8  tophash[BUCKETSIZE]; // top 8 bits of hash of each entry (or special mark below)
+	Bucket *overflow;           // overflow bucket, if any
+	uint64 data[1];             // BUCKETSIZE keys followed by BUCKETSIZE values
+};
+// NOTE: packing all the keys together and then all the values together makes the
+// code a bit more complicated than alternating key/value/key/value/... but it allows
+// us to eliminate padding which would be needed for, e.g., map[int64]int8.
+
+// tophash values.  We reserve a few possibilities for special marks.
+// Each bucket (including its overflow buckets, if any) will have either all or none of its
+// entries in the Evacuated* states (except during the evacuate() method, which only happens
+// during map writes and thus no one else can observe the map during that time).
+enum
+{
+	Empty = 0,		// cell is empty
+	EvacuatedEmpty = 1,	// cell is empty, bucket is evacuated.
+	EvacuatedX = 2,		// key/value is valid.  Entry has been evacuated to first half of larger table.
+	EvacuatedY = 3,		// same as above, but evacuated to second half of larger table.
+	MinTopHash = 4, 	// minimum tophash for a normal filled cell.
+};
+#define evacuated(b) ((b)->tophash[0] > Empty && (b)->tophash[0] < MinTopHash)
+
+struct Hmap
+{
+	// Note: the format of the Hmap is encoded in ../../cmd/gc/reflect.c and
+	// ../reflect/type.go.  Don't change this structure without also changing that code!
+	uintgo  count;        // # live cells == size of map.  Must be first (used by len() builtin)
+	uint32  flags;
+	uint32  hash0;        // hash seed
+	uint8   B;            // log_2 of # of buckets (can hold up to LOAD * 2^B items)
+	uint8   keysize;      // key size in bytes
+	uint8   valuesize;    // value size in bytes
+	uint16  bucketsize;   // bucket size in bytes
+
+	byte    *buckets;     // array of 2^B Buckets. may be nil if count==0.
+	byte    *oldbuckets;  // previous bucket array of half the size, non-nil only when growing
+	uintptr nevacuate;    // progress counter for evacuation (buckets less than this have been evacuated)
+};
+
+// possible flags
+enum
+{
+	IndirectKey = 1,    // storing pointers to keys
+	IndirectValue = 2,  // storing pointers to values
+	Iterator = 4,       // there may be an iterator using buckets
+	OldIterator = 8,    // there may be an iterator using oldbuckets
+};
+
+// Macros for dereferencing indirect keys
+#define IK(h, p) (((h)->flags & IndirectKey) != 0 ? *(byte**)(p) : (p))
+#define IV(h, p) (((h)->flags & IndirectValue) != 0 ? *(byte**)(p) : (p))
+
+// If you modify Hiter, also change cmd/gc/reflect.c to indicate
+// the layout of this structure.
+struct Hiter
+{
+	uint8* key; // Must be in first position.  Write nil to indicate iteration end (see cmd/gc/range.c).
+	uint8* value; // Must be in second position (see cmd/gc/range.c).
+
+	MapType *t;
+	Hmap *h;
+	byte *buckets; // bucket ptr at hash_iter initialization time
+	struct Bucket *bptr; // current bucket
+
+	uint8 offset; // intra-bucket offset to start from during iteration (should be big enough to hold BUCKETSIZE-1)
+	bool done;
+
+	// state of table at time iterator is initialized
+	uint8 B;
+
+	// iter state
+	uintptr bucket;
+	uintptr i;
+	intptr check_bucket;
+};
+
diff --git a/src/pkg/runtime/hashmap_fast.c b/src/pkg/runtime/hashmap_fast.c
index 796582e..83bf6fe 100644
--- a/src/pkg/runtime/hashmap_fast.c
+++ b/src/pkg/runtime/hashmap_fast.c
@@ -5,24 +5,23 @@
 // Fast hashmap lookup specialized to a specific key type.
 // Included by hashmap.c once for each specialized type.
 
-// Note that this code differs from hash_lookup in that
-// it returns a pointer to the result, not the result itself.
-// The returned pointer is only valid until the next GC
-// point, so the caller must dereference it before then.
-
 // +build ignore
 
+// Because this file is #included, it cannot be processed by goc2c,
+// so we have to handle the Go resuts ourselves.
+
 #pragma textflag NOSPLIT
 void
-HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, byte *value)
+HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, GoOutput base, ...)
 {
 	uintptr bucket, i;
 	Bucket *b;
 	KEYTYPE *k;
-	byte *v;
+	byte *v, **valueptr;
 	uint8 top;
 	int8 keymaybe;
 
+	valueptr = (byte**)&base;
 	if(debug) {
 		runtime·prints("runtime.mapaccess1_fastXXX: map=");
 		runtime·printpointer(h);
@@ -31,8 +30,7 @@ HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, byte *value)
 		runtime·prints("\n");
 	}
 	if(h == nil || h->count == 0) {
-		value = empty_value;
-		FLUSH(&value);
+		*valueptr = t->elem->zero;
 		return;
 	}
 	if(raceenabled)
@@ -45,26 +43,24 @@ HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, byte *value)
 		b = (Bucket*)h->buckets;
 		if(FASTKEY(key)) {
 			for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) {
-				if(b->tophash[i] == 0)
+				if(b->tophash[i] == Empty)
 					continue;
 				if(QUICK_NE(key, *k))
 					continue;
 				if(QUICK_EQ(key, *k) || SLOW_EQ(key, *k)) {
-					value = v;
-					FLUSH(&value);
+					*valueptr = v;
 					return;
 				}
 			}
 		} else {
 			keymaybe = -1;
 			for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) {
-				if(b->tophash[i] == 0)
+				if(b->tophash[i] == Empty)
 					continue;
 				if(QUICK_NE(key, *k))
 					continue;
 				if(QUICK_EQ(key, *k)) {
-					value = v;
-					FLUSH(&value);
+					*valueptr = v;
 					return;
 				}
 				if(MAYBE_EQ(key, *k)) {
@@ -82,8 +78,7 @@ HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, byte *value)
 			if(keymaybe >= 0) {
 				k = (KEYTYPE*)b->data + keymaybe;
 				if(SLOW_EQ(key, *k)) {
-					value = (byte*)((KEYTYPE*)b->data + BUCKETSIZE) + keymaybe * h->valuesize;
-					FLUSH(&value);
+					*valueptr = (byte*)((KEYTYPE*)b->data + BUCKETSIZE) + keymaybe * h->valuesize;
 					return;
 				}
 			}
@@ -93,8 +88,8 @@ dohash:
 		bucket = h->hash0;
 		HASHFUNC(&bucket, sizeof(KEYTYPE), &key);
 		top = bucket >> (sizeof(uintptr)*8 - 8);
-		if(top == 0)
-			top = 1;
+		if(top < MinTopHash)
+			top += MinTopHash;
 		bucket &= (((uintptr)1 << h->B) - 1);
 		if(h->oldbuckets != nil) {
 			i = bucket & (((uintptr)1 << (h->B - 1)) - 1);
@@ -112,29 +107,30 @@ dohash:
 				if(QUICK_NE(key, *k))
 					continue;
 				if(QUICK_EQ(key, *k) || SLOW_EQ(key, *k)) {
-					value = v;
-					FLUSH(&value);
+					*valueptr = v;
 					return;
 				}
 			}
 			b = b->overflow;
 		} while(b != nil);
 	}
-	value = empty_value;
-	FLUSH(&value);
+	*valueptr = t->elem->zero;
 }
 
 #pragma textflag NOSPLIT
 void
-HASH_LOOKUP2(MapType *t, Hmap *h, KEYTYPE key, byte *value, bool res)
+HASH_LOOKUP2(MapType *t, Hmap *h, KEYTYPE key, GoOutput base, ...)
 {
 	uintptr bucket, i;
 	Bucket *b;
 	KEYTYPE *k;
-	byte *v;
+	byte *v, **valueptr;
 	uint8 top;
 	int8 keymaybe;
+	bool *okptr;
 
+	valueptr = (byte**)&base;
+	okptr = (bool*)(valueptr+1);
 	if(debug) {
 		runtime·prints("runtime.mapaccess2_fastXXX: map=");
 		runtime·printpointer(h);
@@ -143,10 +139,8 @@ HASH_LOOKUP2(MapType *t, Hmap *h, KEYTYPE key, byte *value, bool res)
 		runtime·prints("\n");
 	}
 	if(h == nil || h->count == 0) {
-		value = empty_value;
-		res = false;
-		FLUSH(&value);
-		FLUSH(&res);
+		*valueptr = t->elem->zero;
+		*okptr = false;
 		return;
 	}
 	if(raceenabled)
@@ -159,30 +153,26 @@ HASH_LOOKUP2(MapType *t, Hmap *h, KEYTYPE key, byte *value, bool res)
 		b = (Bucket*)h->buckets;
 		if(FASTKEY(key)) {
 			for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) {
-				if(b->tophash[i] == 0)
+				if(b->tophash[i] == Empty)
 					continue;
 				if(QUICK_NE(key, *k))
 					continue;
 				if(QUICK_EQ(key, *k) || SLOW_EQ(key, *k)) {
-					value = v;
-					res = true;
-					FLUSH(&value);
-					FLUSH(&res);
+					*valueptr = v;
+					*okptr = true;
 					return;
 				}
 			}
 		} else {
 			keymaybe = -1;
 			for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) {
-				if(b->tophash[i] == 0)
+				if(b->tophash[i] == Empty)
 					continue;
 				if(QUICK_NE(key, *k))
 					continue;
 				if(QUICK_EQ(key, *k)) {
-					value = v;
-					res = true;
-					FLUSH(&value);
-					FLUSH(&res);
+					*valueptr = v;
+					*okptr = true;
 					return;
 				}
 				if(MAYBE_EQ(key, *k)) {
@@ -200,10 +190,8 @@ HASH_LOOKUP2(MapType *t, Hmap *h, KEYTYPE key, byte *value, bool res)
 			if(keymaybe >= 0) {
 				k = (KEYTYPE*)b->data + keymaybe;
 				if(SLOW_EQ(key, *k)) {
-					value = (byte*)((KEYTYPE*)b->data + BUCKETSIZE) + keymaybe * h->valuesize;
-					res = true;
-					FLUSH(&value);
-					FLUSH(&res);
+					*valueptr = (byte*)((KEYTYPE*)b->data + BUCKETSIZE) + keymaybe * h->valuesize;
+					*okptr = true;
 					return;
 				}
 			}
@@ -213,8 +201,8 @@ dohash:
 		bucket = h->hash0;
 		HASHFUNC(&bucket, sizeof(KEYTYPE), &key);
 		top = bucket >> (sizeof(uintptr)*8 - 8);
-		if(top == 0)
-			top = 1;
+		if(top < MinTopHash)
+			top += MinTopHash;
 		bucket &= (((uintptr)1 << h->B) - 1);
 		if(h->oldbuckets != nil) {
 			i = bucket & (((uintptr)1 << (h->B - 1)) - 1);
@@ -232,18 +220,14 @@ dohash:
 				if(QUICK_NE(key, *k))
 					continue;
 				if(QUICK_EQ(key, *k) || SLOW_EQ(key, *k)) {
-					value = v;
-					res = true;
-					FLUSH(&value);
-					FLUSH(&res);
+					*valueptr = v;
+					*okptr = true;
 					return;
 				}
 			}
 			b = b->overflow;
 		} while(b != nil);
 	}
-	value = empty_value;
-	res = false;
-	FLUSH(&value);
-	FLUSH(&res);
+	*valueptr = t->elem->zero;
+	*okptr = false;
 }
diff --git a/src/pkg/runtime/heapdump.c b/src/pkg/runtime/heapdump.c
new file mode 100644
index 0000000..744c59f
--- /dev/null
+++ b/src/pkg/runtime/heapdump.c
@@ -0,0 +1,981 @@
+// 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.
+
+// Implementation of runtime/debug.WriteHeapDump.  Writes all
+// objects in the heap plus additional info (roots, threads,
+// finalizers, etc.) to a file.
+
+// The format of the dumped file is described at
+// http://code.google.com/p/go-wiki/wiki/heapdump13
+
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+#include "mgc0.h"
+#include "type.h"
+#include "typekind.h"
+#include "funcdata.h"
+#include "zaexperiment.h"
+#include "../../cmd/ld/textflag.h"
+
+extern byte data[];
+extern byte edata[];
+extern byte bss[];
+extern byte ebss[];
+extern byte gcdata[];
+extern byte gcbss[];
+
+enum {
+	FieldKindEol = 0,
+	FieldKindPtr = 1,
+	FieldKindString = 2,
+	FieldKindSlice = 3,
+	FieldKindIface = 4,
+	FieldKindEface = 5,
+
+	TagEOF = 0,
+	TagObject = 1,
+	TagOtherRoot = 2,
+	TagType = 3,
+	TagGoRoutine = 4,
+	TagStackFrame = 5,
+	TagParams = 6,
+	TagFinalizer = 7,
+	TagItab = 8,
+	TagOSThread = 9,
+	TagMemStats = 10,
+	TagQueuedFinalizer = 11,
+	TagData = 12,
+	TagBss = 13,
+	TagDefer = 14,
+	TagPanic = 15,
+	TagMemProf = 16,
+	TagAllocSample = 17,
+
+	TypeInfo_Conservative = 127,
+};
+
+static uintptr* playgcprog(uintptr offset, uintptr *prog, void (*callback)(void*,uintptr,uintptr), void *arg);
+static void dumpfields(uintptr *prog);
+static void dumpefacetypes(void *obj, uintptr size, Type *type, uintptr kind);
+static void dumpbvtypes(BitVector *bv, byte *base);
+
+// fd to write the dump to.
+static uintptr dumpfd;
+
+// buffer of pending write data
+enum {
+	BufSize = 4096,
+};
+#pragma dataflag NOPTR
+static byte buf[BufSize];
+static uintptr nbuf;
+
+static void
+write(byte *data, uintptr len)
+{
+	if(len + nbuf <= BufSize) {
+		runtime·memmove(buf + nbuf, data, len);
+		nbuf += len;
+		return;
+	}
+	runtime·write(dumpfd, buf, nbuf);
+	if(len >= BufSize) {
+		runtime·write(dumpfd, data, len);
+		nbuf = 0;
+	} else {
+		runtime·memmove(buf, data, len);
+		nbuf = len;
+	}
+}
+
+static void
+flush(void)
+{
+	runtime·write(dumpfd, buf, nbuf);
+	nbuf = 0;
+}
+
+// Cache of types that have been serialized already.
+// We use a type's hash field to pick a bucket.
+// Inside a bucket, we keep a list of types that
+// have been serialized so far, most recently used first.
+// Note: when a bucket overflows we may end up
+// serializing a type more than once.  That's ok.
+enum {
+	TypeCacheBuckets = 256, // must be a power of 2
+	TypeCacheAssoc = 4,
+};
+typedef struct TypeCacheBucket TypeCacheBucket;
+struct TypeCacheBucket {
+	Type *t[TypeCacheAssoc];
+};
+static TypeCacheBucket typecache[TypeCacheBuckets];
+
+// dump a uint64 in a varint format parseable by encoding/binary
+static void
+dumpint(uint64 v)
+{
+	byte buf[10];
+	int32 n;
+	n = 0;
+	while(v >= 0x80) {
+		buf[n++] = v | 0x80;
+		v >>= 7;
+	}
+	buf[n++] = v;
+	write(buf, n);
+}
+
+static void
+dumpbool(bool b)
+{
+	dumpint(b ? 1 : 0);
+}
+
+// dump varint uint64 length followed by memory contents
+static void
+dumpmemrange(byte *data, uintptr len)
+{
+	dumpint(len);
+	write(data, len);
+}
+
+static void
+dumpstr(String s)
+{
+	dumpmemrange(s.str, s.len);
+}
+
+static void
+dumpcstr(int8 *c)
+{
+	dumpmemrange((byte*)c, runtime·findnull((byte*)c));
+}
+
+// dump information for a type
+static void
+dumptype(Type *t)
+{
+	TypeCacheBucket *b;
+	int32 i, j;
+
+	if(t == nil) {
+		return;
+	}
+
+	// If we've definitely serialized the type before,
+	// no need to do it again.
+	b = &typecache[t->hash & (TypeCacheBuckets-1)];
+	if(t == b->t[0]) return;
+	for(i = 1; i < TypeCacheAssoc; i++) {
+		if(t == b->t[i]) {
+			// Move-to-front
+			for(j = i; j > 0; j--) {
+				b->t[j] = b->t[j-1];
+			}
+			b->t[0] = t;
+			return;
+		}
+	}
+	// Might not have been dumped yet.  Dump it and
+	// remember we did so.
+	for(j = TypeCacheAssoc-1; j > 0; j--) {
+		b->t[j] = b->t[j-1];
+	}
+	b->t[0] = t;
+	
+	// dump the type
+	dumpint(TagType);
+	dumpint((uintptr)t);
+	dumpint(t->size);
+	if(t->x == nil || t->x->pkgPath == nil || t->x->name == nil) {
+		dumpstr(*t->string);
+	} else {
+		dumpint(t->x->pkgPath->len + 1 + t->x->name->len);
+		write(t->x->pkgPath->str, t->x->pkgPath->len);
+		write((byte*)".", 1);
+		write(t->x->name->str, t->x->name->len);
+	}
+	dumpbool(t->size > PtrSize || (t->kind & KindNoPointers) == 0);
+	dumpfields((uintptr*)t->gc + 1);
+}
+
+// returns true if object is scannable
+static bool
+scannable(byte *obj)
+{
+	uintptr *b, off, shift;
+
+	off = (uintptr*)obj - (uintptr*)runtime·mheap.arena_start;  // word offset
+	b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+	shift = off % wordsPerBitmapWord;
+	return ((*b >> shift) & bitScan) != 0;
+}
+
+// dump an object
+static void
+dumpobj(byte *obj, uintptr size, Type *type, uintptr kind)
+{
+	if(type != nil) {
+		dumptype(type);
+		dumpefacetypes(obj, size, type, kind);
+	}
+
+	dumpint(TagObject);
+	dumpint((uintptr)obj);
+	dumpint((uintptr)type);
+	dumpint(kind);
+	dumpmemrange(obj, size);
+}
+
+static void
+dumpotherroot(int8 *description, byte *to)
+{
+	dumpint(TagOtherRoot);
+	dumpcstr(description);
+	dumpint((uintptr)to);
+}
+
+static void
+dumpfinalizer(byte *obj, FuncVal *fn, Type* fint, PtrType *ot)
+{
+	dumpint(TagFinalizer);
+	dumpint((uintptr)obj);
+	dumpint((uintptr)fn);
+	dumpint((uintptr)fn->fn);
+	dumpint((uintptr)fint);
+	dumpint((uintptr)ot);
+}
+
+typedef struct ChildInfo ChildInfo;
+struct ChildInfo {
+	// Information passed up from the callee frame about
+	// the layout of the outargs region.
+	uintptr argoff;     // where the arguments start in the frame
+	uintptr arglen;     // size of args region
+	BitVector args;    // if args.n >= 0, pointer map of args region
+
+	byte *sp;           // callee sp
+	uintptr depth;      // depth in call stack (0 == most recent)
+};
+
+// dump kinds & offsets of interesting fields in bv
+static void
+dumpbv(BitVector *bv, uintptr offset)
+{
+	uintptr i;
+
+	for(i = 0; i < bv->n; i += BitsPerPointer) {
+		switch(bv->data[i/32] >> i%32 & 3) {
+		case BitsDead:
+		case BitsScalar:
+			break;
+		case BitsPointer:
+			dumpint(FieldKindPtr);
+			dumpint(offset + i / BitsPerPointer * PtrSize);
+			break;
+		case BitsMultiWord:
+			switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) {
+			case BitsString:
+				dumpint(FieldKindString);
+				dumpint(offset + i / BitsPerPointer * PtrSize);
+				i += BitsPerPointer;
+				break;
+			case BitsSlice:
+				dumpint(FieldKindSlice);
+				dumpint(offset + i / BitsPerPointer * PtrSize);
+				i += 2 * BitsPerPointer;
+				break;
+			case BitsIface:
+				dumpint(FieldKindIface);
+				dumpint(offset + i / BitsPerPointer * PtrSize);
+				i += BitsPerPointer;
+				break;
+			case BitsEface:
+				dumpint(FieldKindEface);
+				dumpint(offset + i / BitsPerPointer * PtrSize);
+				i += BitsPerPointer;
+				break;
+			}
+		}
+	}
+}
+
+static bool
+dumpframe(Stkframe *s, void *arg)
+{
+	Func *f;
+	ChildInfo *child;
+	uintptr pc, off, size;
+	int32 pcdata;
+	StackMap *stackmap;
+	int8 *name;
+	BitVector bv;
+
+	child = (ChildInfo*)arg;
+	f = s->fn;
+
+	// Figure out what we can about our stack map
+	pc = s->pc;
+	if(pc != f->entry)
+		pc--;
+	pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, pc);
+	if(pcdata == -1) {
+		// We do not have a valid pcdata value but there might be a
+		// stackmap for this function.  It is likely that we are looking
+		// at the function prologue, assume so and hope for the best.
+		pcdata = 0;
+	}
+	stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
+
+	// Dump any types we will need to resolve Efaces.
+	if(child->args.n >= 0)
+		dumpbvtypes(&child->args, (byte*)s->sp + child->argoff);
+	if(stackmap != nil && stackmap->n > 0) {
+		bv = runtime·stackmapdata(stackmap, pcdata);
+		dumpbvtypes(&bv, s->varp - bv.n / BitsPerPointer * PtrSize);
+	} else {
+		bv.n = -1;
+	}
+
+	// Dump main body of stack frame.
+	dumpint(TagStackFrame);
+	dumpint(s->sp); // lowest address in frame
+	dumpint(child->depth); // # of frames deep on the stack
+	dumpint((uintptr)child->sp); // sp of child, or 0 if bottom of stack
+	dumpmemrange((byte*)s->sp, s->fp - s->sp);  // frame contents
+	dumpint(f->entry);
+	dumpint(s->pc);
+	dumpint(s->continpc);
+	name = runtime·funcname(f);
+	if(name == nil)
+		name = "unknown function";
+	dumpcstr(name);
+
+	// Dump fields in the outargs section
+	if(child->args.n >= 0) {
+		dumpbv(&child->args, child->argoff);
+	} else {
+		// conservative - everything might be a pointer
+		for(off = child->argoff; off < child->argoff + child->arglen; off += PtrSize) {
+			dumpint(FieldKindPtr);
+			dumpint(off);
+		}
+	}
+
+	// Dump fields in the local vars section
+	if(stackmap == nil) {
+		// No locals information, dump everything.
+		for(off = child->arglen; off < s->varp - (byte*)s->sp; off += PtrSize) {
+			dumpint(FieldKindPtr);
+			dumpint(off);
+		}
+	} else if(stackmap->n < 0) {
+		// Locals size information, dump just the locals.
+		size = -stackmap->n;
+		for(off = s->varp - size - (byte*)s->sp; off < s->varp - (byte*)s->sp; off += PtrSize) {
+			dumpint(FieldKindPtr);
+			dumpint(off);
+		}
+	} else if(stackmap->n > 0) {
+		// Locals bitmap information, scan just the pointers in
+		// locals.
+		dumpbv(&bv, s->varp - bv.n / BitsPerPointer * PtrSize - (byte*)s->sp);
+	}
+	dumpint(FieldKindEol);
+
+	// Record arg info for parent.
+	child->argoff = s->argp - (byte*)s->fp;
+	child->arglen = s->arglen;
+	child->sp = (byte*)s->sp;
+	child->depth++;
+	stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
+	if(stackmap != nil)
+		child->args = runtime·stackmapdata(stackmap, pcdata);
+	else
+		child->args.n = -1;
+	return true;
+}
+
+static void
+dumpgoroutine(G *gp)
+{
+	uintptr sp, pc, lr;
+	ChildInfo child;
+	Defer *d;
+	Panic *p;
+
+	if(gp->syscallstack != (uintptr)nil) {
+		sp = gp->syscallsp;
+		pc = gp->syscallpc;
+		lr = 0;
+	} else {
+		sp = gp->sched.sp;
+		pc = gp->sched.pc;
+		lr = gp->sched.lr;
+	}
+
+	dumpint(TagGoRoutine);
+	dumpint((uintptr)gp);
+	dumpint((uintptr)sp);
+	dumpint(gp->goid);
+	dumpint(gp->gopc);
+	dumpint(gp->status);
+	dumpbool(gp->issystem);
+	dumpbool(gp->isbackground);
+	dumpint(gp->waitsince);
+	dumpcstr(gp->waitreason);
+	dumpint((uintptr)gp->sched.ctxt);
+	dumpint((uintptr)gp->m);
+	dumpint((uintptr)gp->defer);
+	dumpint((uintptr)gp->panic);
+
+	// dump stack
+	child.args.n = -1;
+	child.arglen = 0;
+	child.sp = nil;
+	child.depth = 0;
+	if(!ScanStackByFrames)
+		runtime·throw("need frame info to dump stacks");
+	runtime·gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, dumpframe, &child, false);
+
+	// dump defer & panic records
+	for(d = gp->defer; d != nil; d = d->link) {
+		dumpint(TagDefer);
+		dumpint((uintptr)d);
+		dumpint((uintptr)gp);
+		dumpint((uintptr)d->argp);
+		dumpint((uintptr)d->pc);
+		dumpint((uintptr)d->fn);
+		dumpint((uintptr)d->fn->fn);
+		dumpint((uintptr)d->link);
+	}
+	for (p = gp->panic; p != nil; p = p->link) {
+		dumpint(TagPanic);
+		dumpint((uintptr)p);
+		dumpint((uintptr)gp);
+		dumpint((uintptr)p->arg.type);
+		dumpint((uintptr)p->arg.data);
+		dumpint((uintptr)p->defer);
+		dumpint((uintptr)p->link);
+	}
+}
+
+static void
+dumpgs(void)
+{
+	G *gp;
+	uint32 i;
+
+	// goroutines & stacks
+	for(i = 0; i < runtime·allglen; i++) {
+		gp = runtime·allg[i];
+		switch(gp->status){
+		default:
+			runtime·printf("unexpected G.status %d\n", gp->status);
+			runtime·throw("mark - bad status");
+		case Gdead:
+			break;
+		case Grunnable:
+		case Gsyscall:
+		case Gwaiting:
+			dumpgoroutine(gp);
+			break;
+		}
+	}
+}
+
+static void
+finq_callback(FuncVal *fn, byte *obj, uintptr nret, Type *fint, PtrType *ot)
+{
+	dumpint(TagQueuedFinalizer);
+	dumpint((uintptr)obj);
+	dumpint((uintptr)fn);
+	dumpint((uintptr)fn->fn);
+	dumpint((uintptr)fint);
+	dumpint((uintptr)ot);
+	USED(&nret);
+}
+
+
+static void
+dumproots(void)
+{
+	MSpan *s, **allspans;
+	uint32 spanidx;
+	Special *sp;
+	SpecialFinalizer *spf;
+	byte *p;
+
+	// data segment
+	dumpint(TagData);
+	dumpint((uintptr)data);
+	dumpmemrange(data, edata - data);
+	dumpfields((uintptr*)gcdata + 1);
+
+	// bss segment
+	dumpint(TagBss);
+	dumpint((uintptr)bss);
+	dumpmemrange(bss, ebss - bss);
+	dumpfields((uintptr*)gcbss + 1);
+	
+	// MSpan.types
+	allspans = runtime·mheap.allspans;
+	for(spanidx=0; spanidx<runtime·mheap.nspan; spanidx++) {
+		s = allspans[spanidx];
+		if(s->state == MSpanInUse) {
+			// The garbage collector ignores type pointers stored in MSpan.types:
+			//  - Compiler-generated types are stored outside of heap.
+			//  - The reflect package has runtime-generated types cached in its data structures.
+			//    The garbage collector relies on finding the references via that cache.
+			switch(s->types.compression) {
+			case MTypes_Empty:
+			case MTypes_Single:
+				break;
+			case MTypes_Words:
+			case MTypes_Bytes:
+				dumpotherroot("runtime type info", (byte*)s->types.data);
+				break;
+			}
+
+			// Finalizers
+			for(sp = s->specials; sp != nil; sp = sp->next) {
+				if(sp->kind != KindSpecialFinalizer)
+					continue;
+				spf = (SpecialFinalizer*)sp;
+				p = (byte*)((s->start << PageShift) + spf->offset);
+				dumpfinalizer(p, spf->fn, spf->fint, spf->ot);
+			}
+		}
+	}
+
+	// Finalizer queue
+	runtime·iterate_finq(finq_callback);
+}
+
+// Bit vector of free marks.
+// Needs to be as big as the largest number of objects per span.
+static byte free[PageSize/8];
+
+static void
+dumpobjs(void)
+{
+	uintptr i, j, size, n, off, shift, *bitp, bits, ti, kind;
+	MSpan *s;
+	MLink *l;
+	byte *p;
+	Type *t;
+
+	for(i = 0; i < runtime·mheap.nspan; i++) {
+		s = runtime·mheap.allspans[i];
+		if(s->state != MSpanInUse)
+			continue;
+		p = (byte*)(s->start << PageShift);
+		size = s->elemsize;
+		n = (s->npages << PageShift) / size;
+		if(n > PageSize/8)
+			runtime·throw("free array doesn't have enough entries");
+		for(l = s->freelist; l != nil; l = l->next) {
+			free[((byte*)l - p) / size] = true;
+		}
+		for(j = 0; j < n; j++, p += size) {
+			if(free[j]) {
+				free[j] = false;
+				continue;
+			}
+			off = (uintptr*)p - (uintptr*)runtime·mheap.arena_start;
+			bitp = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+			shift = off % wordsPerBitmapWord;
+			bits = *bitp >> shift;
+
+			// Skip FlagNoGC allocations (stacks)
+			if((bits & bitAllocated) == 0)
+				continue;
+
+			// extract type and kind
+			ti = runtime·gettype(p);
+			t = (Type*)(ti & ~(uintptr)(PtrSize-1));
+			kind = ti & (PtrSize-1);
+			
+			// dump it
+			if(kind == TypeInfo_Chan)
+				t = ((ChanType*)t)->elem; // use element type for chan encoding
+			if(t == nil && scannable(p))
+				kind = TypeInfo_Conservative; // special kind for conservatively scanned objects
+			dumpobj(p, size, t, kind);
+		}
+	}
+}
+
+static void
+dumpparams(void)
+{
+	byte *x;
+
+	dumpint(TagParams);
+	x = (byte*)1;
+	if(*(byte*)&x == 1)
+		dumpbool(false); // little-endian ptrs
+	else
+		dumpbool(true); // big-endian ptrs
+	dumpint(PtrSize);
+	dumpint(runtime·Hchansize);
+	dumpint((uintptr)runtime·mheap.arena_start);
+	dumpint((uintptr)runtime·mheap.arena_used);
+	dumpint(thechar);
+	dumpcstr(GOEXPERIMENT);
+	dumpint(runtime·ncpu);
+}
+
+static void
+itab_callback(Itab *tab)
+{
+	Type *t;
+
+	dumpint(TagItab);
+	dumpint((uintptr)tab);
+	t = tab->type;
+	dumpbool(t->size > PtrSize || (t->kind & KindNoPointers) == 0);
+}
+
+static void
+dumpitabs(void)
+{
+	runtime·iterate_itabs(itab_callback);
+}
+
+static void
+dumpms(void)
+{
+	M *mp;
+
+	for(mp = runtime·allm; mp != nil; mp = mp->alllink) {
+		dumpint(TagOSThread);
+		dumpint((uintptr)mp);
+		dumpint(mp->id);
+		dumpint(mp->procid);
+	}
+}
+
+static void
+dumpmemstats(void)
+{
+	int32 i;
+
+	dumpint(TagMemStats);
+	dumpint(mstats.alloc);
+	dumpint(mstats.total_alloc);
+	dumpint(mstats.sys);
+	dumpint(mstats.nlookup);
+	dumpint(mstats.nmalloc);
+	dumpint(mstats.nfree);
+	dumpint(mstats.heap_alloc);
+	dumpint(mstats.heap_sys);
+	dumpint(mstats.heap_idle);
+	dumpint(mstats.heap_inuse);
+	dumpint(mstats.heap_released);
+	dumpint(mstats.heap_objects);
+	dumpint(mstats.stacks_inuse);
+	dumpint(mstats.stacks_sys);
+	dumpint(mstats.mspan_inuse);
+	dumpint(mstats.mspan_sys);
+	dumpint(mstats.mcache_inuse);
+	dumpint(mstats.mcache_sys);
+	dumpint(mstats.buckhash_sys);
+	dumpint(mstats.gc_sys);
+	dumpint(mstats.other_sys);
+	dumpint(mstats.next_gc);
+	dumpint(mstats.last_gc);
+	dumpint(mstats.pause_total_ns);
+	for(i = 0; i < 256; i++)
+		dumpint(mstats.pause_ns[i]);
+	dumpint(mstats.numgc);
+}
+
+static void
+dumpmemprof_callback(Bucket *b, uintptr nstk, uintptr *stk, uintptr size, uintptr allocs, uintptr frees)
+{
+	uintptr i, pc;
+	Func *f;
+	byte buf[20];
+	String file;
+	int32 line;
+
+	dumpint(TagMemProf);
+	dumpint((uintptr)b);
+	dumpint(size);
+	dumpint(nstk);
+	for(i = 0; i < nstk; i++) {
+		pc = stk[i];
+		f = runtime·findfunc(pc);
+		if(f == nil) {
+			runtime·snprintf(buf, sizeof(buf), "%X", (uint64)pc);
+			dumpcstr((int8*)buf);
+			dumpcstr("?");
+			dumpint(0);
+		} else {
+			dumpcstr(runtime·funcname(f));
+			// TODO: Why do we need to back up to a call instruction here?
+			// Maybe profiler should do this.
+			if(i > 0 && pc > f->entry) {
+				if(thechar == '6' || thechar == '8')
+					pc--;
+				else
+					pc -= 4; // arm, etc
+			}
+			line = runtime·funcline(f, pc, &file);
+			dumpstr(file);
+			dumpint(line);
+		}
+	}
+	dumpint(allocs);
+	dumpint(frees);
+}
+
+static void
+dumpmemprof(void)
+{
+	MSpan *s, **allspans;
+	uint32 spanidx;
+	Special *sp;
+	SpecialProfile *spp;
+	byte *p;
+
+	runtime·iterate_memprof(dumpmemprof_callback);
+
+	allspans = runtime·mheap.allspans;
+	for(spanidx=0; spanidx<runtime·mheap.nspan; spanidx++) {
+		s = allspans[spanidx];
+		if(s->state != MSpanInUse)
+			continue;
+		for(sp = s->specials; sp != nil; sp = sp->next) {
+			if(sp->kind != KindSpecialProfile)
+				continue;
+			spp = (SpecialProfile*)sp;
+			p = (byte*)((s->start << PageShift) + spp->offset);
+			dumpint(TagAllocSample);
+			dumpint((uintptr)p);
+			dumpint((uintptr)spp->b);
+		}
+	}
+}
+
+static void
+mdump(G *gp)
+{
+	byte *hdr;
+	uintptr i;
+	MSpan *s;
+
+	// make sure we're done sweeping
+	for(i = 0; i < runtime·mheap.nspan; i++) {
+		s = runtime·mheap.allspans[i];
+		if(s->state == MSpanInUse)
+			runtime·MSpan_EnsureSwept(s);
+	}
+
+	runtime·memclr((byte*)&typecache[0], sizeof(typecache));
+	hdr = (byte*)"go1.3 heap dump\n";
+	write(hdr, runtime·findnull(hdr));
+	dumpparams();
+	dumpitabs();
+	dumpobjs();
+	dumpgs();
+	dumpms();
+	dumproots();
+	dumpmemstats();
+	dumpmemprof();
+	dumpint(TagEOF);
+	flush();
+
+	gp->param = nil;
+	gp->status = Grunning;
+	runtime·gogo(&gp->sched);
+}
+
+void
+runtime∕debug·WriteHeapDump(uintptr fd)
+{
+	// Stop the world.
+	runtime·semacquire(&runtime·worldsema, false);
+	m->gcing = 1;
+	m->locks++;
+	runtime·stoptheworld();
+
+	// Update stats so we can dump them.
+	// As a side effect, flushes all the MCaches so the MSpan.freelist
+	// lists contain all the free objects.
+	runtime·updatememstats(nil);
+
+	// Set dump file.
+	dumpfd = fd;
+
+	// Call dump routine on M stack.
+	g->status = Gwaiting;
+	g->waitreason = "dumping heap";
+	runtime·mcall(mdump);
+
+	// Reset dump file.
+	dumpfd = 0;
+
+	// Start up the world again.
+	m->gcing = 0;
+	runtime·semrelease(&runtime·worldsema);
+	runtime·starttheworld();
+	m->locks--;
+}
+
+// Runs the specified gc program.  Calls the callback for every
+// pointer-like field specified by the program and passes to the
+// callback the kind and offset of that field within the object.
+// offset is the offset in the object of the start of the program.
+// Returns a pointer to the opcode that ended the gc program (either
+// GC_END or GC_ARRAY_NEXT).
+static uintptr*
+playgcprog(uintptr offset, uintptr *prog, void (*callback)(void*,uintptr,uintptr), void *arg)
+{
+	uintptr len, elemsize, i, *end;
+
+	for(;;) {
+		switch(prog[0]) {
+		case GC_END:
+			return prog;
+		case GC_PTR:
+			callback(arg, FieldKindPtr, offset + prog[1]);
+			prog += 3;
+			break;
+		case GC_APTR:
+			callback(arg, FieldKindPtr, offset + prog[1]);
+			prog += 2;
+			break;
+		case GC_ARRAY_START:
+			len = prog[2];
+			elemsize = prog[3];
+			end = nil;
+			for(i = 0; i < len; i++) {
+				end = playgcprog(offset + prog[1] + i * elemsize, prog + 4, callback, arg);
+				if(end[0] != GC_ARRAY_NEXT)
+					runtime·throw("GC_ARRAY_START did not have matching GC_ARRAY_NEXT");
+			}
+			prog = end + 1;
+			break;
+		case GC_ARRAY_NEXT:
+			return prog;
+		case GC_CALL:
+			playgcprog(offset + prog[1], (uintptr*)((byte*)prog + *(int32*)&prog[2]), callback, arg);
+			prog += 3;
+			break;
+		case GC_CHAN_PTR:
+			callback(arg, FieldKindPtr, offset + prog[1]);
+			prog += 3;
+			break;
+		case GC_STRING:
+			callback(arg, FieldKindString, offset + prog[1]);
+			prog += 2;
+			break;
+		case GC_EFACE:
+			callback(arg, FieldKindEface, offset + prog[1]);
+			prog += 2;
+			break;
+		case GC_IFACE:
+			callback(arg, FieldKindIface, offset + prog[1]);
+			prog += 2;
+			break;
+		case GC_SLICE:
+			callback(arg, FieldKindSlice, offset + prog[1]);
+			prog += 3;
+			break;
+		case GC_REGION:
+			playgcprog(offset + prog[1], (uintptr*)prog[3] + 1, callback, arg);
+			prog += 4;
+			break;
+		default:
+			runtime·printf("%D\n", (uint64)prog[0]);
+			runtime·throw("bad gc op");
+		}
+	}
+}
+
+static void
+dump_callback(void *p, uintptr kind, uintptr offset)
+{
+	USED(&p);
+	dumpint(kind);
+	dumpint(offset);
+}
+
+// dumpint() the kind & offset of each field in an object.
+static void
+dumpfields(uintptr *prog)
+{
+	playgcprog(0, prog, dump_callback, nil);
+	dumpint(FieldKindEol);
+}
+
+static void
+dumpeface_callback(void *p, uintptr kind, uintptr offset)
+{
+	Eface *e;
+
+	if(kind != FieldKindEface)
+		return;
+	e = (Eface*)((byte*)p + offset);
+	dumptype(e->type);
+}
+
+// The heap dump reader needs to be able to disambiguate
+// Eface entries.  So it needs to know every type that might
+// appear in such an entry.  The following two routines accomplish
+// that.
+
+// Dump all the types that appear in the type field of
+// any Eface contained in obj.
+static void
+dumpefacetypes(void *obj, uintptr size, Type *type, uintptr kind)
+{
+	uintptr i;
+
+	switch(kind) {
+	case TypeInfo_SingleObject:
+		playgcprog(0, (uintptr*)type->gc + 1, dumpeface_callback, obj);
+		break;
+	case TypeInfo_Array:
+		for(i = 0; i <= size - type->size; i += type->size)
+			playgcprog(i, (uintptr*)type->gc + 1, dumpeface_callback, obj);
+		break;
+	case TypeInfo_Chan:
+		if(type->size == 0) // channels may have zero-sized objects in them
+			break;
+		for(i = runtime·Hchansize; i <= size - type->size; i += type->size)
+			playgcprog(i, (uintptr*)type->gc + 1, dumpeface_callback, obj);
+		break;
+	}
+}
+
+// Dump all the types that appear in the type field of
+// any Eface described by this bit vector.
+static void
+dumpbvtypes(BitVector *bv, byte *base)
+{
+	uintptr i;
+
+	for(i = 0; i < bv->n; i += BitsPerPointer) {
+		if((bv->data[i/32] >> i%32 & 3) != BitsMultiWord)
+			continue;
+		switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) {
+		case BitsString:
+		case BitsIface:
+			i += BitsPerPointer;
+			break;
+		case BitsSlice:
+			i += 2 * BitsPerPointer;
+			break;
+		case BitsEface:
+			dumptype(*(Type**)(base + i / BitsPerPointer * PtrSize));
+			i += BitsPerPointer;
+			break;
+		}
+	}
+}
diff --git a/src/pkg/runtime/iface.c b/src/pkg/runtime/iface.c
deleted file mode 100644
index ecbdcc7..0000000
--- a/src/pkg/runtime/iface.c
+++ /dev/null
@@ -1,721 +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 "runtime.h"
-#include "arch_GOARCH.h"
-#include "type.h"
-#include "typekind.h"
-#include "malloc.h"
-#include "../../cmd/ld/textflag.h"
-
-void
-runtime·printiface(Iface i)
-{
-	runtime·printf("(%p,%p)", i.tab, i.data);
-}
-
-void
-runtime·printeface(Eface e)
-{
-	runtime·printf("(%p,%p)", e.type, e.data);
-}
-
-static	Itab*	hash[1009];
-static	Lock	ifacelock;
-
-static Itab*
-itab(InterfaceType *inter, Type *type, int32 canfail)
-{
-	int32 locked;
-	int32 ni;
-	Method *t, *et;
-	IMethod *i, *ei;
-	uint32 h;
-	String *iname, *ipkgPath;
-	Itab *m;
-	UncommonType *x;
-	Type *itype;
-	Eface err;
-
-	if(inter->mhdr.len == 0)
-		runtime·throw("internal error - misuse of itab");
-
-	locked = 0;
-
-	// easy case
-	x = type->x;
-	if(x == nil) {
-		if(canfail)
-			return nil;
-		iname = inter->m[0].name;
-		goto throw;
-	}
-
-	// compiler has provided some good hash codes for us.
-	h = inter->hash;
-	h += 17 * type->hash;
-	// TODO(rsc): h += 23 * x->mhash ?
-	h %= nelem(hash);
-
-	// look twice - once without lock, once with.
-	// common case will be no lock contention.
-	for(locked=0; locked<2; locked++) {
-		if(locked)
-			runtime·lock(&ifacelock);
-		for(m=runtime·atomicloadp(&hash[h]); m!=nil; m=m->link) {
-			if(m->inter == inter && m->type == type) {
-				if(m->bad) {
-					m = nil;
-					if(!canfail) {
-						// this can only happen if the conversion
-						// was already done once using the , ok form
-						// and we have a cached negative result.
-						// the cached result doesn't record which
-						// interface function was missing, so jump
-						// down to the interface check, which will
-						// do more work but give a better error.
-						goto search;
-					}
-				}
-				if(locked)
-					runtime·unlock(&ifacelock);
-				return m;
-			}
-		}
-	}
-
-	ni = inter->mhdr.len;
-	m = runtime·persistentalloc(sizeof(*m) + ni*sizeof m->fun[0], 0, &mstats.other_sys);
-	m->inter = inter;
-	m->type = type;
-
-search:
-	// both inter and type have method sorted by name,
-	// and interface names are unique,
-	// so can iterate over both in lock step;
-	// the loop is O(ni+nt) not O(ni*nt).
-	i = inter->m;
-	ei = i + inter->mhdr.len;
-	t = x->m;
-	et = t + x->mhdr.len;
-	for(; i < ei; i++) {
-		itype = i->type;
-		iname = i->name;
-		ipkgPath = i->pkgPath;
-		for(;; t++) {
-			if(t >= et) {
-				if(!canfail) {
-				throw:
-					// didn't find method
-					runtime·newTypeAssertionError(
-						nil, type->string, inter->string,
-						iname, &err);
-					if(locked)
-						runtime·unlock(&ifacelock);
-					runtime·panic(err);
-					return nil;	// not reached
-				}
-				m->bad = 1;
-				goto out;
-			}
-			if(t->mtyp == itype && t->name == iname && t->pkgPath == ipkgPath)
-				break;
-		}
-		if(m)
-			m->fun[i - inter->m] = t->ifn;
-	}
-
-out:
-	if(!locked)
-		runtime·panicstring("invalid itab locking");
-	m->link = hash[h];
-	runtime·atomicstorep(&hash[h], m);
-	runtime·unlock(&ifacelock);
-	if(m->bad)
-		return nil;
-	return m;
-}
-
-static void
-copyin(Type *t, void *src, void **dst)
-{
-	uintptr size;
-	void *p;
-	Alg *alg;
-
-	size = t->size;
-	alg = t->alg;
-
-	if(size <= sizeof(*dst))
-		alg->copy(size, dst, src);
-	else {
-		p = runtime·mal(size);
-		alg->copy(size, p, src);
-		*dst = p;
-	}
-}
-
-static void
-copyout(Type *t, void **src, void *dst)
-{
-	uintptr size;
-	Alg *alg;
-
-	size = t->size;
-	alg = t->alg;
-
-	if(size <= sizeof(*src))
-		alg->copy(size, dst, src);
-	else
-		alg->copy(size, dst, *src);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·typ2Itab(Type *t, InterfaceType *inter, Itab **cache, Itab *ret)
-{
-	Itab *tab;
-
-	tab = itab(inter, t, 0);
-	runtime·atomicstorep(cache, tab);
-	ret = tab;
-	FLUSH(&ret);
-}
-
-// func convT2I(typ *byte, typ2 *byte, cache **byte, elem any) (ret any)
-#pragma textflag NOSPLIT
-void
-runtime·convT2I(Type *t, InterfaceType *inter, Itab **cache, ...)
-{
-	byte *elem;
-	Iface *ret;
-	Itab *tab;
-	int32 wid;
-
-	elem = (byte*)(&cache+1);
-	wid = t->size;
-	ret = (Iface*)(elem + ROUND(wid, Structrnd));
-	tab = runtime·atomicloadp(cache);
-	if(!tab) {
-		tab = itab(inter, t, 0);
-		runtime·atomicstorep(cache, tab);
-	}
-	ret->tab = tab;
-	copyin(t, elem, &ret->data);
-}
-
-// func convT2E(typ *byte, elem any) (ret any)
-#pragma textflag NOSPLIT
-void
-runtime·convT2E(Type *t, ...)
-{
-	byte *elem;
-	Eface *ret;
-	int32 wid;
-
-	elem = (byte*)(&t+1);
-	wid = t->size;
-	ret = (Eface*)(elem + ROUND(wid, Structrnd));
-	ret->type = t;
-	copyin(t, elem, &ret->data);
-}
-
-static void assertI2Tret(Type *t, Iface i, byte *ret);
-
-// func ifaceI2T(typ *byte, iface any) (ret any)
-#pragma textflag NOSPLIT
-void
-runtime·assertI2T(Type *t, Iface i, ...)
-{
-	byte *ret;
-
-	ret = (byte*)(&i+1);
-	assertI2Tret(t, i, ret);
-}
-
-static void
-assertI2Tret(Type *t, Iface i, byte *ret)
-{
-	Itab *tab;
-	Eface err;
-
-	tab = i.tab;
-	if(tab == nil) {
-		runtime·newTypeAssertionError(
-			nil, nil, t->string,
-			nil, &err);
-		runtime·panic(err);
-	}
-	if(tab->type != t) {
-		runtime·newTypeAssertionError(
-			tab->inter->string, tab->type->string, t->string,
-			nil, &err);
-		runtime·panic(err);
-	}
-	copyout(t, &i.data, ret);
-}
-
-// func ifaceI2T2(typ *byte, iface any) (ret any, ok bool)
-#pragma textflag NOSPLIT
-void
-runtime·assertI2T2(Type *t, Iface i, ...)
-{
-	byte *ret;
-	bool *ok;
-	int32 wid;
-
-	ret = (byte*)(&i+1);
-	wid = t->size;
-	ok = (bool*)(ret + wid);
-
-	if(i.tab == nil || i.tab->type != t) {
-		*ok = false;
-		runtime·memclr(ret, wid);
-		return;
-	}
-
-	*ok = true;
-	copyout(t, &i.data, ret);
-}
-
-void
-runtime·assertI2TOK(Type *t, Iface i, bool ok)
-{
-	ok = i.tab!=nil && i.tab->type==t;
-	FLUSH(&ok);
-}
-
-static void assertE2Tret(Type *t, Eface e, byte *ret);
-
-// func ifaceE2T(typ *byte, iface any) (ret any)
-#pragma textflag NOSPLIT
-void
-runtime·assertE2T(Type *t, Eface e, ...)
-{
-	byte *ret;
-
-	ret = (byte*)(&e+1);
-	assertE2Tret(t, e, ret);
-}
-
-static void
-assertE2Tret(Type *t, Eface e, byte *ret)
-{
-	Eface err;
-
-	if(e.type == nil) {
-		runtime·newTypeAssertionError(
-			nil, nil, t->string,
-			nil, &err);
-		runtime·panic(err);
-	}
-	if(e.type != t) {
-		runtime·newTypeAssertionError(
-			nil, e.type->string, t->string,
-			nil, &err);
-		runtime·panic(err);
-	}
-	copyout(t, &e.data, ret);
-}
-
-// func ifaceE2T2(sigt *byte, iface any) (ret any, ok bool);
-#pragma textflag NOSPLIT
-void
-runtime·assertE2T2(Type *t, Eface e, ...)
-{
-	byte *ret;
-	bool *ok;
-	int32 wid;
-
-	ret = (byte*)(&e+1);
-	wid = t->size;
-	ok = (bool*)(ret + wid);
-
-	if(t != e.type) {
-		*ok = false;
-		runtime·memclr(ret, wid);
-		return;
-	}
-
-	*ok = true;
-	copyout(t, &e.data, ret);
-}
-
-void
-runtime·assertE2TOK(Type *t, Eface e, bool ok)
-{
-	ok = t==e.type;
-	FLUSH(&ok);
-}
-
-// func convI2E(elem any) (ret any)
-void
-runtime·convI2E(Iface i, Eface ret)
-{
-	Itab *tab;
-
-	ret.data = i.data;
-	if((tab = i.tab) == nil)
-		ret.type = nil;
-	else
-		ret.type = tab->type;
-	FLUSH(&ret);
-}
-
-// func ifaceI2E(typ *byte, iface any) (ret any)
-void
-runtime·assertI2E(InterfaceType* inter, Iface i, Eface ret)
-{
-	Itab *tab;
-	Eface err;
-
-	tab = i.tab;
-	if(tab == nil) {
-		// explicit conversions require non-nil interface value.
-		runtime·newTypeAssertionError(
-			nil, nil, inter->string,
-			nil, &err);
-		runtime·panic(err);
-	}
-	ret.data = i.data;
-	ret.type = tab->type;
-	FLUSH(&ret);
-}
-
-// func ifaceI2E2(typ *byte, iface any) (ret any, ok bool)
-void
-runtime·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok)
-{
-	Itab *tab;
-
-	USED(inter);
-	tab = i.tab;
-	if(tab == nil) {
-		ret.type = nil;
-		ok = 0;
-	} else {
-		ret.type = tab->type;
-		ok = 1;
-	}
-	ret.data = i.data;
-	FLUSH(&ret);
-	FLUSH(&ok);
-}
-
-// func convI2I(typ *byte, elem any) (ret any)
-void
-runtime·convI2I(InterfaceType* inter, Iface i, Iface ret)
-{
-	Itab *tab;
-
-	ret.data = i.data;
-	if((tab = i.tab) == nil)
-		ret.tab = nil;
-	else if(tab->inter == inter)
-		ret.tab = tab;
-	else
-		ret.tab = itab(inter, tab->type, 0);
-	FLUSH(&ret);
-}
-
-void
-runtime·ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
-{
-	Itab *tab;
-	Eface err;
-
-	tab = i.tab;
-	if(tab == nil) {
-		// explicit conversions require non-nil interface value.
-		runtime·newTypeAssertionError(
-			nil, nil, inter->string,
-			nil, &err);
-		runtime·panic(err);
-	}
-	ret->data = i.data;
-	ret->tab = itab(inter, tab->type, 0);
-}
-
-// func ifaceI2I(sigi *byte, iface any) (ret any)
-void
-runtime·assertI2I(InterfaceType* inter, Iface i, Iface ret)
-{
-	runtime·ifaceI2I(inter, i, &ret);
-}
-
-// func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool)
-void
-runtime·assertI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
-{
-	Itab *tab;
-
-	tab = i.tab;
-	if(tab != nil && (tab->inter == inter || (tab = itab(inter, tab->type, 1)) != nil)) {
-		ret.data = i.data;
-		ret.tab = tab;
-		ok = 1;
-	} else {
-		ret.data = 0;
-		ret.tab = 0;
-		ok = 0;
-	}
-	FLUSH(&ret);
-	FLUSH(&ok);
-}
-
-void
-runtime·ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
-{
-	Type *t;
-	Eface err;
-
-	t = e.type;
-	if(t == nil) {
-		// explicit conversions require non-nil interface value.
-		runtime·newTypeAssertionError(
-			nil, nil, inter->string,
-			nil, &err);
-		runtime·panic(err);
-	}
-	ret->data = e.data;
-	ret->tab = itab(inter, t, 0);
-}
-
-bool
-runtime·ifaceE2I2(InterfaceType *inter, Eface e, Iface *ret)
-{
-	ret->tab = itab(inter, e.type, 1);
-	if(ret->tab == nil)
-		return false;
-	ret->data = e.data;
-	return true;
-}
-
-// For reflect
-//	func ifaceE2I(t *InterfaceType, e interface{}, dst *Iface)
-void
-reflect·ifaceE2I(InterfaceType *inter, Eface e, Iface *dst)
-{
-	runtime·ifaceE2I(inter, e, dst);
-}
-
-// func ifaceE2I(sigi *byte, iface any) (ret any)
-void
-runtime·assertE2I(InterfaceType* inter, Eface e, Iface ret)
-{
-	runtime·ifaceE2I(inter, e, &ret);
-}
-
-// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool)
-void
-runtime·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
-{
-	if(e.type == nil) {
-		ok = 0;
-		ret.data = nil;
-		ret.tab = nil;
-	} else if((ret.tab = itab(inter, e.type, 1)) == nil) {
-		ok = 0;
-		ret.data = nil;
-	} else {
-		ok = 1;
-		ret.data = e.data;
-	}
-	FLUSH(&ret);
-	FLUSH(&ok);
-}
-
-// func ifaceE2E(typ *byte, iface any) (ret any)
-void
-runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret)
-{
-	Type *t;
-	Eface err;
-
-	t = e.type;
-	if(t == nil) {
-		// explicit conversions require non-nil interface value.
-		runtime·newTypeAssertionError(
-			nil, nil, inter->string,
-			nil, &err);
-		runtime·panic(err);
-	}
-	ret = e;
-	FLUSH(&ret);
-}
-
-// func ifaceE2E2(iface any) (ret any, ok bool)
-void
-runtime·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok)
-{
-	USED(inter);
-	ret = e;
-	ok = e.type != nil;
-	FLUSH(&ret);
-	FLUSH(&ok);
-}
-
-static uintptr
-ifacehash1(void *data, Type *t, uintptr h)
-{
-	Alg *alg;
-	uintptr size;
-	Eface err;
-
-	if(t == nil)
-		return 0;
-
-	alg = t->alg;
-	size = t->size;
-	if(alg->hash == runtime·nohash) {
-		// calling nohash will panic too,
-		// but we can print a better error.
-		runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"hash of unhashable type "), *t->string), &err);
-		runtime·panic(err);
-	}
-	if(size <= sizeof(data))
-		alg->hash(&h, size, &data);
-	else
-		alg->hash(&h, size, data);
-	return h;
-}
-
-uintptr
-runtime·ifacehash(Iface a, uintptr h)
-{
-	if(a.tab == nil)
-		return h;
-	return ifacehash1(a.data, a.tab->type, h);
-}
-
-uintptr
-runtime·efacehash(Eface a, uintptr h)
-{
-	return ifacehash1(a.data, a.type, h);
-}
-
-static bool
-ifaceeq1(void *data1, void *data2, Type *t)
-{
-	uintptr size;
-	Alg *alg;
-	Eface err;
-	bool eq;
-
-	alg = t->alg;
-	size = t->size;
-
-	if(alg->equal == runtime·noequal) {
-		// calling noequal will panic too,
-		// but we can print a better error.
-		runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"comparing uncomparable type "), *t->string), &err);
-		runtime·panic(err);
-	}
-
-	eq = 0;
-	if(size <= sizeof(data1))
-		alg->equal(&eq, size, &data1, &data2);
-	else
-		alg->equal(&eq, size, data1, data2);
-	return eq;
-}
-
-bool
-runtime·ifaceeq_c(Iface i1, Iface i2)
-{
-	if(i1.tab != i2.tab)
-		return false;
-	if(i1.tab == nil)
-		return true;
-	return ifaceeq1(i1.data, i2.data, i1.tab->type);
-}
-
-bool
-runtime·efaceeq_c(Eface e1, Eface e2)
-{
-	if(e1.type != e2.type)
-		return false;
-	if(e1.type == nil)
-		return true;
-	return ifaceeq1(e1.data, e2.data, e1.type);
-}
-
-// ifaceeq(i1 any, i2 any) (ret bool);
-void
-runtime·ifaceeq(Iface i1, Iface i2, bool ret)
-{
-	ret = runtime·ifaceeq_c(i1, i2);
-	FLUSH(&ret);
-}
-
-// efaceeq(i1 any, i2 any) (ret bool)
-void
-runtime·efaceeq(Eface e1, Eface e2, bool ret)
-{
-	ret = runtime·efaceeq_c(e1, e2);
-	FLUSH(&ret);
-}
-
-// ifacethash(i1 any) (ret uint32);
-void
-runtime·ifacethash(Iface i1, uint32 ret)
-{
-	Itab *tab;
-
-	ret = 0;
-	tab = i1.tab;
-	if(tab != nil)
-		ret = tab->type->hash;
-	FLUSH(&ret);
-}
-
-// efacethash(e1 any) (ret uint32)
-void
-runtime·efacethash(Eface e1, uint32 ret)
-{
-	Type *t;
-
-	ret = 0;
-	t = e1.type;
-	if(t != nil)
-		ret = t->hash;
-	FLUSH(&ret);
-}
-
-void
-reflect·unsafe_Typeof(Eface e, Eface ret)
-{
-	if(e.type == nil) {
-		ret.type = nil;
-		ret.data = nil;
-	} else {
-		ret = *(Eface*)(e.type);
-	}
-	FLUSH(&ret);
-}
-
-void
-reflect·unsafe_New(Type *t, void *ret)
-{
-	ret = runtime·cnew(t);
-	FLUSH(&ret);
-}
-
-void
-reflect·unsafe_NewArray(Type *t, intgo n, void *ret)
-{
-	ret = runtime·cnewarray(t, n);
-	FLUSH(&ret);
-}
-
-void
-reflect·typelinks(Slice ret)
-{
-	extern Type *typelink[], *etypelink[];
-	static int32 first = 1;
-	ret.array = (byte*)typelink;
-	ret.len = etypelink - typelink;
-	ret.cap = ret.len;
-	FLUSH(&ret);
-}
diff --git a/src/pkg/runtime/iface.goc b/src/pkg/runtime/iface.goc
new file mode 100644
index 0000000..c0a17e3
--- /dev/null
+++ b/src/pkg/runtime/iface.goc
@@ -0,0 +1,620 @@
+// 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.
+
+package runtime
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "type.h"
+#include "typekind.h"
+#include "malloc.h"
+#include "../../cmd/ld/textflag.h"
+
+func printiface(i Iface) {
+	runtime·printf("(%p,%p)", i.tab, i.data);
+}
+
+func printeface(e Eface) {
+	runtime·printf("(%p,%p)", e.type, e.data);
+}
+
+static	Itab*	hash[1009];
+static	Lock	ifacelock;
+
+static Itab*
+itab(InterfaceType *inter, Type *type, int32 canfail)
+{
+	int32 locked;
+	int32 ni;
+	Method *t, *et;
+	IMethod *i, *ei;
+	uint32 h;
+	String *iname, *ipkgPath;
+	Itab *m;
+	UncommonType *x;
+	Type *itype;
+	Eface err;
+
+	if(inter->mhdr.len == 0)
+		runtime·throw("internal error - misuse of itab");
+
+	locked = 0;
+
+	// easy case
+	x = type->x;
+	if(x == nil) {
+		if(canfail)
+			return nil;
+		iname = inter->m[0].name;
+		goto throw;
+	}
+
+	// compiler has provided some good hash codes for us.
+	h = inter->hash;
+	h += 17 * type->hash;
+	// TODO(rsc): h += 23 * x->mhash ?
+	h %= nelem(hash);
+
+	// look twice - once without lock, once with.
+	// common case will be no lock contention.
+	for(locked=0; locked<2; locked++) {
+		if(locked)
+			runtime·lock(&ifacelock);
+		for(m=runtime·atomicloadp(&hash[h]); m!=nil; m=m->link) {
+			if(m->inter == inter && m->type == type) {
+				if(m->bad) {
+					m = nil;
+					if(!canfail) {
+						// this can only happen if the conversion
+						// was already done once using the , ok form
+						// and we have a cached negative result.
+						// the cached result doesn't record which
+						// interface function was missing, so jump
+						// down to the interface check, which will
+						// do more work but give a better error.
+						goto search;
+					}
+				}
+				if(locked)
+					runtime·unlock(&ifacelock);
+				return m;
+			}
+		}
+	}
+
+	ni = inter->mhdr.len;
+	m = runtime·persistentalloc(sizeof(*m) + ni*sizeof m->fun[0], 0, &mstats.other_sys);
+	m->inter = inter;
+	m->type = type;
+
+search:
+	// both inter and type have method sorted by name,
+	// and interface names are unique,
+	// so can iterate over both in lock step;
+	// the loop is O(ni+nt) not O(ni*nt).
+	i = inter->m;
+	ei = i + inter->mhdr.len;
+	t = x->m;
+	et = t + x->mhdr.len;
+	for(; i < ei; i++) {
+		itype = i->type;
+		iname = i->name;
+		ipkgPath = i->pkgPath;
+		for(;; t++) {
+			if(t >= et) {
+				if(!canfail) {
+				throw:
+					// didn't find method
+					runtime·newTypeAssertionError(
+						nil, type->string, inter->string,
+						iname, &err);
+					if(locked)
+						runtime·unlock(&ifacelock);
+					runtime·panic(err);
+					return nil;	// not reached
+				}
+				m->bad = 1;
+				goto out;
+			}
+			if(t->mtyp == itype && t->name == iname && t->pkgPath == ipkgPath)
+				break;
+		}
+		if(m)
+			m->fun[i - inter->m] = t->ifn;
+	}
+
+out:
+	if(!locked)
+		runtime·panicstring("invalid itab locking");
+	m->link = hash[h];
+	runtime·atomicstorep(&hash[h], m);
+	runtime·unlock(&ifacelock);
+	if(m->bad)
+		return nil;
+	return m;
+}
+
+// call the callback for every itab that is currently allocated.
+void
+runtime·iterate_itabs(void (*callback)(Itab*))
+{
+	int32 i;
+	Itab *tab;
+
+	for(i = 0; i < nelem(hash); i++) {
+		for(tab = hash[i]; tab != nil; tab = tab->link) {
+			callback(tab);
+		}
+	}
+}
+
+static void
+copyin(Type *t, void *src, void **dst)
+{
+	uintptr size;
+	void *p;
+	Alg *alg;
+
+	size = t->size;
+	alg = t->alg;
+
+	if(size <= sizeof(*dst))
+		alg->copy(size, dst, src);
+	else {
+		p = runtime·cnew(t);
+		alg->copy(size, p, src);
+		*dst = p;
+	}
+}
+
+static void
+copyout(Type *t, void **src, void *dst)
+{
+	uintptr size;
+	Alg *alg;
+
+	size = t->size;
+	alg = t->alg;
+
+	if(size <= sizeof(*src))
+		alg->copy(size, dst, src);
+	else
+		alg->copy(size, dst, *src);
+}
+
+#pragma textflag NOSPLIT
+func typ2Itab(t *Type, inter *InterfaceType, cache **Itab) (tab *Itab) {
+	tab = itab(inter, t, 0);
+	runtime·atomicstorep(cache, tab);
+}
+
+#pragma textflag NOSPLIT
+func convT2I(t *Type, inter *InterfaceType, cache **Itab, elem *byte) (ret Iface) {
+	Itab *tab;
+
+	tab = runtime·atomicloadp(cache);
+	if(!tab) {
+		tab = itab(inter, t, 0);
+		runtime·atomicstorep(cache, tab);
+	}
+	ret.tab = tab;
+	copyin(t, elem, &ret.data);
+}
+
+#pragma textflag NOSPLIT
+func convT2E(t *Type, elem *byte) (ret Eface) {
+	ret.type = t;
+	copyin(t, elem, &ret.data);
+}
+
+static void assertI2Tret(Type *t, Iface i, byte *ret);
+
+/*
+ * NOTE: Cannot use 'func' here, because we have to declare
+ * a return value, the only types we have are at least 1 byte large,
+ * goc2c will zero the return value, and the actual return value
+ * might have size 0 bytes, in which case the zeroing of the
+ * 1 or more bytes would be wrong.
+ * Using C lets us control (avoid) the initial zeroing.
+ */
+#pragma textflag NOSPLIT
+void
+runtime·assertI2T(Type *t, Iface i, GoOutput retbase)
+{
+	assertI2Tret(t, i, (byte*)&retbase);
+}
+
+static void
+assertI2Tret(Type *t, Iface i, byte *ret)
+{
+	Itab *tab;
+	Eface err;
+
+	tab = i.tab;
+	if(tab == nil) {
+		runtime·newTypeAssertionError(
+			nil, nil, t->string,
+			nil, &err);
+		runtime·panic(err);
+	}
+	if(tab->type != t) {
+		runtime·newTypeAssertionError(
+			tab->inter->string, tab->type->string, t->string,
+			nil, &err);
+		runtime·panic(err);
+	}
+	copyout(t, &i.data, ret);
+}
+
+#pragma textflag NOSPLIT
+func assertI2T2(t *Type, i Iface) (ret byte, ...) {
+	bool *ok;
+	int32 wid;
+
+	wid = t->size;
+	ok = (bool*)(&ret + wid);
+
+	if(i.tab == nil || i.tab->type != t) {
+		*ok = false;
+		runtime·memclr(&ret, wid);
+		return;
+	}
+
+	*ok = true;
+	copyout(t, &i.data, &ret);
+}
+
+func assertI2TOK(t *Type, i Iface) (ok bool) {
+	ok = i.tab!=nil && i.tab->type==t;
+}
+
+static void assertE2Tret(Type *t, Eface e, byte *ret);
+
+/*
+ * NOTE: Cannot use 'func' here. See assertI2T above.
+ */
+#pragma textflag NOSPLIT
+void
+runtime·assertE2T(Type *t, Eface e, GoOutput retbase)
+{
+	assertE2Tret(t, e, (byte*)&retbase);
+}
+
+static void
+assertE2Tret(Type *t, Eface e, byte *ret)
+{
+	Eface err;
+
+	if(e.type == nil) {
+		runtime·newTypeAssertionError(
+			nil, nil, t->string,
+			nil, &err);
+		runtime·panic(err);
+	}
+	if(e.type != t) {
+		runtime·newTypeAssertionError(
+			nil, e.type->string, t->string,
+			nil, &err);
+		runtime·panic(err);
+	}
+	copyout(t, &e.data, ret);
+}
+
+#pragma textflag NOSPLIT
+func assertE2T2(t *Type, e Eface) (ret byte, ...) {
+	bool *ok;
+	int32 wid;
+
+	wid = t->size;
+	ok = (bool*)(&ret + wid);
+
+	if(t != e.type) {
+		*ok = false;
+		runtime·memclr(&ret, wid);
+		return;
+	}
+
+	*ok = true;
+	copyout(t, &e.data, &ret);
+}
+
+func assertE2TOK(t *Type, e Eface) (ok bool) {
+	ok = t==e.type;
+}
+
+func convI2E(i Iface) (ret Eface) {
+	Itab *tab;
+
+	ret.data = i.data;
+	if((tab = i.tab) == nil)
+		ret.type = nil;
+	else
+		ret.type = tab->type;
+}
+
+func assertI2E(inter *InterfaceType, i Iface) (ret Eface) {
+	Itab *tab;
+	Eface err;
+
+	tab = i.tab;
+	if(tab == nil) {
+		// explicit conversions require non-nil interface value.
+		runtime·newTypeAssertionError(
+			nil, nil, inter->string,
+			nil, &err);
+		runtime·panic(err);
+	}
+	ret.data = i.data;
+	ret.type = tab->type;
+}
+
+func assertI2E2(inter *InterfaceType, i Iface) (ret Eface, ok bool) {
+	Itab *tab;
+
+	USED(inter);
+	tab = i.tab;
+	if(tab == nil) {
+		ret.type = nil;
+		ok = 0;
+	} else {
+		ret.type = tab->type;
+		ok = 1;
+	}
+	ret.data = i.data;
+}
+
+func convI2I(inter *InterfaceType, i Iface) (ret Iface) {
+	Itab *tab;
+
+	ret.data = i.data;
+	if((tab = i.tab) == nil)
+		ret.tab = nil;
+	else if(tab->inter == inter)
+		ret.tab = tab;
+	else
+		ret.tab = itab(inter, tab->type, 0);
+}
+
+void
+runtime·ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
+{
+	Itab *tab;
+	Eface err;
+
+	tab = i.tab;
+	if(tab == nil) {
+		// explicit conversions require non-nil interface value.
+		runtime·newTypeAssertionError(
+			nil, nil, inter->string,
+			nil, &err);
+		runtime·panic(err);
+	}
+	ret->data = i.data;
+	ret->tab = itab(inter, tab->type, 0);
+}
+
+func assertI2I(inter *InterfaceType, i Iface) (ret Iface) {
+	runtime·ifaceI2I(inter, i, &ret);
+}
+
+func assertI2I2(inter *InterfaceType, i Iface) (ret Iface, ok bool) {
+	Itab *tab;
+
+	tab = i.tab;
+	if(tab != nil && (tab->inter == inter || (tab = itab(inter, tab->type, 1)) != nil)) {
+		ret.data = i.data;
+		ret.tab = tab;
+		ok = 1;
+	} else {
+		ret.data = 0;
+		ret.tab = 0;
+		ok = 0;
+	}
+}
+
+void
+runtime·ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
+{
+	Type *t;
+	Eface err;
+
+	t = e.type;
+	if(t == nil) {
+		// explicit conversions require non-nil interface value.
+		runtime·newTypeAssertionError(
+			nil, nil, inter->string,
+			nil, &err);
+		runtime·panic(err);
+	}
+	ret->data = e.data;
+	ret->tab = itab(inter, t, 0);
+}
+
+bool
+runtime·ifaceE2I2(InterfaceType *inter, Eface e, Iface *ret)
+{
+	ret->tab = itab(inter, e.type, 1);
+	if(ret->tab == nil)
+		return false;
+	ret->data = e.data;
+	return true;
+}
+
+func reflect·ifaceE2I(inter *InterfaceType, e Eface, dst *Iface) {
+	runtime·ifaceE2I(inter, e, dst);
+}
+
+func assertE2I(inter *InterfaceType, e Eface) (ret Iface) {
+	runtime·ifaceE2I(inter, e, &ret);
+}
+
+func assertE2I2(inter *InterfaceType, e Eface) (ret Iface, ok bool) {
+	if(e.type == nil) {
+		ok = 0;
+		ret.data = nil;
+		ret.tab = nil;
+	} else if((ret.tab = itab(inter, e.type, 1)) == nil) {
+		ok = 0;
+		ret.data = nil;
+	} else {
+		ok = 1;
+		ret.data = e.data;
+	}
+}
+
+func assertE2E(inter *InterfaceType, e Eface) (ret Eface) {
+	Type *t;
+	Eface err;
+
+	t = e.type;
+	if(t == nil) {
+		// explicit conversions require non-nil interface value.
+		runtime·newTypeAssertionError(
+			nil, nil, inter->string,
+			nil, &err);
+		runtime·panic(err);
+	}
+	ret = e;
+}
+
+func assertE2E2(inter *InterfaceType, e Eface) (ret Eface, ok bool) {
+	USED(inter);
+	ret = e;
+	ok = e.type != nil;
+}
+
+static uintptr
+ifacehash1(void *data, Type *t, uintptr h)
+{
+	Alg *alg;
+	uintptr size;
+	Eface err;
+
+	if(t == nil)
+		return 0;
+
+	alg = t->alg;
+	size = t->size;
+	if(alg->hash == runtime·nohash) {
+		// calling nohash will panic too,
+		// but we can print a better error.
+		runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"hash of unhashable type "), *t->string), &err);
+		runtime·panic(err);
+	}
+	if(size <= sizeof(data))
+		alg->hash(&h, size, &data);
+	else
+		alg->hash(&h, size, data);
+	return h;
+}
+
+uintptr
+runtime·ifacehash(Iface a, uintptr h)
+{
+	if(a.tab == nil)
+		return h;
+	return ifacehash1(a.data, a.tab->type, h);
+}
+
+uintptr
+runtime·efacehash(Eface a, uintptr h)
+{
+	return ifacehash1(a.data, a.type, h);
+}
+
+static bool
+ifaceeq1(void *data1, void *data2, Type *t)
+{
+	uintptr size;
+	Alg *alg;
+	Eface err;
+	bool eq;
+
+	alg = t->alg;
+	size = t->size;
+
+	if(alg->equal == runtime·noequal) {
+		// calling noequal will panic too,
+		// but we can print a better error.
+		runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"comparing uncomparable type "), *t->string), &err);
+		runtime·panic(err);
+	}
+
+	eq = 0;
+	if(size <= sizeof(data1))
+		alg->equal(&eq, size, &data1, &data2);
+	else
+		alg->equal(&eq, size, data1, data2);
+	return eq;
+}
+
+bool
+runtime·ifaceeq_c(Iface i1, Iface i2)
+{
+	if(i1.tab != i2.tab)
+		return false;
+	if(i1.tab == nil)
+		return true;
+	return ifaceeq1(i1.data, i2.data, i1.tab->type);
+}
+
+bool
+runtime·efaceeq_c(Eface e1, Eface e2)
+{
+	if(e1.type != e2.type)
+		return false;
+	if(e1.type == nil)
+		return true;
+	return ifaceeq1(e1.data, e2.data, e1.type);
+}
+
+func ifaceeq(i1 Iface, i2 Iface) (ret bool) {
+	ret = runtime·ifaceeq_c(i1, i2);
+}
+
+func efaceeq(e1 Eface, e2 Eface) (ret bool) {
+	ret = runtime·efaceeq_c(e1, e2);
+}
+
+func ifacethash(i1 Iface) (ret uint32) {
+	Itab *tab;
+
+	ret = 0;
+	tab = i1.tab;
+	if(tab != nil)
+		ret = tab->type->hash;
+}
+
+func efacethash(e1 Eface) (ret uint32) {
+	Type *t;
+
+	ret = 0;
+	t = e1.type;
+	if(t != nil)
+		ret = t->hash;
+}
+
+func reflect·unsafe_Typeof(e Eface) (ret Eface) {
+	if(e.type == nil) {
+		ret.type = nil;
+		ret.data = nil;
+	} else {
+		ret = *(Eface*)(e.type);
+	}
+}
+
+func reflect·unsafe_New(t *Type) (ret *byte) {
+	ret = runtime·cnew(t);
+}
+
+func reflect·unsafe_NewArray(t *Type, n int) (ret *byte) {
+	ret = runtime·cnewarray(t, n);
+}
+
+func reflect·typelinks() (ret Slice) {
+	extern Type *typelink[], *etypelink[];
+	static int32 first = 1;
+	ret.array = (byte*)typelink;
+	ret.len = etypelink - typelink;
+	ret.cap = ret.len;
+}
diff --git a/src/pkg/runtime/lfstack.c b/src/pkg/runtime/lfstack.c
deleted file mode 100644
index 140384d..0000000
--- a/src/pkg/runtime/lfstack.c
+++ /dev/null
@@ -1,65 +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.
-
-// Lock-free stack.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-
-#ifdef _64BIT
-// Amd64 uses 48-bit virtual addresses, 47-th bit is used as kernel/user flag.
-// So we use 17msb of pointers as ABA counter.
-# define PTR_BITS 47
-#else
-# define PTR_BITS 32
-#endif
-#define PTR_MASK ((1ull<<PTR_BITS)-1)
-#define CNT_MASK (0ull-1)
-
-void
-runtime·lfstackpush(uint64 *head, LFNode *node)
-{
-	uint64 old, new;
-
-	if((uintptr)node != ((uintptr)node&PTR_MASK)) {
-		runtime·printf("p=%p\n", node);
-		runtime·throw("runtime·lfstackpush: invalid pointer");
-	}
-
-	node->pushcnt++;
-	new = (uint64)(uintptr)node|(((uint64)node->pushcnt&CNT_MASK)<<PTR_BITS);
-	for(;;) {
-		old = runtime·atomicload64(head);
-		node->next = (LFNode*)(uintptr)(old&PTR_MASK);
-		if(runtime·cas64(head, old, new))
-			break;
-	}
-}
-
-LFNode*
-runtime·lfstackpop(uint64 *head)
-{
-	LFNode *node, *node2;
-	uint64 old, new;
-
-	for(;;) {
-		old = runtime·atomicload64(head);
-		if(old == 0)
-			return nil;
-		node = (LFNode*)(uintptr)(old&PTR_MASK);
-		node2 = runtime·atomicloadp(&node->next);
-		new = 0;
-		if(node2 != nil)
-			new = (uint64)(uintptr)node2|(((uint64)node2->pushcnt&CNT_MASK)<<PTR_BITS);
-		if(runtime·cas64(head, old, new))
-			return node;
-	}
-}
-
-void
-runtime·lfstackpop2(uint64 *head, LFNode *node)
-{
-	node = runtime·lfstackpop(head);
-	FLUSH(&node);
-}
diff --git a/src/pkg/runtime/lfstack.goc b/src/pkg/runtime/lfstack.goc
new file mode 100644
index 0000000..f7b8eff
--- /dev/null
+++ b/src/pkg/runtime/lfstack.goc
@@ -0,0 +1,81 @@
+// 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.
+
+// Lock-free stack.
+
+package runtime
+#include "runtime.h"
+#include "arch_GOARCH.h"
+
+#ifdef _64BIT
+// Amd64 uses 48-bit virtual addresses, 47-th bit is used as kernel/user flag.
+// So we use 17msb of pointers as ABA counter.
+# define PTR_BITS 47
+#else
+# define PTR_BITS 32
+#endif
+#define PTR_MASK ((1ull<<PTR_BITS)-1)
+#define CNT_MASK (0ull-1)
+
+#ifdef _64BIT
+#ifdef GOOS_solaris
+// SPARC64 and Solaris on AMD64 uses all 64 bits of virtual addresses.
+// Use low-order three bits as ABA counter.
+// http://docs.oracle.com/cd/E19120-01/open.solaris/816-5138/6mba6ua5p/index.html
+#undef PTR_BITS
+#undef CNT_MASK
+#undef PTR_MASK
+#define PTR_BITS 0
+#define CNT_MASK 7
+#define PTR_MASK ((0ull-1)<<3)
+#endif
+#endif
+
+void
+runtime·lfstackpush(uint64 *head, LFNode *node)
+{
+	uint64 old, new;
+
+	if((uintptr)node != ((uintptr)node&PTR_MASK)) {
+		runtime·printf("p=%p\n", node);
+		runtime·throw("runtime·lfstackpush: invalid pointer");
+	}
+
+	node->pushcnt++;
+	new = (uint64)(uintptr)node|(((uint64)node->pushcnt&CNT_MASK)<<PTR_BITS);
+	for(;;) {
+		old = runtime·atomicload64(head);
+		node->next = (LFNode*)(uintptr)(old&PTR_MASK);
+		if(runtime·cas64(head, old, new))
+			break;
+	}
+}
+
+LFNode*
+runtime·lfstackpop(uint64 *head)
+{
+	LFNode *node, *node2;
+	uint64 old, new;
+
+	for(;;) {
+		old = runtime·atomicload64(head);
+		if(old == 0)
+			return nil;
+		node = (LFNode*)(uintptr)(old&PTR_MASK);
+		node2 = runtime·atomicloadp(&node->next);
+		new = 0;
+		if(node2 != nil)
+			new = (uint64)(uintptr)node2|(((uint64)node2->pushcnt&CNT_MASK)<<PTR_BITS);
+		if(runtime·cas64(head, old, new))
+			return node;
+	}
+}
+
+func lfstackpush_go(head *uint64, node *LFNode) {
+	runtime·lfstackpush(head, node);
+}
+
+func lfstackpop_go(head *uint64) (node *LFNode) {
+	node = runtime·lfstackpop(head);
+}
diff --git a/src/pkg/runtime/lfstack_test.go b/src/pkg/runtime/lfstack_test.go
index 505aae6..e518777 100644
--- a/src/pkg/runtime/lfstack_test.go
+++ b/src/pkg/runtime/lfstack_test.go
@@ -71,6 +71,8 @@ func TestLFStack(t *testing.T) {
 	}
 }
 
+var stress []*MyNode
+
 func TestLFStackStress(t *testing.T) {
 	const K = 100
 	P := 4 * GOMAXPROCS(-1)
@@ -80,14 +82,15 @@ func TestLFStackStress(t *testing.T) {
 	}
 	// Create 2 stacks.
 	stacks := [2]*uint64{new(uint64), new(uint64)}
-	// Need to keep additional referenfces to nodes, the stack is not all that type-safe.
-	var nodes []*MyNode
+	// Need to keep additional references to nodes,
+	// the lock-free stack is not type-safe.
+	stress = nil
 	// Push K elements randomly onto the stacks.
 	sum := 0
 	for i := 0; i < K; i++ {
 		sum += i
 		node := &MyNode{data: i}
-		nodes = append(nodes, node)
+		stress = append(stress, node)
 		LFStackPush(stacks[i%2], fromMyNode(node))
 	}
 	c := make(chan bool, P)
@@ -127,4 +130,7 @@ func TestLFStackStress(t *testing.T) {
 	if sum2 != sum {
 		t.Fatalf("Wrong sum %d/%d", sum2, sum)
 	}
+
+	// Let nodes be collected now.
+	stress = nil
 }
diff --git a/src/pkg/runtime/lock_futex.c b/src/pkg/runtime/lock_futex.c
index e6e9be9..c16ac90 100644
--- a/src/pkg/runtime/lock_futex.c
+++ b/src/pkg/runtime/lock_futex.c
@@ -130,8 +130,11 @@ runtime·notesleep(Note *n)
 {
 	if(g != m->g0)
 		runtime·throw("notesleep not on g0");
-	while(runtime·atomicload((uint32*)&n->key) == 0)
+	while(runtime·atomicload((uint32*)&n->key) == 0) {
+		m->blocked = true;
 		runtime·futexsleep((uint32*)&n->key, 0, -1);
+		m->blocked = false;
+	}
 }
 
 #pragma textflag NOSPLIT
@@ -143,8 +146,11 @@ notetsleep(Note *n, int64 ns, int64 deadline, int64 now)
 	// does not count against our nosplit stack sequence.
 
 	if(ns < 0) {
-		while(runtime·atomicload((uint32*)&n->key) == 0)
+		while(runtime·atomicload((uint32*)&n->key) == 0) {
+			m->blocked = true;
 			runtime·futexsleep((uint32*)&n->key, 0, -1);
+			m->blocked = false;
+		}
 		return true;
 	}
 
@@ -153,7 +159,9 @@ notetsleep(Note *n, int64 ns, int64 deadline, int64 now)
 
 	deadline = runtime·nanotime() + ns;
 	for(;;) {
+		m->blocked = true;
 		runtime·futexsleep((uint32*)&n->key, 0, ns);
+		m->blocked = false;
 		if(runtime·atomicload((uint32*)&n->key) != 0)
 			break;
 		now = runtime·nanotime();
diff --git a/src/pkg/runtime/lock_sema.c b/src/pkg/runtime/lock_sema.c
index 3d58cc8..ff8fdfd 100644
--- a/src/pkg/runtime/lock_sema.c
+++ b/src/pkg/runtime/lock_sema.c
@@ -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 netbsd openbsd plan9 windows
+// +build darwin nacl netbsd openbsd plan9 solaris windows
 
 #include "runtime.h"
 #include "stack.h"
@@ -161,7 +161,9 @@ runtime·notesleep(Note *n)
 		return;
 	}
 	// Queued.  Sleep.
+	m->blocked = true;
 	runtime·semasleep(-1);
+	m->blocked = false;
 }
 
 #pragma textflag NOSPLIT
@@ -181,18 +183,23 @@ notetsleep(Note *n, int64 ns, int64 deadline, M *mp)
 
 	if(ns < 0) {
 		// Queued.  Sleep.
+		m->blocked = true;
 		runtime·semasleep(-1);
+		m->blocked = false;
 		return true;
 	}
 
 	deadline = runtime·nanotime() + ns;
 	for(;;) {
 		// Registered.  Sleep.
+		m->blocked = true;
 		if(runtime·semasleep(ns) >= 0) {
+			m->blocked = false;
 			// Acquired semaphore, semawakeup unregistered us.
 			// Done.
 			return true;
 		}
+		m->blocked = false;
 
 		// Interrupted or timed out.  Still registered.  Semaphore not acquired.
 		ns = deadline - runtime·nanotime();
@@ -214,8 +221,10 @@ notetsleep(Note *n, int64 ns, int64 deadline, M *mp)
 		} else if(mp == (M*)LOCKED) {
 			// Wakeup happened so semaphore is available.
 			// Grab it to avoid getting out of sync.
+			m->blocked = true;
 			if(runtime·semasleep(-1) < 0)
 				runtime·throw("runtime: unable to acquire - semaphore out of sync");
+			m->blocked = false;
 			return true;
 		} else
 			runtime·throw("runtime: unexpected waitm - semaphore out of sync");
diff --git a/src/pkg/runtime/malloc.goc b/src/pkg/runtime/malloc.goc
index c3ede4a..7b7e350 100644
--- a/src/pkg/runtime/malloc.goc
+++ b/src/pkg/runtime/malloc.goc
@@ -19,6 +19,8 @@ package runtime
 // Mark mheap as 'no pointers', it does not contain interesting pointers but occupies ~45K.
 #pragma dataflag NOPTR
 MHeap runtime·mheap;
+#pragma dataflag NOPTR
+MStats mstats;
 
 int32	runtime·checking;
 
@@ -26,6 +28,10 @@ extern MStats mstats;	// defined in zruntime_def_$GOOS_$GOARCH.go
 
 extern volatile intgo runtime·MemProfileRate;
 
+static MSpan* largealloc(uint32, uintptr*);
+static void profilealloc(void *v, uintptr size);
+static void settype(MSpan *s, void *v, uintptr typ);
+
 // Allocate an object of at least size bytes.
 // Small objects are allocated from the per-thread cache's free lists.
 // Large objects (> 32 kB) are allocated straight from the heap.
@@ -34,12 +40,12 @@ void*
 runtime·mallocgc(uintptr size, uintptr typ, uint32 flag)
 {
 	int32 sizeclass;
+	uintptr tinysize, size1;
 	intgo rate;
 	MCache *c;
-	MCacheList *l;
-	uintptr npages;
 	MSpan *s;
-	MLink *v;
+	MLink *v, *next;
+	byte *tiny;
 
 	if(size == 0) {
 		// All 0-length allocations use this pointer.
@@ -49,8 +55,8 @@ runtime·mallocgc(uintptr size, uintptr typ, uint32 flag)
 	}
 	if(m->mallocing)
 		runtime·throw("malloc/free - deadlock");
-	// Disable preemption during settype_flush.
-	// We can not use m->mallocing for this, because settype_flush calls mallocgc.
+	// Disable preemption during settype.
+	// We can not use m->mallocing for this, because settype calls mallocgc.
 	m->locks++;
 	m->mallocing = 1;
 
@@ -58,7 +64,82 @@ runtime·mallocgc(uintptr size, uintptr typ, uint32 flag)
 		size += sizeof(uintptr);
 
 	c = m->mcache;
-	if(size <= MaxSmallSize) {
+	if(!runtime·debug.efence && size <= MaxSmallSize) {
+		if((flag&(FlagNoScan|FlagNoGC)) == FlagNoScan && size < TinySize) {
+			// Tiny allocator.
+			//
+			// Tiny allocator combines several tiny allocation requests
+			// into a single memory block. The resulting memory block
+			// is freed when all subobjects are unreachable. The subobjects
+			// must be FlagNoScan (don't have pointers), this ensures that
+			// the amount of potentially wasted memory is bounded.
+			//
+			// Size of the memory block used for combining (TinySize) is tunable.
+			// Current setting is 16 bytes, which relates to 2x worst case memory
+			// wastage (when all but one subobjects are unreachable).
+			// 8 bytes would result in no wastage at all, but provides less
+			// opportunities for combining.
+			// 32 bytes provides more opportunities for combining,
+			// but can lead to 4x worst case wastage.
+			// The best case winning is 8x regardless of block size.
+			//
+			// Objects obtained from tiny allocator must not be freed explicitly.
+			// So when an object will be freed explicitly, we ensure that
+			// its size >= TinySize.
+			//
+			// SetFinalizer has a special case for objects potentially coming
+			// from tiny allocator, it such case it allows to set finalizers
+			// for an inner byte of a memory block.
+			//
+			// The main targets of tiny allocator are small strings and
+			// standalone escaping variables. On a json benchmark
+			// the allocator reduces number of allocations by ~12% and
+			// reduces heap size by ~20%.
+
+			tinysize = c->tinysize;
+			if(size <= tinysize) {
+				tiny = c->tiny;
+				// Align tiny pointer for required (conservative) alignment.
+				if((size&7) == 0)
+					tiny = (byte*)ROUND((uintptr)tiny, 8);
+				else if((size&3) == 0)
+					tiny = (byte*)ROUND((uintptr)tiny, 4);
+				else if((size&1) == 0)
+					tiny = (byte*)ROUND((uintptr)tiny, 2);
+				size1 = size + (tiny - c->tiny);
+				if(size1 <= tinysize) {
+					// The object fits into existing tiny block.
+					v = (MLink*)tiny;
+					c->tiny += size1;
+					c->tinysize -= size1;
+					m->mallocing = 0;
+					m->locks--;
+					if(m->locks == 0 && g->preempt)  // restore the preemption request in case we've cleared it in newstack
+						g->stackguard0 = StackPreempt;
+					return v;
+				}
+			}
+			// Allocate a new TinySize block.
+			s = c->alloc[TinySizeClass];
+			if(s->freelist == nil)
+				s = runtime·MCache_Refill(c, TinySizeClass);
+			v = s->freelist;
+			next = v->next;
+			s->freelist = next;
+			s->ref++;
+			if(next != nil)  // prefetching nil leads to a DTLB miss
+				PREFETCH(next);
+			((uint64*)v)[0] = 0;
+			((uint64*)v)[1] = 0;
+			// See if we need to replace the existing tiny block with the new one
+			// based on amount of remaining free space.
+			if(TinySize-size > tinysize) {
+				c->tiny = (byte*)v + size;
+				c->tinysize = TinySize - size;
+			}
+			size = TinySize;
+			goto done;
+		}
 		// Allocate from mcache free lists.
 		// Inlined version of SizeToClass().
 		if(size <= 1024-8)
@@ -66,87 +147,117 @@ runtime·mallocgc(uintptr size, uintptr typ, uint32 flag)
 		else
 			sizeclass = runtime·size_to_class128[(size-1024+127) >> 7];
 		size = runtime·class_to_size[sizeclass];
-		l = &c->list[sizeclass];
-		if(l->list == nil)
-			runtime·MCache_Refill(c, sizeclass);
-		v = l->list;
-		l->list = v->next;
-		l->nlist--;
+		s = c->alloc[sizeclass];
+		if(s->freelist == nil)
+			s = runtime·MCache_Refill(c, sizeclass);
+		v = s->freelist;
+		next = v->next;
+		s->freelist = next;
+		s->ref++;
+		if(next != nil)  // prefetching nil leads to a DTLB miss
+			PREFETCH(next);
 		if(!(flag & FlagNoZero)) {
 			v->next = nil;
 			// block is zeroed iff second word is zero ...
-			if(size > sizeof(uintptr) && ((uintptr*)v)[1] != 0)
+			if(size > 2*sizeof(uintptr) && ((uintptr*)v)[1] != 0)
 				runtime·memclr((byte*)v, size);
 		}
+	done:
 		c->local_cachealloc += size;
 	} else {
-		// TODO(rsc): Report tracebacks for very large allocations.
-
 		// Allocate directly from heap.
-		npages = size >> PageShift;
-		if((size & PageMask) != 0)
-			npages++;
-		s = runtime·MHeap_Alloc(&runtime·mheap, npages, 0, 1, !(flag & FlagNoZero));
-		if(s == nil)
-			runtime·throw("out of memory");
-		s->limit = (byte*)(s->start<<PageShift) + size;
-		size = npages<<PageShift;
+		s = largealloc(flag, &size);
 		v = (void*)(s->start << PageShift);
-
-		// setup for mark sweep
-		runtime·markspan(v, 0, 0, true);
 	}
 
-	if(!(flag & FlagNoGC))
-		runtime·markallocated(v, size, (flag&FlagNoScan) != 0);
+	if(flag & FlagNoGC)
+		runtime·marknogc(v);
+	else if(!(flag & FlagNoScan))
+		runtime·markscan(v);
 
 	if(DebugTypeAtBlockEnd)
 		*(uintptr*)((uintptr)v+size-sizeof(uintptr)) = typ;
 
+	m->mallocing = 0;
 	// TODO: save type even if FlagNoScan?  Potentially expensive but might help
 	// heap profiling/tracing.
-	if(UseSpanType && !(flag & FlagNoScan) && typ != 0) {
-		uintptr *buf, i;
-
-		buf = m->settype_buf;
-		i = m->settype_bufsize;
-		buf[i++] = (uintptr)v;
-		buf[i++] = typ;
-		m->settype_bufsize = i;
+	if(UseSpanType && !(flag & FlagNoScan) && typ != 0)
+		settype(s, v, typ);
+
+	if(raceenabled)
+		runtime·racemalloc(v, size);
+
+	if(runtime·debug.allocfreetrace)
+		runtime·tracealloc(v, size, typ);
+
+	if(!(flag & FlagNoProfiling) && (rate = runtime·MemProfileRate) > 0) {
+		if(size < rate && size < c->next_sample)
+			c->next_sample -= size;
+		else
+			profilealloc(v, size);
 	}
 
-	m->mallocing = 0;
-	if(UseSpanType && !(flag & FlagNoScan) && typ != 0 && m->settype_bufsize == nelem(m->settype_buf))
-		runtime·settype_flush(m);
 	m->locks--;
 	if(m->locks == 0 && g->preempt)  // restore the preemption request in case we've cleared it in newstack
 		g->stackguard0 = StackPreempt;
 
-	if(!(flag & FlagNoProfiling) && (rate = runtime·MemProfileRate) > 0) {
-		if(size >= rate)
-			goto profile;
-		if(m->mcache->next_sample > size)
-			m->mcache->next_sample -= size;
-		else {
-			// pick next profile time
-			// If you change this, also change allocmcache.
-			if(rate > 0x3fffffff)	// make 2*rate not overflow
-				rate = 0x3fffffff;
-			m->mcache->next_sample = runtime·fastrand1() % (2*rate);
-		profile:
-			runtime·setblockspecial(v, true);
-			runtime·MProf_Malloc(v, size);
-		}
-	}
-
 	if(!(flag & FlagNoInvokeGC) && mstats.heap_alloc >= mstats.next_gc)
 		runtime·gc(0);
 
-	if(raceenabled)
-		runtime·racemalloc(v, size);
 	return v;
 }
 
+static MSpan*
+largealloc(uint32 flag, uintptr *sizep)
+{
+	uintptr npages, size;
+	MSpan *s;
+	void *v;
+
+	// Allocate directly from heap.
+	size = *sizep;
+	if(size + PageSize < size)
+		runtime·throw("out of memory");
+	npages = size >> PageShift;
+	if((size & PageMask) != 0)
+		npages++;
+	s = runtime·MHeap_Alloc(&runtime·mheap, npages, 0, 1, !(flag & FlagNoZero));
+	if(s == nil)
+		runtime·throw("out of memory");
+	s->limit = (byte*)(s->start<<PageShift) + size;
+	*sizep = npages<<PageShift;
+	v = (void*)(s->start << PageShift);
+	// setup for mark sweep
+	runtime·markspan(v, 0, 0, true);
+	return s;
+}
+
+static void
+profilealloc(void *v, uintptr size)
+{
+	uintptr rate;
+	int32 next;
+	MCache *c;
+
+	c = m->mcache;
+	rate = runtime·MemProfileRate;
+	if(size < rate) {
+		// pick next profile time
+		// If you change this, also change allocmcache.
+		if(rate > 0x3fffffff)	// make 2*rate not overflow
+			rate = 0x3fffffff;
+		next = runtime·fastrand1() % (2*rate);
+		// Subtract the "remainder" of the current allocation.
+		// Otherwise objects that are close in size to sampling rate
+		// will be under-sampled, because we consistently discard this remainder.
+		next -= (size - c->next_sample);
+		if(next < 0)
+			next = 0;
+		c->next_sample = next;
+	}
+	runtime·MProf_Malloc(v, size);
+}
+
 void*
 runtime·malloc(uintptr size)
 {
@@ -160,7 +271,6 @@ runtime·free(void *v)
 	int32 sizeclass;
 	MSpan *s;
 	MCache *c;
-	uint32 prof;
 	uintptr size;
 
 	if(v == nil)
@@ -177,39 +287,73 @@ runtime·free(void *v)
 		runtime·printf("free %p: not an allocated block\n", v);
 		runtime·throw("free runtime·mlookup");
 	}
-	prof = runtime·blockspecial(v);
+	size = s->elemsize;
+	sizeclass = s->sizeclass;
+	// Objects that are smaller than TinySize can be allocated using tiny alloc,
+	// if then such object is combined with an object with finalizer, we will crash.
+	if(size < TinySize)
+		runtime·throw("freeing too small block");
 
-	if(raceenabled)
-		runtime·racefree(v);
+	if(runtime·debug.allocfreetrace)
+		runtime·tracefree(v, size);
+
+	// Ensure that the span is swept.
+	// If we free into an unswept span, we will corrupt GC bitmaps.
+	runtime·MSpan_EnsureSwept(s);
+
+	if(s->specials != nil)
+		runtime·freeallspecials(s, v, size);
 
-	// Find size class for v.
-	sizeclass = s->sizeclass;
 	c = m->mcache;
 	if(sizeclass == 0) {
 		// Large object.
-		size = s->npages<<PageShift;
-		*(uintptr*)(s->start<<PageShift) = (uintptr)0xfeedfeedfeedfeedll;	// mark as "needs to be zeroed"
+		s->needzero = 1;
 		// Must mark v freed before calling unmarkspan and MHeap_Free:
 		// they might coalesce v into other spans and change the bitmap further.
-		runtime·markfreed(v, size);
+		runtime·markfreed(v);
 		runtime·unmarkspan(v, 1<<PageShift);
-		runtime·MHeap_Free(&runtime·mheap, s, 1);
+		// NOTE(rsc,dvyukov): The original implementation of efence
+		// in CL 22060046 used SysFree instead of SysFault, so that
+		// the operating system would eventually give the memory
+		// back to us again, so that an efence program could run
+		// longer without running out of memory. Unfortunately,
+		// calling SysFree here without any kind of adjustment of the
+		// heap data structures means that when the memory does
+		// come back to us, we have the wrong metadata for it, either in
+		// the MSpan structures or in the garbage collection bitmap.
+		// Using SysFault here means that the program will run out of
+		// memory fairly quickly in efence mode, but at least it won't
+		// have mysterious crashes due to confused memory reuse.
+		// It should be possible to switch back to SysFree if we also 
+		// implement and then call some kind of MHeap_DeleteSpan.
+		if(runtime·debug.efence)
+			runtime·SysFault((void*)(s->start<<PageShift), size);
+		else
+			runtime·MHeap_Free(&runtime·mheap, s, 1);
 		c->local_nlargefree++;
 		c->local_largefree += size;
 	} else {
 		// Small object.
-		size = runtime·class_to_size[sizeclass];
-		if(size > sizeof(uintptr))
+		if(size > 2*sizeof(uintptr))
 			((uintptr*)v)[1] = (uintptr)0xfeedfeedfeedfeedll;	// mark as "needs to be zeroed"
+		else if(size > sizeof(uintptr))
+			((uintptr*)v)[1] = 0;
 		// Must mark v freed before calling MCache_Free:
 		// it might coalesce v and other blocks into a bigger span
 		// and change the bitmap further.
-		runtime·markfreed(v, size);
 		c->local_nsmallfree[sizeclass]++;
-		runtime·MCache_Free(c, v, sizeclass, size);
+		c->local_cachealloc -= size;
+		if(c->alloc[sizeclass] == s) {
+			// We own the span, so we can just add v to the freelist
+			runtime·markfreed(v);
+			((MLink*)v)->next = s->freelist;
+			s->freelist = v;
+			s->ref--;
+		} else {
+			// Someone else owns this span.  Add to free queue.
+			runtime·MCache_Free(c, v, sizeclass, size);
+		}
 	}
-	if(prof)
-		runtime·MProf_Free(v, size);
 	m->mallocing = 0;
 }
 
@@ -261,37 +405,6 @@ runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp)
 	return 1;
 }
 
-MCache*
-runtime·allocmcache(void)
-{
-	intgo rate;
-	MCache *c;
-
-	runtime·lock(&runtime·mheap);
-	c = runtime·FixAlloc_Alloc(&runtime·mheap.cachealloc);
-	runtime·unlock(&runtime·mheap);
-	runtime·memclr((byte*)c, sizeof(*c));
-
-	// Set first allocation sample size.
-	rate = runtime·MemProfileRate;
-	if(rate > 0x3fffffff)	// make 2*rate not overflow
-		rate = 0x3fffffff;
-	if(rate != 0)
-		c->next_sample = runtime·fastrand1() % (2*rate);
-
-	return c;
-}
-
-void
-runtime·freemcache(MCache *c)
-{
-	runtime·MCache_ReleaseAll(c);
-	runtime·lock(&runtime·mheap);
-	runtime·purgecachedstats(c);
-	runtime·FixAlloc_Free(&runtime·mheap.cachealloc, c);
-	runtime·unlock(&runtime·mheap);
-}
-
 void
 runtime·purgecachedstats(MCache *c)
 {
@@ -314,33 +427,42 @@ runtime·purgecachedstats(MCache *c)
 	}
 }
 
-uintptr runtime·sizeof_C_MStats = sizeof(MStats);
+// Size of the trailing by_size array differs between Go and C,
+// NumSizeClasses was changed, but we can not change Go struct because of backward compatibility.
+// sizeof_C_MStats is what C thinks about size of Go struct.
+uintptr runtime·sizeof_C_MStats = sizeof(MStats) - (NumSizeClasses - 61) * sizeof(mstats.by_size[0]);
 
 #define MaxArena32 (2U<<30)
 
 void
 runtime·mallocinit(void)
 {
-	byte *p;
-	uintptr arena_size, bitmap_size, spans_size;
+	byte *p, *p1;
+	uintptr arena_size, bitmap_size, spans_size, p_size;
 	extern byte end[];
-	byte *want;
 	uintptr limit;
 	uint64 i;
+	bool reserved;
 
 	p = nil;
+	p_size = 0;
 	arena_size = 0;
 	bitmap_size = 0;
 	spans_size = 0;
+	reserved = false;
 
 	// for 64-bit build
 	USED(p);
+	USED(p_size);
 	USED(arena_size);
 	USED(bitmap_size);
 	USED(spans_size);
 
 	runtime·InitSizes();
 
+	if(runtime·class_to_size[TinySizeClass] != TinySize)
+		runtime·throw("bad TinySizeClass");
+
 	// limit = runtime·memlimit();
 	// See https://code.google.com/p/go/issues/detail?id=5049
 	// TODO(rsc): Fix after 1.1.
@@ -380,7 +502,8 @@ runtime·mallocinit(void)
 		spans_size = ROUND(spans_size, PageSize);
 		for(i = 0; i <= 0x7f; i++) {
 			p = (void*)(i<<40 | 0x00c0ULL<<32);
-			p = runtime·SysReserve(p, bitmap_size + spans_size + arena_size);
+			p_size = bitmap_size + spans_size + arena_size + PageSize;
+			p = runtime·SysReserve(p, p_size, &reserved);
 			if(p != nil)
 				break;
 		}
@@ -422,91 +545,119 @@ runtime·mallocinit(void)
 		// So adjust it upward a little bit ourselves: 1/4 MB to get
 		// away from the running binary image and then round up
 		// to a MB boundary.
-		want = (byte*)ROUND((uintptr)end + (1<<18), 1<<20);
-		p = runtime·SysReserve(want, bitmap_size + spans_size + arena_size);
+		p = (byte*)ROUND((uintptr)end + (1<<18), 1<<20);
+		p_size = bitmap_size + spans_size + arena_size + PageSize;
+		p = runtime·SysReserve(p, p_size, &reserved);
 		if(p == nil)
 			runtime·throw("runtime: cannot reserve arena virtual address space");
-		if((uintptr)p & (((uintptr)1<<PageShift)-1))
-			runtime·printf("runtime: SysReserve returned unaligned address %p; asked for %p", p,
-				bitmap_size+spans_size+arena_size);
 	}
-	if((uintptr)p & (((uintptr)1<<PageShift)-1))
-		runtime·throw("runtime: SysReserve returned unaligned address");
 
-	runtime·mheap.spans = (MSpan**)p;
-	runtime·mheap.bitmap = p + spans_size;
-	runtime·mheap.arena_start = p + spans_size + bitmap_size;
+	// PageSize can be larger than OS definition of page size,
+	// so SysReserve can give us a PageSize-unaligned pointer.
+	// To overcome this we ask for PageSize more and round up the pointer.
+	p1 = (byte*)ROUND((uintptr)p, PageSize);
+
+	runtime·mheap.spans = (MSpan**)p1;
+	runtime·mheap.bitmap = p1 + spans_size;
+	runtime·mheap.arena_start = p1 + spans_size + bitmap_size;
 	runtime·mheap.arena_used = runtime·mheap.arena_start;
-	runtime·mheap.arena_end = runtime·mheap.arena_start + arena_size;
+	runtime·mheap.arena_end = p + p_size;
+	runtime·mheap.arena_reserved = reserved;
+
+	if(((uintptr)runtime·mheap.arena_start & (PageSize-1)) != 0)
+		runtime·throw("misrounded allocation in mallocinit");
 
 	// Initialize the rest of the allocator.	
 	runtime·MHeap_Init(&runtime·mheap);
 	m->mcache = runtime·allocmcache();
 
 	// See if it works.
-	runtime·free(runtime·malloc(1));
+	runtime·free(runtime·malloc(TinySize));
 }
 
 void*
 runtime·MHeap_SysAlloc(MHeap *h, uintptr n)
 {
-	byte *p;
+	byte *p, *p_end;
+	uintptr p_size;
+	bool reserved;
 
 	if(n > h->arena_end - h->arena_used) {
 		// We are in 32-bit mode, maybe we didn't use all possible address space yet.
 		// Reserve some more space.
 		byte *new_end;
-		uintptr needed;
 
-		needed = (uintptr)h->arena_used + n - (uintptr)h->arena_end;
-		needed = ROUND(needed, 256<<20);
-		new_end = h->arena_end + needed;
+		p_size = ROUND(n + PageSize, 256<<20);
+		new_end = h->arena_end + p_size;
 		if(new_end <= h->arena_start + MaxArena32) {
-			p = runtime·SysReserve(h->arena_end, new_end - h->arena_end);
-			if(p == h->arena_end)
+			// TODO: It would be bad if part of the arena
+			// is reserved and part is not.
+			p = runtime·SysReserve(h->arena_end, p_size, &reserved);
+			if(p == h->arena_end) {
 				h->arena_end = new_end;
+				h->arena_reserved = reserved;
+			}
+			else if(p+p_size <= h->arena_start + MaxArena32) {
+				// Keep everything page-aligned.
+				// Our pages are bigger than hardware pages.
+				h->arena_end = p+p_size;
+				h->arena_used = p + (-(uintptr)p&(PageSize-1));
+				h->arena_reserved = reserved;
+			} else {
+				uint64 stat;
+				stat = 0;
+				runtime·SysFree(p, p_size, &stat);
+			}
 		}
 	}
 	if(n <= h->arena_end - h->arena_used) {
 		// Keep taking from our reservation.
 		p = h->arena_used;
-		runtime·SysMap(p, n, &mstats.heap_sys);
+		runtime·SysMap(p, n, h->arena_reserved, &mstats.heap_sys);
 		h->arena_used += n;
 		runtime·MHeap_MapBits(h);
 		runtime·MHeap_MapSpans(h);
 		if(raceenabled)
 			runtime·racemapshadow(p, n);
+		
+		if(((uintptr)p & (PageSize-1)) != 0)
+			runtime·throw("misrounded allocation in MHeap_SysAlloc");
 		return p;
 	}
 	
 	// If using 64-bit, our reservation is all we have.
-	if(sizeof(void*) == 8 && (uintptr)h->bitmap >= 0xffffffffU)
+	if(h->arena_end - h->arena_start >= MaxArena32)
 		return nil;
 
 	// On 32-bit, once the reservation is gone we can
 	// try to get memory at a location chosen by the OS
 	// and hope that it is in the range we allocated bitmap for.
-	p = runtime·SysAlloc(n, &mstats.heap_sys);
+	p_size = ROUND(n, PageSize) + PageSize;
+	p = runtime·SysAlloc(p_size, &mstats.heap_sys);
 	if(p == nil)
 		return nil;
 
-	if(p < h->arena_start || p+n - h->arena_start >= MaxArena32) {
+	if(p < h->arena_start || p+p_size - h->arena_start >= MaxArena32) {
 		runtime·printf("runtime: memory allocated by OS (%p) not in usable range [%p,%p)\n",
 			p, h->arena_start, h->arena_start+MaxArena32);
-		runtime·SysFree(p, n, &mstats.heap_sys);
+		runtime·SysFree(p, p_size, &mstats.heap_sys);
 		return nil;
 	}
-
+	
+	p_end = p + p_size;
+	p += -(uintptr)p & (PageSize-1);
 	if(p+n > h->arena_used) {
 		h->arena_used = p+n;
-		if(h->arena_used > h->arena_end)
-			h->arena_end = h->arena_used;
+		if(p_end > h->arena_end)
+			h->arena_end = p_end;
 		runtime·MHeap_MapBits(h);
 		runtime·MHeap_MapSpans(h);
 		if(raceenabled)
 			runtime·racemapshadow(p, n);
 	}
 	
+	if(((uintptr)p & (PageSize-1)) != 0)
+		runtime·throw("misrounded allocation in MHeap_SysAlloc");
 	return p;
 }
 
@@ -534,7 +685,7 @@ runtime·persistentalloc(uintptr size, uintptr align, uint64 *stat)
 
 	if(align != 0) {
 		if(align&(align-1))
-			runtime·throw("persistentalloc: align is now a power of 2");
+			runtime·throw("persistentalloc: align is not a power of 2");
 		if(align > PageSize)
 			runtime·throw("persistentalloc: align is too large");
 	} else
@@ -562,95 +713,67 @@ runtime·persistentalloc(uintptr size, uintptr align, uint64 *stat)
 	return p;
 }
 
-static Lock settype_lock;
-
-void
-runtime·settype_flush(M *mp)
+static void
+settype(MSpan *s, void *v, uintptr typ)
 {
-	uintptr *buf, *endbuf;
 	uintptr size, ofs, j, t;
 	uintptr ntypes, nbytes2, nbytes3;
 	uintptr *data2;
 	byte *data3;
-	void *v;
-	uintptr typ, p;
-	MSpan *s;
 
-	buf = mp->settype_buf;
-	endbuf = buf + mp->settype_bufsize;
-
-	runtime·lock(&settype_lock);
-	while(buf < endbuf) {
-		v = (void*)*buf;
-		*buf = 0;
-		buf++;
-		typ = *buf;
-		buf++;
-
-		// (Manually inlined copy of runtime·MHeap_Lookup)
-		p = (uintptr)v>>PageShift;
-		if(sizeof(void*) == 8)
-			p -= (uintptr)runtime·mheap.arena_start >> PageShift;
-		s = runtime·mheap.spans[p];
-
-		if(s->sizeclass == 0) {
-			s->types.compression = MTypes_Single;
-			s->types.data = typ;
-			continue;
+	if(s->sizeclass == 0) {
+		s->types.compression = MTypes_Single;
+		s->types.data = typ;
+		return;
+	}
+	size = s->elemsize;
+	ofs = ((uintptr)v - (s->start<<PageShift)) / size;
+
+	switch(s->types.compression) {
+	case MTypes_Empty:
+		ntypes = (s->npages << PageShift) / size;
+		nbytes3 = 8*sizeof(uintptr) + 1*ntypes;
+		data3 = runtime·mallocgc(nbytes3, 0, FlagNoProfiling|FlagNoScan|FlagNoInvokeGC);
+		s->types.compression = MTypes_Bytes;
+		s->types.data = (uintptr)data3;
+		((uintptr*)data3)[1] = typ;
+		data3[8*sizeof(uintptr) + ofs] = 1;
+		break;
+		
+	case MTypes_Words:
+		((uintptr*)s->types.data)[ofs] = typ;
+		break;
+		
+	case MTypes_Bytes:
+		data3 = (byte*)s->types.data;
+		for(j=1; j<8; j++) {
+			if(((uintptr*)data3)[j] == typ) {
+				break;
+			}
+			if(((uintptr*)data3)[j] == 0) {
+				((uintptr*)data3)[j] = typ;
+				break;
+			}
 		}
-
-		size = s->elemsize;
-		ofs = ((uintptr)v - (s->start<<PageShift)) / size;
-
-		switch(s->types.compression) {
-		case MTypes_Empty:
+		if(j < 8) {
+			data3[8*sizeof(uintptr) + ofs] = j;
+		} else {
 			ntypes = (s->npages << PageShift) / size;
-			nbytes3 = 8*sizeof(uintptr) + 1*ntypes;
-			data3 = runtime·mallocgc(nbytes3, 0, FlagNoProfiling|FlagNoScan|FlagNoInvokeGC);
-			s->types.compression = MTypes_Bytes;
-			s->types.data = (uintptr)data3;
-			((uintptr*)data3)[1] = typ;
-			data3[8*sizeof(uintptr) + ofs] = 1;
-			break;
-
-		case MTypes_Words:
-			((uintptr*)s->types.data)[ofs] = typ;
-			break;
-
-		case MTypes_Bytes:
-			data3 = (byte*)s->types.data;
-			for(j=1; j<8; j++) {
-				if(((uintptr*)data3)[j] == typ) {
-					break;
-				}
-				if(((uintptr*)data3)[j] == 0) {
-					((uintptr*)data3)[j] = typ;
-					break;
-				}
+			nbytes2 = ntypes * sizeof(uintptr);
+			data2 = runtime·mallocgc(nbytes2, 0, FlagNoProfiling|FlagNoScan|FlagNoInvokeGC);
+			s->types.compression = MTypes_Words;
+			s->types.data = (uintptr)data2;
+			
+			// Move the contents of data3 to data2. Then deallocate data3.
+			for(j=0; j<ntypes; j++) {
+				t = data3[8*sizeof(uintptr) + j];
+				t = ((uintptr*)data3)[t];
+				data2[j] = t;
 			}
-			if(j < 8) {
-				data3[8*sizeof(uintptr) + ofs] = j;
-			} else {
-				ntypes = (s->npages << PageShift) / size;
-				nbytes2 = ntypes * sizeof(uintptr);
-				data2 = runtime·mallocgc(nbytes2, 0, FlagNoProfiling|FlagNoScan|FlagNoInvokeGC);
-				s->types.compression = MTypes_Words;
-				s->types.data = (uintptr)data2;
-
-				// Move the contents of data3 to data2. Then deallocate data3.
-				for(j=0; j<ntypes; j++) {
-					t = data3[8*sizeof(uintptr) + j];
-					t = ((uintptr*)data3)[t];
-					data2[j] = t;
-				}
-				data2[ofs] = typ;
-			}
-			break;
+			data2[ofs] = typ;
 		}
+		break;
 	}
-	runtime·unlock(&settype_lock);
-
-	mp->settype_bufsize = 0;
 }
 
 uintptr
@@ -683,9 +806,7 @@ runtime·gettype(void *v)
 			runtime·throw("runtime·gettype: invalid compression kind");
 		}
 		if(0) {
-			runtime·lock(&settype_lock);
 			runtime·printf("%p -> %d,%X\n", v, (int32)s->types.compression, (int64)t);
-			runtime·unlock(&settype_lock);
 		}
 		return t;
 	}
@@ -701,11 +822,8 @@ runtime·mal(uintptr n)
 }
 
 #pragma textflag NOSPLIT
-void
-runtime·new(Type *typ, uint8 *ret)
-{
+func new(typ *Type) (ret *uint8) {
 	ret = runtime·mallocgc(typ->size, (uintptr)typ | TypeInfo_SingleObject, typ->kind&KindNoPointers ? FlagNoScan : 0);
-	FLUSH(&ret);
 }
 
 static void*
@@ -732,7 +850,7 @@ runtime·cnewarray(Type *typ, intgo n)
 }
 
 func GC() {
-	runtime·gc(1);
+	runtime·gc(2);  // force GC and do eager sweep
 }
 
 func SetFinalizer(obj Eface, finalizer Eface) {
@@ -754,14 +872,30 @@ func SetFinalizer(obj Eface, finalizer Eface) {
 		runtime·printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *obj.type->string);
 		goto throw;
 	}
+	ot = (PtrType*)obj.type;
+	// As an implementation detail we do not run finalizers for zero-sized objects,
+	// because we use &runtime·zerobase for all such allocations.
+	if(ot->elem != nil && ot->elem->size == 0)
+		return;
+	// The following check is required for cases when a user passes a pointer to composite literal,
+	// but compiler makes it a pointer to global. For example:
+	//	var Foo = &Object{}
+	//	func main() {
+	//		runtime.SetFinalizer(Foo, nil)
+	//	}
+	// See issue 7656.
+	if((byte*)obj.data < runtime·mheap.arena_start || runtime·mheap.arena_used <= (byte*)obj.data)
+		return;
 	if(!runtime·mlookup(obj.data, &base, &size, nil) || obj.data != base) {
-		runtime·printf("runtime.SetFinalizer: pointer not at beginning of allocated block\n");
-		goto throw;
+		// As an implementation detail we allow to set finalizers for an inner byte
+		// of an object if it could come from tiny alloc (see mallocgc for details).
+		if(ot->elem == nil || (ot->elem->kind&KindNoPointers) == 0 || ot->elem->size >= TinySize) {
+			runtime·printf("runtime.SetFinalizer: pointer not at beginning of allocated block (%p)\n", obj.data);
+			goto throw;
+		}
 	}
-	nret = 0;
-	ot = (PtrType*)obj.type;
-	fint = nil;
 	if(finalizer.type != nil) {
+		runtime·createfing();
 		if(finalizer.type->kind != KindFunc)
 			goto badfunc;
 		ft = (FuncType*)finalizer.type;
@@ -781,16 +915,20 @@ func SetFinalizer(obj Eface, finalizer Eface) {
 			goto badfunc;
 
 		// compute size needed for return parameters
+		nret = 0;
 		for(i=0; i<ft->out.len; i++) {
 			t = ((Type**)ft->out.array)[i];
 			nret = ROUND(nret, t->align) + t->size;
 		}
 		nret = ROUND(nret, sizeof(void*));
-	}
-	
-	if(!runtime·addfinalizer(obj.data, finalizer.data, nret, fint, ot)) {
-		runtime·printf("runtime.SetFinalizer: finalizer already set\n");
-		goto throw;
+		ot = (PtrType*)obj.type;
+		if(!runtime·addfinalizer(obj.data, finalizer.data, nret, fint, ot)) {
+			runtime·printf("runtime.SetFinalizer: finalizer already set\n");
+			goto throw;
+		}
+	} else {
+		// NOTE: asking to remove a finalizer when there currently isn't one set is OK.
+		runtime·removefinalizer(obj.data);
 	}
 	return;
 
diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h
index 2c66c6f..798c130 100644
--- a/src/pkg/runtime/malloc.h
+++ b/src/pkg/runtime/malloc.h
@@ -20,7 +20,7 @@
 //	MHeap: the malloc heap, managed at page (4096-byte) granularity.
 //	MSpan: a run of pages managed by the MHeap.
 //	MCentral: a shared free list for a given size class.
-//	MCache: a per-thread (in Go, per-M) cache for small objects.
+//	MCache: a per-thread (in Go, per-P) cache for small objects.
 //	MStats: allocation statistics.
 //
 // Allocating a small object proceeds up a hierarchy of caches:
@@ -66,14 +66,14 @@
 //
 // The small objects on the MCache and MCentral free lists
 // may or may not be zeroed.  They are zeroed if and only if
-// the second word of the object is zero.  The spans in the
-// page heap are always zeroed.  When a span full of objects
-// is returned to the page heap, the objects that need to be
-// are zeroed first.  There are two main benefits to delaying the
+// the second word of the object is zero.  A span in the
+// page heap is zeroed unless s->needzero is set. When a span
+// is allocated to break into small objects, it is zeroed if needed
+// and s->needzero is set. There are two main benefits to delaying the
 // zeroing this way:
 //
 //	1. stack frames allocated from the small object lists
-//	   can avoid zeroing altogether.
+//	   or the page heap can avoid zeroing altogether.
 //	2. the cost of zeroing when reusing a small object is
 //	   charged to the mutator, not the garbage collector.
 //
@@ -90,7 +90,7 @@ typedef struct GCStats	GCStats;
 
 enum
 {
-	PageShift	= 12,
+	PageShift	= 13,
 	PageSize	= 1<<PageShift,
 	PageMask	= PageSize - 1,
 };
@@ -103,11 +103,15 @@ enum
 	// size classes.  NumSizeClasses is that number.  It's needed here
 	// because there are static arrays of this length; when msize runs its
 	// size choosing algorithm it double-checks that NumSizeClasses agrees.
-	NumSizeClasses = 61,
+	NumSizeClasses = 67,
 
 	// Tunable constants.
 	MaxSmallSize = 32<<10,
 
+	// Tiny allocator parameters, see "Tiny allocator" comment in malloc.goc.
+	TinySize = 16,
+	TinySizeClass = 2,
+
 	FixAllocChunk = 16<<10,		// Chunk size for FixAlloc
 	MaxMHeapList = 1<<(20 - PageShift),	// Maximum page length for fixed-size list in MHeap.
 	HeapAllocChunk = 1<<20,		// Chunk size for heap growth
@@ -154,6 +158,9 @@ struct MLink
 // SysAlloc obtains a large chunk of zeroed memory from the
 // operating system, typically on the order of a hundred kilobytes
 // or a megabyte.
+// NOTE: SysAlloc returns OS-aligned memory, but the heap allocator
+// may use larger alignment, so the caller must be careful to realign the
+// memory obtained by SysAlloc.
 //
 // SysUnused notifies the operating system that the contents
 // of the memory region are no longer needed and can be reused
@@ -168,16 +175,29 @@ struct MLink
 // SysReserve reserves address space without allocating memory.
 // If the pointer passed to it is non-nil, the caller wants the
 // reservation there, but SysReserve can still choose another
-// location if that one is unavailable.
+// location if that one is unavailable.  On some systems and in some
+// cases SysReserve will simply check that the address space is
+// available and not actually reserve it.  If SysReserve returns
+// non-nil, it sets *reserved to true if the address space is
+// reserved, false if it has merely been checked.
+// NOTE: SysReserve returns OS-aligned memory, but the heap allocator
+// may use larger alignment, so the caller must be careful to realign the
+// memory obtained by SysAlloc.
 //
 // SysMap maps previously reserved address space for use.
+// The reserved argument is true if the address space was really
+// reserved, not merely checked.
+//
+// SysFault marks a (already SysAlloc'd) region to fault
+// if accessed.  Used only for debugging the runtime.
 
 void*	runtime·SysAlloc(uintptr nbytes, uint64 *stat);
 void	runtime·SysFree(void *v, uintptr nbytes, uint64 *stat);
 void	runtime·SysUnused(void *v, uintptr nbytes);
 void	runtime·SysUsed(void *v, uintptr nbytes);
-void	runtime·SysMap(void *v, uintptr nbytes, uint64 *stat);
-void*	runtime·SysReserve(void *v, uintptr nbytes);
+void	runtime·SysMap(void *v, uintptr nbytes, bool reserved, uint64 *stat);
+void*	runtime·SysReserve(void *v, uintptr nbytes, bool *reserved);
+void	runtime·SysFault(void *v, uintptr nbytes);
 
 // FixAlloc is a simple free-list allocator for fixed size objects.
 // Malloc uses a FixAlloc wrapped around SysAlloc to manages its
@@ -255,8 +275,9 @@ struct MStats
 	} by_size[NumSizeClasses];
 };
 
-#define mstats runtime·memStats	/* name shared with Go */
+#define mstats runtime·memStats
 extern MStats mstats;
+void	runtime·updatememstats(GCStats *stats);
 
 // Size classes.  Computed and initialized by InitSizes.
 //
@@ -269,6 +290,7 @@ extern MStats mstats;
 //	making new objects in class i
 
 int32	runtime·SizeToClass(int32);
+uintptr	runtime·roundupsize(uintptr);
 extern	int32	runtime·class_to_size[NumSizeClasses];
 extern	int32	runtime·class_to_allocnpages[NumSizeClasses];
 extern	int8	runtime·size_to_class8[1024/8 + 1];
@@ -276,8 +298,6 @@ extern	int8	runtime·size_to_class128[(MaxSmallSize-1024)/128 + 1];
 extern	void	runtime·InitSizes(void);
 
 
-// Per-thread (in Go, per-M) cache for small objects.
-// No locking needed because it is per-thread (per-M).
 typedef struct MCacheList MCacheList;
 struct MCacheList
 {
@@ -285,14 +305,21 @@ struct MCacheList
 	uint32 nlist;
 };
 
+// Per-thread (in Go, per-P) cache for small objects.
+// No locking needed because it is per-thread (per-P).
 struct MCache
 {
 	// The following members are accessed on every malloc,
 	// so they are grouped here for better caching.
 	int32 next_sample;		// trigger heap sample after allocating this many bytes
 	intptr local_cachealloc;	// bytes allocated (or freed) from cache since last lock of heap
+	// Allocator cache for tiny objects w/o pointers.
+	// See "Tiny allocator" comment in malloc.goc.
+	byte*	tiny;
+	uintptr	tinysize;
 	// The rest is not accessed on every malloc.
-	MCacheList list[NumSizeClasses];
+	MSpan*	alloc[NumSizeClasses];	// spans to allocate from
+	MCacheList free[NumSizeClasses];// lists of explicitly freed objects
 	// Local allocator stats, flushed during GC.
 	uintptr local_nlookup;		// number of pointer lookups
 	uintptr local_largefree;	// bytes freed for large objects (>MaxSmallSize)
@@ -300,8 +327,8 @@ struct MCache
 	uintptr local_nsmallfree[NumSizeClasses];	// number of frees for small objects (<=MaxSmallSize)
 };
 
-void	runtime·MCache_Refill(MCache *c, int32 sizeclass);
-void	runtime·MCache_Free(MCache *c, void *p, int32 sizeclass, uintptr size);
+MSpan*	runtime·MCache_Refill(MCache *c, int32 sizeclass);
+void	runtime·MCache_Free(MCache *c, MLink *p, int32 sizeclass, uintptr size);
 void	runtime·MCache_ReleaseAll(MCache *c);
 
 // MTypes describes the types of blocks allocated within a span.
@@ -341,6 +368,44 @@ struct MTypes
 	uintptr	data;
 };
 
+enum
+{
+	KindSpecialFinalizer = 1,
+	KindSpecialProfile = 2,
+	// Note: The finalizer special must be first because if we're freeing
+	// an object, a finalizer special will cause the freeing operation
+	// to abort, and we want to keep the other special records around
+	// if that happens.
+};
+
+typedef struct Special Special;
+struct Special
+{
+	Special*	next;	// linked list in span
+	uint16		offset;	// span offset of object
+	byte		kind;	// kind of Special
+};
+
+// The described object has a finalizer set for it.
+typedef struct SpecialFinalizer SpecialFinalizer;
+struct SpecialFinalizer
+{
+	Special;
+	FuncVal*	fn;
+	uintptr		nret;
+	Type*		fint;
+	PtrType*	ot;
+};
+
+// The described object is being heap profiled.
+typedef struct Bucket Bucket; // from mprof.goc
+typedef struct SpecialProfile SpecialProfile;
+struct SpecialProfile
+{
+	Special;
+	Bucket*	b;
+};
+
 // An MSpan is a run of pages.
 enum
 {
@@ -356,17 +421,30 @@ struct MSpan
 	PageID	start;		// starting page number
 	uintptr	npages;		// number of pages in span
 	MLink	*freelist;	// list of free objects
-	uint32	ref;		// number of allocated objects in this span
-	int32	sizeclass;	// size class
+	// sweep generation:
+	// if sweepgen == h->sweepgen - 2, the span needs sweeping
+	// if sweepgen == h->sweepgen - 1, the span is currently being swept
+	// if sweepgen == h->sweepgen, the span is swept and ready to use
+	// h->sweepgen is incremented by 2 after every GC
+	uint32	sweepgen;
+	uint16	ref;		// capacity - number of objects in freelist
+	uint8	sizeclass;	// size class
+	bool	incache;	// being used by an MCache
+	uint8	state;		// MSpanInUse etc
+	uint8	needzero;	// needs to be zeroed before allocation
 	uintptr	elemsize;	// computed from sizeclass or from npages
-	uint32	state;		// MSpanInUse etc
 	int64   unusedsince;	// First time spotted by GC in MSpanFree state
 	uintptr npreleased;	// number of pages released to the OS
 	byte	*limit;		// end of data in span
 	MTypes	types;		// types of allocated objects in this span
+	Lock	specialLock;	// guards specials list
+	Special	*specials;	// linked list of special records sorted by offset.
+	MLink	*freebuf;	// objects freed explicitly, not incorporated into freelist yet
 };
 
 void	runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages);
+void	runtime·MSpan_EnsureSwept(MSpan *span);
+bool	runtime·MSpan_Sweep(MSpan *span);
 
 // Every MSpan is in one doubly-linked list,
 // either one of the MHeap's free lists or one of the
@@ -374,6 +452,7 @@ void	runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages);
 void	runtime·MSpanList_Init(MSpan *list);
 bool	runtime·MSpanList_IsEmpty(MSpan *list);
 void	runtime·MSpanList_Insert(MSpan *list, MSpan *span);
+void	runtime·MSpanList_InsertBack(MSpan *list, MSpan *span);
 void	runtime·MSpanList_Remove(MSpan *span);	// from whatever list it is in
 
 
@@ -382,15 +461,16 @@ struct MCentral
 {
 	Lock;
 	int32 sizeclass;
-	MSpan nonempty;
-	MSpan empty;
-	int32 nfree;
+	MSpan nonempty;	// list of spans with a free object
+	MSpan empty;	// list of spans with no free objects (or cached in an MCache)
+	int32 nfree;	// # of objects available in nonempty spans
 };
 
 void	runtime·MCentral_Init(MCentral *c, int32 sizeclass);
-int32	runtime·MCentral_AllocList(MCentral *c, MLink **first);
-void	runtime·MCentral_FreeList(MCentral *c, MLink *first);
-void	runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *end);
+MSpan*	runtime·MCentral_CacheSpan(MCentral *c);
+void	runtime·MCentral_UncacheSpan(MCentral *c, MSpan *s);
+bool	runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *end);
+void	runtime·MCentral_FreeList(MCentral *c, MLink *start); // TODO: need this?
 
 // Main malloc heap.
 // The heap itself is the "free[]" and "large" arrays,
@@ -399,10 +479,15 @@ struct MHeap
 {
 	Lock;
 	MSpan free[MaxMHeapList];	// free lists of given length
-	MSpan large;			// free lists length >= MaxMHeapList
-	MSpan **allspans;
+	MSpan freelarge;		// free lists length >= MaxMHeapList
+	MSpan busy[MaxMHeapList];	// busy lists of large objects of given length
+	MSpan busylarge;		// busy lists of large objects length >= MaxMHeapList
+	MSpan **allspans;		// all spans out there
+	MSpan **sweepspans;		// copy of allspans referenced by sweeper
 	uint32	nspan;
 	uint32	nspancap;
+	uint32	sweepgen;		// sweep generation, see comment in MSpan
+	uint32	sweepdone;		// all spans are swept
 
 	// span lookup
 	MSpan**	spans;
@@ -414,6 +499,7 @@ struct MHeap
 	byte *arena_start;
 	byte *arena_used;
 	byte *arena_end;
+	bool arena_reserved;
 
 	// central free lists for small size classes.
 	// the padding makes sure that the MCentrals are
@@ -426,6 +512,9 @@ struct MHeap
 
 	FixAlloc spanalloc;	// allocator for Span*
 	FixAlloc cachealloc;	// allocator for MCache*
+	FixAlloc specialfinalizeralloc;	// allocator for SpecialFinalizer*
+	FixAlloc specialprofilealloc;	// allocator for SpecialProfile*
+	Lock speciallock; // lock for sepcial record allocators.
 
 	// Malloc stats.
 	uint64 largefree;	// bytes freed for large objects (>MaxSmallSize)
@@ -435,7 +524,7 @@ struct MHeap
 extern MHeap runtime·mheap;
 
 void	runtime·MHeap_Init(MHeap *h);
-MSpan*	runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct, int32 zeroed);
+MSpan*	runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large, bool needzero);
 void	runtime·MHeap_Free(MHeap *h, MSpan *s, int32 acct);
 MSpan*	runtime·MHeap_Lookup(MHeap *h, void *v);
 MSpan*	runtime·MHeap_LookupMaybe(MHeap *h, void *v);
@@ -444,26 +533,28 @@ void*	runtime·MHeap_SysAlloc(MHeap *h, uintptr n);
 void	runtime·MHeap_MapBits(MHeap *h);
 void	runtime·MHeap_MapSpans(MHeap *h);
 void	runtime·MHeap_Scavenger(void);
+void	runtime·MHeap_SplitSpan(MHeap *h, MSpan *s);
 
 void*	runtime·mallocgc(uintptr size, uintptr typ, uint32 flag);
 void*	runtime·persistentalloc(uintptr size, uintptr align, uint64 *stat);
 int32	runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **s);
 void	runtime·gc(int32 force);
-void	runtime·markallocated(void *v, uintptr n, bool noptr);
+uintptr	runtime·sweepone(void);
+void	runtime·markscan(void *v);
+void	runtime·marknogc(void *v);
 void	runtime·checkallocated(void *v, uintptr n);
-void	runtime·markfreed(void *v, uintptr n);
+void	runtime·markfreed(void *v);
 void	runtime·checkfreed(void *v, uintptr n);
 extern	int32	runtime·checking;
 void	runtime·markspan(void *v, uintptr size, uintptr n, bool leftover);
 void	runtime·unmarkspan(void *v, uintptr size);
-bool	runtime·blockspecial(void*);
-void	runtime·setblockspecial(void*, bool);
 void	runtime·purgecachedstats(MCache*);
 void*	runtime·cnew(Type*);
 void*	runtime·cnewarray(Type*, intgo);
+void	runtime·tracealloc(void*, uintptr, uintptr);
+void	runtime·tracefree(void*, uintptr);
+void	runtime·tracegc(void);
 
-void	runtime·settype_flush(M*);
-void	runtime·settype_sysfree(MSpan*);
 uintptr	runtime·gettype(void*);
 
 enum
@@ -477,13 +568,25 @@ enum
 };
 
 void	runtime·MProf_Malloc(void*, uintptr);
-void	runtime·MProf_Free(void*, uintptr);
+void	runtime·MProf_Free(Bucket*, uintptr, bool);
 void	runtime·MProf_GC(void);
+void	runtime·iterate_memprof(void (*callback)(Bucket*, uintptr, uintptr*, uintptr, uintptr, uintptr));
 int32	runtime·gcprocs(void);
 void	runtime·helpgc(int32 nproc);
 void	runtime·gchelper(void);
+void	runtime·createfing(void);
+G*	runtime·wakefing(void);
+extern bool	runtime·fingwait;
+extern bool	runtime·fingwake;
 
-void	runtime·walkfintab(void (*fn)(void*));
+void	runtime·setprofilebucket(void *p, Bucket *b);
+
+bool	runtime·addfinalizer(void*, FuncVal *fn, uintptr, Type*, PtrType*);
+void	runtime·removefinalizer(void*);
+void	runtime·queuefinalizer(byte *p, FuncVal *fn, uintptr nret, Type *fint, PtrType *ot);
+
+void	runtime·freeallspecials(MSpan *span, void *p, uintptr size);
+bool	runtime·freespecial(Special *s, void *p, uintptr size, bool freed);
 
 enum
 {
@@ -495,8 +598,46 @@ enum
 	DebugTypeAtBlockEnd = 0,
 };
 
+// Information from the compiler about the layout of stack frames.
+typedef struct BitVector BitVector;
+struct BitVector
+{
+	int32 n; // # of bits
+	uint32 *data;
+};
+typedef struct StackMap StackMap;
+struct StackMap
+{
+	int32 n; // number of bitmaps
+	int32 nbit; // number of bits in each bitmap
+	uint32 data[];
+};
+enum {
+	// Pointer map
+	BitsPerPointer = 2,
+	BitsDead = 0,
+	BitsScalar = 1,
+	BitsPointer = 2,
+	BitsMultiWord = 3,
+	// BitsMultiWord will be set for the first word of a multi-word item.
+	// When it is set, one of the following will be set for the second word.
+	BitsString = 0,
+	BitsSlice = 1,
+	BitsIface = 2,
+	BitsEface = 3,
+};
+// Returns pointer map data for the given stackmap index
+// (the index is encoded in PCDATA_StackMapIndex).
+BitVector	runtime·stackmapdata(StackMap *stackmap, int32 n);
+
 // defined in mgc0.go
 void	runtime·gc_m_ptr(Eface*);
+void	runtime·gc_g_ptr(Eface*);
 void	runtime·gc_itab_ptr(Eface*);
 
 void	runtime·memorydump(void);
+int32	runtime·setgcpercent(int32);
+
+// Value we use to mark dead pointers when GODEBUG=gcdead=1.
+#define PoisonGC ((uintptr)0xf969696969696969ULL)
+#define PoisonStack ((uintptr)0x6868686868686868ULL)
diff --git a/src/pkg/runtime/map_test.go b/src/pkg/runtime/map_test.go
index a221cb2..e4e8383 100644
--- a/src/pkg/runtime/map_test.go
+++ b/src/pkg/runtime/map_test.go
@@ -409,3 +409,69 @@ func TestMapNanGrowIterator(t *testing.T) {
 		t.Fatalf("missing value")
 	}
 }
+
+func TestMapIterOrder(t *testing.T) {
+	for _, n := range [...]int{3, 7, 9, 15} {
+		// Make m be {0: true, 1: true, ..., n-1: true}.
+		m := make(map[int]bool)
+		for i := 0; i < n; i++ {
+			m[i] = true
+		}
+		// Check that iterating over the map produces at least two different orderings.
+		ord := func() []int {
+			var s []int
+			for key := range m {
+				s = append(s, key)
+			}
+			return s
+		}
+		first := ord()
+		ok := false
+		for try := 0; try < 100; try++ {
+			if !reflect.DeepEqual(first, ord()) {
+				ok = true
+				break
+			}
+		}
+		if !ok {
+			t.Errorf("Map with n=%d elements had consistent iteration order: %v", n, first)
+		}
+	}
+}
+
+func TestMapStringBytesLookup(t *testing.T) {
+	// Use large string keys to avoid small-allocation coalescing,
+	// which can cause AllocsPerRun to report lower counts than it should.
+	m := map[string]int{
+		"1000000000000000000000000000000000000000000000000": 1,
+		"2000000000000000000000000000000000000000000000000": 2,
+	}
+	buf := []byte("1000000000000000000000000000000000000000000000000")
+	if x := m[string(buf)]; x != 1 {
+		t.Errorf(`m[string([]byte("1"))] = %d, want 1`, x)
+	}
+	buf[0] = '2'
+	if x := m[string(buf)]; x != 2 {
+		t.Errorf(`m[string([]byte("2"))] = %d, want 2`, x)
+	}
+
+	var x int
+	n := testing.AllocsPerRun(100, func() {
+		x += m[string(buf)]
+	})
+	if n != 0 {
+		t.Errorf("AllocsPerRun for m[string(buf)] = %v, want 0", n)
+	}
+
+	x = 0
+	n = testing.AllocsPerRun(100, func() {
+		y, ok := m[string(buf)]
+		if !ok {
+			panic("!ok")
+		}
+		x += y
+	})
+	if n != 0 {
+		t.Errorf("AllocsPerRun for x,ok = m[string(buf)] = %v, want 0", n)
+	}
+}
diff --git a/src/pkg/runtime/mapspeed_test.go b/src/pkg/runtime/mapspeed_test.go
index d643d98..da45ea1 100644
--- a/src/pkg/runtime/mapspeed_test.go
+++ b/src/pkg/runtime/mapspeed_test.go
@@ -268,3 +268,33 @@ func BenchmarkSameLengthMap(b *testing.B) {
 		_ = m[s1]
 	}
 }
+
+type BigKey [3]int64
+
+func BenchmarkBigKeyMap(b *testing.B) {
+	m := make(map[BigKey]bool)
+	k := BigKey{3, 4, 5}
+	m[k] = true
+	for i := 0; i < b.N; i++ {
+		_ = m[k]
+	}
+}
+
+type BigVal [3]int64
+
+func BenchmarkBigValMap(b *testing.B) {
+	m := make(map[BigKey]BigVal)
+	k := BigKey{3, 4, 5}
+	m[k] = BigVal{6, 7, 8}
+	for i := 0; i < b.N; i++ {
+		_ = m[k]
+	}
+}
+
+func BenchmarkSmallKeyMap(b *testing.B) {
+	m := make(map[int16]bool)
+	m[5] = true
+	for i := 0; i < b.N; i++ {
+		_ = m[5]
+	}
+}
diff --git a/src/pkg/runtime/mcache.c b/src/pkg/runtime/mcache.c
index 863030e..26e3db2 100644
--- a/src/pkg/runtime/mcache.c
+++ b/src/pkg/runtime/mcache.c
@@ -10,69 +10,118 @@
 #include "arch_GOARCH.h"
 #include "malloc.h"
 
+extern volatile intgo runtime·MemProfileRate;
+
+// dummy MSpan that contains no free objects.
+static MSpan emptymspan;
+
+MCache*
+runtime·allocmcache(void)
+{
+	intgo rate;
+	MCache *c;
+	int32 i;
+
+	runtime·lock(&runtime·mheap);
+	c = runtime·FixAlloc_Alloc(&runtime·mheap.cachealloc);
+	runtime·unlock(&runtime·mheap);
+	runtime·memclr((byte*)c, sizeof(*c));
+	for(i = 0; i < NumSizeClasses; i++)
+		c->alloc[i] = &emptymspan;
+
+	// Set first allocation sample size.
+	rate = runtime·MemProfileRate;
+	if(rate > 0x3fffffff)	// make 2*rate not overflow
+		rate = 0x3fffffff;
+	if(rate != 0)
+		c->next_sample = runtime·fastrand1() % (2*rate);
+
+	return c;
+}
+
 void
+runtime·freemcache(MCache *c)
+{
+	runtime·MCache_ReleaseAll(c);
+	runtime·lock(&runtime·mheap);
+	runtime·purgecachedstats(c);
+	runtime·FixAlloc_Free(&runtime·mheap.cachealloc, c);
+	runtime·unlock(&runtime·mheap);
+}
+
+// Gets a span that has a free object in it and assigns it
+// to be the cached span for the given sizeclass.  Returns this span.
+MSpan*
 runtime·MCache_Refill(MCache *c, int32 sizeclass)
 {
 	MCacheList *l;
+	MSpan *s;
 
-	// Replenish using central lists.
-	l = &c->list[sizeclass];
-	if(l->list)
-		runtime·throw("MCache_Refill: the list is not empty");
-	l->nlist = runtime·MCentral_AllocList(&runtime·mheap.central[sizeclass], &l->list);
-	if(l->list == nil)
-		runtime·throw("out of memory");
-}
+	m->locks++;
+	// Return the current cached span to the central lists.
+	s = c->alloc[sizeclass];
+	if(s->freelist != nil)
+		runtime·throw("refill on a nonempty span");
+	if(s != &emptymspan)
+		runtime·MCentral_UncacheSpan(&runtime·mheap.central[sizeclass], s);
 
-// Take n elements off l and return them to the central free list.
-static void
-ReleaseN(MCacheList *l, int32 n, int32 sizeclass)
-{
-	MLink *first, **lp;
-	int32 i;
+	// Push any explicitly freed objects to the central lists.
+	// Not required, but it seems like a good time to do it.
+	l = &c->free[sizeclass];
+	if(l->nlist > 0) {
+		runtime·MCentral_FreeList(&runtime·mheap.central[sizeclass], l->list);
+		l->list = nil;
+		l->nlist = 0;
+	}
 
-	// Cut off first n elements.
-	first = l->list;
-	lp = &l->list;
-	for(i=0; i<n; i++)
-		lp = &(*lp)->next;
-	l->list = *lp;
-	*lp = nil;
-	l->nlist -= n;
-
-	// Return them to central free list.
-	runtime·MCentral_FreeList(&runtime·mheap.central[sizeclass], first);
+	// Get a new cached span from the central lists.
+	s = runtime·MCentral_CacheSpan(&runtime·mheap.central[sizeclass]);
+	if(s == nil)
+		runtime·throw("out of memory");
+	if(s->freelist == nil) {
+		runtime·printf("%d %d\n", s->ref, (int32)((s->npages << PageShift) / s->elemsize));
+		runtime·throw("empty span");
+	}
+	c->alloc[sizeclass] = s;
+	m->locks--;
+	return s;
 }
 
 void
-runtime·MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
+runtime·MCache_Free(MCache *c, MLink *p, int32 sizeclass, uintptr size)
 {
 	MCacheList *l;
-	MLink *p;
 
-	// Put back on list.
-	l = &c->list[sizeclass];
-	p = v;
+	// Put on free list.
+	l = &c->free[sizeclass];
 	p->next = l->list;
 	l->list = p;
 	l->nlist++;
-	c->local_cachealloc -= size;
 
-	// We transfer span at a time from MCentral to MCache,
-	// if we have 2 times more than that, release a half back.
-	if(l->nlist >= 2*(runtime·class_to_allocnpages[sizeclass]<<PageShift)/size)
-		ReleaseN(l, l->nlist/2, sizeclass);
+	// We transfer a span at a time from MCentral to MCache,
+	// so we'll do the same in the other direction.
+	if(l->nlist >= (runtime·class_to_allocnpages[sizeclass]<<PageShift)/size) {
+		runtime·MCentral_FreeList(&runtime·mheap.central[sizeclass], l->list);
+		l->list = nil;
+		l->nlist = 0;
+	}
 }
 
 void
 runtime·MCache_ReleaseAll(MCache *c)
 {
 	int32 i;
+	MSpan *s;
 	MCacheList *l;
 
 	for(i=0; i<NumSizeClasses; i++) {
-		l = &c->list[i];
-		if(l->list) {
+		s = c->alloc[i];
+		if(s != &emptymspan) {
+			runtime·MCentral_UncacheSpan(&runtime·mheap.central[i], s);
+			c->alloc[i] = &emptymspan;
+		}
+		l = &c->free[i];
+		if(l->nlist > 0) {
 			runtime·MCentral_FreeList(&runtime·mheap.central[i], l->list);
 			l->list = nil;
 			l->nlist = 0;
diff --git a/src/pkg/runtime/mcentral.c b/src/pkg/runtime/mcentral.c
index 735a7e6..203558f 100644
--- a/src/pkg/runtime/mcentral.c
+++ b/src/pkg/runtime/mcentral.c
@@ -19,7 +19,8 @@
 #include "malloc.h"
 
 static bool MCentral_Grow(MCentral *c);
-static void MCentral_Free(MCentral *c, void *v);
+static void MCentral_Free(MCentral *c, MLink *v);
+static void MCentral_ReturnToHeap(MCentral *c, MSpan *s);
 
 // Initialize a single central free list.
 void
@@ -30,39 +31,115 @@ runtime·MCentral_Init(MCentral *c, int32 sizeclass)
 	runtime·MSpanList_Init(&c->empty);
 }
 
-// Allocate a list of objects from the central free list.
-// Return the number of objects allocated.
-// The objects are linked together by their first words.
-// On return, *pfirst points at the first object.
-int32
-runtime·MCentral_AllocList(MCentral *c, MLink **pfirst)
+// Allocate a span to use in an MCache.
+MSpan*
+runtime·MCentral_CacheSpan(MCentral *c)
 {
 	MSpan *s;
 	int32 cap, n;
+	uint32 sg;
 
 	runtime·lock(c);
-	// Replenish central list if empty.
-	if(runtime·MSpanList_IsEmpty(&c->nonempty)) {
-		if(!MCentral_Grow(c)) {
+	sg = runtime·mheap.sweepgen;
+retry:
+	for(s = c->nonempty.next; s != &c->nonempty; s = s->next) {
+		if(s->sweepgen == sg-2 && runtime·cas(&s->sweepgen, sg-2, sg-1)) {
+			runtime·unlock(c);
+			runtime·MSpan_Sweep(s);
+			runtime·lock(c);
+			// the span could have been moved to heap, retry
+			goto retry;
+		}
+		if(s->sweepgen == sg-1) {
+			// the span is being swept by background sweeper, skip
+			continue;
+		}
+		// we have a nonempty span that does not require sweeping, allocate from it
+		goto havespan;
+	}
+
+	for(s = c->empty.next; s != &c->empty; s = s->next) {
+		if(s->sweepgen == sg-2 && runtime·cas(&s->sweepgen, sg-2, sg-1)) {
+			// we have an empty span that requires sweeping,
+			// sweep it and see if we can free some space in it
+			runtime·MSpanList_Remove(s);
+			// swept spans are at the end of the list
+			runtime·MSpanList_InsertBack(&c->empty, s);
 			runtime·unlock(c);
-			*pfirst = nil;
-			return 0;
+			runtime·MSpan_Sweep(s);
+			runtime·lock(c);
+			// the span could be moved to nonempty or heap, retry
+			goto retry;
 		}
+		if(s->sweepgen == sg-1) {
+			// the span is being swept by background sweeper, skip
+			continue;
+		}
+		// already swept empty span,
+		// all subsequent ones must also be either swept or in process of sweeping
+		break;
 	}
-	s = c->nonempty.next;
+
+	// Replenish central list if empty.
+	if(!MCentral_Grow(c)) {
+		runtime·unlock(c);
+		return nil;
+	}
+	goto retry;
+
+havespan:
 	cap = (s->npages << PageShift) / s->elemsize;
 	n = cap - s->ref;
-	*pfirst = s->freelist;
-	s->freelist = nil;
-	s->ref += n;
+	if(n == 0)
+		runtime·throw("empty span");
+	if(s->freelist == nil)
+		runtime·throw("freelist empty");
 	c->nfree -= n;
 	runtime·MSpanList_Remove(s);
-	runtime·MSpanList_Insert(&c->empty, s);
+	runtime·MSpanList_InsertBack(&c->empty, s);
+	s->incache = true;
 	runtime·unlock(c);
-	return n;
+	return s;
 }
 
-// Free the list of objects back into the central free list.
+// Return span from an MCache.
+void
+runtime·MCentral_UncacheSpan(MCentral *c, MSpan *s)
+{
+	MLink *v;
+	int32 cap, n;
+
+	runtime·lock(c);
+
+	s->incache = false;
+
+	// Move any explicitly freed items from the freebuf to the freelist.
+	while((v = s->freebuf) != nil) {
+		s->freebuf = v->next;
+		runtime·markfreed(v);
+		v->next = s->freelist;
+		s->freelist = v;
+		s->ref--;
+	}
+
+	if(s->ref == 0) {
+		// Free back to heap.  Unlikely, but possible.
+		MCentral_ReturnToHeap(c, s); // unlocks c
+		return;
+	}
+	
+	cap = (s->npages << PageShift) / s->elemsize;
+	n = cap - s->ref;
+	if(n > 0) {
+		c->nfree += n;
+		runtime·MSpanList_Remove(s);
+		runtime·MSpanList_Insert(&c->nonempty, s);
+	}
+	runtime·unlock(c);
+}
+
+// Free the list of objects back into the central free list c.
+// Called from runtime·free.
 void
 runtime·MCentral_FreeList(MCentral *c, MLink *start)
 {
@@ -77,51 +154,58 @@ runtime·MCentral_FreeList(MCentral *c, MLink *start)
 }
 
 // Helper: free one object back into the central free list.
+// Caller must hold lock on c on entry.  Holds lock on exit.
 static void
-MCentral_Free(MCentral *c, void *v)
+MCentral_Free(MCentral *c, MLink *v)
 {
 	MSpan *s;
-	MLink *p;
-	int32 size;
 
 	// Find span for v.
 	s = runtime·MHeap_Lookup(&runtime·mheap, v);
 	if(s == nil || s->ref == 0)
 		runtime·throw("invalid free");
+	if(s->sweepgen != runtime·mheap.sweepgen)
+		runtime·throw("free into unswept span");
+	
+	// If the span is currently being used unsynchronized by an MCache,
+	// we can't modify the freelist.  Add to the freebuf instead.  The
+	// items will get moved to the freelist when the span is returned
+	// by the MCache.
+	if(s->incache) {
+		v->next = s->freebuf;
+		s->freebuf = v;
+		return;
+	}
 
-	// Move to nonempty if necessary.
+	// Move span to nonempty if necessary.
 	if(s->freelist == nil) {
 		runtime·MSpanList_Remove(s);
 		runtime·MSpanList_Insert(&c->nonempty, s);
 	}
 
-	// Add v back to s's free list.
-	p = v;
-	p->next = s->freelist;
-	s->freelist = p;
+	// Add the object to span's free list.
+	runtime·markfreed(v);
+	v->next = s->freelist;
+	s->freelist = v;
+	s->ref--;
 	c->nfree++;
 
 	// If s is completely freed, return it to the heap.
-	if(--s->ref == 0) {
-		size = runtime·class_to_size[c->sizeclass];
-		runtime·MSpanList_Remove(s);
-		runtime·unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift);
-		*(uintptr*)(s->start<<PageShift) = 1;  // needs zeroing
-		s->freelist = nil;
-		c->nfree -= (s->npages << PageShift) / size;
-		runtime·unlock(c);
-		runtime·MHeap_Free(&runtime·mheap, s, 0);
+	if(s->ref == 0) {
+		MCentral_ReturnToHeap(c, s); // unlocks c
 		runtime·lock(c);
 	}
 }
 
 // Free n objects from a span s back into the central free list c.
-// Called from GC.
-void
+// Called during sweep.
+// Returns true if the span was returned to heap.  Sets sweepgen to
+// the latest generation.
+bool
 runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *end)
 {
-	int32 size;
-
+	if(s->incache)
+		runtime·throw("freespan into cached span");
 	runtime·lock(c);
 
 	// Move to nonempty if necessary.
@@ -135,20 +219,21 @@ runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *
 	s->freelist = start;
 	s->ref -= n;
 	c->nfree += n;
+	
+	// delay updating sweepgen until here.  This is the signal that
+	// the span may be used in an MCache, so it must come after the
+	// linked list operations above (actually, just after the
+	// lock of c above.)
+	runtime·atomicstore(&s->sweepgen, runtime·mheap.sweepgen);
 
-	// If s is completely freed, return it to the heap.
-	if(s->ref == 0) {
-		size = runtime·class_to_size[c->sizeclass];
-		runtime·MSpanList_Remove(s);
-		*(uintptr*)(s->start<<PageShift) = 1;  // needs zeroing
-		s->freelist = nil;
-		c->nfree -= (s->npages << PageShift) / size;
-		runtime·unlock(c);
-		runtime·unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift);
-		runtime·MHeap_Free(&runtime·mheap, s, 0);
-	} else {
+	if(s->ref != 0) {
 		runtime·unlock(c);
+		return false;
 	}
+
+	// s is completely freed, return it to the heap.
+	MCentral_ReturnToHeap(c, s); // unlocks c
+	return true;
 }
 
 void
@@ -202,3 +287,21 @@ MCentral_Grow(MCentral *c)
 	runtime·MSpanList_Insert(&c->nonempty, s);
 	return true;
 }
+
+// Return s to the heap.  s must be unused (s->ref == 0).  Unlocks c.
+static void
+MCentral_ReturnToHeap(MCentral *c, MSpan *s)
+{
+	int32 size;
+
+	size = runtime·class_to_size[c->sizeclass];
+	runtime·MSpanList_Remove(s);
+	s->needzero = 1;
+	s->freelist = nil;
+	if(s->ref != 0)
+		runtime·throw("ref wrong");
+	c->nfree -= (s->npages << PageShift) / size;
+	runtime·unlock(c);
+	runtime·unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift);
+	runtime·MHeap_Free(&runtime·mheap, s, 0);
+}
diff --git a/src/pkg/runtime/mem.go b/src/pkg/runtime/mem.go
index dc735e4..fa308b5 100644
--- a/src/pkg/runtime/mem.go
+++ b/src/pkg/runtime/mem.go
@@ -60,9 +60,8 @@ type MemStats struct {
 
 var sizeof_C_MStats uintptr // filled in by malloc.goc
 
-var memStats MemStats
-
 func init() {
+	var memStats MemStats
 	if sizeof_C_MStats != unsafe.Sizeof(memStats) {
 		println(sizeof_C_MStats, unsafe.Sizeof(memStats))
 		panic("MStats vs MemStatsType size mismatch")
diff --git a/src/pkg/runtime/mem_darwin.c b/src/pkg/runtime/mem_darwin.c
index a75c46d..878c4e1 100644
--- a/src/pkg/runtime/mem_darwin.c
+++ b/src/pkg/runtime/mem_darwin.c
@@ -41,11 +41,18 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
 	runtime·munmap(v, n);
 }
 
+void
+runtime·SysFault(void *v, uintptr n)
+{
+	runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
 void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
 {
 	void *p;
 
+	*reserved = true;
 	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
 	if(p < (void*)4096)
 		return nil;
@@ -58,10 +65,12 @@ enum
 };
 
 void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
 {
 	void *p;
 	
+	USED(reserved);
+
 	runtime·xadd64(stat, n);
 	p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
 	if(p == (void*)ENOMEM)
diff --git a/src/pkg/runtime/mem_dragonfly.c b/src/pkg/runtime/mem_dragonfly.c
index 025b62e..c270332 100644
--- a/src/pkg/runtime/mem_dragonfly.c
+++ b/src/pkg/runtime/mem_dragonfly.c
@@ -45,17 +45,26 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
 	runtime·munmap(v, n);
 }
 
+void
+runtime·SysFault(void *v, uintptr n)
+{
+	runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
 void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
 {
 	void *p;
 
 	// On 64-bit, people with ulimit -v set complain if we reserve too
 	// much address space.  Instead, assume that the reservation is okay
 	// and check the assumption in SysMap.
-	if(sizeof(void*) == 8)
+	if(sizeof(void*) == 8 && n > 1LL<<32) {
+		*reserved = false;
 		return v;
-	
+	}
+
+	*reserved = true;
 	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
 	if(p < (void*)4096)
 		return nil;
@@ -63,14 +72,14 @@ runtime·SysReserve(void *v, uintptr n)
 }
 
 void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
 {
 	void *p;
 	
 	runtime·xadd64(stat, n);
 
 	// On 64-bit, we don't actually have v reserved, so tread carefully.
-	if(sizeof(void*) == 8) {
+	if(!reserved) {
 		// TODO(jsing): For some reason DragonFly seems to return
 		// memory at a different address than we requested, even when
 		// there should be no reason for it to do so. This can be
diff --git a/src/pkg/runtime/mem_freebsd.c b/src/pkg/runtime/mem_freebsd.c
index 1ee2a55..586947a 100644
--- a/src/pkg/runtime/mem_freebsd.c
+++ b/src/pkg/runtime/mem_freebsd.c
@@ -45,17 +45,26 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
 	runtime·munmap(v, n);
 }
 
+void
+runtime·SysFault(void *v, uintptr n)
+{
+	runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
 void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
 {
 	void *p;
 
 	// On 64-bit, people with ulimit -v set complain if we reserve too
 	// much address space.  Instead, assume that the reservation is okay
 	// and check the assumption in SysMap.
-	if(sizeof(void*) == 8)
+	if(sizeof(void*) == 8 && n > 1LL<<32) {
+		*reserved = false;
 		return v;
-	
+	}
+
+	*reserved = true;
 	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
 	if(p < (void*)4096)
 		return nil;
@@ -63,14 +72,14 @@ runtime·SysReserve(void *v, uintptr n)
 }
 
 void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
 {
 	void *p;
 	
 	runtime·xadd64(stat, n);
 
 	// On 64-bit, we don't actually have v reserved, so tread carefully.
-	if(sizeof(void*) == 8) {
+	if(!reserved) {
 		p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
 		if(p == (void*)ENOMEM)
 			runtime·throw("runtime: out of memory");
diff --git a/src/pkg/runtime/mem_linux.c b/src/pkg/runtime/mem_linux.c
index b0f2956..635594c 100644
--- a/src/pkg/runtime/mem_linux.c
+++ b/src/pkg/runtime/mem_linux.c
@@ -11,6 +11,7 @@
 enum
 {
 	_PAGE_SIZE = 4096,
+	EACCES = 13,
 };
 
 static int32
@@ -19,15 +20,22 @@ addrspace_free(void *v, uintptr n)
 	int32 errval;
 	uintptr chunk;
 	uintptr off;
-	static byte vec[4096];
+	
+	// NOTE: vec must be just 1 byte long here.
+	// Mincore returns ENOMEM if any of the pages are unmapped,
+	// but we want to know that all of the pages are unmapped.
+	// To make these the same, we can only ask about one page
+	// at a time. See golang.org/issue/7476.
+	static byte vec[1];
 
 	for(off = 0; off < n; off += chunk) {
 		chunk = _PAGE_SIZE * sizeof vec;
 		if(chunk > (n - off))
 			chunk = n - off;
 		errval = runtime·mincore((int8*)v + off, chunk, vec);
-		// errval is 0 if success, or -(error_code) if error.
-		if (errval == 0 || errval != -ENOMEM)
+		// ENOMEM means unmapped, which is what we want.
+		// Anything else we assume means the pages are mapped.
+		if (errval != -ENOMEM)
 			return 0;
 	}
 	return 1;
@@ -91,8 +99,14 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
 	runtime·munmap(v, n);
 }
 
+void
+runtime·SysFault(void *v, uintptr n)
+{
+	runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
 void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
 {
 	void *p;
 
@@ -100,7 +114,7 @@ runtime·SysReserve(void *v, uintptr n)
 	// much address space.  Instead, assume that the reservation is okay
 	// if we can reserve at least 64K and check the assumption in SysMap.
 	// Only user-mode Linux (UML) rejects these requests.
-	if(sizeof(void*) == 8 && (uintptr)v >= 0xffffffffU) {
+	if(sizeof(void*) == 8 && n > 1LL<<32) {
 		p = mmap_fixed(v, 64<<10, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
 		if (p != v) {
 			if(p >= (void*)4096)
@@ -108,24 +122,26 @@ runtime·SysReserve(void *v, uintptr n)
 			return nil;
 		}
 		runtime·munmap(p, 64<<10);
+		*reserved = false;
 		return v;
 	}
 
 	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
 	if((uintptr)p < 4096)
 		return nil;
+	*reserved = true;
 	return p;
 }
 
 void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
 {
 	void *p;
 	
 	runtime·xadd64(stat, n);
 
 	// On 64-bit, we don't actually have v reserved, so tread carefully.
-	if(sizeof(void*) == 8 && (uintptr)v >= 0xffffffffU) {
+	if(!reserved) {
 		p = mmap_fixed(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
 		if(p == (void*)ENOMEM)
 			runtime·throw("runtime: out of memory");
diff --git a/src/pkg/runtime/mem_nacl.c b/src/pkg/runtime/mem_nacl.c
new file mode 100644
index 0000000..e2bca40
--- /dev/null
+++ b/src/pkg/runtime/mem_nacl.c
@@ -0,0 +1,118 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "malloc.h"
+
+enum
+{
+	Debug = 0,
+};
+
+void*
+runtime·SysAlloc(uintptr n, uint64 *stat)
+{
+	void *v;
+
+	v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
+	if(v < (void*)4096) {
+		if(Debug)
+			runtime·printf("SysAlloc(%p): %p\n", n, v);
+		return nil;
+	}
+	runtime·xadd64(stat, n);
+	if(Debug)
+		runtime·printf("SysAlloc(%p) = %p\n", n, v);
+	return v;
+}
+
+void
+runtime·SysUnused(void *v, uintptr n)
+{
+	if(Debug)
+		runtime·printf("SysUnused(%p, %p)\n", v, n);
+}
+
+void
+runtime·SysUsed(void *v, uintptr n)
+{
+	USED(v);
+	USED(n);
+}
+
+void
+runtime·SysFree(void *v, uintptr n, uint64 *stat)
+{
+	if(Debug)
+		runtime·printf("SysFree(%p, %p)\n", v, n);
+	runtime·xadd64(stat, -(uint64)n);
+	runtime·munmap(v, n);
+}
+
+void
+runtime·SysFault(void *v, uintptr n)
+{
+	runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
+void*
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
+{
+	void *p;
+
+	// On 64-bit, people with ulimit -v set complain if we reserve too
+	// much address space.  Instead, assume that the reservation is okay
+	// and check the assumption in SysMap.
+	if(NaCl || sizeof(void*) == 8) {
+		*reserved = false;
+		return v;
+	}
+	
+	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+	if(p < (void*)4096)
+		return nil;
+	*reserved = true;
+	return p;
+}
+
+void
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
+{
+	void *p;
+	
+	runtime·xadd64(stat, n);
+
+	// On 64-bit, we don't actually have v reserved, so tread carefully.
+	if(!reserved) {
+		p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
+		if(p == (void*)ENOMEM) {
+			runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
+			runtime·throw("runtime: out of memory");
+		}
+		if(p != v) {
+			runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
+			runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
+			runtime·throw("runtime: address space conflict");
+		}
+		if(Debug)
+			runtime·printf("SysMap(%p, %p) = %p\n", v, n, p);
+		return;
+	}
+
+	p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
+	if(p == (void*)ENOMEM) {
+		runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
+		runtime·throw("runtime: out of memory");
+	}
+	if(p != v) {
+		runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
+		runtime·printf("mmap MAP_FIXED %p returned %p\n", v, p);
+		runtime·throw("runtime: cannot map pages in arena address space");
+	}
+	if(Debug)
+		runtime·printf("SysMap(%p, %p) = %p\n", v, n, p);
+}
diff --git a/src/pkg/runtime/mem_netbsd.c b/src/pkg/runtime/mem_netbsd.c
index 91e36eb..861ae90 100644
--- a/src/pkg/runtime/mem_netbsd.c
+++ b/src/pkg/runtime/mem_netbsd.c
@@ -45,32 +45,41 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
 	runtime·munmap(v, n);
 }
 
+void
+runtime·SysFault(void *v, uintptr n)
+{
+	runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
 void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
 {
 	void *p;
 
 	// On 64-bit, people with ulimit -v set complain if we reserve too
 	// much address space.  Instead, assume that the reservation is okay
 	// and check the assumption in SysMap.
-	if(sizeof(void*) == 8)
+	if(sizeof(void*) == 8 && n > 1LL<<32) {
+		*reserved = false;
 		return v;
+	}
 
 	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
 	if(p < (void*)4096)
 		return nil;
+	*reserved = true;
 	return p;
 }
 
 void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
 {
 	void *p;
 	
 	runtime·xadd64(stat, n);
 
 	// On 64-bit, we don't actually have v reserved, so tread carefully.
-	if(sizeof(void*) == 8) {
+	if(!reserved) {
 		p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
 		if(p == (void*)ENOMEM)
 			runtime·throw("runtime: out of memory");
diff --git a/src/pkg/runtime/mem_openbsd.c b/src/pkg/runtime/mem_openbsd.c
index 91e36eb..861ae90 100644
--- a/src/pkg/runtime/mem_openbsd.c
+++ b/src/pkg/runtime/mem_openbsd.c
@@ -45,32 +45,41 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
 	runtime·munmap(v, n);
 }
 
+void
+runtime·SysFault(void *v, uintptr n)
+{
+	runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
 void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
 {
 	void *p;
 
 	// On 64-bit, people with ulimit -v set complain if we reserve too
 	// much address space.  Instead, assume that the reservation is okay
 	// and check the assumption in SysMap.
-	if(sizeof(void*) == 8)
+	if(sizeof(void*) == 8 && n > 1LL<<32) {
+		*reserved = false;
 		return v;
+	}
 
 	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
 	if(p < (void*)4096)
 		return nil;
+	*reserved = true;
 	return p;
 }
 
 void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
 {
 	void *p;
 	
 	runtime·xadd64(stat, n);
 
 	// On 64-bit, we don't actually have v reserved, so tread carefully.
-	if(sizeof(void*) == 8) {
+	if(!reserved) {
 		p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
 		if(p == (void*)ENOMEM)
 			runtime·throw("runtime: out of memory");
diff --git a/src/pkg/runtime/mem_plan9.c b/src/pkg/runtime/mem_plan9.c
index edf970b..bbf04c7 100644
--- a/src/pkg/runtime/mem_plan9.c
+++ b/src/pkg/runtime/mem_plan9.c
@@ -62,14 +62,21 @@ runtime·SysUsed(void *v, uintptr nbytes)
 }
 
 void
-runtime·SysMap(void *v, uintptr nbytes, uint64 *stat)
+runtime·SysMap(void *v, uintptr nbytes, bool reserved, uint64 *stat)
 {
-	USED(v, nbytes, stat);
+	USED(v, nbytes, reserved, stat);
+}
+
+void
+runtime·SysFault(void *v, uintptr nbytes)
+{
+	USED(v, nbytes);
 }
 
 void*
-runtime·SysReserve(void *v, uintptr nbytes)
+runtime·SysReserve(void *v, uintptr nbytes, bool *reserved)
 {
 	USED(v);
+	*reserved = true;
 	return runtime·SysAlloc(nbytes, &mstats.heap_sys);
 }
diff --git a/src/pkg/runtime/mem_solaris.c b/src/pkg/runtime/mem_solaris.c
new file mode 100644
index 0000000..0342228
--- /dev/null
+++ b/src/pkg/runtime/mem_solaris.c
@@ -0,0 +1,99 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "malloc.h"
+
+enum
+{
+	ENOMEM = 12,
+};
+
+void*
+runtime·SysAlloc(uintptr n, uint64 *stat)
+{
+	void *v;
+
+	v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
+	if(v < (void*)4096)
+		return nil;
+	runtime·xadd64(stat, n);
+	return v;
+}
+
+void
+runtime·SysUnused(void *v, uintptr n)
+{
+	USED(v);
+	USED(n);
+}
+
+void
+runtime·SysUsed(void *v, uintptr n)
+{
+	USED(v);
+	USED(n);
+}
+
+void
+runtime·SysFree(void *v, uintptr n, uint64 *stat)
+{
+	runtime·xadd64(stat, -(uint64)n);
+	runtime·munmap(v, n);
+}
+
+void
+runtime·SysFault(void *v, uintptr n)
+{
+	runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
+}
+
+void*
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
+{
+	void *p;
+
+	// On 64-bit, people with ulimit -v set complain if we reserve too
+	// much address space.  Instead, assume that the reservation is okay
+	// and check the assumption in SysMap.
+	if(sizeof(void*) == 8 && n > 1LL<<32) {
+		*reserved = false;
+		return v;
+	}
+	
+	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+	if(p < (void*)4096)
+		return nil;
+	*reserved = true;
+	return p;
+}
+
+void
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
+{
+	void *p;
+	
+	runtime·xadd64(stat, n);
+
+	// On 64-bit, we don't actually have v reserved, so tread carefully.
+	if(!reserved) {
+		p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
+		if(p == (void*)ENOMEM)
+			runtime·throw("runtime: out of memory");
+		if(p != v) {
+			runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
+			runtime·throw("runtime: address space conflict");
+		}
+		return;
+	}
+
+	p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
+	if(p == (void*)ENOMEM)
+		runtime·throw("runtime: out of memory");
+	if(p != v)
+		runtime·throw("runtime: cannot map pages in arena address space");
+}
diff --git a/src/pkg/runtime/mem_windows.c b/src/pkg/runtime/mem_windows.c
index abdc72a..77ec6e9 100644
--- a/src/pkg/runtime/mem_windows.c
+++ b/src/pkg/runtime/mem_windows.c
@@ -15,12 +15,15 @@ enum {
 	MEM_RELEASE = 0x8000,
 	
 	PAGE_READWRITE = 0x0004,
+	PAGE_NOACCESS = 0x0001,
 };
 
 #pragma dynimport runtime·VirtualAlloc VirtualAlloc "kernel32.dll"
 #pragma dynimport runtime·VirtualFree VirtualFree "kernel32.dll"
+#pragma dynimport runtime·VirtualProtect VirtualProtect "kernel32.dll"
 extern void *runtime·VirtualAlloc;
 extern void *runtime·VirtualFree;
+extern void *runtime·VirtualProtect;
 
 void*
 runtime·SysAlloc(uintptr n, uint64 *stat)
@@ -33,10 +36,30 @@ void
 runtime·SysUnused(void *v, uintptr n)
 {
 	void *r;
+	uintptr small;
 
 	r = runtime·stdcall(runtime·VirtualFree, 3, v, n, (uintptr)MEM_DECOMMIT);
-	if(r == nil)
-		runtime·throw("runtime: failed to decommit pages");
+	if(r != nil)
+		return;
+
+	// Decommit failed. Usual reason is that we've merged memory from two different
+	// VirtualAlloc calls, and Windows will only let each VirtualFree handle pages from
+	// a single VirtualAlloc. It is okay to specify a subset of the pages from a single alloc,
+	// just not pages from multiple allocs. This is a rare case, arising only when we're
+	// trying to give memory back to the operating system, which happens on a time
+	// scale of minutes. It doesn't have to be terribly fast. Instead of extra bookkeeping
+	// on all our VirtualAlloc calls, try freeing successively smaller pieces until
+	// we manage to free something, and then repeat. This ends up being O(n log n)
+	// in the worst case, but that's fast enough.
+	while(n > 0) {
+		small = n;
+		while(small >= 4096 && runtime·stdcall(runtime·VirtualFree, 3, v, small, (uintptr)MEM_DECOMMIT) == nil)
+			small = (small / 2) & ~(4096-1);
+		if(small < 4096)
+			runtime·throw("runtime: failed to decommit pages");
+		v = (byte*)v + small;
+		n -= small;
+	}
 }
 
 void
@@ -60,9 +83,17 @@ runtime·SysFree(void *v, uintptr n, uint64 *stat)
 		runtime·throw("runtime: failed to release pages");
 }
 
+void
+runtime·SysFault(void *v, uintptr n)
+{
+	// SysUnused makes the memory inaccessible and prevents its reuse
+	runtime·SysUnused(v, n);
+}
+
 void*
-runtime·SysReserve(void *v, uintptr n)
+runtime·SysReserve(void *v, uintptr n, bool *reserved)
 {
+	*reserved = true;
 	// v is just a hint.
 	// First try at v.
 	v = runtime·stdcall(runtime·VirtualAlloc, 4, v, n, (uintptr)MEM_RESERVE, (uintptr)PAGE_READWRITE);
@@ -74,10 +105,12 @@ runtime·SysReserve(void *v, uintptr n)
 }
 
 void
-runtime·SysMap(void *v, uintptr n, uint64 *stat)
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
 {
 	void *p;
-	
+
+	USED(reserved);
+
 	runtime·xadd64(stat, n);
 	p = runtime·stdcall(runtime·VirtualAlloc, 4, v, n, (uintptr)MEM_COMMIT, (uintptr)PAGE_READWRITE);
 	if(p != v)
diff --git a/src/pkg/runtime/memclr_386.s b/src/pkg/runtime/memclr_386.s
new file mode 100644
index 0000000..4b7580c
--- /dev/null
+++ b/src/pkg/runtime/memclr_386.s
@@ -0,0 +1,127 @@
+// 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 !plan9
+
+#include "../../cmd/ld/textflag.h"
+
+// void runtime·memclr(void*, uintptr)
+TEXT runtime·memclr(SB), NOSPLIT, $0-8
+	MOVL	ptr+0(FP), DI
+	MOVL	n+4(FP), BX
+	XORL	AX, AX
+
+	// MOVOU seems always faster than REP STOSL.
+clr_tail:
+	TESTL	BX, BX
+	JEQ	clr_0
+	CMPL	BX, $2
+	JBE	clr_1or2
+	CMPL	BX, $4
+	JBE	clr_3or4
+	CMPL	BX, $8
+	JBE	clr_5through8
+	CMPL	BX, $16
+	JBE	clr_9through16
+	TESTL	$0x4000000, runtime·cpuid_edx(SB) // check for sse2
+	JEQ	nosse2
+	PXOR	X0, X0
+	CMPL	BX, $32
+	JBE	clr_17through32
+	CMPL	BX, $64
+	JBE	clr_33through64
+	CMPL	BX, $128
+	JBE	clr_65through128
+	CMPL	BX, $256
+	JBE	clr_129through256
+	// TODO: use branch table and BSR to make this just a single dispatch
+
+clr_loop:
+	MOVOU	X0, 0(DI)
+	MOVOU	X0, 16(DI)
+	MOVOU	X0, 32(DI)
+	MOVOU	X0, 48(DI)
+	MOVOU	X0, 64(DI)
+	MOVOU	X0, 80(DI)
+	MOVOU	X0, 96(DI)
+	MOVOU	X0, 112(DI)
+	MOVOU	X0, 128(DI)
+	MOVOU	X0, 144(DI)
+	MOVOU	X0, 160(DI)
+	MOVOU	X0, 176(DI)
+	MOVOU	X0, 192(DI)
+	MOVOU	X0, 208(DI)
+	MOVOU	X0, 224(DI)
+	MOVOU	X0, 240(DI)
+	SUBL	$256, BX
+	ADDL	$256, DI
+	CMPL	BX, $256
+	JAE	clr_loop
+	JMP	clr_tail
+
+clr_1or2:
+	MOVB	AX, (DI)
+	MOVB	AX, -1(DI)(BX*1)
+clr_0:
+	RET
+clr_3or4:
+	MOVW	AX, (DI)
+	MOVW	AX, -2(DI)(BX*1)
+	RET
+clr_5through8:
+	MOVL	AX, (DI)
+	MOVL	AX, -4(DI)(BX*1)
+	RET
+clr_9through16:
+	MOVL	AX, (DI)
+	MOVL	AX, 4(DI)
+	MOVL	AX, -8(DI)(BX*1)
+	MOVL	AX, -4(DI)(BX*1)
+	RET
+clr_17through32:
+	MOVOU	X0, (DI)
+	MOVOU	X0, -16(DI)(BX*1)
+	RET
+clr_33through64:
+	MOVOU	X0, (DI)
+	MOVOU	X0, 16(DI)
+	MOVOU	X0, -32(DI)(BX*1)
+	MOVOU	X0, -16(DI)(BX*1)
+	RET
+clr_65through128:
+	MOVOU	X0, (DI)
+	MOVOU	X0, 16(DI)
+	MOVOU	X0, 32(DI)
+	MOVOU	X0, 48(DI)
+	MOVOU	X0, -64(DI)(BX*1)
+	MOVOU	X0, -48(DI)(BX*1)
+	MOVOU	X0, -32(DI)(BX*1)
+	MOVOU	X0, -16(DI)(BX*1)
+	RET
+clr_129through256:
+	MOVOU	X0, (DI)
+	MOVOU	X0, 16(DI)
+	MOVOU	X0, 32(DI)
+	MOVOU	X0, 48(DI)
+	MOVOU	X0, 64(DI)
+	MOVOU	X0, 80(DI)
+	MOVOU	X0, 96(DI)
+	MOVOU	X0, 112(DI)
+	MOVOU	X0, -128(DI)(BX*1)
+	MOVOU	X0, -112(DI)(BX*1)
+	MOVOU	X0, -96(DI)(BX*1)
+	MOVOU	X0, -80(DI)(BX*1)
+	MOVOU	X0, -64(DI)(BX*1)
+	MOVOU	X0, -48(DI)(BX*1)
+	MOVOU	X0, -32(DI)(BX*1)
+	MOVOU	X0, -16(DI)(BX*1)
+	RET
+nosse2:
+	MOVL	BX, CX
+	SHRL	$2, CX
+	REP
+	STOSL
+	ANDL	$3, BX
+	JNE	clr_tail
+	RET
diff --git a/src/pkg/runtime/memclr_amd64.s b/src/pkg/runtime/memclr_amd64.s
new file mode 100644
index 0000000..6b79363
--- /dev/null
+++ b/src/pkg/runtime/memclr_amd64.s
@@ -0,0 +1,116 @@
+// 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 !plan9
+
+#include "../../cmd/ld/textflag.h"
+
+// void runtime·memclr(void*, uintptr)
+TEXT runtime·memclr(SB), NOSPLIT, $0-16
+	MOVQ	ptr+0(FP), DI
+	MOVQ	n+8(FP), BX
+	XORQ	AX, AX
+
+	// MOVOU seems always faster than REP STOSQ.
+clr_tail:
+	TESTQ	BX, BX
+	JEQ	clr_0
+	CMPQ	BX, $2
+	JBE	clr_1or2
+	CMPQ	BX, $4
+	JBE	clr_3or4
+	CMPQ	BX, $8
+	JBE	clr_5through8
+	CMPQ	BX, $16
+	JBE	clr_9through16
+	PXOR	X0, X0
+	CMPQ	BX, $32
+	JBE	clr_17through32
+	CMPQ	BX, $64
+	JBE	clr_33through64
+	CMPQ	BX, $128
+	JBE	clr_65through128
+	CMPQ	BX, $256
+	JBE	clr_129through256
+	// TODO: use branch table and BSR to make this just a single dispatch
+	// TODO: for really big clears, use MOVNTDQ.
+
+clr_loop:
+	MOVOU	X0, 0(DI)
+	MOVOU	X0, 16(DI)
+	MOVOU	X0, 32(DI)
+	MOVOU	X0, 48(DI)
+	MOVOU	X0, 64(DI)
+	MOVOU	X0, 80(DI)
+	MOVOU	X0, 96(DI)
+	MOVOU	X0, 112(DI)
+	MOVOU	X0, 128(DI)
+	MOVOU	X0, 144(DI)
+	MOVOU	X0, 160(DI)
+	MOVOU	X0, 176(DI)
+	MOVOU	X0, 192(DI)
+	MOVOU	X0, 208(DI)
+	MOVOU	X0, 224(DI)
+	MOVOU	X0, 240(DI)
+	SUBQ	$256, BX
+	ADDQ	$256, DI
+	CMPQ	BX, $256
+	JAE	clr_loop
+	JMP	clr_tail
+
+clr_1or2:
+	MOVB	AX, (DI)
+	MOVB	AX, -1(DI)(BX*1)
+clr_0:
+	RET
+clr_3or4:
+	MOVW	AX, (DI)
+	MOVW	AX, -2(DI)(BX*1)
+	RET
+clr_5through8:
+	MOVL	AX, (DI)
+	MOVL	AX, -4(DI)(BX*1)
+	RET
+clr_9through16:
+	MOVQ	AX, (DI)
+	MOVQ	AX, -8(DI)(BX*1)
+	RET
+clr_17through32:
+	MOVOU	X0, (DI)
+	MOVOU	X0, -16(DI)(BX*1)
+	RET
+clr_33through64:
+	MOVOU	X0, (DI)
+	MOVOU	X0, 16(DI)
+	MOVOU	X0, -32(DI)(BX*1)
+	MOVOU	X0, -16(DI)(BX*1)
+	RET
+clr_65through128:
+	MOVOU	X0, (DI)
+	MOVOU	X0, 16(DI)
+	MOVOU	X0, 32(DI)
+	MOVOU	X0, 48(DI)
+	MOVOU	X0, -64(DI)(BX*1)
+	MOVOU	X0, -48(DI)(BX*1)
+	MOVOU	X0, -32(DI)(BX*1)
+	MOVOU	X0, -16(DI)(BX*1)
+	RET
+clr_129through256:
+	MOVOU	X0, (DI)
+	MOVOU	X0, 16(DI)
+	MOVOU	X0, 32(DI)
+	MOVOU	X0, 48(DI)
+	MOVOU	X0, 64(DI)
+	MOVOU	X0, 80(DI)
+	MOVOU	X0, 96(DI)
+	MOVOU	X0, 112(DI)
+	MOVOU	X0, -128(DI)(BX*1)
+	MOVOU	X0, -112(DI)(BX*1)
+	MOVOU	X0, -96(DI)(BX*1)
+	MOVOU	X0, -80(DI)(BX*1)
+	MOVOU	X0, -64(DI)(BX*1)
+	MOVOU	X0, -48(DI)(BX*1)
+	MOVOU	X0, -32(DI)(BX*1)
+	MOVOU	X0, -16(DI)(BX*1)
+	RET
diff --git a/src/pkg/runtime/memclr_arm.s b/src/pkg/runtime/memclr_arm.s
index d5ff75d..b19ea72 100644
--- a/src/pkg/runtime/memclr_arm.s
+++ b/src/pkg/runtime/memclr_arm.s
@@ -40,12 +40,6 @@ TEXT runtime·memclr(SB),NOSPLIT,$0-8
 	CMP	$4, R(N)		/* need at least 4 bytes to copy */
 	BLT	_1tail
 
-	AND	$0xFF, R(0)		/* it's a byte */
-	SLL	$8, R(0), R(TMP)	/* replicate to a word */
-	ORR	R(TMP), R(0)
-	SLL	$16, R(0), R(TMP)
-	ORR	R(TMP), R(0)
-
 _4align:				/* align on 4 */
 	AND.S	$3, R(TO), R(TMP)
 	BEQ	_4aligned
diff --git a/src/pkg/runtime/memclr_plan9_386.s b/src/pkg/runtime/memclr_plan9_386.s
new file mode 100644
index 0000000..9b49678
--- /dev/null
+++ b/src/pkg/runtime/memclr_plan9_386.s
@@ -0,0 +1,50 @@
+// 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 "../../cmd/ld/textflag.h"
+
+// void runtime·memclr(void*, uintptr)
+TEXT runtime·memclr(SB), NOSPLIT, $0-8
+	MOVL	ptr+0(FP), DI
+	MOVL	n+4(FP), BX
+	XORL	AX, AX
+
+clr_tail:
+	TESTL	BX, BX
+	JEQ	clr_0
+	CMPL	BX, $2
+	JBE	clr_1or2
+	CMPL	BX, $4
+	JBE	clr_3or4
+	CMPL	BX, $8
+	JBE	clr_5through8
+	CMPL	BX, $16
+	JBE	clr_9through16
+	MOVL	BX, CX
+	SHRL	$2, CX
+	REP
+	STOSL
+	ANDL	$3, BX
+	JNE	clr_tail
+	RET
+
+clr_1or2:
+	MOVB	AX, (DI)
+	MOVB	AX, -1(DI)(BX*1)
+clr_0:
+	RET
+clr_3or4:
+	MOVW	AX, (DI)
+	MOVW	AX, -2(DI)(BX*1)
+	RET
+clr_5through8:
+	MOVL	AX, (DI)
+	MOVL	AX, -4(DI)(BX*1)
+	RET
+clr_9through16:
+	MOVL	AX, (DI)
+	MOVL	AX, 4(DI)
+	MOVL	AX, -8(DI)(BX*1)
+	MOVL	AX, -4(DI)(BX*1)
+	RET
diff --git a/src/pkg/runtime/memclr_plan9_amd64.s b/src/pkg/runtime/memclr_plan9_amd64.s
new file mode 100644
index 0000000..6b33054
--- /dev/null
+++ b/src/pkg/runtime/memclr_plan9_amd64.s
@@ -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.
+
+#include "../../cmd/ld/textflag.h"
+
+// void runtime·memclr(void*, uintptr)
+TEXT runtime·memclr(SB), NOSPLIT, $0-16
+	MOVQ	ptr+0(FP), DI
+	MOVQ	n+8(FP), BX
+	XORQ	AX, AX
+
+clr_tail:
+	TESTQ	BX, BX
+	JEQ	clr_0
+	CMPQ	BX, $2
+	JBE	clr_1or2
+	CMPQ	BX, $4
+	JBE	clr_3or4
+	CMPQ	BX, $8
+	JBE	clr_5through8
+	CMPQ	BX, $16
+	JBE	clr_9through16
+	MOVQ	BX, CX
+	SHRQ	$2, CX
+	REP
+	STOSQ
+	ANDQ	$3, BX
+	JNE	clr_tail
+	RET
+
+clr_1or2:
+	MOVB	AX, (DI)
+	MOVB	AX, -1(DI)(BX*1)
+clr_0:
+	RET
+clr_3or4:
+	MOVW	AX, (DI)
+	MOVW	AX, -2(DI)(BX*1)
+	RET
+clr_5through8:
+	MOVL	AX, (DI)
+	MOVL	AX, -4(DI)(BX*1)
+	RET
+clr_9through16:
+	MOVQ	AX, (DI)
+	MOVQ	AX, -8(DI)(BX*1)
+	RET
diff --git a/src/pkg/runtime/memmove_386.s b/src/pkg/runtime/memmove_386.s
index 13d5759..3aed8ad 100644
--- a/src/pkg/runtime/memmove_386.s
+++ b/src/pkg/runtime/memmove_386.s
@@ -23,6 +23,8 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+// +build !plan9
+
 #include "../../cmd/ld/textflag.h"
 
 TEXT runtime·memmove(SB), NOSPLIT, $0-12
diff --git a/src/pkg/runtime/memmove_amd64.s b/src/pkg/runtime/memmove_amd64.s
index f1641cd..5895846 100644
--- a/src/pkg/runtime/memmove_amd64.s
+++ b/src/pkg/runtime/memmove_amd64.s
@@ -23,6 +23,8 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+// +build !plan9
+
 #include "../../cmd/ld/textflag.h"
 
 // void runtime·memmove(void*, void*, uintptr)
diff --git a/src/pkg/runtime/memmove_nacl_amd64p32.s b/src/pkg/runtime/memmove_nacl_amd64p32.s
new file mode 100644
index 0000000..1b57331
--- /dev/null
+++ b/src/pkg/runtime/memmove_nacl_amd64p32.s
@@ -0,0 +1,46 @@
+// 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 "../../cmd/ld/textflag.h"
+
+TEXT runtime·memmove(SB), NOSPLIT, $0-12
+	MOVL	to+0(FP), DI
+	MOVL	fr+4(FP), SI
+	MOVL	n+8(FP), BX
+
+	CMPL	SI, DI
+	JLS back
+
+forward:
+	MOVL	BX, CX
+	SHRL	$3, CX
+	ANDL	$7, BX
+	REP; MOVSQ
+	MOVL	BX, CX
+	REP; MOVSB
+	RET
+
+back:
+	MOVL	SI, CX
+	ADDL	BX, CX
+	CMPL	CX, DI
+	JLS forward
+
+	ADDL	BX, DI
+	ADDL	BX, SI
+	STD
+	
+	MOVL	BX, CX
+	SHRL	$3, CX
+	ANDL	$7, BX
+	SUBL	$8, DI
+	SUBL	$8, SI
+	REP; MOVSQ
+	ADDL	$7, DI
+	ADDL	$7, SI
+	MOVL	BX, CX
+	REP; MOVSB
+	CLD
+
+	RET
diff --git a/src/pkg/runtime/memmove_plan9_386.s b/src/pkg/runtime/memmove_plan9_386.s
new file mode 100644
index 0000000..187616c
--- /dev/null
+++ b/src/pkg/runtime/memmove_plan9_386.s
@@ -0,0 +1,127 @@
+// Inferno's libkern/memmove-386.s
+// http://code.google.com/p/inferno-os/source/browse/libkern/memmove-386.s
+//
+//         Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//         Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  All rights reserved.
+//         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 "../../cmd/ld/textflag.h"
+
+TEXT runtime·memmove(SB), NOSPLIT, $0-12
+	MOVL	to+0(FP), DI
+	MOVL	fr+4(FP), SI
+	MOVL	n+8(FP), BX
+
+	// REP instructions have a high startup cost, so we handle small sizes
+	// with some straightline code.  The REP MOVSL instruction is really fast
+	// for large sizes.  The cutover is approximately 1K.
+tail:
+	TESTL	BX, BX
+	JEQ	move_0
+	CMPL	BX, $2
+	JBE	move_1or2
+	CMPL	BX, $4
+	JBE	move_3or4
+	CMPL	BX, $8
+	JBE	move_5through8
+	CMPL	BX, $16
+	JBE	move_9through16
+
+/*
+ * check and set for backwards
+ */
+	CMPL	SI, DI
+	JLS	back
+
+/*
+ * forward copy loop
+ */
+forward:	
+	MOVL	BX, CX
+	SHRL	$2, CX
+	ANDL	$3, BX
+
+	REP;	MOVSL
+	JMP	tail
+/*
+ * check overlap
+ */
+back:
+	MOVL	SI, CX
+	ADDL	BX, CX
+	CMPL	CX, DI
+	JLS	forward
+/*
+ * whole thing backwards has
+ * adjusted addresses
+ */
+
+	ADDL	BX, DI
+	ADDL	BX, SI
+	STD
+
+/*
+ * copy
+ */
+	MOVL	BX, CX
+	SHRL	$2, CX
+	ANDL	$3, BX
+
+	SUBL	$4, DI
+	SUBL	$4, SI
+	REP;	MOVSL
+
+	CLD
+	ADDL	$4, DI
+	ADDL	$4, SI
+	SUBL	BX, DI
+	SUBL	BX, SI
+	JMP	tail
+
+move_1or2:
+	MOVB	(SI), AX
+	MOVB	-1(SI)(BX*1), CX
+	MOVB	AX, (DI)
+	MOVB	CX, -1(DI)(BX*1)
+move_0:
+	RET
+move_3or4:
+	MOVW	(SI), AX
+	MOVW	-2(SI)(BX*1), CX
+	MOVW	AX, (DI)
+	MOVW	CX, -2(DI)(BX*1)
+	RET
+move_5through8:
+	MOVL	(SI), AX
+	MOVL	-4(SI)(BX*1), CX
+	MOVL	AX, (DI)
+	MOVL	CX, -4(DI)(BX*1)
+	RET
+move_9through16:
+	MOVL	(SI), AX
+	MOVL	4(SI), CX
+	MOVL	-8(SI)(BX*1), DX
+	MOVL	-4(SI)(BX*1), BP
+	MOVL	AX, (DI)
+	MOVL	CX, 4(DI)
+	MOVL	DX, -8(DI)(BX*1)
+	MOVL	BP, -4(DI)(BX*1)
+	RET
diff --git a/src/pkg/runtime/memmove_plan9_amd64.s b/src/pkg/runtime/memmove_plan9_amd64.s
new file mode 100644
index 0000000..6010827
--- /dev/null
+++ b/src/pkg/runtime/memmove_plan9_amd64.s
@@ -0,0 +1,126 @@
+// Derived from Inferno's libkern/memmove-386.s (adapted for amd64)
+// http://code.google.com/p/inferno-os/source/browse/libkern/memmove-386.s
+//
+//         Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//         Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  All rights reserved.
+//         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 "../../cmd/ld/textflag.h"
+
+// void runtime·memmove(void*, void*, uintptr)
+TEXT runtime·memmove(SB), NOSPLIT, $0-24
+
+	MOVQ	to+0(FP), DI
+	MOVQ	fr+8(FP), SI
+	MOVQ	n+16(FP), BX
+
+	// REP instructions have a high startup cost, so we handle small sizes
+	// with some straightline code.  The REP MOVSQ instruction is really fast
+	// for large sizes.  The cutover is approximately 1K.
+tail:
+	TESTQ	BX, BX
+	JEQ	move_0
+	CMPQ	BX, $2
+	JBE	move_1or2
+	CMPQ	BX, $4
+	JBE	move_3or4
+	CMPQ	BX, $8
+	JBE	move_5through8
+	CMPQ	BX, $16
+	JBE	move_9through16
+
+/*
+ * check and set for backwards
+ */
+	CMPQ	SI, DI
+	JLS	back
+
+/*
+ * forward copy loop
+ */
+forward:
+	MOVQ	BX, CX
+	SHRQ	$3, CX
+	ANDQ	$7, BX
+
+	REP;	MOVSQ
+	JMP	tail
+
+back:
+/*
+ * check overlap
+ */
+	MOVQ	SI, CX
+	ADDQ	BX, CX
+	CMPQ	CX, DI
+	JLS	forward
+	
+/*
+ * whole thing backwards has
+ * adjusted addresses
+ */
+	ADDQ	BX, DI
+	ADDQ	BX, SI
+	STD
+
+/*
+ * copy
+ */
+	MOVQ	BX, CX
+	SHRQ	$3, CX
+	ANDQ	$7, BX
+
+	SUBQ	$8, DI
+	SUBQ	$8, SI
+	REP;	MOVSQ
+
+	CLD
+	ADDQ	$8, DI
+	ADDQ	$8, SI
+	SUBQ	BX, DI
+	SUBQ	BX, SI
+	JMP	tail
+
+move_1or2:
+	MOVB	(SI), AX
+	MOVB	-1(SI)(BX*1), CX
+	MOVB	AX, (DI)
+	MOVB	CX, -1(DI)(BX*1)
+move_0:
+	RET
+move_3or4:
+	MOVW	(SI), AX
+	MOVW	-2(SI)(BX*1), CX
+	MOVW	AX, (DI)
+	MOVW	CX, -2(DI)(BX*1)
+	RET
+move_5through8:
+	MOVL	(SI), AX
+	MOVL	-4(SI)(BX*1), CX
+	MOVL	AX, (DI)
+	MOVL	CX, -4(DI)(BX*1)
+	RET
+move_9through16:
+	MOVQ	(SI), AX
+	MOVQ	-8(SI)(BX*1), CX
+	MOVQ	AX, (DI)
+	MOVQ	CX, -8(DI)(BX*1)
+	RET
diff --git a/src/pkg/runtime/memmove_test.go b/src/pkg/runtime/memmove_test.go
index 9525f06..540f0fe 100644
--- a/src/pkg/runtime/memmove_test.go
+++ b/src/pkg/runtime/memmove_test.go
@@ -5,6 +5,7 @@
 package runtime_test
 
 import (
+	. "runtime"
 	"testing"
 )
 
@@ -80,7 +81,7 @@ func TestMemmoveAlias(t *testing.T) {
 	}
 }
 
-func bmMemmove(n int, b *testing.B) {
+func bmMemmove(b *testing.B, n int) {
 	x := make([]byte, n)
 	y := make([]byte, n)
 	b.SetBytes(int64(n))
@@ -89,28 +90,154 @@ func bmMemmove(n int, b *testing.B) {
 	}
 }
 
-func BenchmarkMemmove0(b *testing.B)    { bmMemmove(0, b) }
-func BenchmarkMemmove1(b *testing.B)    { bmMemmove(1, b) }
-func BenchmarkMemmove2(b *testing.B)    { bmMemmove(2, b) }
-func BenchmarkMemmove3(b *testing.B)    { bmMemmove(3, b) }
-func BenchmarkMemmove4(b *testing.B)    { bmMemmove(4, b) }
-func BenchmarkMemmove5(b *testing.B)    { bmMemmove(5, b) }
-func BenchmarkMemmove6(b *testing.B)    { bmMemmove(6, b) }
-func BenchmarkMemmove7(b *testing.B)    { bmMemmove(7, b) }
-func BenchmarkMemmove8(b *testing.B)    { bmMemmove(8, b) }
-func BenchmarkMemmove9(b *testing.B)    { bmMemmove(9, b) }
-func BenchmarkMemmove10(b *testing.B)   { bmMemmove(10, b) }
-func BenchmarkMemmove11(b *testing.B)   { bmMemmove(11, b) }
-func BenchmarkMemmove12(b *testing.B)   { bmMemmove(12, b) }
-func BenchmarkMemmove13(b *testing.B)   { bmMemmove(13, b) }
-func BenchmarkMemmove14(b *testing.B)   { bmMemmove(14, b) }
-func BenchmarkMemmove15(b *testing.B)   { bmMemmove(15, b) }
-func BenchmarkMemmove16(b *testing.B)   { bmMemmove(16, b) }
-func BenchmarkMemmove32(b *testing.B)   { bmMemmove(32, b) }
-func BenchmarkMemmove64(b *testing.B)   { bmMemmove(64, b) }
-func BenchmarkMemmove128(b *testing.B)  { bmMemmove(128, b) }
-func BenchmarkMemmove256(b *testing.B)  { bmMemmove(256, b) }
-func BenchmarkMemmove512(b *testing.B)  { bmMemmove(512, b) }
-func BenchmarkMemmove1024(b *testing.B) { bmMemmove(1024, b) }
-func BenchmarkMemmove2048(b *testing.B) { bmMemmove(2048, b) }
-func BenchmarkMemmove4096(b *testing.B) { bmMemmove(4096, b) }
+func BenchmarkMemmove0(b *testing.B)    { bmMemmove(b, 0) }
+func BenchmarkMemmove1(b *testing.B)    { bmMemmove(b, 1) }
+func BenchmarkMemmove2(b *testing.B)    { bmMemmove(b, 2) }
+func BenchmarkMemmove3(b *testing.B)    { bmMemmove(b, 3) }
+func BenchmarkMemmove4(b *testing.B)    { bmMemmove(b, 4) }
+func BenchmarkMemmove5(b *testing.B)    { bmMemmove(b, 5) }
+func BenchmarkMemmove6(b *testing.B)    { bmMemmove(b, 6) }
+func BenchmarkMemmove7(b *testing.B)    { bmMemmove(b, 7) }
+func BenchmarkMemmove8(b *testing.B)    { bmMemmove(b, 8) }
+func BenchmarkMemmove9(b *testing.B)    { bmMemmove(b, 9) }
+func BenchmarkMemmove10(b *testing.B)   { bmMemmove(b, 10) }
+func BenchmarkMemmove11(b *testing.B)   { bmMemmove(b, 11) }
+func BenchmarkMemmove12(b *testing.B)   { bmMemmove(b, 12) }
+func BenchmarkMemmove13(b *testing.B)   { bmMemmove(b, 13) }
+func BenchmarkMemmove14(b *testing.B)   { bmMemmove(b, 14) }
+func BenchmarkMemmove15(b *testing.B)   { bmMemmove(b, 15) }
+func BenchmarkMemmove16(b *testing.B)   { bmMemmove(b, 16) }
+func BenchmarkMemmove32(b *testing.B)   { bmMemmove(b, 32) }
+func BenchmarkMemmove64(b *testing.B)   { bmMemmove(b, 64) }
+func BenchmarkMemmove128(b *testing.B)  { bmMemmove(b, 128) }
+func BenchmarkMemmove256(b *testing.B)  { bmMemmove(b, 256) }
+func BenchmarkMemmove512(b *testing.B)  { bmMemmove(b, 512) }
+func BenchmarkMemmove1024(b *testing.B) { bmMemmove(b, 1024) }
+func BenchmarkMemmove2048(b *testing.B) { bmMemmove(b, 2048) }
+func BenchmarkMemmove4096(b *testing.B) { bmMemmove(b, 4096) }
+
+func TestMemclr(t *testing.T) {
+	size := 512
+	if testing.Short() {
+		size = 128 + 16
+	}
+	mem := make([]byte, size)
+	for i := 0; i < size; i++ {
+		mem[i] = 0xee
+	}
+	for n := 0; n < size; n++ {
+		for x := 0; x <= size-n; x++ { // offset in mem
+			MemclrBytes(mem[x : x+n])
+			for i := 0; i < x; i++ {
+				if mem[i] != 0xee {
+					t.Fatalf("overwrite prefix mem[%d] = %d", i, mem[i])
+				}
+			}
+			for i := x; i < x+n; i++ {
+				if mem[i] != 0 {
+					t.Fatalf("failed clear mem[%d] = %d", i, mem[i])
+				}
+				mem[i] = 0xee
+			}
+			for i := x + n; i < size; i++ {
+				if mem[i] != 0xee {
+					t.Fatalf("overwrite suffix mem[%d] = %d", i, mem[i])
+				}
+			}
+		}
+	}
+}
+
+func bmMemclr(b *testing.B, n int) {
+	x := make([]byte, n)
+	b.SetBytes(int64(n))
+	for i := 0; i < b.N; i++ {
+		MemclrBytes(x)
+	}
+}
+func BenchmarkMemclr5(b *testing.B)     { bmMemclr(b, 5) }
+func BenchmarkMemclr16(b *testing.B)    { bmMemclr(b, 16) }
+func BenchmarkMemclr64(b *testing.B)    { bmMemclr(b, 64) }
+func BenchmarkMemclr256(b *testing.B)   { bmMemclr(b, 256) }
+func BenchmarkMemclr4096(b *testing.B)  { bmMemclr(b, 4096) }
+func BenchmarkMemclr65536(b *testing.B) { bmMemclr(b, 65536) }
+
+func BenchmarkClearFat32(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		var x [32]byte
+		_ = x
+	}
+}
+func BenchmarkClearFat64(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		var x [64]byte
+		_ = x
+	}
+}
+func BenchmarkClearFat128(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		var x [128]byte
+		_ = x
+	}
+}
+func BenchmarkClearFat256(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		var x [256]byte
+		_ = x
+	}
+}
+func BenchmarkClearFat512(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		var x [512]byte
+		_ = x
+	}
+}
+func BenchmarkClearFat1024(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		var x [1024]byte
+		_ = x
+	}
+}
+
+func BenchmarkCopyFat32(b *testing.B) {
+	var x [32 / 4]uint32
+	for i := 0; i < b.N; i++ {
+		y := x
+		_ = y
+	}
+}
+func BenchmarkCopyFat64(b *testing.B) {
+	var x [64 / 4]uint32
+	for i := 0; i < b.N; i++ {
+		y := x
+		_ = y
+	}
+}
+func BenchmarkCopyFat128(b *testing.B) {
+	var x [128 / 4]uint32
+	for i := 0; i < b.N; i++ {
+		y := x
+		_ = y
+	}
+}
+func BenchmarkCopyFat256(b *testing.B) {
+	var x [256 / 4]uint32
+	for i := 0; i < b.N; i++ {
+		y := x
+		_ = y
+	}
+}
+func BenchmarkCopyFat512(b *testing.B) {
+	var x [512 / 4]uint32
+	for i := 0; i < b.N; i++ {
+		y := x
+		_ = y
+	}
+}
+func BenchmarkCopyFat1024(b *testing.B) {
+	var x [1024 / 4]uint32
+	for i := 0; i < b.N; i++ {
+		y := x
+		_ = y
+	}
+}
diff --git a/src/pkg/runtime/mfinal.c b/src/pkg/runtime/mfinal.c
deleted file mode 100644
index 3e524d3..0000000
--- a/src/pkg/runtime/mfinal.c
+++ /dev/null
@@ -1,219 +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.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "type.h"
-
-enum { debug = 0 };
-
-typedef struct Fin Fin;
-struct Fin
-{
-	FuncVal *fn;
-	uintptr nret;
-	Type *fint;
-	PtrType *ot;
-};
-
-// Finalizer hash table.  Direct hash, linear scan, at most 3/4 full.
-// Table size is power of 3 so that hash can be key % max.
-// Key[i] == (void*)-1 denotes free but formerly occupied entry
-// (doesn't stop the linear scan).
-// Key and val are separate tables because the garbage collector
-// must be instructed to ignore the pointers in key but follow the
-// pointers in val.
-typedef struct Fintab Fintab;
-struct Fintab
-{
-	Lock;
-	void **key;
-	Fin *val;
-	int32 nkey;	// number of non-nil entries in key
-	int32 ndead;	// number of dead (-1) entries in key
-	int32 max;	// size of key, val allocations
-};
-
-#define TABSZ 17
-#define TAB(p) (&fintab[((uintptr)(p)>>3)%TABSZ])
-
-static struct {
-	Fintab;
-	uint8 pad[CacheLineSize - sizeof(Fintab)];	
-} fintab[TABSZ];
-
-static void
-addfintab(Fintab *t, void *k, FuncVal *fn, uintptr nret, Type *fint, PtrType *ot)
-{
-	int32 i, j;
-
-	i = (uintptr)k % (uintptr)t->max;
-	for(j=0; j<t->max; j++) {
-		if(t->key[i] == nil) {
-			t->nkey++;
-			goto ret;
-		}
-		if(t->key[i] == (void*)-1) {
-			t->ndead--;
-			goto ret;
-		}
-		if(++i == t->max)
-			i = 0;
-	}
-
-	// cannot happen - table is known to be non-full
-	runtime·throw("finalizer table inconsistent");
-
-ret:
-	t->key[i] = k;
-	t->val[i].fn = fn;
-	t->val[i].nret = nret;
-	t->val[i].fint = fint;
-	t->val[i].ot = ot;
-}
-
-static bool
-lookfintab(Fintab *t, void *k, bool del, Fin *f)
-{
-	int32 i, j;
-
-	if(t->max == 0)
-		return false;
-	i = (uintptr)k % (uintptr)t->max;
-	for(j=0; j<t->max; j++) {
-		if(t->key[i] == nil)
-			return false;
-		if(t->key[i] == k) {
-			if(f)
-				*f = t->val[i];
-			if(del) {
-				t->key[i] = (void*)-1;
-				t->val[i].fn = nil;
-				t->val[i].nret = 0;
-				t->val[i].ot = nil;
-				t->ndead++;
-			}
-			return true;
-		}
-		if(++i == t->max)
-			i = 0;
-	}
-
-	// cannot happen - table is known to be non-full
-	runtime·throw("finalizer table inconsistent");
-	return false;
-}
-
-static void
-resizefintab(Fintab *tab)
-{
-	Fintab newtab;
-	void *k;
-	int32 i;
-
-	runtime·memclr((byte*)&newtab, sizeof newtab);
-	newtab.max = tab->max;
-	if(newtab.max == 0)
-		newtab.max = 3*3*3;
-	else if(tab->ndead < tab->nkey/2) {
-		// grow table if not many dead values.
-		// otherwise just rehash into table of same size.
-		newtab.max *= 3;
-	}
-	
-	newtab.key = runtime·mallocgc(newtab.max*sizeof newtab.key[0], 0, FlagNoInvokeGC|FlagNoScan);
-	newtab.val = runtime·mallocgc(newtab.max*sizeof newtab.val[0], 0, FlagNoInvokeGC);
-	
-	for(i=0; i<tab->max; i++) {
-		k = tab->key[i];
-		if(k != nil && k != (void*)-1)
-			addfintab(&newtab, k, tab->val[i].fn, tab->val[i].nret, tab->val[i].fint, tab->val[i].ot);
-	}
-	
-	runtime·free(tab->key);
-	runtime·free(tab->val);
-	
-	tab->key = newtab.key;
-	tab->val = newtab.val;
-	tab->nkey = newtab.nkey;
-	tab->ndead = newtab.ndead;
-	tab->max = newtab.max;
-}
-
-bool
-runtime·addfinalizer(void *p, FuncVal *f, uintptr nret, Type *fint, PtrType *ot)
-{
-	Fintab *tab;
-	byte *base;
-	
-	if(debug) {
-		if(!runtime·mlookup(p, &base, nil, nil) || p != base)
-			runtime·throw("addfinalizer on invalid pointer");
-	}
-	
-	tab = TAB(p);
-	runtime·lock(tab);
-	if(f == nil) {
-		lookfintab(tab, p, true, nil);
-		runtime·unlock(tab);
-		return true;
-	}
-
-	if(lookfintab(tab, p, false, nil)) {
-		runtime·unlock(tab);
-		return false;
-	}
-
-	if(tab->nkey >= tab->max/2+tab->max/4) {
-		// keep table at most 3/4 full:
-		// allocate new table and rehash.
-		resizefintab(tab);
-	}
-
-	addfintab(tab, p, f, nret, fint, ot);
-	runtime·setblockspecial(p, true);
-	runtime·unlock(tab);
-	return true;
-}
-
-// get finalizer; if del, delete finalizer.
-// caller is responsible for updating RefHasFinalizer (special) bit.
-bool
-runtime·getfinalizer(void *p, bool del, FuncVal **fn, uintptr *nret, Type **fint, PtrType **ot)
-{
-	Fintab *tab;
-	bool res;
-	Fin f;
-	
-	tab = TAB(p);
-	runtime·lock(tab);
-	res = lookfintab(tab, p, del, &f);
-	runtime·unlock(tab);
-	if(res==false)
-		return false;
-	*fn = f.fn;
-	*nret = f.nret;
-	*fint = f.fint;
-	*ot = f.ot;
-	return true;
-}
-
-void
-runtime·walkfintab(void (*fn)(void*))
-{
-	void **key;
-	void **ekey;
-	int32 i;
-
-	for(i=0; i<TABSZ; i++) {
-		runtime·lock(&fintab[i]);
-		key = fintab[i].key;
-		ekey = key + fintab[i].max;
-		for(; key < ekey; key++)
-			if(*key != nil && *key != ((void*)-1))
-				fn(*key);
-		runtime·unlock(&fintab[i]);
-	}
-}
diff --git a/src/pkg/runtime/mfinal_test.go b/src/pkg/runtime/mfinal_test.go
index 6efef9b..6b53888 100644
--- a/src/pkg/runtime/mfinal_test.go
+++ b/src/pkg/runtime/mfinal_test.go
@@ -6,10 +6,9 @@ package runtime_test
 
 import (
 	"runtime"
-	"sync"
-	"sync/atomic"
 	"testing"
 	"time"
+	"unsafe"
 )
 
 type Tintptr *int // assignable to *int
@@ -46,13 +45,15 @@ func TestFinalizerType(t *testing.T) {
 	}
 
 	for _, tt := range finalizerTests {
+		done := make(chan bool, 1)
 		go func() {
 			v := new(int)
 			*v = 97531
 			runtime.SetFinalizer(tt.convert(v), tt.finalizer)
 			v = nil
+			done <- true
 		}()
-		time.Sleep(1 * time.Second)
+		<-done
 		runtime.GC()
 		select {
 		case <-ch:
@@ -73,6 +74,7 @@ func TestFinalizerInterfaceBig(t *testing.T) {
 		t.Skipf("Skipping on non-amd64 machine")
 	}
 	ch := make(chan bool)
+	done := make(chan bool, 1)
 	go func() {
 		v := &bigValue{0xDEADBEEFDEADBEEF, true, "It matters not how strait the gate"}
 		old := *v
@@ -87,8 +89,9 @@ func TestFinalizerInterfaceBig(t *testing.T) {
 			close(ch)
 		})
 		v = nil
+		done <- true
 	}()
-	time.Sleep(1 * time.Second)
+	<-done
 	runtime.GC()
 	select {
 	case <-ch:
@@ -100,51 +103,137 @@ func TestFinalizerInterfaceBig(t *testing.T) {
 func fin(v *int) {
 }
 
+// Verify we don't crash at least. golang.org/issue/6857
+func TestFinalizerZeroSizedStruct(t *testing.T) {
+	type Z struct{}
+	z := new(Z)
+	runtime.SetFinalizer(z, func(*Z) {})
+}
+
 func BenchmarkFinalizer(b *testing.B) {
-	const CallsPerSched = 1000
-	procs := runtime.GOMAXPROCS(-1)
-	N := int32(b.N / CallsPerSched)
-	var wg sync.WaitGroup
-	wg.Add(procs)
-	for p := 0; p < procs; p++ {
-		go func() {
-			var data [CallsPerSched]*int
-			for i := 0; i < CallsPerSched; i++ {
-				data[i] = new(int)
+	const Batch = 1000
+	b.RunParallel(func(pb *testing.PB) {
+		var data [Batch]*int
+		for i := 0; i < Batch; i++ {
+			data[i] = new(int)
+		}
+		for pb.Next() {
+			for i := 0; i < Batch; i++ {
+				runtime.SetFinalizer(data[i], fin)
 			}
-			for atomic.AddInt32(&N, -1) >= 0 {
-				runtime.Gosched()
-				for i := 0; i < CallsPerSched; i++ {
-					runtime.SetFinalizer(data[i], fin)
-				}
-				for i := 0; i < CallsPerSched; i++ {
-					runtime.SetFinalizer(data[i], nil)
-				}
+			for i := 0; i < Batch; i++ {
+				runtime.SetFinalizer(data[i], nil)
 			}
-			wg.Done()
-		}()
-	}
-	wg.Wait()
+		}
+	})
 }
 
 func BenchmarkFinalizerRun(b *testing.B) {
-	const CallsPerSched = 1000
-	procs := runtime.GOMAXPROCS(-1)
-	N := int32(b.N / CallsPerSched)
-	var wg sync.WaitGroup
-	wg.Add(procs)
-	for p := 0; p < procs; p++ {
-		go func() {
-			for atomic.AddInt32(&N, -1) >= 0 {
-				runtime.Gosched()
-				for i := 0; i < CallsPerSched; i++ {
-					v := new(int)
-					runtime.SetFinalizer(v, fin)
-				}
-				runtime.GC()
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			v := new(int)
+			runtime.SetFinalizer(v, fin)
+		}
+	})
+}
+
+// One chunk must be exactly one sizeclass in size.
+// It should be a sizeclass not used much by others, so we
+// have a greater chance of finding adjacent ones.
+// size class 19: 320 byte objects, 25 per page, 1 page alloc at a time
+const objsize = 320
+
+type objtype [objsize]byte
+
+func adjChunks() (*objtype, *objtype) {
+	var s []*objtype
+
+	for {
+		c := new(objtype)
+		for _, d := range s {
+			if uintptr(unsafe.Pointer(c))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(d)) {
+				return c, d
 			}
-			wg.Done()
-		}()
+			if uintptr(unsafe.Pointer(d))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(c)) {
+				return d, c
+			}
+		}
+		s = append(s, c)
+	}
+}
+
+// Make sure an empty slice on the stack doesn't pin the next object in memory.
+func TestEmptySlice(t *testing.T) {
+	if true { // disable until bug 7564 is fixed.
+		return
+	}
+	x, y := adjChunks()
+
+	// the pointer inside xs points to y.
+	xs := x[objsize:] // change objsize to objsize-1 and the test passes
+
+	fin := make(chan bool, 1)
+	runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
+	runtime.GC()
+	select {
+	case <-fin:
+	case <-time.After(4 * time.Second):
+		t.Errorf("finalizer of next object in memory didn't run")
+	}
+	xsglobal = xs // keep empty slice alive until here
+}
+
+var xsglobal []byte
+
+func adjStringChunk() (string, *objtype) {
+	b := make([]byte, objsize)
+	for {
+		s := string(b)
+		t := new(objtype)
+		p := *(*uintptr)(unsafe.Pointer(&s))
+		q := uintptr(unsafe.Pointer(t))
+		if p+objsize == q {
+			return s, t
+		}
+	}
+}
+
+// Make sure an empty string on the stack doesn't pin the next object in memory.
+func TestEmptyString(t *testing.T) {
+	x, y := adjStringChunk()
+
+	ss := x[objsize:] // change objsize to objsize-1 and the test passes
+	fin := make(chan bool, 1)
+	// set finalizer on string contents of y
+	runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
+	runtime.GC()
+	select {
+	case <-fin:
+	case <-time.After(4 * time.Second):
+		t.Errorf("finalizer of next string in memory didn't run")
 	}
-	wg.Wait()
+	ssglobal = ss // keep 0-length string live until here
+}
+
+var ssglobal string
+
+// Test for issue 7656.
+func TestFinalizerOnGlobal(t *testing.T) {
+	runtime.SetFinalizer(Foo1, func(p *Object1) {})
+	runtime.SetFinalizer(Foo2, func(p *Object2) {})
+	runtime.SetFinalizer(Foo1, nil)
+	runtime.SetFinalizer(Foo2, nil)
 }
+
+type Object1 struct {
+	Something []byte
+}
+
+type Object2 struct {
+	Something byte
+}
+
+var (
+	Foo2 = &Object2{}
+	Foo1 = &Object1{}
+)
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
index 761f128..392da53 100644
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -2,13 +2,60 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Garbage collector.
+// Garbage collector (GC).
+//
+// GC is:
+// - mark&sweep
+// - mostly precise (with the exception of some C-allocated objects, assembly frames/arguments, etc)
+// - parallel (up to MaxGcproc threads)
+// - partially concurrent (mark is stop-the-world, while sweep is concurrent)
+// - non-moving/non-compacting
+// - full (non-partial)
+//
+// GC rate.
+// Next GC is after we've allocated an extra amount of memory proportional to
+// the amount already in use. The proportion is controlled by GOGC environment variable
+// (100 by default). If GOGC=100 and we're using 4M, we'll GC again when we get to 8M
+// (this mark is tracked in next_gc variable). This keeps the GC cost in linear
+// proportion to the allocation cost. Adjusting GOGC just changes the linear constant
+// (and also the amount of extra memory used).
+//
+// Concurrent sweep.
+// The sweep phase proceeds concurrently with normal program execution.
+// The heap is swept span-by-span both lazily (when a goroutine needs another span)
+// and concurrently in a background goroutine (this helps programs that are not CPU bound).
+// However, at the end of the stop-the-world GC phase we don't know the size of the live heap,
+// and so next_gc calculation is tricky and happens as follows.
+// At the end of the stop-the-world phase next_gc is conservatively set based on total
+// heap size; all spans are marked as "needs sweeping".
+// Whenever a span is swept, next_gc is decremented by GOGC*newly_freed_memory.
+// The background sweeper goroutine simply sweeps spans one-by-one bringing next_gc
+// closer to the target value. However, this is not enough to avoid over-allocating memory.
+// Consider that a goroutine wants to allocate a new span for a large object and
+// there are no free swept spans, but there are small-object unswept spans.
+// If the goroutine naively allocates a new span, it can surpass the yet-unknown
+// target next_gc value. In order to prevent such cases (1) when a goroutine needs
+// to allocate a new small-object span, it sweeps small-object spans for the same
+// object size until it frees at least one object; (2) when a goroutine needs to
+// allocate large-object span from heap, it sweeps spans until it frees at least
+// that many pages into heap. Together these two measures ensure that we don't surpass
+// target next_gc value by a large margin. There is an exception: if a goroutine sweeps
+// and frees two nonadjacent one-page spans to the heap, it will allocate a new two-page span,
+// but there can still be other one-page unswept spans which could be combined into a two-page span.
+// It's critical to ensure that no operations proceed on unswept spans (that would corrupt
+// mark bits in GC bitmap). During GC all mcaches are flushed into the central cache,
+// so they are empty. When a goroutine grabs a new span into mcache, it sweeps it.
+// When a goroutine explicitly frees an object or sets a finalizer, it ensures that
+// the span is swept (either by sweeping it, or by waiting for the concurrent sweep to finish).
+// The finalizer goroutine is kicked off only when all spans are swept.
+// When the next GC starts, it sweeps all not-yet-swept spans (if any).
 
 #include "runtime.h"
 #include "arch_GOARCH.h"
 #include "malloc.h"
 #include "stack.h"
 #include "mgc0.h"
+#include "chan.h"
 #include "race.h"
 #include "type.h"
 #include "typekind.h"
@@ -17,14 +64,11 @@
 
 enum {
 	Debug = 0,
-	DebugMark = 0,  // run second pass to check mark
 	CollectStats = 0,
-	ScanStackByFrames = 0,
-	IgnorePreciseGC = 0,
+	ConcurrentSweep = 1,
 
-	// Four bits per word (see #defines below).
-	wordsPerBitmapWord = sizeof(void*)*8/4,
-	bitShift = sizeof(void*)*8/4,
+	WorkbufSize	= 16*1024,
+	FinBlockSize	= 4*1024,
 
 	handoffThreshold = 4,
 	IntermediateBufferCapacity = 64,
@@ -34,46 +78,50 @@ enum {
 	LOOP = 2,
 	PC_BITS = PRECISE | LOOP,
 
-	// Pointer map
-	BitsPerPointer = 2,
-	BitsNoPointer = 0,
-	BitsPointer = 1,
-	BitsIface = 2,
-	BitsEface = 3,
+	RootData	= 0,
+	RootBss		= 1,
+	RootFinalizers	= 2,
+	RootSpanTypes	= 3,
+	RootFlushCaches = 4,
+	RootCount	= 5,
 };
 
-// Bits in per-word bitmap.
-// #defines because enum might not be able to hold the values.
-//
-// Each word in the bitmap describes wordsPerBitmapWord words
-// of heap memory.  There are 4 bitmap bits dedicated to each heap word,
-// so on a 64-bit system there is one bitmap word per 16 heap words.
-// The bits in the word are packed together by type first, then by
-// heap location, so each 64-bit bitmap word consists of, from top to bottom,
-// the 16 bitSpecial bits for the corresponding heap words, then the 16 bitMarked bits,
-// then the 16 bitNoScan/bitBlockBoundary bits, then the 16 bitAllocated bits.
-// This layout makes it easier to iterate over the bits of a given type.
-//
-// The bitmap starts at mheap.arena_start and extends *backward* from
-// there.  On a 64-bit system the off'th word in the arena is tracked by
-// the off/16+1'th word before mheap.arena_start.  (On a 32-bit system,
-// the only difference is that the divisor is 8.)
-//
-// To pull out the bits corresponding to a given pointer p, we use:
-//
-//	off = p - (uintptr*)mheap.arena_start;  // word offset
-//	b = (uintptr*)mheap.arena_start - off/wordsPerBitmapWord - 1;
-//	shift = off % wordsPerBitmapWord
-//	bits = *b >> shift;
-//	/* then test bits & bitAllocated, bits & bitMarked, etc. */
-//
-#define bitAllocated		((uintptr)1<<(bitShift*0))
-#define bitNoScan		((uintptr)1<<(bitShift*1))	/* when bitAllocated is set */
-#define bitMarked		((uintptr)1<<(bitShift*2))	/* when bitAllocated is set */
-#define bitSpecial		((uintptr)1<<(bitShift*3))	/* when bitAllocated is set - has finalizer or being profiled */
-#define bitBlockBoundary	((uintptr)1<<(bitShift*1))	/* when bitAllocated is NOT set */
+#define GcpercentUnknown (-2)
+
+// Initialized from $GOGC.  GOGC=off means no gc.
+static int32 gcpercent = GcpercentUnknown;
+
+static FuncVal* poolcleanup;
+
+void
+sync·runtime_registerPoolCleanup(FuncVal *f)
+{
+	poolcleanup = f;
+}
+
+static void
+clearpools(void)
+{
+	P *p, **pp;
+	MCache *c;
+	int32 i;
+
+	// clear sync.Pool's
+	if(poolcleanup != nil)
+		reflect·call(poolcleanup, nil, 0, 0);
 
-#define bitMask (bitBlockBoundary | bitAllocated | bitMarked | bitSpecial)
+	for(pp=runtime·allp; p=*pp; pp++) {
+		// clear tinyalloc pool
+		c = p->mcache;
+		if(c != nil) {
+			c->tiny = nil;
+			c->tinysize = 0;
+		}
+		// clear defer pools
+		for(i=0; i<nelem(p->deferpool); i++)
+			p->deferpool[i] = nil;
+	}
+}
 
 // Holding worldsema grants an M the right to try to stop the world.
 // The procedure is:
@@ -98,11 +146,10 @@ struct Obj
 	uintptr	ti;	// type info
 };
 
-// The size of Workbuf is N*PageSize.
 typedef struct Workbuf Workbuf;
 struct Workbuf
 {
-#define SIZE (2*PageSize-sizeof(LFNode)-sizeof(uintptr))
+#define SIZE (WorkbufSize-sizeof(LFNode)-sizeof(uintptr))
 	LFNode  node; // must be first
 	uintptr nobj;
 	Obj     obj[SIZE/sizeof(Obj) - 1];
@@ -138,39 +185,44 @@ extern byte ebss[];
 extern byte gcdata[];
 extern byte gcbss[];
 
-static G *fing;
-static FinBlock *finq; // list of finalizers that are to be executed
-static FinBlock *finc; // cache of free blocks
-static FinBlock *allfin; // list of all blocks
-static Lock finlock;
-static int32 fingwait;
+static Lock	finlock;	// protects the following variables
+static FinBlock	*finq;		// list of finalizers that are to be executed
+static FinBlock	*finc;		// cache of free blocks
+static FinBlock	*allfin;	// list of all blocks
+bool	runtime·fingwait;
+bool	runtime·fingwake;
+
+static Lock	gclock;
+static G*	fing;
 
-static void runfinq(void);
+static void	runfinq(void);
+static void	bgsweep(void);
 static Workbuf* getempty(Workbuf*);
 static Workbuf* getfull(Workbuf*);
 static void	putempty(Workbuf*);
 static Workbuf* handoff(Workbuf*);
 static void	gchelperstart(void);
+static void	flushallmcaches(void);
+static bool	scanframe(Stkframe *frame, void *wbufp);
+static void	addstackroots(G *gp, Workbuf **wbufp);
+
+static FuncVal runfinqv = {runfinq};
+static FuncVal bgsweepv = {bgsweep};
 
 static struct {
 	uint64	full;  // lock-free list of full blocks
 	uint64	empty; // lock-free list of empty blocks
 	byte	pad0[CacheLineSize]; // prevents false-sharing between full/empty and nproc/nwait
 	uint32	nproc;
+	int64	tstart;
 	volatile uint32	nwait;
 	volatile uint32	ndone;
-	volatile uint32 debugmarkdone;
 	Note	alldone;
 	ParFor	*markfor;
-	ParFor	*sweepfor;
 
 	Lock;
 	byte	*chunk;
 	uintptr	nchunk;
-
-	Obj	*roots;
-	uint32	nroot;
-	uint32	rootcap;
 } work;
 
 enum {
@@ -207,6 +259,8 @@ static struct {
 		uint64 foundword;
 		uint64 foundspan;
 	} markonly;
+	uint32 nbgsweep;
+	uint32 npausesweep;
 } gcstats;
 
 // markonly marks an object. It returns true if the object
@@ -260,8 +314,7 @@ markonly(void *obj)
 	// (Manually inlined copy of MHeap_LookupMaybe.)
 	k = (uintptr)obj>>PageShift;
 	x = k;
-	if(sizeof(void*) == 8)
-		x -= (uintptr)runtime·mheap.arena_start>>PageShift;
+	x -= (uintptr)runtime·mheap.arena_start>>PageShift;
 	s = runtime·mheap.spans[x];
 	if(s == nil || k < s->start || obj >= s->limit || s->state != MSpanInUse)
 		return false;
@@ -317,6 +370,24 @@ struct PtrTarget
 	uintptr ti;
 };
 
+typedef	struct Scanbuf Scanbuf;
+struct	Scanbuf
+{
+	struct {
+		PtrTarget *begin;
+		PtrTarget *end;
+		PtrTarget *pos;
+	} ptr;
+	struct {
+		Obj *begin;
+		Obj *end;
+		Obj *pos;
+	} obj;
+	Workbuf *wbuf;
+	Obj *wp;
+	uintptr nobj;
+};
+
 typedef struct BufferList BufferList;
 struct BufferList
 {
@@ -350,7 +421,7 @@ static void enqueue(Obj obj, Workbuf **_wbuf, Obj **_wp, uintptr *_nobj);
 //     flushptrbuf
 //  (find block start, mark and enqueue)
 static void
-flushptrbuf(PtrTarget *ptrbuf, PtrTarget **ptrbufpos, Obj **_wp, Workbuf **_wbuf, uintptr *_nobj)
+flushptrbuf(Scanbuf *sbuf)
 {
 	byte *p, *arena_start, *obj;
 	uintptr size, *bitp, bits, shift, j, x, xbits, off, nobj, ti, n;
@@ -358,17 +429,19 @@ flushptrbuf(PtrTarget *ptrbuf, PtrTarget **ptrbufpos, Obj **_wp, Workbuf **_wbuf
 	PageID k;
 	Obj *wp;
 	Workbuf *wbuf;
+	PtrTarget *ptrbuf;
 	PtrTarget *ptrbuf_end;
 
 	arena_start = runtime·mheap.arena_start;
 
-	wp = *_wp;
-	wbuf = *_wbuf;
-	nobj = *_nobj;
+	wp = sbuf->wp;
+	wbuf = sbuf->wbuf;
+	nobj = sbuf->nobj;
 
-	ptrbuf_end = *ptrbufpos;
-	n = ptrbuf_end - ptrbuf;
-	*ptrbufpos = ptrbuf;
+	ptrbuf = sbuf->ptr.begin;
+	ptrbuf_end = sbuf->ptr.pos;
+	n = ptrbuf_end - sbuf->ptr.begin;
+	sbuf->ptr.pos = sbuf->ptr.begin;
 
 	if(CollectStats) {
 		runtime·xadd64(&gcstats.ptr.sum, n);
@@ -387,152 +460,146 @@ flushptrbuf(PtrTarget *ptrbuf, PtrTarget **ptrbufpos, Obj **_wp, Workbuf **_wbuf
 			runtime·throw("ptrbuf has to be smaller than WorkBuf");
 	}
 
-	// TODO(atom): This block is a branch of an if-then-else statement.
-	//             The single-threaded branch may be added in a next CL.
-	{
-		// Multi-threaded version.
+	while(ptrbuf < ptrbuf_end) {
+		obj = ptrbuf->p;
+		ti = ptrbuf->ti;
+		ptrbuf++;
+
+		// obj belongs to interval [mheap.arena_start, mheap.arena_used).
+		if(Debug > 1) {
+			if(obj < runtime·mheap.arena_start || obj >= runtime·mheap.arena_used)
+				runtime·throw("object is outside of mheap");
+		}
 
-		while(ptrbuf < ptrbuf_end) {
-			obj = ptrbuf->p;
-			ti = ptrbuf->ti;
-			ptrbuf++;
+		// obj may be a pointer to a live object.
+		// Try to find the beginning of the object.
 
-			// obj belongs to interval [mheap.arena_start, mheap.arena_used).
-			if(Debug > 1) {
-				if(obj < runtime·mheap.arena_start || obj >= runtime·mheap.arena_used)
-					runtime·throw("object is outside of mheap");
-			}
+		// Round down to word boundary.
+		if(((uintptr)obj & ((uintptr)PtrSize-1)) != 0) {
+			obj = (void*)((uintptr)obj & ~((uintptr)PtrSize-1));
+			ti = 0;
+		}
 
-			// obj may be a pointer to a live object.
-			// Try to find the beginning of the object.
+		// Find bits for this word.
+		off = (uintptr*)obj - (uintptr*)arena_start;
+		bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
+		shift = off % wordsPerBitmapWord;
+		xbits = *bitp;
+		bits = xbits >> shift;
 
-			// Round down to word boundary.
-			if(((uintptr)obj & ((uintptr)PtrSize-1)) != 0) {
-				obj = (void*)((uintptr)obj & ~((uintptr)PtrSize-1));
-				ti = 0;
-			}
+		// Pointing at the beginning of a block?
+		if((bits & (bitAllocated|bitBlockBoundary)) != 0) {
+			if(CollectStats)
+				runtime·xadd64(&gcstats.flushptrbuf.foundbit, 1);
+			goto found;
+		}
 
-			// Find bits for this word.
-			off = (uintptr*)obj - (uintptr*)arena_start;
-			bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
-			shift = off % wordsPerBitmapWord;
-			xbits = *bitp;
-			bits = xbits >> shift;
+		ti = 0;
 
-			// Pointing at the beginning of a block?
-			if((bits & (bitAllocated|bitBlockBoundary)) != 0) {
+		// Pointing just past the beginning?
+		// Scan backward a little to find a block boundary.
+		for(j=shift; j-->0; ) {
+			if(((xbits>>j) & (bitAllocated|bitBlockBoundary)) != 0) {
+				obj = (byte*)obj - (shift-j)*PtrSize;
+				shift = j;
+				bits = xbits>>shift;
 				if(CollectStats)
-					runtime·xadd64(&gcstats.flushptrbuf.foundbit, 1);
+					runtime·xadd64(&gcstats.flushptrbuf.foundword, 1);
 				goto found;
 			}
+		}
 
-			ti = 0;
-
-			// Pointing just past the beginning?
-			// Scan backward a little to find a block boundary.
-			for(j=shift; j-->0; ) {
-				if(((xbits>>j) & (bitAllocated|bitBlockBoundary)) != 0) {
-					obj = (byte*)obj - (shift-j)*PtrSize;
-					shift = j;
-					bits = xbits>>shift;
-					if(CollectStats)
-						runtime·xadd64(&gcstats.flushptrbuf.foundword, 1);
-					goto found;
-				}
-			}
-
-			// Otherwise consult span table to find beginning.
-			// (Manually inlined copy of MHeap_LookupMaybe.)
-			k = (uintptr)obj>>PageShift;
-			x = k;
-			if(sizeof(void*) == 8)
-				x -= (uintptr)arena_start>>PageShift;
-			s = runtime·mheap.spans[x];
-			if(s == nil || k < s->start || obj >= s->limit || s->state != MSpanInUse)
-				continue;
-			p = (byte*)((uintptr)s->start<<PageShift);
-			if(s->sizeclass == 0) {
-				obj = p;
-			} else {
-				size = s->elemsize;
-				int32 i = ((byte*)obj - p)/size;
-				obj = p+i*size;
-			}
+		// Otherwise consult span table to find beginning.
+		// (Manually inlined copy of MHeap_LookupMaybe.)
+		k = (uintptr)obj>>PageShift;
+		x = k;
+		x -= (uintptr)arena_start>>PageShift;
+		s = runtime·mheap.spans[x];
+		if(s == nil || k < s->start || obj >= s->limit || s->state != MSpanInUse)
+			continue;
+		p = (byte*)((uintptr)s->start<<PageShift);
+		if(s->sizeclass == 0) {
+			obj = p;
+		} else {
+			size = s->elemsize;
+			int32 i = ((byte*)obj - p)/size;
+			obj = p+i*size;
+		}
 
-			// Now that we know the object header, reload bits.
-			off = (uintptr*)obj - (uintptr*)arena_start;
-			bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
-			shift = off % wordsPerBitmapWord;
-			xbits = *bitp;
-			bits = xbits >> shift;
-			if(CollectStats)
-				runtime·xadd64(&gcstats.flushptrbuf.foundspan, 1);
+		// Now that we know the object header, reload bits.
+		off = (uintptr*)obj - (uintptr*)arena_start;
+		bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
+		shift = off % wordsPerBitmapWord;
+		xbits = *bitp;
+		bits = xbits >> shift;
+		if(CollectStats)
+			runtime·xadd64(&gcstats.flushptrbuf.foundspan, 1);
 
-		found:
-			// Now we have bits, bitp, and shift correct for
-			// obj pointing at the base of the object.
-			// Only care about allocated and not marked.
-			if((bits & (bitAllocated|bitMarked)) != bitAllocated)
-				continue;
-			if(work.nproc == 1)
-				*bitp |= bitMarked<<shift;
-			else {
-				for(;;) {
-					x = *bitp;
-					if(x & (bitMarked<<shift))
-						goto continue_obj;
-					if(runtime·casp((void**)bitp, (void*)x, (void*)(x|(bitMarked<<shift))))
-						break;
-				}
+	found:
+		// Now we have bits, bitp, and shift correct for
+		// obj pointing at the base of the object.
+		// Only care about allocated and not marked.
+		if((bits & (bitAllocated|bitMarked)) != bitAllocated)
+			continue;
+		if(work.nproc == 1)
+			*bitp |= bitMarked<<shift;
+		else {
+			for(;;) {
+				x = *bitp;
+				if(x & (bitMarked<<shift))
+					goto continue_obj;
+				if(runtime·casp((void**)bitp, (void*)x, (void*)(x|(bitMarked<<shift))))
+					break;
 			}
+		}
 
-			// If object has no pointers, don't need to scan further.
-			if((bits & bitNoScan) != 0)
-				continue;
+		// If object has no pointers, don't need to scan further.
+		if((bits & bitScan) == 0)
+			continue;
 
-			// Ask span about size class.
-			// (Manually inlined copy of MHeap_Lookup.)
-			x = (uintptr)obj >> PageShift;
-			if(sizeof(void*) == 8)
-				x -= (uintptr)arena_start>>PageShift;
-			s = runtime·mheap.spans[x];
+		// Ask span about size class.
+		// (Manually inlined copy of MHeap_Lookup.)
+		x = (uintptr)obj >> PageShift;
+		x -= (uintptr)arena_start>>PageShift;
+		s = runtime·mheap.spans[x];
 
-			PREFETCH(obj);
+		PREFETCH(obj);
 
-			*wp = (Obj){obj, s->elemsize, ti};
-			wp++;
-			nobj++;
-		continue_obj:;
-		}
+		*wp = (Obj){obj, s->elemsize, ti};
+		wp++;
+		nobj++;
+	continue_obj:;
+	}
 
-		// If another proc wants a pointer, give it some.
-		if(work.nwait > 0 && nobj > handoffThreshold && work.full == 0) {
-			wbuf->nobj = nobj;
-			wbuf = handoff(wbuf);
-			nobj = wbuf->nobj;
-			wp = wbuf->obj + nobj;
-		}
+	// If another proc wants a pointer, give it some.
+	if(work.nwait > 0 && nobj > handoffThreshold && work.full == 0) {
+		wbuf->nobj = nobj;
+		wbuf = handoff(wbuf);
+		nobj = wbuf->nobj;
+		wp = wbuf->obj + nobj;
 	}
 
-	*_wp = wp;
-	*_wbuf = wbuf;
-	*_nobj = nobj;
+	sbuf->wp = wp;
+	sbuf->wbuf = wbuf;
+	sbuf->nobj = nobj;
 }
 
 static void
-flushobjbuf(Obj *objbuf, Obj **objbufpos, Obj **_wp, Workbuf **_wbuf, uintptr *_nobj)
+flushobjbuf(Scanbuf *sbuf)
 {
 	uintptr nobj, off;
 	Obj *wp, obj;
 	Workbuf *wbuf;
+	Obj *objbuf;
 	Obj *objbuf_end;
 
-	wp = *_wp;
-	wbuf = *_wbuf;
-	nobj = *_nobj;
+	wp = sbuf->wp;
+	wbuf = sbuf->wbuf;
+	nobj = sbuf->nobj;
 
-	objbuf_end = *objbufpos;
-	*objbufpos = objbuf;
+	objbuf = sbuf->obj.begin;
+	objbuf_end = sbuf->obj.pos;
+	sbuf->obj.pos = sbuf->obj.begin;
 
 	while(objbuf < objbuf_end) {
 		obj = *objbuf++;
@@ -570,9 +637,9 @@ flushobjbuf(Obj *objbuf, Obj **objbufpos, Obj **_wp, Workbuf **_wbuf, uintptr *_
 		wp = wbuf->obj + nobj;
 	}
 
-	*_wp = wp;
-	*_wbuf = wbuf;
-	*_nobj = nobj;
+	sbuf->wp = wp;
+	sbuf->wbuf = wbuf;
+	sbuf->nobj = nobj;
 }
 
 // Program that scans the whole block and treats every block element as a potential pointer
@@ -607,8 +674,7 @@ checkptr(void *obj, uintptr objti)
 	if(t == nil)
 		return;
 	x = (uintptr)obj >> PageShift;
-	if(sizeof(void*) == 8)
-		x -= (uintptr)(runtime·mheap.arena_start)>>PageShift;
+	x -= (uintptr)(runtime·mheap.arena_start)>>PageShift;
 	s = runtime·mheap.spans[x];
 	objstart = (byte*)((uintptr)s->start<<PageShift);
 	if(s->sizeclass != 0) {
@@ -636,8 +702,8 @@ checkptr(void *obj, uintptr objti)
 		// A simple best-effort check until first GC_END.
 		for(j = 1; pc1[j] != GC_END && pc2[j] != GC_END; j++) {
 			if(pc1[j] != pc2[j]) {
-				runtime·printf("invalid gc type info for '%s' at %p, type info %p, block info %p\n",
-					       t->string ? (int8*)t->string->str : (int8*)"?", j, pc1[j], pc2[j]);
+				runtime·printf("invalid gc type info for '%s', type info %p [%d]=%p, block info %p [%d]=%p\n",
+					       t->string ? (int8*)t->string->str : (int8*)"?", pc1, (int32)j, pc1[j], pc2, (int32)j, pc2[j]);
 				runtime·throw("invalid gc type info");
 			}
 		}
@@ -650,30 +716,27 @@ checkptr(void *obj, uintptr objti)
 // a work list in the Workbuf* structures and loops in the main function
 // body.  Keeping an explicit work list is easier on the stack allocator and
 // more efficient.
-//
-// wbuf: current work buffer
-// wp:   storage for next queued pointer (write pointer)
-// nobj: number of queued objects
 static void
-scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
+scanblock(Workbuf *wbuf, bool keepworking)
 {
 	byte *b, *arena_start, *arena_used;
-	uintptr n, i, end_b, elemsize, size, ti, objti, count, type;
+	uintptr n, i, end_b, elemsize, size, ti, objti, count, type, nobj;
 	uintptr *pc, precise_type, nominal_size;
 	uintptr *chan_ret, chancap;
 	void *obj;
-	Type *t;
+	Type *t, *et;
 	Slice *sliceptr;
+	String *stringptr;
 	Frame *stack_ptr, stack_top, stack[GC_STACK_CAPACITY+4];
 	BufferList *scanbuffers;
-	PtrTarget *ptrbuf, *ptrbuf_end, *ptrbufpos;
-	Obj *objbuf, *objbuf_end, *objbufpos;
+	Scanbuf sbuf;
 	Eface *eface;
 	Iface *iface;
 	Hchan *chan;
 	ChanType *chantype;
+	Obj *wp;
 
-	if(sizeof(Workbuf) % PageSize != 0)
+	if(sizeof(Workbuf) % WorkbufSize != 0)
 		runtime·throw("scanblock: size of Workbuf is suboptimal");
 
 	// Memory arena parameters.
@@ -681,21 +744,30 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
 	arena_used = runtime·mheap.arena_used;
 
 	stack_ptr = stack+nelem(stack)-1;
-	
+
 	precise_type = false;
 	nominal_size = 0;
 
-	// Allocate ptrbuf
-	{
-		scanbuffers = &bufferList[m->helpgc];
-		ptrbuf = &scanbuffers->ptrtarget[0];
-		ptrbuf_end = &scanbuffers->ptrtarget[0] + nelem(scanbuffers->ptrtarget);
-		objbuf = &scanbuffers->obj[0];
-		objbuf_end = &scanbuffers->obj[0] + nelem(scanbuffers->obj);
+	if(wbuf) {
+		nobj = wbuf->nobj;
+		wp = &wbuf->obj[nobj];
+	} else {
+		nobj = 0;
+		wp = nil;
 	}
 
-	ptrbufpos = ptrbuf;
-	objbufpos = objbuf;
+	// Initialize sbuf
+	scanbuffers = &bufferList[m->helpgc];
+
+	sbuf.ptr.begin = sbuf.ptr.pos = &scanbuffers->ptrtarget[0];
+	sbuf.ptr.end = sbuf.ptr.begin + nelem(scanbuffers->ptrtarget);
+
+	sbuf.obj.begin = sbuf.obj.pos = &scanbuffers->obj[0];
+	sbuf.obj.end = sbuf.obj.begin + nelem(scanbuffers->obj);
+
+	sbuf.wbuf = wbuf;
+	sbuf.wp = wp;
+	sbuf.nobj = nobj;
 
 	// (Silence the compiler)
 	chan = nil;
@@ -707,17 +779,17 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
 	for(;;) {
 		// Each iteration scans the block b of length n, queueing pointers in
 		// the work buffer.
-		if(Debug > 1) {
-			runtime·printf("scanblock %p %D\n", b, (int64)n);
-		}
 
 		if(CollectStats) {
 			runtime·xadd64(&gcstats.nbytes, n);
-			runtime·xadd64(&gcstats.obj.sum, nobj);
+			runtime·xadd64(&gcstats.obj.sum, sbuf.nobj);
 			runtime·xadd64(&gcstats.obj.cnt, 1);
 		}
 
 		if(ti != 0) {
+			if(Debug > 1) {
+				runtime·printf("scanblock %p %D ti %p\n", b, (int64)n, ti);
+			}
 			pc = (uintptr*)(ti & ~(uintptr)PC_BITS);
 			precise_type = (ti & PRECISE);
 			stack_top.elemsize = pc[0];
@@ -773,14 +845,22 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
 					pc = chanProg;
 					break;
 				default:
+					if(Debug > 1)
+						runtime·printf("scanblock %p %D type %p %S\n", b, (int64)n, type, *t->string);
 					runtime·throw("scanblock: invalid type");
 					return;
 				}
+				if(Debug > 1)
+					runtime·printf("scanblock %p %D type %p %S pc=%p\n", b, (int64)n, type, *t->string, pc);
 			} else {
 				pc = defaultProg;
+				if(Debug > 1)
+					runtime·printf("scanblock %p %D unknown type\n", b, (int64)n);
 			}
 		} else {
 			pc = defaultProg;
+			if(Debug > 1)
+				runtime·printf("scanblock %p %D no span types\n", b, (int64)n);
 		}
 
 		if(IgnorePreciseGC)
@@ -788,7 +868,6 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
 
 		pc++;
 		stack_top.b = (uintptr)b;
-
 		end_b = (uintptr)b + n - PtrSize;
 
 	for(;;) {
@@ -801,6 +880,8 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
 		case GC_PTR:
 			obj = *(void**)(stack_top.b + pc[1]);
 			objti = pc[2];
+			if(Debug > 2)
+				runtime·printf("gc_ptr @%p: %p ti=%p\n", stack_top.b+pc[1], obj, objti);
 			pc += 3;
 			if(Debug)
 				checkptr(obj, objti);
@@ -808,6 +889,8 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
 
 		case GC_SLICE:
 			sliceptr = (Slice*)(stack_top.b + pc[1]);
+			if(Debug > 2)
+				runtime·printf("gc_slice @%p: %p/%D/%D\n", sliceptr, sliceptr->array, (int64)sliceptr->len, (int64)sliceptr->cap);
 			if(sliceptr->cap != 0) {
 				obj = sliceptr->array;
 				// Can't use slice element type for scanning,
@@ -821,27 +904,34 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
 
 		case GC_APTR:
 			obj = *(void**)(stack_top.b + pc[1]);
+			if(Debug > 2)
+				runtime·printf("gc_aptr @%p: %p\n", stack_top.b+pc[1], obj);
 			pc += 2;
 			break;
 
 		case GC_STRING:
-			obj = *(void**)(stack_top.b + pc[1]);
-			markonly(obj);
+			stringptr = (String*)(stack_top.b + pc[1]);
+			if(Debug > 2)
+				runtime·printf("gc_string @%p: %p/%D\n", stack_top.b+pc[1], stringptr->str, (int64)stringptr->len);
+			if(stringptr->len != 0)
+				markonly(stringptr->str);
 			pc += 2;
 			continue;
 
 		case GC_EFACE:
 			eface = (Eface*)(stack_top.b + pc[1]);
 			pc += 2;
+			if(Debug > 2)
+				runtime·printf("gc_eface @%p: %p %p\n", stack_top.b+pc[1], eface->type, eface->data);
 			if(eface->type == nil)
 				continue;
 
 			// eface->type
 			t = eface->type;
 			if((void*)t >= arena_start && (void*)t < arena_used) {
-				*ptrbufpos++ = (PtrTarget){t, 0};
-				if(ptrbufpos == ptrbuf_end)
-					flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
+				*sbuf.ptr.pos++ = (PtrTarget){t, 0};
+				if(sbuf.ptr.pos == sbuf.ptr.end)
+					flushptrbuf(&sbuf);
 			}
 
 			// eface->data
@@ -851,8 +941,14 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
 						continue;
 
 					obj = eface->data;
-					if((t->kind & ~KindNoPointers) == KindPtr)
-						objti = (uintptr)((PtrType*)t)->elem->gc;
+					if((t->kind & ~KindNoPointers) == KindPtr) {
+						// Only use type information if it is a pointer-containing type.
+						// This matches the GC programs written by cmd/gc/reflect.c's
+						// dgcsym1 in case TPTR32/case TPTR64. See rationale there.
+						et = ((PtrType*)t)->elem;
+						if(!(et->kind & KindNoPointers))
+							objti = (uintptr)((PtrType*)t)->elem->gc;
+					}
 				} else {
 					obj = eface->data;
 					objti = (uintptr)t->gc;
@@ -863,14 +959,16 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
 		case GC_IFACE:
 			iface = (Iface*)(stack_top.b + pc[1]);
 			pc += 2;
+			if(Debug > 2)
+				runtime·printf("gc_iface @%p: %p/%p %p\n", stack_top.b+pc[1], iface->tab, nil, iface->data);
 			if(iface->tab == nil)
 				continue;
 			
 			// iface->tab
 			if((void*)iface->tab >= arena_start && (void*)iface->tab < arena_used) {
-				*ptrbufpos++ = (PtrTarget){iface->tab, (uintptr)itabtype->gc};
-				if(ptrbufpos == ptrbuf_end)
-					flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
+				*sbuf.ptr.pos++ = (PtrTarget){iface->tab, (uintptr)itabtype->gc};
+				if(sbuf.ptr.pos == sbuf.ptr.end)
+					flushptrbuf(&sbuf);
 			}
 
 			// iface->data
@@ -881,8 +979,14 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
 						continue;
 
 					obj = iface->data;
-					if((t->kind & ~KindNoPointers) == KindPtr)
-						objti = (uintptr)((PtrType*)t)->elem->gc;
+					if((t->kind & ~KindNoPointers) == KindPtr) {
+						// Only use type information if it is a pointer-containing type.
+						// This matches the GC programs written by cmd/gc/reflect.c's
+						// dgcsym1 in case TPTR32/case TPTR64. See rationale there.
+						et = ((PtrType*)t)->elem;
+						if(!(et->kind & KindNoPointers))
+							objti = (uintptr)((PtrType*)t)->elem->gc;
+					}
 				} else {
 					obj = iface->data;
 					objti = (uintptr)t->gc;
@@ -893,11 +997,13 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
 		case GC_DEFAULT_PTR:
 			while(stack_top.b <= end_b) {
 				obj = *(byte**)stack_top.b;
+				if(Debug > 2)
+					runtime·printf("gc_default_ptr @%p: %p\n", stack_top.b, obj);
 				stack_top.b += PtrSize;
 				if(obj >= arena_start && obj < arena_used) {
-					*ptrbufpos++ = (PtrTarget){obj, 0};
-					if(ptrbufpos == ptrbuf_end)
-						flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
+					*sbuf.ptr.pos++ = (PtrTarget){obj, 0};
+					if(sbuf.ptr.pos == sbuf.ptr.end)
+						flushptrbuf(&sbuf);
 				}
 			}
 			goto next_block;
@@ -926,7 +1032,7 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
 					if(*(byte**)i != nil) {
 						// Found a value that may be a pointer.
 						// Do a rescan of the entire block.
-						enqueue((Obj){b, n, 0}, &wbuf, &wp, &nobj);
+						enqueue((Obj){b, n, 0}, &sbuf.wbuf, &sbuf.wp, &sbuf.nobj);
 						if(CollectStats) {
 							runtime·xadd64(&gcstats.rescan, 1);
 							runtime·xadd64(&gcstats.rescanbytes, n);
@@ -972,13 +1078,17 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
 			objti = pc[3];
 			pc += 4;
 
-			*objbufpos++ = (Obj){obj, size, objti};
-			if(objbufpos == objbuf_end)
-				flushobjbuf(objbuf, &objbufpos, &wp, &wbuf, &nobj);
+			if(Debug > 2)
+				runtime·printf("gc_region @%p: %D %p\n", stack_top.b+pc[1], (int64)size, objti);
+			*sbuf.obj.pos++ = (Obj){obj, size, objti};
+			if(sbuf.obj.pos == sbuf.obj.end)
+				flushobjbuf(&sbuf);
 			continue;
 
 		case GC_CHAN_PTR:
 			chan = *(Hchan**)(stack_top.b + pc[1]);
+			if(Debug > 2 && chan != nil)
+				runtime·printf("gc_chan_ptr @%p: %p/%D/%D %p\n", stack_top.b+pc[1], chan, (int64)chan->qcount, (int64)chan->dataqsiz, pc[2]);
 			if(chan == nil) {
 				pc += 3;
 				continue;
@@ -1007,10 +1117,10 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
 					// in-use part of the circular buffer is scanned.
 					// (Channel routines zero the unused part, so the current
 					// code does not lead to leaks, it's just a little inefficient.)
-					*objbufpos++ = (Obj){(byte*)chan+runtime·Hchansize, chancap*chantype->elem->size,
+					*sbuf.obj.pos++ = (Obj){(byte*)chan+runtime·Hchansize, chancap*chantype->elem->size,
 						(uintptr)chantype->elem->gc | PRECISE | LOOP};
-					if(objbufpos == objbuf_end)
-						flushobjbuf(objbuf, &objbufpos, &wp, &wbuf, &nobj);
+					if(sbuf.obj.pos == sbuf.obj.end)
+						flushobjbuf(&sbuf);
 				}
 			}
 			if(chan_ret == nil)
@@ -1019,14 +1129,15 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
 			continue;
 
 		default:
+			runtime·printf("runtime: invalid GC instruction %p at %p\n", pc[0], pc);
 			runtime·throw("scanblock: invalid GC instruction");
 			return;
 		}
 
 		if(obj >= arena_start && obj < arena_used) {
-			*ptrbufpos++ = (PtrTarget){obj, objti};
-			if(ptrbufpos == ptrbuf_end)
-				flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
+			*sbuf.ptr.pos++ = (PtrTarget){obj, objti};
+			if(sbuf.ptr.pos == sbuf.ptr.end)
+				flushptrbuf(&sbuf);
 		}
 	}
 
@@ -1034,109 +1145,31 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
 		// Done scanning [b, b+n).  Prepare for the next iteration of
 		// the loop by setting b, n, ti to the parameters for the next block.
 
-		if(nobj == 0) {
-			flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
-			flushobjbuf(objbuf, &objbufpos, &wp, &wbuf, &nobj);
+		if(sbuf.nobj == 0) {
+			flushptrbuf(&sbuf);
+			flushobjbuf(&sbuf);
 
-			if(nobj == 0) {
+			if(sbuf.nobj == 0) {
 				if(!keepworking) {
-					if(wbuf)
-						putempty(wbuf);
-					goto endscan;
+					if(sbuf.wbuf)
+						putempty(sbuf.wbuf);
+					return;
 				}
 				// Emptied our buffer: refill.
-				wbuf = getfull(wbuf);
-				if(wbuf == nil)
-					goto endscan;
-				nobj = wbuf->nobj;
-				wp = wbuf->obj + wbuf->nobj;
+				sbuf.wbuf = getfull(sbuf.wbuf);
+				if(sbuf.wbuf == nil)
+					return;
+				sbuf.nobj = sbuf.wbuf->nobj;
+				sbuf.wp = sbuf.wbuf->obj + sbuf.wbuf->nobj;
 			}
 		}
 
 		// Fetch b from the work buffer.
-		--wp;
-		b = wp->p;
-		n = wp->n;
-		ti = wp->ti;
-		nobj--;
-	}
-
-endscan:;
-}
-
-// debug_scanblock is the debug copy of scanblock.
-// it is simpler, slower, single-threaded, recursive,
-// and uses bitSpecial as the mark bit.
-static void
-debug_scanblock(byte *b, uintptr n)
-{
-	byte *obj, *p;
-	void **vp;
-	uintptr size, *bitp, bits, shift, i, xbits, off;
-	MSpan *s;
-
-	if(!DebugMark)
-		runtime·throw("debug_scanblock without DebugMark");
-
-	if((intptr)n < 0) {
-		runtime·printf("debug_scanblock %p %D\n", b, (int64)n);
-		runtime·throw("debug_scanblock");
-	}
-
-	// Align b to a word boundary.
-	off = (uintptr)b & (PtrSize-1);
-	if(off != 0) {
-		b += PtrSize - off;
-		n -= PtrSize - off;
-	}
-
-	vp = (void**)b;
-	n /= PtrSize;
-	for(i=0; i<n; i++) {
-		obj = (byte*)vp[i];
-
-		// Words outside the arena cannot be pointers.
-		if((byte*)obj < runtime·mheap.arena_start || (byte*)obj >= runtime·mheap.arena_used)
-			continue;
-
-		// Round down to word boundary.
-		obj = (void*)((uintptr)obj & ~((uintptr)PtrSize-1));
-
-		// Consult span table to find beginning.
-		s = runtime·MHeap_LookupMaybe(&runtime·mheap, obj);
-		if(s == nil)
-			continue;
-
-		p =  (byte*)((uintptr)s->start<<PageShift);
-		size = s->elemsize;
-		if(s->sizeclass == 0) {
-			obj = p;
-		} else {
-			int32 i = ((byte*)obj - p)/size;
-			obj = p+i*size;
-		}
-
-		// Now that we know the object header, reload bits.
-		off = (uintptr*)obj - (uintptr*)runtime·mheap.arena_start;
-		bitp = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
-		shift = off % wordsPerBitmapWord;
-		xbits = *bitp;
-		bits = xbits >> shift;
-
-		// Now we have bits, bitp, and shift correct for
-		// obj pointing at the base of the object.
-		// If not allocated or already marked, done.
-		if((bits & bitAllocated) == 0 || (bits & bitSpecial) != 0)  // NOTE: bitSpecial not bitMarked
-			continue;
-		*bitp |= bitSpecial<<shift;
-		if(!(bits & bitMarked))
-			runtime·printf("found unmarked block %p in %p\n", obj, vp+i);
-
-		// If object has no pointers, don't need to scan further.
-		if((bits & bitNoScan) != 0)
-			continue;
-
-		debug_scanblock(obj, size);
+		--sbuf.wp;
+		b = sbuf.wp->p;
+		n = sbuf.wp->n;
+		ti = sbuf.wp->ti;
+		sbuf.nobj--;
 	}
 }
 
@@ -1196,18 +1229,102 @@ enqueue(Obj obj, Workbuf **_wbuf, Obj **_wp, uintptr *_nobj)
 }
 
 static void
+enqueue1(Workbuf **wbufp, Obj obj)
+{
+	Workbuf *wbuf;
+
+	wbuf = *wbufp;
+	if(wbuf->nobj >= nelem(wbuf->obj))
+		*wbufp = wbuf = getempty(wbuf);
+	wbuf->obj[wbuf->nobj++] = obj;
+}
+
+static void
 markroot(ParFor *desc, uint32 i)
 {
-	Obj *wp;
 	Workbuf *wbuf;
-	uintptr nobj;
+	FinBlock *fb;
+	MHeap *h;
+	MSpan **allspans, *s;
+	uint32 spanidx, sg;
+	G *gp;
+	void *p;
 
 	USED(&desc);
-	wp = nil;
-	wbuf = nil;
-	nobj = 0;
-	enqueue(work.roots[i], &wbuf, &wp, &nobj);
-	scanblock(wbuf, wp, nobj, false);
+	wbuf = getempty(nil);
+	// Note: if you add a case here, please also update heapdump.c:dumproots.
+	switch(i) {
+	case RootData:
+		enqueue1(&wbuf, (Obj){data, edata - data, (uintptr)gcdata});
+		break;
+
+	case RootBss:
+		enqueue1(&wbuf, (Obj){bss, ebss - bss, (uintptr)gcbss});
+		break;
+
+	case RootFinalizers:
+		for(fb=allfin; fb; fb=fb->alllink)
+			enqueue1(&wbuf, (Obj){(byte*)fb->fin, fb->cnt*sizeof(fb->fin[0]), 0});
+		break;
+
+	case RootSpanTypes:
+		// mark span types and MSpan.specials (to walk spans only once)
+		h = &runtime·mheap;
+		sg = h->sweepgen;
+		allspans = h->allspans;
+		for(spanidx=0; spanidx<runtime·mheap.nspan; spanidx++) {
+			Special *sp;
+			SpecialFinalizer *spf;
+
+			s = allspans[spanidx];
+			if(s->sweepgen != sg) {
+				runtime·printf("sweep %d %d\n", s->sweepgen, sg);
+				runtime·throw("gc: unswept span");
+			}
+			if(s->state != MSpanInUse)
+				continue;
+			// The garbage collector ignores type pointers stored in MSpan.types:
+			//  - Compiler-generated types are stored outside of heap.
+			//  - The reflect package has runtime-generated types cached in its data structures.
+			//    The garbage collector relies on finding the references via that cache.
+			if(s->types.compression == MTypes_Words || s->types.compression == MTypes_Bytes)
+				markonly((byte*)s->types.data);
+			for(sp = s->specials; sp != nil; sp = sp->next) {
+				if(sp->kind != KindSpecialFinalizer)
+					continue;
+				// don't mark finalized object, but scan it so we
+				// retain everything it points to.
+				spf = (SpecialFinalizer*)sp;
+				// A finalizer can be set for an inner byte of an object, find object beginning.
+				p = (void*)((s->start << PageShift) + spf->offset/s->elemsize*s->elemsize);
+				enqueue1(&wbuf, (Obj){p, s->elemsize, 0});
+				enqueue1(&wbuf, (Obj){(void*)&spf->fn, PtrSize, 0});
+				enqueue1(&wbuf, (Obj){(void*)&spf->fint, PtrSize, 0});
+				enqueue1(&wbuf, (Obj){(void*)&spf->ot, PtrSize, 0});
+			}
+		}
+		break;
+
+	case RootFlushCaches:
+		flushallmcaches();
+		break;
+
+	default:
+		// the rest is scanning goroutine stacks
+		if(i - RootCount >= runtime·allglen)
+			runtime·throw("markroot: bad index");
+		gp = runtime·allg[i - RootCount];
+		// remember when we've first observed the G blocked
+		// needed only to output in traceback
+		if((gp->status == Gwaiting || gp->status == Gsyscall) && gp->waitsince == 0)
+			gp->waitsince = work.tstart;
+		addstackroots(gp, &wbuf);
+		break;
+		
+	}
+
+	if(wbuf)
+		scanblock(wbuf, false);
 }
 
 // Get an empty work buffer off the work.empty list,
@@ -1304,43 +1421,20 @@ handoff(Workbuf *b)
 	return b1;
 }
 
-static void
-addroot(Obj obj)
-{
-	uint32 cap;
-	Obj *new;
-
-	if(work.nroot >= work.rootcap) {
-		cap = PageSize/sizeof(Obj);
-		if(cap < 2*work.rootcap)
-			cap = 2*work.rootcap;
-		new = (Obj*)runtime·SysAlloc(cap*sizeof(Obj), &mstats.gc_sys);
-		if(new == nil)
-			runtime·throw("runtime: cannot allocate memory");
-		if(work.roots != nil) {
-			runtime·memmove(new, work.roots, work.rootcap*sizeof(Obj));
-			runtime·SysFree(work.roots, work.rootcap*sizeof(Obj), &mstats.gc_sys);
-		}
-		work.roots = new;
-		work.rootcap = cap;
-	}
-	work.roots[work.nroot] = obj;
-	work.nroot++;
-}
-
 extern byte pclntab[]; // base for f->ptrsoff
 
-typedef struct BitVector BitVector;
-struct BitVector
+BitVector
+runtime·stackmapdata(StackMap *stackmap, int32 n)
 {
-	int32 n;
-	uint32 data[];
-};
+	if(n < 0 || n >= stackmap->n)
+		runtime·throw("stackmapdata: index out of range");
+	return (BitVector){stackmap->nbit, stackmap->data + n*((stackmap->nbit+31)/32)};
+}
 
 // Scans an interface data value when the interface type indicates
 // that it is a pointer.
 static void
-scaninterfacedata(uintptr bits, byte *scanp, bool afterprologue)
+scaninterfacedata(uintptr bits, byte *scanp, bool afterprologue, void *wbufp)
 {
 	Itab *tab;
 	Type *type;
@@ -1356,16 +1450,17 @@ scaninterfacedata(uintptr bits, byte *scanp, bool afterprologue)
 				return;
 		}
 	}
-	addroot((Obj){scanp+PtrSize, PtrSize, 0});
+	enqueue1(wbufp, (Obj){scanp+PtrSize, PtrSize, 0});
 }
 
 // Starting from scanp, scans words corresponding to set bits.
 static void
-scanbitvector(byte *scanp, BitVector *bv, bool afterprologue)
+scanbitvector(Func *f, bool precise, byte *scanp, BitVector *bv, bool afterprologue, void *wbufp)
 {
 	uintptr word, bits;
 	uint32 *wordp;
 	int32 i, remptrs;
+	byte *p;
 
 	wordp = bv->data;
 	for(remptrs = bv->n; remptrs > 0; remptrs -= 32) {
@@ -1377,11 +1472,88 @@ scanbitvector(byte *scanp, BitVector *bv, bool afterprologue)
 		i /= BitsPerPointer;
 		for(; i > 0; i--) {
 			bits = word & 3;
-			if(bits != BitsNoPointer && *(void**)scanp != nil)
-				if(bits == BitsPointer)
-					addroot((Obj){scanp, PtrSize, 0});
-				else
-					scaninterfacedata(bits, scanp, afterprologue);
+			switch(bits) {
+			case BitsDead:
+				if(runtime·debug.gcdead)
+					*(uintptr*)scanp = PoisonGC;
+				break;
+			case BitsScalar:
+				break;
+			case BitsPointer:
+				p = *(byte**)scanp;
+				if(p != nil) {
+					if(Debug > 2)
+						runtime·printf("frame %s @%p: ptr %p\n", runtime·funcname(f), scanp, p);
+					if(precise && (p < (byte*)PageSize || (uintptr)p == PoisonGC || (uintptr)p == PoisonStack)) {
+						// Looks like a junk value in a pointer slot.
+						// Liveness analysis wrong?
+						m->traceback = 2;
+						runtime·printf("bad pointer in frame %s at %p: %p\n", runtime·funcname(f), scanp, p);
+						runtime·throw("bad pointer in scanbitvector");
+					}
+					enqueue1(wbufp, (Obj){scanp, PtrSize, 0});
+				}
+				break;
+			case BitsMultiWord:
+				p = scanp;
+				word >>= BitsPerPointer;
+				scanp += PtrSize;
+				i--;
+				if(i == 0) {
+					// Get next chunk of bits
+					remptrs -= 32;
+					word = *wordp++;
+					if(remptrs < 32)
+						i = remptrs;
+					else
+						i = 32;
+					i /= BitsPerPointer;
+				}
+				switch(word & 3) {
+				case BitsString:
+					if(Debug > 2)
+						runtime·printf("frame %s @%p: string %p/%D\n", runtime·funcname(f), p, ((String*)p)->str, (int64)((String*)p)->len);
+					if(((String*)p)->len != 0)
+						markonly(((String*)p)->str);
+					break;
+				case BitsSlice:
+					word >>= BitsPerPointer;
+					scanp += PtrSize;
+					i--;
+					if(i == 0) {
+						// Get next chunk of bits
+						remptrs -= 32;
+						word = *wordp++;
+						if(remptrs < 32)
+							i = remptrs;
+						else
+							i = 32;
+						i /= BitsPerPointer;
+					}
+					if(Debug > 2)
+						runtime·printf("frame %s @%p: slice %p/%D/%D\n", runtime·funcname(f), p, ((Slice*)p)->array, (int64)((Slice*)p)->len, (int64)((Slice*)p)->cap);
+					if(((Slice*)p)->cap < ((Slice*)p)->len) {
+						m->traceback = 2;
+						runtime·printf("bad slice in frame %s at %p: %p/%p/%p\n", runtime·funcname(f), p, ((byte**)p)[0], ((byte**)p)[1], ((byte**)p)[2]);
+						runtime·throw("slice capacity smaller than length");
+					}
+					if(((Slice*)p)->cap != 0)
+						enqueue1(wbufp, (Obj){p, PtrSize, 0});
+					break;
+				case BitsIface:
+				case BitsEface:
+					if(*(byte**)p != nil) {
+						if(Debug > 2) {
+							if((word&3) == BitsEface)
+								runtime·printf("frame %s @%p: eface %p %p\n", runtime·funcname(f), p, ((uintptr*)p)[0], ((uintptr*)p)[1]);
+							else
+								runtime·printf("frame %s @%p: iface %p %p\n", runtime·funcname(f), p, ((uintptr*)p)[0], ((uintptr*)p)[1]);
+						}
+						scaninterfacedata(word & 3, p, afterprologue, wbufp);
+					}
+					break;
+				}
+			}
 			word >>= BitsPerPointer;
 			scanp += PtrSize;
 		}
@@ -1389,64 +1561,111 @@ scanbitvector(byte *scanp, BitVector *bv, bool afterprologue)
 }
 
 // Scan a stack frame: local variables and function arguments/results.
-static void
-addframeroots(Stkframe *frame, void*)
+static bool
+scanframe(Stkframe *frame, void *wbufp)
 {
 	Func *f;
-	BitVector *args, *locals;
+	StackMap *stackmap;
+	BitVector bv;
 	uintptr size;
+	uintptr targetpc;
+	int32 pcdata;
 	bool afterprologue;
+	bool precise;
 
 	f = frame->fn;
+	targetpc = frame->continpc;
+	if(targetpc == 0) {
+		// Frame is dead.
+		return true;
+	}
+	if(targetpc != f->entry)
+		targetpc--;
+	pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc);
+	if(pcdata == -1) {
+		// We do not have a valid pcdata value but there might be a
+		// stackmap for this function.  It is likely that we are looking
+		// at the function prologue, assume so and hope for the best.
+		pcdata = 0;
+	}
 
 	// Scan local variables if stack frame has been allocated.
 	// Use pointer information if known.
 	afterprologue = (frame->varp > (byte*)frame->sp);
+	precise = false;
 	if(afterprologue) {
-		locals = runtime·funcdata(f, FUNCDATA_GCLocals);
-		if(locals == nil) {
+		stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
+		if(stackmap == nil) {
 			// No locals information, scan everything.
 			size = frame->varp - (byte*)frame->sp;
-			addroot((Obj){frame->varp - size, size, 0});
-		} else if(locals->n < 0) {
-			// Locals size information, scan just the
+			if(Debug > 2)
+				runtime·printf("frame %s unsized locals %p+%p\n", runtime·funcname(f), frame->varp-size, size);
+			enqueue1(wbufp, (Obj){frame->varp - size, size, 0});
+		} else if(stackmap->n < 0) {
+			// Locals size information, scan just the locals.
+			size = -stackmap->n;
+			if(Debug > 2)
+				runtime·printf("frame %s conservative locals %p+%p\n", runtime·funcname(f), frame->varp-size, size);
+			enqueue1(wbufp, (Obj){frame->varp - size, size, 0});
+		} else if(stackmap->n > 0) {
+			// Locals bitmap information, scan just the pointers in
 			// locals.
-			size = -locals->n;
-			addroot((Obj){frame->varp - size, size, 0});
-		} else if(locals->n > 0) {
-			// Locals bitmap information, scan just the
-			// pointers in locals.
-			size = (locals->n*PtrSize) / BitsPerPointer;
-			scanbitvector(frame->varp - size, locals, afterprologue);
+			if(pcdata < 0 || pcdata >= stackmap->n) {
+				// don't know where we are
+				runtime·printf("pcdata is %d and %d stack map entries for %s (targetpc=%p)\n",
+					pcdata, stackmap->n, runtime·funcname(f), targetpc);
+				runtime·throw("scanframe: bad symbol table");
+			}
+			bv = runtime·stackmapdata(stackmap, pcdata);
+			size = (bv.n * PtrSize) / BitsPerPointer;
+			precise = true;
+			scanbitvector(f, true, frame->varp - size, &bv, afterprologue, wbufp);
 		}
 	}
 
 	// Scan arguments.
 	// Use pointer information if known.
-	args = runtime·funcdata(f, FUNCDATA_GCArgs);
-	if(args != nil && args->n > 0)
-		scanbitvector(frame->argp, args, false);
-	else
-		addroot((Obj){frame->argp, frame->arglen, 0});
+	stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
+	if(stackmap != nil) {
+		bv = runtime·stackmapdata(stackmap, pcdata);
+		scanbitvector(f, precise, frame->argp, &bv, true, wbufp);
+	} else {
+		if(Debug > 2)
+			runtime·printf("frame %s conservative args %p+%p\n", runtime·funcname(f), frame->argp, (uintptr)frame->arglen);
+		enqueue1(wbufp, (Obj){frame->argp, frame->arglen, 0});
+	}
+	return true;
 }
 
 static void
-addstackroots(G *gp)
+addstackroots(G *gp, Workbuf **wbufp)
 {
 	M *mp;
 	int32 n;
 	Stktop *stk;
-	uintptr sp, guard, pc, lr;
+	uintptr sp, guard;
 	void *base;
 	uintptr size;
 
-	stk = (Stktop*)gp->stackbase;
-	guard = gp->stackguard;
+	switch(gp->status){
+	default:
+		runtime·printf("unexpected G.status %d (goroutine %p %D)\n", gp->status, gp, gp->goid);
+		runtime·throw("mark - bad status");
+	case Gdead:
+		return;
+	case Grunning:
+		runtime·throw("mark - world not stopped");
+	case Grunnable:
+	case Gsyscall:
+	case Gwaiting:
+		break;
+	}
 
 	if(gp == g)
 		runtime·throw("can't scan our own stack");
 	if((mp = gp->m) != nil && mp->helpgc)
 		runtime·throw("can't scan gchelper stack");
+
 	if(gp->syscallstack != (uintptr)nil) {
 		// Scanning another goroutine that is about to enter or might
 		// have just exited a system call. It may be executing code such
@@ -1454,35 +1673,33 @@ addstackroots(G *gp)
 		// Use the stack segment and stack pointer at the time of
 		// the system call instead, since that won't change underfoot.
 		sp = gp->syscallsp;
-		pc = gp->syscallpc;
-		lr = 0;
 		stk = (Stktop*)gp->syscallstack;
 		guard = gp->syscallguard;
 	} else {
 		// Scanning another goroutine's stack.
 		// The goroutine is usually asleep (the world is stopped).
 		sp = gp->sched.sp;
-		pc = gp->sched.pc;
-		lr = gp->sched.lr;
-
+		stk = (Stktop*)gp->stackbase;
+		guard = gp->stackguard;
 		// For function about to start, context argument is a root too.
 		if(gp->sched.ctxt != 0 && runtime·mlookup(gp->sched.ctxt, &base, &size, nil))
-			addroot((Obj){base, size, 0});
+			enqueue1(wbufp, (Obj){base, size, 0});
 	}
 	if(ScanStackByFrames) {
+		USED(sp);
 		USED(stk);
 		USED(guard);
-		runtime·gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, addframeroots, nil, false);
+		runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, scanframe, wbufp, false);
 	} else {
-		USED(lr);
-		USED(pc);
 		n = 0;
 		while(stk) {
 			if(sp < guard-StackGuard || (uintptr)stk < sp) {
 				runtime·printf("scanstack inconsistent: g%D#%d sp=%p not in [%p,%p]\n", gp->goid, n, sp, guard-StackGuard, stk);
 				runtime·throw("scanstack");
 			}
-			addroot((Obj){(byte*)sp, (uintptr)stk - sp, (uintptr)defaultProg | PRECISE | LOOP});
+			if(Debug > 2)
+				runtime·printf("conservative stack %p+%p\n", (byte*)sp, (uintptr)stk-sp);
+			enqueue1(wbufp, (Obj){(byte*)sp, (uintptr)stk - sp, (uintptr)defaultProg | PRECISE | LOOP});
 			sp = stk->gobuf.sp;
 			guard = stk->stackguard;
 			stk = (Stktop*)stk->stackbase;
@@ -1491,101 +1708,17 @@ addstackroots(G *gp)
 	}
 }
 
-static void
-addfinroots(void *v)
-{
-	uintptr size;
-	void *base;
-
-	size = 0;
-	if(!runtime·mlookup(v, &base, &size, nil) || !runtime·blockspecial(base))
-		runtime·throw("mark - finalizer inconsistency");
-
-	// do not mark the finalizer block itself.  just mark the things it points at.
-	addroot((Obj){base, size, 0});
-}
-
-static void
-addroots(void)
-{
-	G *gp;
-	FinBlock *fb;
-	MSpan *s, **allspans;
-	uint32 spanidx;
-
-	work.nroot = 0;
-
-	// data & bss
-	// TODO(atom): load balancing
-	addroot((Obj){data, edata - data, (uintptr)gcdata});
-	addroot((Obj){bss, ebss - bss, (uintptr)gcbss});
-
-	// MSpan.types
-	allspans = runtime·mheap.allspans;
-	for(spanidx=0; spanidx<runtime·mheap.nspan; spanidx++) {
-		s = allspans[spanidx];
-		if(s->state == MSpanInUse) {
-			// The garbage collector ignores type pointers stored in MSpan.types:
-			//  - Compiler-generated types are stored outside of heap.
-			//  - The reflect package has runtime-generated types cached in its data structures.
-			//    The garbage collector relies on finding the references via that cache.
-			switch(s->types.compression) {
-			case MTypes_Empty:
-			case MTypes_Single:
-				break;
-			case MTypes_Words:
-			case MTypes_Bytes:
-				markonly((byte*)s->types.data);
-				break;
-			}
-		}
-	}
-
-	// stacks
-	for(gp=runtime·allg; gp!=nil; gp=gp->alllink) {
-		switch(gp->status){
-		default:
-			runtime·printf("unexpected G.status %d\n", gp->status);
-			runtime·throw("mark - bad status");
-		case Gdead:
-			break;
-		case Grunning:
-			runtime·throw("mark - world not stopped");
-		case Grunnable:
-		case Gsyscall:
-		case Gwaiting:
-			addstackroots(gp);
-			break;
-		}
-	}
-
-	runtime·walkfintab(addfinroots);
-
-	for(fb=allfin; fb; fb=fb->alllink)
-		addroot((Obj){(byte*)fb->fin, fb->cnt*sizeof(fb->fin[0]), 0});
-}
-
-static bool
-handlespecial(byte *p, uintptr size)
+void
+runtime·queuefinalizer(byte *p, FuncVal *fn, uintptr nret, Type *fint, PtrType *ot)
 {
-	FuncVal *fn;
-	uintptr nret;
-	PtrType *ot;
-	Type *fint;
 	FinBlock *block;
 	Finalizer *f;
 
-	if(!runtime·getfinalizer(p, true, &fn, &nret, &fint, &ot)) {
-		runtime·setblockspecial(p, false);
-		runtime·MProf_Free(p, size);
-		return false;
-	}
-
 	runtime·lock(&finlock);
 	if(finq == nil || finq->cnt == finq->cap) {
 		if(finc == nil) {
-			finc = runtime·persistentalloc(PageSize, 0, &mstats.gc_sys);
-			finc->cap = (PageSize - sizeof(FinBlock)) / sizeof(Finalizer) + 1;
+			finc = runtime·persistentalloc(FinBlockSize, 0, &mstats.gc_sys);
+			finc->cap = (FinBlockSize - sizeof(FinBlock)) / sizeof(Finalizer) + 1;
 			finc->alllink = allfin;
 			allfin = finc;
 		}
@@ -1601,33 +1734,79 @@ handlespecial(byte *p, uintptr size)
 	f->fint = fint;
 	f->ot = ot;
 	f->arg = p;
+	runtime·fingwake = true;
 	runtime·unlock(&finlock);
-	return true;
+}
+
+void
+runtime·iterate_finq(void (*callback)(FuncVal*, byte*, uintptr, Type*, PtrType*))
+{
+	FinBlock *fb;
+	Finalizer *f;
+	uintptr i;
+
+	for(fb = allfin; fb; fb = fb->alllink) {
+		for(i = 0; i < fb->cnt; i++) {
+			f = &fb->fin[i];
+			callback(f->fn, f->arg, f->nret, f->fint, f->ot);
+		}
+	}
+}
+
+void
+runtime·MSpan_EnsureSwept(MSpan *s)
+{
+	uint32 sg;
+
+	// Caller must disable preemption.
+	// Otherwise when this function returns the span can become unswept again
+	// (if GC is triggered on another goroutine).
+	if(m->locks == 0 && m->mallocing == 0 && g != m->g0)
+		runtime·throw("MSpan_EnsureSwept: m is not locked");
+
+	sg = runtime·mheap.sweepgen;
+	if(runtime·atomicload(&s->sweepgen) == sg)
+		return;
+	if(runtime·cas(&s->sweepgen, sg-2, sg-1)) {
+		runtime·MSpan_Sweep(s);
+		return;
+	}
+	// unfortunate condition, and we don't have efficient means to wait
+	while(runtime·atomicload(&s->sweepgen) != sg)
+		runtime·osyield();  
 }
 
 // Sweep frees or collects finalizers for blocks not marked in the mark phase.
 // It clears the mark bits in preparation for the next GC round.
-static void
-sweepspan(ParFor *desc, uint32 idx)
+// Returns true if the span was returned to heap.
+bool
+runtime·MSpan_Sweep(MSpan *s)
 {
-	int32 cl, n, npages;
-	uintptr size;
+	int32 cl, n, npages, nfree;
+	uintptr size, off, *bitp, shift, bits;
+	uint32 sweepgen;
 	byte *p;
 	MCache *c;
 	byte *arena_start;
 	MLink head, *end;
-	int32 nfree;
 	byte *type_data;
 	byte compression;
 	uintptr type_data_inc;
-	MSpan *s;
-
-	USED(&desc);
-	s = runtime·mheap.allspans[idx];
-	if(s->state != MSpanInUse)
-		return;
+	MLink *x;
+	Special *special, **specialp, *y;
+	bool res, sweepgenset;
+
+	// It's critical that we enter this function with preemption disabled,
+	// GC must not start while we are in the middle of this function.
+	if(m->locks == 0 && m->mallocing == 0 && g != m->g0)
+		runtime·throw("MSpan_Sweep: m is not locked");
+	sweepgen = runtime·mheap.sweepgen;
+	if(s->state != MSpanInUse || s->sweepgen != sweepgen-1) {
+		runtime·printf("MSpan_Sweep: state=%d sweepgen=%d mheap.sweepgen=%d\n",
+			s->state, s->sweepgen, sweepgen);
+		runtime·throw("MSpan_Sweep: bad span state");
+	}
 	arena_start = runtime·mheap.arena_start;
-	p = (byte*)(s->start << PageShift);
 	cl = s->sizeclass;
 	size = s->elemsize;
 	if(cl == 0) {
@@ -1637,10 +1816,52 @@ sweepspan(ParFor *desc, uint32 idx)
 		npages = runtime·class_to_allocnpages[cl];
 		n = (npages << PageShift) / size;
 	}
+	res = false;
 	nfree = 0;
 	end = &head;
 	c = m->mcache;
-	
+	sweepgenset = false;
+
+	// mark any free objects in this span so we don't collect them
+	for(x = s->freelist; x != nil; x = x->next) {
+		// This is markonly(x) but faster because we don't need
+		// atomic access and we're guaranteed to be pointing at
+		// the head of a valid object.
+		off = (uintptr*)x - (uintptr*)runtime·mheap.arena_start;
+		bitp = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+		shift = off % wordsPerBitmapWord;
+		*bitp |= bitMarked<<shift;
+	}
+
+	// Unlink & free special records for any objects we're about to free.
+	specialp = &s->specials;
+	special = *specialp;
+	while(special != nil) {
+		// A finalizer can be set for an inner byte of an object, find object beginning.
+		p = (byte*)(s->start << PageShift) + special->offset/size*size;
+		off = (uintptr*)p - (uintptr*)arena_start;
+		bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
+		shift = off % wordsPerBitmapWord;
+		bits = *bitp>>shift;
+		if((bits & (bitAllocated|bitMarked)) == bitAllocated) {
+			// Find the exact byte for which the special was setup
+			// (as opposed to object beginning).
+			p = (byte*)(s->start << PageShift) + special->offset;
+			// about to free object: splice out special record
+			y = special;
+			special = special->next;
+			*specialp = special;
+			if(!runtime·freespecial(y, p, size, false)) {
+				// stop freeing of object if it has a finalizer
+				*bitp |= bitMarked << shift;
+			}
+		} else {
+			// object is still live: keep special record
+			specialp = &special->next;
+			special = *specialp;
+		}
+	}
+
 	type_data = (byte*)s->types.data;
 	type_data_inc = sizeof(uintptr);
 	compression = s->types.compression;
@@ -1654,9 +1875,8 @@ sweepspan(ParFor *desc, uint32 idx)
 	// Sweep through n objects of given size starting at p.
 	// This thread owns the span now, so it can manipulate
 	// the block bitmap without atomic operations.
+	p = (byte*)(s->start << PageShift);
 	for(; n > 0; n--, p += size, type_data+=type_data_inc) {
-		uintptr off, *bitp, shift, bits;
-
 		off = (uintptr*)p - (uintptr*)arena_start;
 		bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
 		shift = off % wordsPerBitmapWord;
@@ -1666,33 +1886,32 @@ sweepspan(ParFor *desc, uint32 idx)
 			continue;
 
 		if((bits & bitMarked) != 0) {
-			if(DebugMark) {
-				if(!(bits & bitSpecial))
-					runtime·printf("found spurious mark on %p\n", p);
-				*bitp &= ~(bitSpecial<<shift);
-			}
 			*bitp &= ~(bitMarked<<shift);
 			continue;
 		}
 
-		// Special means it has a finalizer or is being profiled.
-		// In DebugMark mode, the bit has been coopted so
-		// we have to assume all blocks are special.
-		if(DebugMark || (bits & bitSpecial) != 0) {
-			if(handlespecial(p, size))
-				continue;
-		}
+		if(runtime·debug.allocfreetrace)
+			runtime·tracefree(p, size);
 
-		// Mark freed; restore block boundary bit.
-		*bitp = (*bitp & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
+		// Clear mark and scan bits.
+		*bitp &= ~((bitScan|bitMarked)<<shift);
 
 		if(cl == 0) {
 			// Free large span.
 			runtime·unmarkspan(p, 1<<PageShift);
-			*(uintptr*)p = (uintptr)0xdeaddeaddeaddeadll;	// needs zeroing
-			runtime·MHeap_Free(&runtime·mheap, s, 1);
+			s->needzero = 1;
+			// important to set sweepgen before returning it to heap
+			runtime·atomicstore(&s->sweepgen, sweepgen);
+			sweepgenset = true;
+			// See note about SysFault vs SysFree in malloc.goc.
+			if(runtime·debug.efence)
+				runtime·SysFault(p, size);
+			else
+				runtime·MHeap_Free(&runtime·mheap, s, 1);
 			c->local_nlargefree++;
 			c->local_largefree += size;
+			runtime·xadd64(&mstats.next_gc, -(uint64)(size * (gcpercent + 100)/100));
+			res = true;
 		} else {
 			// Free small object.
 			switch(compression) {
@@ -1703,19 +1922,113 @@ sweepspan(ParFor *desc, uint32 idx)
 				*(byte*)type_data = 0;
 				break;
 			}
-			if(size > sizeof(uintptr))
+			if(size > 2*sizeof(uintptr))
 				((uintptr*)p)[1] = (uintptr)0xdeaddeaddeaddeadll;	// mark as "needs to be zeroed"
-			
+			else if(size > sizeof(uintptr))
+				((uintptr*)p)[1] = 0;
+
 			end->next = (MLink*)p;
 			end = (MLink*)p;
 			nfree++;
 		}
 	}
 
-	if(nfree) {
+	// We need to set s->sweepgen = h->sweepgen only when all blocks are swept,
+	// because of the potential for a concurrent free/SetFinalizer.
+	// But we need to set it before we make the span available for allocation
+	// (return it to heap or mcentral), because allocation code assumes that a
+	// span is already swept if available for allocation.
+
+	if(!sweepgenset && nfree == 0) {
+		// The span must be in our exclusive ownership until we update sweepgen,
+		// check for potential races.
+		if(s->state != MSpanInUse || s->sweepgen != sweepgen-1) {
+			runtime·printf("MSpan_Sweep: state=%d sweepgen=%d mheap.sweepgen=%d\n",
+				s->state, s->sweepgen, sweepgen);
+			runtime·throw("MSpan_Sweep: bad span state after sweep");
+		}
+		runtime·atomicstore(&s->sweepgen, sweepgen);
+	}
+	if(nfree > 0) {
 		c->local_nsmallfree[cl] += nfree;
 		c->local_cachealloc -= nfree * size;
-		runtime·MCentral_FreeSpan(&runtime·mheap.central[cl], s, nfree, head.next, end);
+		runtime·xadd64(&mstats.next_gc, -(uint64)(nfree * size * (gcpercent + 100)/100));
+		res = runtime·MCentral_FreeSpan(&runtime·mheap.central[cl], s, nfree, head.next, end);
+		//MCentral_FreeSpan updates sweepgen
+	}
+	return res;
+}
+
+// State of background sweep.
+// Pretected by gclock.
+static struct
+{
+	G*	g;
+	bool	parked;
+
+	MSpan**	spans;
+	uint32	nspan;
+	uint32	spanidx;
+} sweep;
+
+// background sweeping goroutine
+static void
+bgsweep(void)
+{
+	g->issystem = 1;
+	for(;;) {
+		while(runtime·sweepone() != -1) {
+			gcstats.nbgsweep++;
+			runtime·gosched();
+		}
+		runtime·lock(&gclock);
+		if(!runtime·mheap.sweepdone) {
+			// It's possible if GC has happened between sweepone has
+			// returned -1 and gclock lock.
+			runtime·unlock(&gclock);
+			continue;
+		}
+		sweep.parked = true;
+		g->isbackground = true;
+		runtime·parkunlock(&gclock, "GC sweep wait");
+		g->isbackground = false;
+	}
+}
+
+// sweeps one span
+// returns number of pages returned to heap, or -1 if there is nothing to sweep
+uintptr
+runtime·sweepone(void)
+{
+	MSpan *s;
+	uint32 idx, sg;
+	uintptr npages;
+
+	// increment locks to ensure that the goroutine is not preempted
+	// in the middle of sweep thus leaving the span in an inconsistent state for next GC
+	m->locks++;
+	sg = runtime·mheap.sweepgen;
+	for(;;) {
+		idx = runtime·xadd(&sweep.spanidx, 1) - 1;
+		if(idx >= sweep.nspan) {
+			runtime·mheap.sweepdone = true;
+			m->locks--;
+			return -1;
+		}
+		s = sweep.spans[idx];
+		if(s->state != MSpanInUse) {
+			s->sweepgen = sg;
+			continue;
+		}
+		if(s->sweepgen != sg-2 || !runtime·cas(&s->sweepgen, sg-2, sg-1))
+			continue;
+		if(s->incache)
+			runtime·throw("sweep of incache span");
+		npages = s->npages;
+		if(!runtime·MSpan_Sweep(s))
+			npages = 0;
+		m->locks--;
+		return npages;
 	}
 }
 
@@ -1727,7 +2040,7 @@ dumpspan(uint32 idx)
 	byte *p;
 	byte *arena_start;
 	MSpan *s;
-	bool allocated, special;
+	bool allocated;
 
 	s = runtime·mheap.allspans[idx];
 	if(s->state != MSpanInUse)
@@ -1754,7 +2067,6 @@ dumpspan(uint32 idx)
 		bits = *bitp>>shift;
 
 		allocated = ((bits & bitAllocated) != 0);
-		special = ((bits & bitSpecial) != 0);
 
 		for(i=0; i<size; i+=sizeof(void*)) {
 			if(column == 0) {
@@ -1762,7 +2074,6 @@ dumpspan(uint32 idx)
 			}
 			if(i == 0) {
 				runtime·printf(allocated ? "(" : "[");
-				runtime·printf(special ? "@" : "");
 				runtime·printf("%p: ", p+i);
 			} else {
 				runtime·printf(" ");
@@ -1798,42 +2109,24 @@ runtime·memorydump(void)
 void
 runtime·gchelper(void)
 {
-	int32 nproc;
+	uint32 nproc;
 
+	m->traceback = 2;
 	gchelperstart();
 
 	// parallel mark for over gc roots
 	runtime·parfordo(work.markfor);
 
 	// help other threads scan secondary blocks
-	scanblock(nil, nil, 0, true);
-
-	if(DebugMark) {
-		// wait while the main thread executes mark(debug_scanblock)
-		while(runtime·atomicload(&work.debugmarkdone) == 0)
-			runtime·usleep(10);
-	}
+	scanblock(nil, true);
 
-	runtime·parfordo(work.sweepfor);
 	bufferList[m->helpgc].busy = 0;
 	nproc = work.nproc;  // work.nproc can change right after we increment work.ndone
 	if(runtime·xadd(&work.ndone, +1) == nproc-1)
 		runtime·notewakeup(&work.alldone);
+	m->traceback = 0;
 }
 
-#define GcpercentUnknown (-2)
-
-// Initialized from $GOGC.  GOGC=off means no gc.
-//
-// Next gc is after we've allocated an extra amount of
-// memory proportional to the amount already in use.
-// If gcpercent=100 and we're using 4M, we'll gc again
-// when we get to 8M.  This keeps the gc cost in linear
-// proportion to the allocation cost.  Adjusting gcpercent
-// just changes the linear constant (and also the amount of
-// extra memory used).
-static int32 gcpercent = GcpercentUnknown;
-
 static void
 cachestats(void)
 {
@@ -1849,12 +2142,25 @@ cachestats(void)
 }
 
 static void
-updatememstats(GCStats *stats)
+flushallmcaches(void)
+{
+	P *p, **pp;
+	MCache *c;
+
+	// Flush MCache's to MCentral.
+	for(pp=runtime·allp; p=*pp; pp++) {
+		c = p->mcache;
+		if(c==nil)
+			continue;
+		runtime·MCache_ReleaseAll(c);
+	}
+}
+
+void
+runtime·updatememstats(GCStats *stats)
 {
 	M *mp;
 	MSpan *s;
-	MCache *c;
-	P *p, **pp;
 	int32 i;
 	uint64 stacks_inuse, smallfree;
 	uint64 *src, *dst;
@@ -1895,12 +2201,7 @@ updatememstats(GCStats *stats)
 	}
 
 	// Flush MCache's to MCentral.
-	for(pp=runtime·allp; p=*pp; pp++) {
-		c = p->mcache;
-		if(c==nil)
-			continue;
-		runtime·MCache_ReleaseAll(c);
-	}
+	flushallmcaches();
 
 	// Aggregate local stats.
 	cachestats();
@@ -1942,6 +2243,7 @@ updatememstats(GCStats *stats)
 struct gc_args
 {
 	int64 start_time; // start time of GC in ns (just before stoptheworld)
+	bool  eagersweep;
 };
 
 static void gc(struct gc_args *args);
@@ -1960,8 +2262,8 @@ readgogc(void)
 	return runtime·atoi(p);
 }
 
-static FuncVal runfinqv = {runfinq};
-
+// force = 1 - do GC regardless of current heap usage
+// force = 2 - go GC and eager sweep
 void
 runtime·gc(int32 force)
 {
@@ -1997,7 +2299,7 @@ runtime·gc(int32 force)
 		return;
 
 	runtime·semacquire(&runtime·worldsema, false);
-	if(!force && mstats.heap_alloc < mstats.next_gc) {
+	if(force==0 && mstats.heap_alloc < mstats.next_gc) {
 		// typically threads which lost the race to grab
 		// worldsema exit here when gc is done.
 		runtime·semrelease(&runtime·worldsema);
@@ -2006,22 +2308,25 @@ runtime·gc(int32 force)
 
 	// Ok, we're doing it!  Stop everybody else
 	a.start_time = runtime·nanotime();
+	a.eagersweep = force >= 2;
 	m->gcing = 1;
 	runtime·stoptheworld();
 	
+	clearpools();
+
 	// Run gc on the g0 stack.  We do this so that the g stack
 	// we're currently running on will no longer change.  Cuts
 	// the root set down a bit (g0 stacks are not scanned, and
 	// we don't need to scan gc's internal state).  Also an
 	// enabler for copyable stacks.
 	for(i = 0; i < (runtime·debug.gctrace > 1 ? 2 : 1); i++) {
+		if(i > 0)
+			a.start_time = runtime·nanotime();
 		// switch to g0, call gc(&a), then switch back
 		g->param = &a;
 		g->status = Gwaiting;
 		g->waitreason = "garbage collection";
 		runtime·mcall(mgc);
-		// record a new start time in case we're going around again
-		a.start_time = runtime·nanotime();
 	}
 
 	// all done
@@ -2032,19 +2337,10 @@ runtime·gc(int32 force)
 	m->locks--;
 
 	// now that gc is done, kick off finalizer thread if needed
-	if(finq != nil) {
-		runtime·lock(&finlock);
-		// kick off or wake up goroutine to run queued finalizers
-		if(fing == nil)
-			fing = runtime·newproc1(&runfinqv, nil, 0, 0, runtime·gc);
-		else if(fingwait) {
-			fingwait = 0;
-			runtime·ready(fing);
-		}
-		runtime·unlock(&finlock);
+	if(!ConcurrentSweep) {
+		// give the queued finalizers, if any, a chance to run
+		runtime·gosched();
 	}
-	// give the queued finalizers, if any, a chance to run
-	runtime·gosched();
 }
 
 static void
@@ -2060,33 +2356,24 @@ static void
 gc(struct gc_args *args)
 {
 	int64 t0, t1, t2, t3, t4;
-	uint64 heap0, heap1, obj0, obj1, ninstr;
+	uint64 heap0, heap1, obj, ninstr;
 	GCStats stats;
-	M *mp;
 	uint32 i;
 	Eface eface;
 
+	if(runtime·debug.allocfreetrace)
+		runtime·tracegc();
+
+	m->traceback = 2;
 	t0 = args->start_time;
+	work.tstart = args->start_time; 
 
 	if(CollectStats)
 		runtime·memclr((byte*)&gcstats, sizeof(gcstats));
 
-	for(mp=runtime·allm; mp; mp=mp->alllink)
-		runtime·settype_flush(mp);
-
-	heap0 = 0;
-	obj0 = 0;
-	if(runtime·debug.gctrace) {
-		updatememstats(nil);
-		heap0 = mstats.heap_alloc;
-		obj0 = mstats.nmalloc - mstats.nfree;
-	}
-
 	m->locks++;	// disable gc during mallocs in parforalloc
 	if(work.markfor == nil)
 		work.markfor = runtime·parforalloc(MaxGcproc);
-	if(work.sweepfor == nil)
-		work.sweepfor = runtime·parforalloc(MaxGcproc);
 	m->locks--;
 
 	if(itabtype == nil) {
@@ -2095,43 +2382,49 @@ gc(struct gc_args *args)
 		itabtype = ((PtrType*)eface.type)->elem;
 	}
 
+	t1 = 0;
+	if(runtime·debug.gctrace)
+		t1 = runtime·nanotime();
+
+	// Sweep what is not sweeped by bgsweep.
+	while(runtime·sweepone() != -1)
+		gcstats.npausesweep++;
+
 	work.nwait = 0;
 	work.ndone = 0;
-	work.debugmarkdone = 0;
 	work.nproc = runtime·gcprocs();
-	addroots();
-	runtime·parforsetup(work.markfor, work.nproc, work.nroot, nil, false, markroot);
-	runtime·parforsetup(work.sweepfor, work.nproc, runtime·mheap.nspan, nil, true, sweepspan);
+	runtime·parforsetup(work.markfor, work.nproc, RootCount + runtime·allglen, nil, false, markroot);
 	if(work.nproc > 1) {
 		runtime·noteclear(&work.alldone);
 		runtime·helpgc(work.nproc);
 	}
 
-	t1 = runtime·nanotime();
+	t2 = 0;
+	if(runtime·debug.gctrace)
+		t2 = runtime·nanotime();
 
 	gchelperstart();
 	runtime·parfordo(work.markfor);
-	scanblock(nil, nil, 0, true);
+	scanblock(nil, true);
 
-	if(DebugMark) {
-		for(i=0; i<work.nroot; i++)
-			debug_scanblock(work.roots[i].p, work.roots[i].n);
-		runtime·atomicstore(&work.debugmarkdone, 1);
-	}
-	t2 = runtime·nanotime();
+	t3 = 0;
+	if(runtime·debug.gctrace)
+		t3 = runtime·nanotime();
 
-	runtime·parfordo(work.sweepfor);
 	bufferList[m->helpgc].busy = 0;
-	t3 = runtime·nanotime();
-
 	if(work.nproc > 1)
 		runtime·notesleep(&work.alldone);
 
 	cachestats();
+	// next_gc calculation is tricky with concurrent sweep since we don't know size of live heap
+	// estimate what was live heap size after previous GC (for tracing only)
+	heap0 = mstats.next_gc*100/(gcpercent+100);
+	// conservatively set next_gc to high value assuming that everything is live
+	// concurrent/lazy sweep will reduce this number while discovering new garbage
 	mstats.next_gc = mstats.heap_alloc+mstats.heap_alloc*gcpercent/100;
 
 	t4 = runtime·nanotime();
-	mstats.last_gc = t4;
+	mstats.last_gc = runtime·unixnanotime();  // must be Unix time to make sense to user
 	mstats.pause_ns[mstats.numgc%nelem(mstats.pause_ns)] = t4 - t0;
 	mstats.pause_total_ns += t4 - t0;
 	mstats.numgc++;
@@ -2139,22 +2432,29 @@ gc(struct gc_args *args)
 		runtime·printf("pause %D\n", t4-t0);
 
 	if(runtime·debug.gctrace) {
-		updatememstats(&stats);
 		heap1 = mstats.heap_alloc;
-		obj1 = mstats.nmalloc - mstats.nfree;
+		runtime·updatememstats(&stats);
+		if(heap1 != mstats.heap_alloc) {
+			runtime·printf("runtime: mstats skew: heap=%D/%D\n", heap1, mstats.heap_alloc);
+			runtime·throw("mstats skew");
+		}
+		obj = mstats.nmalloc - mstats.nfree;
 
-		stats.nprocyield += work.sweepfor->nprocyield;
-		stats.nosyield += work.sweepfor->nosyield;
-		stats.nsleep += work.sweepfor->nsleep;
+		stats.nprocyield += work.markfor->nprocyield;
+		stats.nosyield += work.markfor->nosyield;
+		stats.nsleep += work.markfor->nsleep;
 
-		runtime·printf("gc%d(%d): %D+%D+%D ms, %D -> %D MB %D -> %D (%D-%D) objects,"
+		runtime·printf("gc%d(%d): %D+%D+%D+%D us, %D -> %D MB, %D (%D-%D) objects,"
+				" %d/%d/%d sweeps,"
 				" %D(%D) handoff, %D(%D) steal, %D/%D/%D yields\n",
-			mstats.numgc, work.nproc, (t2-t1)/1000000, (t3-t2)/1000000, (t1-t0+t4-t3)/1000000,
-			heap0>>20, heap1>>20, obj0, obj1,
+			mstats.numgc, work.nproc, (t1-t0)/1000, (t2-t1)/1000, (t3-t2)/1000, (t4-t3)/1000,
+			heap0>>20, heap1>>20, obj,
 			mstats.nmalloc, mstats.nfree,
+			sweep.nspan, gcstats.nbgsweep, gcstats.npausesweep,
 			stats.nhandoff, stats.nhandoffcnt,
-			work.sweepfor->nsteal, work.sweepfor->nstealcnt,
+			work.markfor->nsteal, work.markfor->nstealcnt,
 			stats.nprocyield, stats.nosyield, stats.nsleep);
+		gcstats.nbgsweep = gcstats.npausesweep = 0;
 		if(CollectStats) {
 			runtime·printf("scan: %D bytes, %D objects, %D untyped, %D types from MSpan\n",
 				gcstats.nbytes, gcstats.obj.cnt, gcstats.obj.notype, gcstats.obj.typelookup);
@@ -2181,9 +2481,49 @@ gc(struct gc_args *args)
 		}
 	}
 
+	// We cache current runtime·mheap.allspans array in sweep.spans,
+	// because the former can be resized and freed.
+	// Otherwise we would need to take heap lock every time
+	// we want to convert span index to span pointer.
+
+	// Free the old cached array if necessary.
+	if(sweep.spans && sweep.spans != runtime·mheap.allspans)
+		runtime·SysFree(sweep.spans, sweep.nspan*sizeof(sweep.spans[0]), &mstats.other_sys);
+	// Cache the current array.
+	runtime·mheap.sweepspans = runtime·mheap.allspans;
+	runtime·mheap.sweepgen += 2;
+	runtime·mheap.sweepdone = false;
+	sweep.spans = runtime·mheap.allspans;
+	sweep.nspan = runtime·mheap.nspan;
+	sweep.spanidx = 0;
+
+	// Temporary disable concurrent sweep, because we see failures on builders.
+	if(ConcurrentSweep && !args->eagersweep) {
+		runtime·lock(&gclock);
+		if(sweep.g == nil)
+			sweep.g = runtime·newproc1(&bgsweepv, nil, 0, 0, runtime·gc);
+		else if(sweep.parked) {
+			sweep.parked = false;
+			runtime·ready(sweep.g);
+		}
+		runtime·unlock(&gclock);
+	} else {
+		// Sweep all spans eagerly.
+		while(runtime·sweepone() != -1)
+			gcstats.npausesweep++;
+	}
+
+	// Shrink a stack if not much of it is being used.
+	// TODO: do in a parfor
+	for(i = 0; i < runtime·allglen; i++)
+		runtime·shrinkstack(runtime·allg[i]);
+
 	runtime·MProf_GC();
+	m->traceback = 0;
 }
 
+extern uintptr runtime·sizeof_C_MStats;
+
 void
 runtime·ReadMemStats(MStats *stats)
 {
@@ -2194,8 +2534,10 @@ runtime·ReadMemStats(MStats *stats)
 	runtime·semacquire(&runtime·worldsema, false);
 	m->gcing = 1;
 	runtime·stoptheworld();
-	updatememstats(nil);
-	*stats = mstats;
+	runtime·updatememstats(nil);
+	// Size of the trailing by_size array differs between Go and C,
+	// NumSizeClasses was changed, but we can not change Go struct because of backward compatibility.
+	runtime·memcopy(runtime·sizeof_C_MStats, stats, &mstats);
 	m->gcing = 0;
 	m->locks++;
 	runtime·semrelease(&runtime·worldsema);
@@ -2234,9 +2576,10 @@ runtime∕debug·readGCStats(Slice *pauses)
 	pauses->len = n+3;
 }
 
-void
-runtime∕debug·setGCPercent(intgo in, intgo out)
-{
+int32
+runtime·setgcpercent(int32 in) {
+	int32 out;
+
 	runtime·lock(&runtime·mheap);
 	if(gcpercent == GcpercentUnknown)
 		gcpercent = readgogc();
@@ -2245,7 +2588,7 @@ runtime∕debug·setGCPercent(intgo in, intgo out)
 		in = -1;
 	gcpercent = in;
 	runtime·unlock(&runtime·mheap);
-	FLUSH(&out);
+	return out;
 }
 
 static void
@@ -2268,15 +2611,38 @@ runfinq(void)
 	uint32 framesz, framecap, i;
 	Eface *ef, ef1;
 
+	// This function blocks for long periods of time, and because it is written in C
+	// we have no liveness information. Zero everything so that uninitialized pointers
+	// do not cause memory leaks.
+	f = nil;
+	fb = nil;
+	next = nil;
 	frame = nil;
 	framecap = 0;
+	framesz = 0;
+	i = 0;
+	ef = nil;
+	ef1.type = nil;
+	ef1.data = nil;
+	
+	// force flush to memory
+	USED(&f);
+	USED(&fb);
+	USED(&next);
+	USED(&framesz);
+	USED(&i);
+	USED(&ef);
+	USED(&ef1);
+
 	for(;;) {
 		runtime·lock(&finlock);
 		fb = finq;
 		finq = nil;
 		if(fb == nil) {
-			fingwait = 1;
-			runtime·park(runtime·unlock, &finlock, "finalizer wait");
+			runtime·fingwait = true;
+			g->isbackground = true;
+			runtime·parkunlock(&finlock, "finalizer wait");
+			g->isbackground = false;
 			continue;
 		}
 		runtime·unlock(&finlock);
@@ -2290,7 +2656,7 @@ runfinq(void)
 				if(framecap < framesz) {
 					runtime·free(frame);
 					// The frame does not contain pointers interesting for GC,
-					// all not yet finalized objects are stored in finc.
+					// all not yet finalized objects are stored in finq.
 					// If we do not mark it as FlagNoScan,
 					// the last finalized object is not collected.
 					frame = runtime·mallocgc(framesz, 0, FlagNoScan|FlagNoInvokeGC);
@@ -2313,80 +2679,99 @@ runfinq(void)
 					if(!runtime·ifaceE2I2((InterfaceType*)f->fint, ef1, (Iface*)frame))
 						runtime·throw("invalid type conversion in runfinq");
 				}
-				reflect·call(f->fn, frame, framesz);
+				reflect·call(f->fn, frame, framesz, framesz);
 				f->fn = nil;
 				f->arg = nil;
 				f->ot = nil;
 			}
 			fb->cnt = 0;
+			runtime·lock(&finlock);
 			fb->next = finc;
 			finc = fb;
+			runtime·unlock(&finlock);
 		}
+
+		// Zero everything that's dead, to avoid memory leaks.
+		// See comment at top of function.
+		f = nil;
+		fb = nil;
+		next = nil;
+		i = 0;
+		ef = nil;
+		ef1.type = nil;
+		ef1.data = nil;
 		runtime·gc(1);	// trigger another gc to clean up the finalized objects, if possible
 	}
 }
 
-// mark the block at v of size n as allocated.
-// If noscan is true, mark it as not needing scanning.
 void
-runtime·markallocated(void *v, uintptr n, bool noscan)
+runtime·createfing(void)
 {
-	uintptr *b, obits, bits, off, shift;
+	if(fing != nil)
+		return;
+	// Here we use gclock instead of finlock,
+	// because newproc1 can allocate, which can cause on-demand span sweep,
+	// which can queue finalizers, which would deadlock.
+	runtime·lock(&gclock);
+	if(fing == nil)
+		fing = runtime·newproc1(&runfinqv, nil, 0, 0, runtime·gc);
+	runtime·unlock(&gclock);
+}
 
-	if(0)
-		runtime·printf("markallocated %p+%p\n", v, n);
+G*
+runtime·wakefing(void)
+{
+	G *res;
 
-	if((byte*)v+n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
-		runtime·throw("markallocated: bad pointer");
+	res = nil;
+	runtime·lock(&finlock);
+	if(runtime·fingwait && runtime·fingwake) {
+		runtime·fingwait = false;
+		runtime·fingwake = false;
+		res = fing;
+	}
+	runtime·unlock(&finlock);
+	return res;
+}
+
+void
+runtime·marknogc(void *v)
+{
+	uintptr *b, off, shift;
 
 	off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start;  // word offset
 	b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
 	shift = off % wordsPerBitmapWord;
+	*b = (*b & ~(bitAllocated<<shift)) | bitBlockBoundary<<shift;
+}
 
-	for(;;) {
-		obits = *b;
-		bits = (obits & ~(bitMask<<shift)) | (bitAllocated<<shift);
-		if(noscan)
-			bits |= bitNoScan<<shift;
-		if(runtime·gomaxprocs == 1) {
-			*b = bits;
-			break;
-		} else {
-			// more than one goroutine is potentially running: use atomic op
-			if(runtime·casp((void**)b, (void*)obits, (void*)bits))
-				break;
-		}
-	}
+void
+runtime·markscan(void *v)
+{
+	uintptr *b, off, shift;
+
+	off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start;  // word offset
+	b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
+	shift = off % wordsPerBitmapWord;
+	*b |= bitScan<<shift;
 }
 
-// mark the block at v of size n as freed.
+// mark the block at v as freed.
 void
-runtime·markfreed(void *v, uintptr n)
+runtime·markfreed(void *v)
 {
-	uintptr *b, obits, bits, off, shift;
+	uintptr *b, off, shift;
 
 	if(0)
-		runtime·printf("markfreed %p+%p\n", v, n);
+		runtime·printf("markfreed %p\n", v);
 
-	if((byte*)v+n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
+	if((byte*)v > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
 		runtime·throw("markfreed: bad pointer");
 
 	off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start;  // word offset
 	b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
 	shift = off % wordsPerBitmapWord;
-
-	for(;;) {
-		obits = *b;
-		bits = (obits & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
-		if(runtime·gomaxprocs == 1) {
-			*b = bits;
-			break;
-		} else {
-			// more than one goroutine is potentially running: use atomic op
-			if(runtime·casp((void**)b, (void*)obits, (void*)bits))
-				break;
-		}
-	}
+	*b = (*b & ~(bitMask<<shift)) | (bitAllocated<<shift);
 }
 
 // check that the block at v of size n is marked freed.
@@ -2418,15 +2803,28 @@ runtime·checkfreed(void *v, uintptr n)
 void
 runtime·markspan(void *v, uintptr size, uintptr n, bool leftover)
 {
-	uintptr *b, off, shift;
+	uintptr *b, *b0, off, shift, i, x;
 	byte *p;
 
 	if((byte*)v+size*n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
 		runtime·throw("markspan: bad pointer");
 
+	if(runtime·checking) {
+		// bits should be all zero at the start
+		off = (byte*)v + size - runtime·mheap.arena_start;
+		b = (uintptr*)(runtime·mheap.arena_start - off/wordsPerBitmapWord);
+		for(i = 0; i < size/PtrSize/wordsPerBitmapWord; i++) {
+			if(b[i] != 0)
+				runtime·throw("markspan: span bits not zero");
+		}
+	}
+
 	p = v;
 	if(leftover)	// mark a boundary just past end of last block too
 		n++;
+
+	b0 = nil;
+	x = 0;
 	for(; n-- > 0; p += size) {
 		// Okay to use non-atomic ops here, because we control
 		// the entire span, and each bitmap word has bits for only
@@ -2435,8 +2833,15 @@ runtime·markspan(void *v, uintptr size, uintptr n, bool leftover)
 		off = (uintptr*)p - (uintptr*)runtime·mheap.arena_start;  // word offset
 		b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
 		shift = off % wordsPerBitmapWord;
-		*b = (*b & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
+		if(b0 != b) {
+			if(b0 != nil)
+				*b0 = x;
+			b0 = b;
+			x = 0;
+		}
+		x |= bitAllocated<<shift;
 	}
+	*b0 = x;
 }
 
 // unmark the span of memory at v of length n bytes.
@@ -2465,50 +2870,6 @@ runtime·unmarkspan(void *v, uintptr n)
 		*b-- = 0;
 }
 
-bool
-runtime·blockspecial(void *v)
-{
-	uintptr *b, off, shift;
-
-	if(DebugMark)
-		return true;
-
-	off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start;
-	b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
-	shift = off % wordsPerBitmapWord;
-
-	return (*b & (bitSpecial<<shift)) != 0;
-}
-
-void
-runtime·setblockspecial(void *v, bool s)
-{
-	uintptr *b, off, shift, bits, obits;
-
-	if(DebugMark)
-		return;
-
-	off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start;
-	b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1;
-	shift = off % wordsPerBitmapWord;
-
-	for(;;) {
-		obits = *b;
-		if(s)
-			bits = obits | (bitSpecial<<shift);
-		else
-			bits = obits & ~(bitSpecial<<shift);
-		if(runtime·gomaxprocs == 1) {
-			*b = bits;
-			break;
-		} else {
-			// more than one goroutine is potentially running: use atomic op
-			if(runtime·casp((void**)b, (void*)obits, (void*)bits))
-				break;
-		}
-	}
-}
-
 void
 runtime·MHeap_MapBits(MHeap *h)
 {
@@ -2522,9 +2883,10 @@ runtime·MHeap_MapBits(MHeap *h)
 
 	n = (h->arena_used - h->arena_start) / wordsPerBitmapWord;
 	n = ROUND(n, bitmapChunk);
+	n = ROUND(n, PhysPageSize);
 	if(h->bitmap_mapped >= n)
 		return;
 
-	runtime·SysMap(h->arena_start - n, n - h->bitmap_mapped, &mstats.gc_sys);
+	runtime·SysMap(h->arena_start - n, n - h->bitmap_mapped, h->arena_reserved, &mstats.gc_sys);
 	h->bitmap_mapped = n;
 }
diff --git a/src/pkg/runtime/mgc0.go b/src/pkg/runtime/mgc0.go
index b150546..624485d 100644
--- a/src/pkg/runtime/mgc0.go
+++ b/src/pkg/runtime/mgc0.go
@@ -9,7 +9,19 @@ func gc_m_ptr(ret *interface{}) {
 	*ret = (*m)(nil)
 }
 
+// Called from C. Returns the Go type *g.
+func gc_g_ptr(ret *interface{}) {
+	*ret = (*g)(nil)
+}
+
 // Called from C. Returns the Go type *itab.
 func gc_itab_ptr(ret *interface{}) {
 	*ret = (*itab)(nil)
 }
+
+func timenow() (sec int64, nsec int32)
+
+func gc_unixnanotime(now *int64) {
+	sec, nsec := timenow()
+	*now = sec*1e9 + int64(nsec)
+}
diff --git a/src/pkg/runtime/mgc0.h b/src/pkg/runtime/mgc0.h
index f8abe6c..16000d1 100644
--- a/src/pkg/runtime/mgc0.h
+++ b/src/pkg/runtime/mgc0.h
@@ -44,3 +44,44 @@ enum {
 	//  - at most GC_STACK_CAPACITY allocations because of GC_ARRAY_START
 	GC_STACK_CAPACITY = 8,	
 };
+
+enum {
+	ScanStackByFrames = 1,
+	IgnorePreciseGC = 0,
+
+	// Four bits per word (see #defines below).
+	wordsPerBitmapWord = sizeof(void*)*8/4,
+	bitShift = sizeof(void*)*8/4,
+};
+
+// Bits in per-word bitmap.
+// #defines because enum might not be able to hold the values.
+//
+// Each word in the bitmap describes wordsPerBitmapWord words
+// of heap memory.  There are 4 bitmap bits dedicated to each heap word,
+// so on a 64-bit system there is one bitmap word per 16 heap words.
+// The bits in the word are packed together by type first, then by
+// heap location, so each 64-bit bitmap word consists of, from top to bottom,
+// the 16 bitMarked bits for the corresponding heap words,
+// then the 16 bitScan/bitBlockBoundary bits, then the 16 bitAllocated bits.
+// This layout makes it easier to iterate over the bits of a given type.
+//
+// The bitmap starts at mheap.arena_start and extends *backward* from
+// there.  On a 64-bit system the off'th word in the arena is tracked by
+// the off/16+1'th word before mheap.arena_start.  (On a 32-bit system,
+// the only difference is that the divisor is 8.)
+//
+// To pull out the bits corresponding to a given pointer p, we use:
+//
+//	off = p - (uintptr*)mheap.arena_start;  // word offset
+//	b = (uintptr*)mheap.arena_start - off/wordsPerBitmapWord - 1;
+//	shift = off % wordsPerBitmapWord
+//	bits = *b >> shift;
+//	/* then test bits & bitAllocated, bits & bitMarked, etc. */
+//
+#define bitAllocated		((uintptr)1<<(bitShift*0))	/* block start; eligible for garbage collection */
+#define bitScan			((uintptr)1<<(bitShift*1))	/* when bitAllocated is set */
+#define bitMarked		((uintptr)1<<(bitShift*2))	/* when bitAllocated is set */
+#define bitBlockBoundary	((uintptr)1<<(bitShift*1))	/* when bitAllocated is NOT set - mark for FlagNoGC objects */
+
+#define bitMask (bitAllocated | bitScan | bitMarked)
diff --git a/src/pkg/runtime/mheap.c b/src/pkg/runtime/mheap.c
index fc80c26..7e83eb2 100644
--- a/src/pkg/runtime/mheap.c
+++ b/src/pkg/runtime/mheap.c
@@ -41,7 +41,10 @@ RecordSpan(void *vh, byte *p)
 			runtime·throw("runtime: cannot allocate memory");
 		if(h->allspans) {
 			runtime·memmove(all, h->allspans, h->nspancap*sizeof(all[0]));
-			runtime·SysFree(h->allspans, h->nspancap*sizeof(all[0]), &mstats.other_sys);
+			// Don't free the old array if it's referenced by sweep.
+			// See the comment in mgc0.c.
+			if(h->allspans != runtime·mheap.sweepspans)
+				runtime·SysFree(h->allspans, h->nspancap*sizeof(all[0]), &mstats.other_sys);
 		}
 		h->allspans = all;
 		h->nspancap = cap;
@@ -57,10 +60,15 @@ runtime·MHeap_Init(MHeap *h)
 
 	runtime·FixAlloc_Init(&h->spanalloc, sizeof(MSpan), RecordSpan, h, &mstats.mspan_sys);
 	runtime·FixAlloc_Init(&h->cachealloc, sizeof(MCache), nil, nil, &mstats.mcache_sys);
+	runtime·FixAlloc_Init(&h->specialfinalizeralloc, sizeof(SpecialFinalizer), nil, nil, &mstats.other_sys);
+	runtime·FixAlloc_Init(&h->specialprofilealloc, sizeof(SpecialProfile), nil, nil, &mstats.other_sys);
 	// h->mapcache needs no init
-	for(i=0; i<nelem(h->free); i++)
+	for(i=0; i<nelem(h->free); i++) {
 		runtime·MSpanList_Init(&h->free[i]);
-	runtime·MSpanList_Init(&h->large);
+		runtime·MSpanList_Init(&h->busy[i]);
+	}
+	runtime·MSpanList_Init(&h->freelarge);
+	runtime·MSpanList_Init(&h->busylarge);
 	for(i=0; i<nelem(h->central); i++)
 		runtime·MCentral_Init(&h->central[i], i);
 }
@@ -72,20 +80,95 @@ runtime·MHeap_MapSpans(MHeap *h)
 
 	// Map spans array, PageSize at a time.
 	n = (uintptr)h->arena_used;
-	if(sizeof(void*) == 8)
-		n -= (uintptr)h->arena_start;
+	n -= (uintptr)h->arena_start;
 	n = n / PageSize * sizeof(h->spans[0]);
-	n = ROUND(n, PageSize);
+	n = ROUND(n, PhysPageSize);
 	if(h->spans_mapped >= n)
 		return;
-	runtime·SysMap((byte*)h->spans + h->spans_mapped, n - h->spans_mapped, &mstats.other_sys);
+	runtime·SysMap((byte*)h->spans + h->spans_mapped, n - h->spans_mapped, h->arena_reserved, &mstats.other_sys);
 	h->spans_mapped = n;
 }
 
+// Sweeps spans in list until reclaims at least npages into heap.
+// Returns the actual number of pages reclaimed.
+static uintptr
+MHeap_ReclaimList(MHeap *h, MSpan *list, uintptr npages)
+{
+	MSpan *s;
+	uintptr n;
+	uint32 sg;
+
+	n = 0;
+	sg = runtime·mheap.sweepgen;
+retry:
+	for(s = list->next; s != list; s = s->next) {
+		if(s->sweepgen == sg-2 && runtime·cas(&s->sweepgen, sg-2, sg-1)) {
+			runtime·MSpanList_Remove(s);
+			// swept spans are at the end of the list
+			runtime·MSpanList_InsertBack(list, s);
+			runtime·unlock(h);
+			n += runtime·MSpan_Sweep(s);
+			runtime·lock(h);
+			if(n >= npages)
+				return n;
+			// the span could have been moved elsewhere
+			goto retry;
+		}
+		if(s->sweepgen == sg-1) {
+			// the span is being sweept by background sweeper, skip
+			continue;
+		}
+		// already swept empty span,
+		// all subsequent ones must also be either swept or in process of sweeping
+		break;
+	}
+	return n;
+}
+
+// Sweeps and reclaims at least npage pages into heap.
+// Called before allocating npage pages.
+static void
+MHeap_Reclaim(MHeap *h, uintptr npage)
+{
+	uintptr reclaimed, n;
+
+	// First try to sweep busy spans with large objects of size >= npage,
+	// this has good chances of reclaiming the necessary space.
+	for(n=npage; n < nelem(h->busy); n++) {
+		if(MHeap_ReclaimList(h, &h->busy[n], npage))
+			return;  // Bingo!
+	}
+
+	// Then -- even larger objects.
+	if(MHeap_ReclaimList(h, &h->busylarge, npage))
+		return;  // Bingo!
+
+	// Now try smaller objects.
+	// One such object is not enough, so we need to reclaim several of them.
+	reclaimed = 0;
+	for(n=0; n < npage && n < nelem(h->busy); n++) {
+		reclaimed += MHeap_ReclaimList(h, &h->busy[n], npage-reclaimed);
+		if(reclaimed >= npage)
+			return;
+	}
+
+	// Now sweep everything that is not yet swept.
+	runtime·unlock(h);
+	for(;;) {
+		n = runtime·sweepone();
+		if(n == -1)  // all spans are swept
+			break;
+		reclaimed += n;
+		if(reclaimed >= npage)
+			break;
+	}
+	runtime·lock(h);
+}
+
 // Allocate a new span of npage pages from the heap
 // and record its size class in the HeapMap and HeapMapCache.
 MSpan*
-runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct, int32 zeroed)
+runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large, bool needzero)
 {
 	MSpan *s;
 
@@ -95,14 +178,22 @@ runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct, int32
 	s = MHeap_AllocLocked(h, npage, sizeclass);
 	if(s != nil) {
 		mstats.heap_inuse += npage<<PageShift;
-		if(acct) {
+		if(large) {
 			mstats.heap_objects++;
 			mstats.heap_alloc += npage<<PageShift;
+			// Swept spans are at the end of lists.
+			if(s->npages < nelem(h->free))
+				runtime·MSpanList_InsertBack(&h->busy[s->npages], s);
+			else
+				runtime·MSpanList_InsertBack(&h->busylarge, s);
 		}
 	}
 	runtime·unlock(h);
-	if(s != nil && *(uintptr*)(s->start<<PageShift) != 0 && zeroed)
-		runtime·memclr((byte*)(s->start<<PageShift), s->npages<<PageShift);
+	if(s != nil) {
+		if(needzero && s->needzero)
+			runtime·memclr((byte*)(s->start<<PageShift), s->npages<<PageShift);
+		s->needzero = 0;
+	}
 	return s;
 }
 
@@ -113,6 +204,11 @@ MHeap_AllocLocked(MHeap *h, uintptr npage, int32 sizeclass)
 	MSpan *s, *t;
 	PageID p;
 
+	// To prevent excessive heap growth, before allocating n pages
+	// we need to sweep and reclaim at least n pages.
+	if(!h->sweepdone)
+		MHeap_Reclaim(h, npage);
+
 	// Try in fixed-size lists up to max.
 	for(n=npage; n < nelem(h->free); n++) {
 		if(!runtime·MSpanList_IsEmpty(&h->free[n])) {
@@ -136,29 +232,12 @@ HaveSpan:
 	if(s->npages < npage)
 		runtime·throw("MHeap_AllocLocked - bad npages");
 	runtime·MSpanList_Remove(s);
+	runtime·atomicstore(&s->sweepgen, h->sweepgen);
 	s->state = MSpanInUse;
 	mstats.heap_idle -= s->npages<<PageShift;
 	mstats.heap_released -= s->npreleased<<PageShift;
-	if(s->npreleased > 0) {
-		// We have called runtime·SysUnused with these pages, and on
-		// Unix systems it called madvise.  At this point at least
-		// some BSD-based kernels will return these pages either as
-		// zeros or with the old data.  For our caller, the first word
-		// in the page indicates whether the span contains zeros or
-		// not (this word was set when the span was freed by
-		// MCentral_Free or runtime·MCentral_FreeSpan).  If the first
-		// page in the span is returned as zeros, and some subsequent
-		// page is returned with the old data, then we will be
-		// returning a span that is assumed to be all zeros, but the
-		// actual data will not be all zeros.  Avoid that problem by
-		// explicitly marking the span as not being zeroed, just in
-		// case.  The beadbead constant we use here means nothing, it
-		// is just a unique constant not seen elsewhere in the
-		// runtime, as a clue in case it turns up unexpectedly in
-		// memory or in a stack trace.
+	if(s->npreleased > 0)
 		runtime·SysUsed((void*)(s->start<<PageShift), s->npages<<PageShift);
-		*(uintptr*)(s->start<<PageShift) = (uintptr)0xbeadbeadbeadbeadULL;
-	}
 	s->npreleased = 0;
 
 	if(s->npages > npage) {
@@ -167,13 +246,13 @@ HaveSpan:
 		runtime·MSpan_Init(t, s->start + npage, s->npages - npage);
 		s->npages = npage;
 		p = t->start;
-		if(sizeof(void*) == 8)
-			p -= ((uintptr)h->arena_start>>PageShift);
+		p -= ((uintptr)h->arena_start>>PageShift);
 		if(p > 0)
 			h->spans[p-1] = s;
 		h->spans[p] = t;
 		h->spans[p+t->npages-1] = t;
-		*(uintptr*)(t->start<<PageShift) = *(uintptr*)(s->start<<PageShift);  // copy "needs zeroing" mark
+		t->needzero = s->needzero;
+		runtime·atomicstore(&t->sweepgen, h->sweepgen);
 		t->state = MSpanInUse;
 		MHeap_FreeLocked(h, t);
 		t->unusedsince = s->unusedsince; // preserve age
@@ -186,8 +265,7 @@ HaveSpan:
 	s->elemsize = (sizeclass==0 ? s->npages<<PageShift : runtime·class_to_size[sizeclass]);
 	s->types.compression = MTypes_Empty;
 	p = s->start;
-	if(sizeof(void*) == 8)
-		p -= ((uintptr)h->arena_start>>PageShift);
+	p -= ((uintptr)h->arena_start>>PageShift);
 	for(n=0; n<npage; n++)
 		h->spans[p+n] = s;
 	return s;
@@ -197,7 +275,7 @@ HaveSpan:
 static MSpan*
 MHeap_AllocLarge(MHeap *h, uintptr npage)
 {
-	return BestFit(&h->large, npage, nil);
+	return BestFit(&h->freelarge, npage, nil);
 }
 
 // Search list for smallest span with >= npage pages.
@@ -255,10 +333,10 @@ MHeap_Grow(MHeap *h, uintptr npage)
 	s = runtime·FixAlloc_Alloc(&h->spanalloc);
 	runtime·MSpan_Init(s, (uintptr)v>>PageShift, ask>>PageShift);
 	p = s->start;
-	if(sizeof(void*) == 8)
-		p -= ((uintptr)h->arena_start>>PageShift);
+	p -= ((uintptr)h->arena_start>>PageShift);
 	h->spans[p] = s;
 	h->spans[p + s->npages - 1] = s;
+	runtime·atomicstore(&s->sweepgen, h->sweepgen);
 	s->state = MSpanInUse;
 	MHeap_FreeLocked(h, s);
 	return true;
@@ -273,8 +351,7 @@ runtime·MHeap_Lookup(MHeap *h, void *v)
 	uintptr p;
 	
 	p = (uintptr)v;
-	if(sizeof(void*) == 8)
-		p -= (uintptr)h->arena_start;
+	p -= (uintptr)h->arena_start;
 	return h->spans[p >> PageShift];
 }
 
@@ -295,8 +372,7 @@ runtime·MHeap_LookupMaybe(MHeap *h, void *v)
 		return nil;
 	p = (uintptr)v>>PageShift;
 	q = p;
-	if(sizeof(void*) == 8)
-		q -= (uintptr)h->arena_start >> PageShift;
+	q -= (uintptr)h->arena_start >> PageShift;
 	s = h->spans[q];
 	if(s == nil || p < s->start || v >= s->limit || s->state != MSpanInUse)
 		return nil;
@@ -322,20 +398,19 @@ runtime·MHeap_Free(MHeap *h, MSpan *s, int32 acct)
 static void
 MHeap_FreeLocked(MHeap *h, MSpan *s)
 {
-	uintptr *sp, *tp;
 	MSpan *t;
 	PageID p;
 
 	s->types.compression = MTypes_Empty;
 
-	if(s->state != MSpanInUse || s->ref != 0) {
-		runtime·printf("MHeap_FreeLocked - span %p ptr %p state %d ref %d\n", s, s->start<<PageShift, s->state, s->ref);
+	if(s->state != MSpanInUse || s->ref != 0 || s->sweepgen != h->sweepgen) {
+		runtime·printf("MHeap_FreeLocked - span %p ptr %p state %d ref %d sweepgen %d/%d\n",
+			s, s->start<<PageShift, s->state, s->ref, s->sweepgen, h->sweepgen);
 		runtime·throw("MHeap_FreeLocked - invalid free");
 	}
 	mstats.heap_idle += s->npages<<PageShift;
 	s->state = MSpanFree;
 	runtime·MSpanList_Remove(s);
-	sp = (uintptr*)(s->start<<PageShift);
 	// Stamp newly unused spans. The scavenger will use that
 	// info to potentially give back some pages to the OS.
 	s->unusedsince = runtime·nanotime();
@@ -343,16 +418,12 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
 
 	// Coalesce with earlier, later spans.
 	p = s->start;
-	if(sizeof(void*) == 8)
-		p -= (uintptr)h->arena_start >> PageShift;
+	p -= (uintptr)h->arena_start >> PageShift;
 	if(p > 0 && (t = h->spans[p-1]) != nil && t->state != MSpanInUse) {
-		if(t->npreleased == 0) {  // cant't touch this otherwise
-			tp = (uintptr*)(t->start<<PageShift);
-			*tp |= *sp;	// propagate "needs zeroing" mark
-		}
 		s->start = t->start;
 		s->npages += t->npages;
 		s->npreleased = t->npreleased; // absorb released pages
+		s->needzero |= t->needzero;
 		p -= t->npages;
 		h->spans[p] = s;
 		runtime·MSpanList_Remove(t);
@@ -360,12 +431,9 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
 		runtime·FixAlloc_Free(&h->spanalloc, t);
 	}
 	if((p+s->npages)*sizeof(h->spans[0]) < h->spans_mapped && (t = h->spans[p+s->npages]) != nil && t->state != MSpanInUse) {
-		if(t->npreleased == 0) {  // cant't touch this otherwise
-			tp = (uintptr*)(t->start<<PageShift);
-			*sp |= *tp;	// propagate "needs zeroing" mark
-		}
 		s->npages += t->npages;
 		s->npreleased += t->npreleased;
+		s->needzero |= t->needzero;
 		h->spans[p + s->npages - 1] = s;
 		runtime·MSpanList_Remove(t);
 		t->state = MSpanDead;
@@ -376,7 +444,7 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
 	if(s->npages < nelem(h->free))
 		runtime·MSpanList_Insert(&h->free[s->npages], s);
 	else
-		runtime·MSpanList_Insert(&h->large, s);
+		runtime·MSpanList_Insert(&h->freelarge, s);
 }
 
 static void
@@ -419,7 +487,7 @@ scavenge(int32 k, uint64 now, uint64 limit)
 	sumreleased = 0;
 	for(i=0; i < nelem(h->free); i++)
 		sumreleased += scavengelist(&h->free[i], now, limit);
-	sumreleased += scavengelist(&h->large, now, limit);
+	sumreleased += scavengelist(&h->freelarge, now, limit);
 
 	if(runtime·debug.gctrace > 0) {
 		if(sumreleased > 0)
@@ -440,6 +508,7 @@ runtime·MHeap_Scavenger(void)
 {
 	MHeap *h;
 	uint64 tick, now, forcegc, limit;
+	int64 unixnow;
 	int32 k;
 	Note note, *notep;
 
@@ -463,8 +532,8 @@ runtime·MHeap_Scavenger(void)
 		runtime·notetsleepg(&note, tick);
 
 		runtime·lock(h);
-		now = runtime·nanotime();
-		if(now - mstats.last_gc > forcegc) {
+		unixnow = runtime·unixnanotime();
+		if(unixnow - mstats.last_gc > forcegc) {
 			runtime·unlock(h);
 			// The scavenger can not block other goroutines,
 			// otherwise deadlock detector can fire spuriously.
@@ -476,8 +545,8 @@ runtime·MHeap_Scavenger(void)
 			if(runtime·debug.gctrace > 0)
 				runtime·printf("scvg%d: GC forced\n", k);
 			runtime·lock(h);
-			now = runtime·nanotime();
 		}
+		now = runtime·nanotime();
 		scavenge(k, now, limit);
 		runtime·unlock(h);
 	}
@@ -486,7 +555,7 @@ runtime·MHeap_Scavenger(void)
 void
 runtime∕debug·freeOSMemory(void)
 {
-	runtime·gc(1);
+	runtime·gc(2);  // force GC and do eager sweep
 	runtime·lock(&runtime·mheap);
 	scavenge(-1, ~(uintptr)0, 0);
 	runtime·unlock(&runtime·mheap);
@@ -503,11 +572,16 @@ runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages)
 	span->freelist = nil;
 	span->ref = 0;
 	span->sizeclass = 0;
+	span->incache = false;
 	span->elemsize = 0;
-	span->state = 0;
+	span->state = MSpanDead;
 	span->unusedsince = 0;
 	span->npreleased = 0;
 	span->types.compression = MTypes_Empty;
+	span->specialLock.key = 0;
+	span->specials = nil;
+	span->needzero = 0;
+	span->freebuf = nil;
 }
 
 // Initialize an empty doubly-linked list.
@@ -549,4 +623,310 @@ runtime·MSpanList_Insert(MSpan *list, MSpan *span)
 	span->prev->next = span;
 }
 
+void
+runtime·MSpanList_InsertBack(MSpan *list, MSpan *span)
+{
+	if(span->next != nil || span->prev != nil) {
+		runtime·printf("failed MSpanList_Insert %p %p %p\n", span, span->next, span->prev);
+		runtime·throw("MSpanList_Insert");
+	}
+	span->next = list;
+	span->prev = list->prev;
+	span->next->prev = span;
+	span->prev->next = span;
+}
 
+// Adds the special record s to the list of special records for
+// the object p.  All fields of s should be filled in except for
+// offset & next, which this routine will fill in.
+// Returns true if the special was successfully added, false otherwise.
+// (The add will fail only if a record with the same p and s->kind
+//  already exists.)
+static bool
+addspecial(void *p, Special *s)
+{
+	MSpan *span;
+	Special **t, *x;
+	uintptr offset;
+	byte kind;
+
+	span = runtime·MHeap_LookupMaybe(&runtime·mheap, p);
+	if(span == nil)
+		runtime·throw("addspecial on invalid pointer");
+
+	// Ensure that the span is swept.
+	// GC accesses specials list w/o locks. And it's just much safer.
+	m->locks++;
+	runtime·MSpan_EnsureSwept(span);
+
+	offset = (uintptr)p - (span->start << PageShift);
+	kind = s->kind;
+
+	runtime·lock(&span->specialLock);
+
+	// Find splice point, check for existing record.
+	t = &span->specials;
+	while((x = *t) != nil) {
+		if(offset == x->offset && kind == x->kind) {
+			runtime·unlock(&span->specialLock);
+			m->locks--;
+			return false; // already exists
+		}
+		if(offset < x->offset || (offset == x->offset && kind < x->kind))
+			break;
+		t = &x->next;
+	}
+	// Splice in record, fill in offset.
+	s->offset = offset;
+	s->next = x;
+	*t = s;
+	runtime·unlock(&span->specialLock);
+	m->locks--;
+	return true;
+}
+
+// Removes the Special record of the given kind for the object p.
+// Returns the record if the record existed, nil otherwise.
+// The caller must FixAlloc_Free the result.
+static Special*
+removespecial(void *p, byte kind)
+{
+	MSpan *span;
+	Special *s, **t;
+	uintptr offset;
+
+	span = runtime·MHeap_LookupMaybe(&runtime·mheap, p);
+	if(span == nil)
+		runtime·throw("removespecial on invalid pointer");
+
+	// Ensure that the span is swept.
+	// GC accesses specials list w/o locks. And it's just much safer.
+	m->locks++;
+	runtime·MSpan_EnsureSwept(span);
+
+	offset = (uintptr)p - (span->start << PageShift);
+
+	runtime·lock(&span->specialLock);
+	t = &span->specials;
+	while((s = *t) != nil) {
+		// This function is used for finalizers only, so we don't check for
+		// "interior" specials (p must be exactly equal to s->offset).
+		if(offset == s->offset && kind == s->kind) {
+			*t = s->next;
+			runtime·unlock(&span->specialLock);
+			m->locks--;
+			return s;
+		}
+		t = &s->next;
+	}
+	runtime·unlock(&span->specialLock);
+	m->locks--;
+	return nil;
+}
+
+// Adds a finalizer to the object p.  Returns true if it succeeded.
+bool
+runtime·addfinalizer(void *p, FuncVal *f, uintptr nret, Type *fint, PtrType *ot)
+{
+	SpecialFinalizer *s;
+
+	runtime·lock(&runtime·mheap.speciallock);
+	s = runtime·FixAlloc_Alloc(&runtime·mheap.specialfinalizeralloc);
+	runtime·unlock(&runtime·mheap.speciallock);
+	s->kind = KindSpecialFinalizer;
+	s->fn = f;
+	s->nret = nret;
+	s->fint = fint;
+	s->ot = ot;
+	if(addspecial(p, s))
+		return true;
+
+	// There was an old finalizer
+	runtime·lock(&runtime·mheap.speciallock);
+	runtime·FixAlloc_Free(&runtime·mheap.specialfinalizeralloc, s);
+	runtime·unlock(&runtime·mheap.speciallock);
+	return false;
+}
+
+// Removes the finalizer (if any) from the object p.
+void
+runtime·removefinalizer(void *p)
+{
+	SpecialFinalizer *s;
+
+	s = (SpecialFinalizer*)removespecial(p, KindSpecialFinalizer);
+	if(s == nil)
+		return; // there wasn't a finalizer to remove
+	runtime·lock(&runtime·mheap.speciallock);
+	runtime·FixAlloc_Free(&runtime·mheap.specialfinalizeralloc, s);
+	runtime·unlock(&runtime·mheap.speciallock);
+}
+
+// Set the heap profile bucket associated with addr to b.
+void
+runtime·setprofilebucket(void *p, Bucket *b)
+{
+	SpecialProfile *s;
+
+	runtime·lock(&runtime·mheap.speciallock);
+	s = runtime·FixAlloc_Alloc(&runtime·mheap.specialprofilealloc);
+	runtime·unlock(&runtime·mheap.speciallock);
+	s->kind = KindSpecialProfile;
+	s->b = b;
+	if(!addspecial(p, s))
+		runtime·throw("setprofilebucket: profile already set");
+}
+
+// Do whatever cleanup needs to be done to deallocate s.  It has
+// already been unlinked from the MSpan specials list.
+// Returns true if we should keep working on deallocating p.
+bool
+runtime·freespecial(Special *s, void *p, uintptr size, bool freed)
+{
+	SpecialFinalizer *sf;
+	SpecialProfile *sp;
+
+	switch(s->kind) {
+	case KindSpecialFinalizer:
+		sf = (SpecialFinalizer*)s;
+		runtime·queuefinalizer(p, sf->fn, sf->nret, sf->fint, sf->ot);
+		runtime·lock(&runtime·mheap.speciallock);
+		runtime·FixAlloc_Free(&runtime·mheap.specialfinalizeralloc, sf);
+		runtime·unlock(&runtime·mheap.speciallock);
+		return false; // don't free p until finalizer is done
+	case KindSpecialProfile:
+		sp = (SpecialProfile*)s;
+		runtime·MProf_Free(sp->b, size, freed);
+		runtime·lock(&runtime·mheap.speciallock);
+		runtime·FixAlloc_Free(&runtime·mheap.specialprofilealloc, sp);
+		runtime·unlock(&runtime·mheap.speciallock);
+		return true;
+	default:
+		runtime·throw("bad special kind");
+		return true;
+	}
+}
+
+// Free all special records for p.
+void
+runtime·freeallspecials(MSpan *span, void *p, uintptr size)
+{
+	Special *s, **t, *list;
+	uintptr offset;
+
+	if(span->sweepgen != runtime·mheap.sweepgen)
+		runtime·throw("runtime: freeallspecials: unswept span");
+	// first, collect all specials into the list; then, free them
+	// this is required to not cause deadlock between span->specialLock and proflock
+	list = nil;
+	offset = (uintptr)p - (span->start << PageShift);
+	runtime·lock(&span->specialLock);
+	t = &span->specials;
+	while((s = *t) != nil) {
+		if(offset + size <= s->offset)
+			break;
+		if(offset <= s->offset) {
+			*t = s->next;
+			s->next = list;
+			list = s;
+		} else
+			t = &s->next;
+	}
+	runtime·unlock(&span->specialLock);
+
+	while(list != nil) {
+		s = list;
+		list = s->next;
+		if(!runtime·freespecial(s, p, size, true))
+			runtime·throw("can't explicitly free an object with a finalizer");
+	}
+}
+
+// Split an allocated span into two equal parts.
+void
+runtime·MHeap_SplitSpan(MHeap *h, MSpan *s)
+{
+	MSpan *t;
+	MCentral *c;
+	uintptr i;
+	uintptr npages;
+	PageID p;
+
+	if(s->state != MSpanInUse)
+		runtime·throw("MHeap_SplitSpan on a free span");
+	if(s->sizeclass != 0 && s->ref != 1)
+		runtime·throw("MHeap_SplitSpan doesn't have an allocated object");
+	npages = s->npages;
+
+	// remove the span from whatever list it is in now
+	if(s->sizeclass > 0) {
+		// must be in h->central[x].empty
+		c = &h->central[s->sizeclass];
+		runtime·lock(c);
+		runtime·MSpanList_Remove(s);
+		runtime·unlock(c);
+		runtime·lock(h);
+	} else {
+		// must be in h->busy/busylarge
+		runtime·lock(h);
+		runtime·MSpanList_Remove(s);
+	}
+	// heap is locked now
+
+	if(npages == 1) {
+		// convert span of 1 PageSize object to a span of 2 PageSize/2 objects.
+		s->ref = 2;
+		s->sizeclass = runtime·SizeToClass(PageSize/2);
+		s->elemsize = PageSize/2;
+	} else {
+		// convert span of n>1 pages into two spans of n/2 pages each.
+		if((s->npages & 1) != 0)
+			runtime·throw("MHeap_SplitSpan on an odd size span");
+
+		// compute position in h->spans
+		p = s->start;
+		p -= (uintptr)h->arena_start >> PageShift;
+
+		// Allocate a new span for the first half.
+		t = runtime·FixAlloc_Alloc(&h->spanalloc);
+		runtime·MSpan_Init(t, s->start, npages/2);
+		t->limit = (byte*)((t->start + npages/2) << PageShift);
+		t->state = MSpanInUse;
+		t->elemsize = npages << (PageShift - 1);
+		t->sweepgen = s->sweepgen;
+		if(t->elemsize <= MaxSmallSize) {
+			t->sizeclass = runtime·SizeToClass(t->elemsize);
+			t->ref = 1;
+		}
+
+		// the old span holds the second half.
+		s->start += npages/2;
+		s->npages = npages/2;
+		s->elemsize = npages << (PageShift - 1);
+		if(s->elemsize <= MaxSmallSize) {
+			s->sizeclass = runtime·SizeToClass(s->elemsize);
+			s->ref = 1;
+		}
+
+		// update span lookup table
+		for(i = p; i < p + npages/2; i++)
+			h->spans[i] = t;
+	}
+
+	// place the span into a new list
+	if(s->sizeclass > 0) {
+		runtime·unlock(h);
+		c = &h->central[s->sizeclass];
+		runtime·lock(c);
+		// swept spans are at the end of the list
+		runtime·MSpanList_InsertBack(&c->empty, s);
+		runtime·unlock(c);
+	} else {
+		// Swept spans are at the end of lists.
+		if(s->npages < nelem(h->free))
+			runtime·MSpanList_InsertBack(&h->busy[s->npages], s);
+		else
+			runtime·MSpanList_InsertBack(&h->busylarge, s);
+		runtime·unlock(h);
+	}
+}
diff --git a/src/pkg/runtime/mknacl.sh b/src/pkg/runtime/mknacl.sh
new file mode 100644
index 0000000..47fb7bd
--- /dev/null
+++ b/src/pkg/runtime/mknacl.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+# 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.
+
+cat /Users/rsc/pub/native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h |
+	awk '
+	BEGIN {
+		printf("// generated by mknacl.sh - do not edit\n")
+	}
+	NF==3 && $1=="#define" && $2~/^NACL_sys_/ {
+		name=$2
+		sub(/^NACL_sys_/, "SYS_", name)
+		printf("#define %s %s\n", name, $3)
+	}' >syscall_nacl.h
diff --git a/src/pkg/runtime/mprof.goc b/src/pkg/runtime/mprof.goc
index 4ae74f0..9c23a16 100644
--- a/src/pkg/runtime/mprof.goc
+++ b/src/pkg/runtime/mprof.goc
@@ -22,7 +22,6 @@ enum { MProf, BProf };  // profile types
 
 // Per-call-stack profiling information.
 // Lookup by hashing call stack into a linked-list hash table.
-typedef struct Bucket Bucket;
 struct Bucket
 {
 	Bucket	*next;	// next in hash list
@@ -34,14 +33,33 @@ struct Bucket
 	{
 		struct  // typ == MProf
 		{
+			// The following complex 3-stage scheme of stats accumulation
+			// is required to obtain a consistent picture of mallocs and frees
+			// for some point in time.
+			// The problem is that mallocs come in real time, while frees
+			// come only after a GC during concurrent sweeping. So if we would
+			// naively count them, we would get a skew toward mallocs.
+			//
+			// Mallocs are accounted in recent stats.
+			// Explicit frees are accounted in recent stats.
+			// GC frees are accounted in prev stats.
+			// After GC prev stats are added to final stats and
+			// recent stats are moved into prev stats.
 			uintptr	allocs;
 			uintptr	frees;
 			uintptr	alloc_bytes;
 			uintptr	free_bytes;
-			uintptr	recent_allocs;  // since last gc
+
+			uintptr	prev_allocs;  // since last but one till last gc
+			uintptr	prev_frees;
+			uintptr	prev_alloc_bytes;
+			uintptr	prev_free_bytes;
+
+			uintptr	recent_allocs;  // since last gc till now
 			uintptr	recent_frees;
 			uintptr	recent_alloc_bytes;
 			uintptr	recent_free_bytes;
+
 		};
 		struct  // typ == BProf
 		{
@@ -49,7 +67,8 @@ struct Bucket
 			int64	cycles;
 		};
 	};
-	uintptr	hash;
+	uintptr	hash;	// hash of size + stk
+	uintptr	size;
 	uintptr	nstk;
 	uintptr	stk[1];
 };
@@ -63,7 +82,7 @@ static uintptr bucketmem;
 
 // Return the bucket for stk[0:nstk], allocating new bucket if needed.
 static Bucket*
-stkbucket(int32 typ, uintptr *stk, int32 nstk, bool alloc)
+stkbucket(int32 typ, uintptr size, uintptr *stk, int32 nstk, bool alloc)
 {
 	int32 i;
 	uintptr h;
@@ -82,12 +101,17 @@ stkbucket(int32 typ, uintptr *stk, int32 nstk, bool alloc)
 		h += h<<10;
 		h ^= h>>6;
 	}
+	// hash in size
+	h += size;
+	h += h<<10;
+	h ^= h>>6;
+	// finalize
 	h += h<<3;
 	h ^= h>>11;
 
 	i = h%BuckHashSize;
 	for(b = buckhash[i]; b; b=b->next)
-		if(b->typ == typ && b->hash == h && b->nstk == nstk &&
+		if(b->typ == typ && b->hash == h && b->size == size && b->nstk == nstk &&
 		   runtime·mcmp((byte*)b->stk, (byte*)stk, nstk*sizeof stk[0]) == 0)
 			return b;
 
@@ -99,6 +123,7 @@ stkbucket(int32 typ, uintptr *stk, int32 nstk, bool alloc)
 	runtime·memmove(b->stk, stk, nstk*sizeof stk[0]);
 	b->typ = typ;
 	b->hash = h;
+	b->size = size;
 	b->nstk = nstk;
 	b->next = buckhash[i];
 	buckhash[i] = b;
@@ -118,10 +143,16 @@ MProf_GC(void)
 	Bucket *b;
 
 	for(b=mbuckets; b; b=b->allnext) {
-		b->allocs += b->recent_allocs;
-		b->frees += b->recent_frees;
-		b->alloc_bytes += b->recent_alloc_bytes;
-		b->free_bytes += b->recent_free_bytes;
+		b->allocs += b->prev_allocs;
+		b->frees += b->prev_frees;
+		b->alloc_bytes += b->prev_alloc_bytes;
+		b->free_bytes += b->prev_free_bytes;
+
+		b->prev_allocs = b->recent_allocs;
+		b->prev_frees = b->recent_frees;
+		b->prev_alloc_bytes = b->recent_alloc_bytes;
+		b->prev_free_bytes = b->recent_free_bytes;
+
 		b->recent_allocs = 0;
 		b->recent_frees = 0;
 		b->recent_alloc_bytes = 0;
@@ -138,143 +169,39 @@ runtime·MProf_GC(void)
 	runtime·unlock(&proflock);
 }
 
-// Map from pointer to Bucket* that allocated it.
-// Three levels:
-//	Linked-list hash table for top N-AddrHashShift bits.
-//	Array index for next AddrDenseBits bits.
-//	Linked list for next AddrHashShift-AddrDenseBits bits.
-// This is more efficient than using a general map,
-// because of the typical clustering of the pointer keys.
-
-typedef struct AddrHash AddrHash;
-typedef struct AddrEntry AddrEntry;
-
-enum {
-	AddrHashBits = 12,	// good for 4GB of used address space
-	AddrHashShift = 20,	// each AddrHash knows about 1MB of address space
-	AddrDenseBits = 8,	// good for a profiling rate of 4096 bytes
-};
-
-struct AddrHash
-{
-	AddrHash *next;	// next in top-level hash table linked list
-	uintptr addr;	// addr>>20
-	AddrEntry *dense[1<<AddrDenseBits];
-};
-
-struct AddrEntry
-{
-	AddrEntry *next;	// next in bottom-level linked list
-	uint32 addr;
-	Bucket *b;
-};
-
-static AddrHash **addrhash;	// points to (AddrHash*)[1<<AddrHashBits]
-static AddrEntry *addrfree;
-static uintptr addrmem;
-
-// Multiplicative hash function:
-// hashMultiplier is the bottom 32 bits of int((sqrt(5)-1)/2 * (1<<32)).
-// This is a good multiplier as suggested in CLR, Knuth.  The hash
-// value is taken to be the top AddrHashBits bits of the bottom 32 bits
-// of the multiplied value.
-enum {
-	HashMultiplier = 2654435769U
-};
-
-// Set the bucket associated with addr to b.
-static void
-setaddrbucket(uintptr addr, Bucket *b)
-{
-	int32 i;
-	uint32 h;
-	AddrHash *ah;
-	AddrEntry *e;
-
-	h = (uint32)((addr>>AddrHashShift)*HashMultiplier) >> (32-AddrHashBits);
-	for(ah=addrhash[h]; ah; ah=ah->next)
-		if(ah->addr == (addr>>AddrHashShift))
-			goto found;
-
-	ah = runtime·persistentalloc(sizeof *ah, 0, &mstats.buckhash_sys);
-	addrmem += sizeof *ah;
-	ah->next = addrhash[h];
-	ah->addr = addr>>AddrHashShift;
-	addrhash[h] = ah;
-
-found:
-	if((e = addrfree) == nil) {
-		e = runtime·persistentalloc(64*sizeof *e, 0, &mstats.buckhash_sys);
-		addrmem += 64*sizeof *e;
-		for(i=0; i+1<64; i++)
-			e[i].next = &e[i+1];
-		e[63].next = nil;
-	}
-	addrfree = e->next;
-	e->addr = (uint32)~(addr & ((1<<AddrHashShift)-1));
-	e->b = b;
-	h = (addr>>(AddrHashShift-AddrDenseBits))&(nelem(ah->dense)-1);	// entry in dense is top 8 bits of low 20.
-	e->next = ah->dense[h];
-	ah->dense[h] = e;
-}
-
-// Get the bucket associated with addr and clear the association.
-static Bucket*
-getaddrbucket(uintptr addr)
-{
-	uint32 h;
-	AddrHash *ah;
-	AddrEntry *e, **l;
-	Bucket *b;
-
-	h = (uint32)((addr>>AddrHashShift)*HashMultiplier) >> (32-AddrHashBits);
-	for(ah=addrhash[h]; ah; ah=ah->next)
-		if(ah->addr == (addr>>AddrHashShift))
-			goto found;
-	return nil;
-
-found:
-	h = (addr>>(AddrHashShift-AddrDenseBits))&(nelem(ah->dense)-1);	// entry in dense is top 8 bits of low 20.
-	for(l=&ah->dense[h]; (e=*l) != nil; l=&e->next) {
-		if(e->addr == (uint32)~(addr & ((1<<AddrHashShift)-1))) {
-			*l = e->next;
-			b = e->b;
-			e->next = addrfree;
-			addrfree = e;
-			return b;
-		}
-	}
-	return nil;
-}
-
 // Called by malloc to record a profiled block.
 void
 runtime·MProf_Malloc(void *p, uintptr size)
 {
-	int32 nstk;
 	uintptr stk[32];
 	Bucket *b;
+	int32 nstk;
 
-	nstk = runtime·callers(1, stk, 32);
+	nstk = runtime·callers(1, stk, nelem(stk));
 	runtime·lock(&proflock);
-	b = stkbucket(MProf, stk, nstk, true);
+	b = stkbucket(MProf, size, stk, nstk, true);
 	b->recent_allocs++;
 	b->recent_alloc_bytes += size;
-	setaddrbucket((uintptr)p, b);
 	runtime·unlock(&proflock);
+
+	// Setprofilebucket locks a bunch of other mutexes, so we call it outside of proflock.
+	// This reduces potential contention and chances of deadlocks.
+	// Since the object must be alive during call to MProf_Malloc,
+	// it's fine to do this non-atomically.
+	runtime·setprofilebucket(p, b);
 }
 
 // Called when freeing a profiled block.
 void
-runtime·MProf_Free(void *p, uintptr size)
+runtime·MProf_Free(Bucket *b, uintptr size, bool freed)
 {
-	Bucket *b;
-
 	runtime·lock(&proflock);
-	b = getaddrbucket((uintptr)p);
-	if(b != nil) {
+	if(freed) {
 		b->recent_frees++;
 		b->recent_free_bytes += size;
+	} else {
+		b->prev_frees++;
+		b->prev_free_bytes += size;
 	}
 	runtime·unlock(&proflock);
 }
@@ -311,9 +238,9 @@ runtime·blockevent(int64 cycles, int32 skip)
 	if(rate <= 0 || (rate > cycles && runtime·fastrand1()%rate > cycles))
 		return;
 
-	nstk = runtime·callers(skip, stk, 32);
+	nstk = runtime·callers(skip, stk, nelem(stk));
 	runtime·lock(&proflock);
-	b = stkbucket(BProf, stk, nstk, true);
+	b = stkbucket(BProf, 0, stk, nstk, true);
 	b->count++;
 	b->cycles += cycles;
 	runtime·unlock(&proflock);
@@ -365,6 +292,7 @@ func MemProfile(p Slice, include_inuse_zero bool) (n int, ok bool) {
 		// garbage collection is disabled from the beginning of execution,
 		// accumulate stats as if a GC just happened, and recount buckets.
 		MProf_GC();
+		MProf_GC();
 		n = 0;
 		for(b=mbuckets; b; b=b->allnext)
 			if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
@@ -381,6 +309,18 @@ func MemProfile(p Slice, include_inuse_zero bool) (n int, ok bool) {
 	runtime·unlock(&proflock);
 }
 
+void
+runtime·iterate_memprof(void (*callback)(Bucket*, uintptr, uintptr*, uintptr, uintptr, uintptr))
+{
+	Bucket *b;
+
+	runtime·lock(&proflock);
+	for(b=mbuckets; b; b=b->allnext) {
+		callback(b, b->nstk, b->stk, b->size, b->allocs, b->frees);
+	}
+	runtime·unlock(&proflock);
+}
+
 // Must match BlockProfileRecord in debug.go.
 typedef struct BRecord BRecord;
 struct BRecord {
@@ -483,7 +423,7 @@ saveg(uintptr pc, uintptr sp, G *gp, TRecord *r)
 }
 
 func GoroutineProfile(b Slice) (n int, ok bool) {
-	uintptr pc, sp;
+	uintptr pc, sp, i;
 	TRecord *r;
 	G *gp;
 	
@@ -502,7 +442,8 @@ func GoroutineProfile(b Slice) (n int, ok bool) {
 			ok = true;
 			r = (TRecord*)b.array;
 			saveg(pc, sp, g, r++);
-			for(gp = runtime·allg; gp != nil; gp = gp->alllink) {
+			for(i = 0; i < runtime·allglen; i++) {
+				gp = runtime·allg[i];
 				if(gp == g || gp->status == Gdead)
 					continue;
 				saveg(~(uintptr)0, ~(uintptr)0, gp, r++);
@@ -515,8 +456,72 @@ func GoroutineProfile(b Slice) (n int, ok bool) {
 	}
 }
 
+// Tracing of alloc/free/gc.
+
+static Lock tracelock;
+
+static int8*
+typeinfoname(int32 typeinfo)
+{
+	if(typeinfo == TypeInfo_SingleObject)
+		return "single object";
+	else if(typeinfo == TypeInfo_Array)
+		return "array";
+	else if(typeinfo == TypeInfo_Chan)
+		return "channel";
+	runtime·throw("typinfoname: unknown type info");
+	return nil;
+}
+
+void
+runtime·tracealloc(void *p, uintptr size, uintptr typ)
+{
+	int8 *name;
+	Type *type;
+
+	runtime·lock(&tracelock);
+	m->traceback = 2;
+	type = (Type*)(typ & ~3);
+	name = typeinfoname(typ & 3);
+	if(type == nil)
+		runtime·printf("tracealloc(%p, %p, %s)\n", p, size, name);
+	else	
+		runtime·printf("tracealloc(%p, %p, %s of %S)\n", p, size, name, *type->string);
+	if(m->curg == nil || g == m->curg) {
+		runtime·goroutineheader(g);
+		runtime·traceback((uintptr)runtime·getcallerpc(&p), (uintptr)runtime·getcallersp(&p), 0, g);
+	} else {
+		runtime·goroutineheader(m->curg);
+		runtime·traceback(~(uintptr)0, ~(uintptr)0, 0, m->curg);
+	}
+	runtime·printf("\n");
+	m->traceback = 0;
+	runtime·unlock(&tracelock);
+}
+
+void
+runtime·tracefree(void *p, uintptr size)
+{
+	runtime·lock(&tracelock);
+	m->traceback = 2;
+	runtime·printf("tracefree(%p, %p)\n", p, size);
+	runtime·goroutineheader(g);
+	runtime·traceback((uintptr)runtime·getcallerpc(&p), (uintptr)runtime·getcallersp(&p), 0, g);
+	runtime·printf("\n");
+	m->traceback = 0;
+	runtime·unlock(&tracelock);
+}
+
 void
-runtime·mprofinit(void)
+runtime·tracegc(void)
 {
-	addrhash = runtime·persistentalloc((1<<AddrHashBits)*sizeof *addrhash, 0, &mstats.buckhash_sys);
+	runtime·lock(&tracelock);
+	m->traceback = 2;
+	runtime·printf("tracegc()\n");
+	// running on m->g0 stack; show all non-g0 goroutines
+	runtime·tracebackothers(g);
+	runtime·printf("end tracegc\n");
+	runtime·printf("\n");
+	m->traceback = 0;
+	runtime·unlock(&tracelock);
 }
diff --git a/src/pkg/runtime/msize.c b/src/pkg/runtime/msize.c
index 50b372b..2fbd5e1 100644
--- a/src/pkg/runtime/msize.c
+++ b/src/pkg/runtime/msize.c
@@ -28,8 +28,11 @@
 #include "runtime.h"
 #include "arch_GOARCH.h"
 #include "malloc.h"
+#include "../../cmd/ld/textflag.h"
 
+#pragma dataflag NOPTR
 int32 runtime·class_to_size[NumSizeClasses];
+#pragma dataflag NOPTR
 int32 runtime·class_to_allocnpages[NumSizeClasses];
 
 // The SizeToClass lookup is implemented using two arrays,
@@ -41,11 +44,15 @@ int32 runtime·class_to_allocnpages[NumSizeClasses];
 // size divided by 128 (rounded up).  The arrays are filled in
 // by InitSizes.
 
+#pragma dataflag NOPTR
 int8 runtime·size_to_class8[1024/8 + 1];
+#pragma dataflag NOPTR
 int8 runtime·size_to_class128[(MaxSmallSize-1024)/128 + 1];
 
-static int32
-SizeToClass(int32 size)
+void runtime·testdefersizes(void);
+
+int32
+runtime·SizeToClass(int32 size)
 {
 	if(size > MaxSmallSize)
 		runtime·throw("SizeToClass - invalid size");
@@ -90,9 +97,9 @@ runtime·InitSizes(void)
 		// objects into the page, we might as well
 		// use just this size instead of having two
 		// different sizes.
-		if(sizeclass > 1
-		&& npages == runtime·class_to_allocnpages[sizeclass-1]
-		&& allocsize/size == allocsize/runtime·class_to_size[sizeclass-1]) {
+		if(sizeclass > 1 &&
+			npages == runtime·class_to_allocnpages[sizeclass-1] &&
+			allocsize/size == allocsize/runtime·class_to_size[sizeclass-1]) {
 			runtime·class_to_size[sizeclass-1] = size;
 			continue;
 		}
@@ -119,7 +126,7 @@ runtime·InitSizes(void)
 	// Double-check SizeToClass.
 	if(0) {
 		for(n=0; n < MaxSmallSize; n++) {
-			sizeclass = SizeToClass(n);
+			sizeclass = runtime·SizeToClass(n);
 			if(sizeclass < 1 || sizeclass >= NumSizeClasses || runtime·class_to_size[sizeclass] < n) {
 				runtime·printf("size=%d sizeclass=%d runtime·class_to_size=%d\n", n, sizeclass, runtime·class_to_size[sizeclass]);
 				runtime·printf("incorrect SizeToClass");
@@ -133,6 +140,8 @@ runtime·InitSizes(void)
 		}
 	}
 
+	runtime·testdefersizes();
+
 	// Copy out for statistics table.
 	for(i=0; i<nelem(runtime·class_to_size); i++)
 		mstats.by_size[i].size = runtime·class_to_size[i];
@@ -158,3 +167,18 @@ dump:
 	}
 	runtime·throw("InitSizes failed");
 }
+
+// Returns size of the memory block that mallocgc will allocate if you ask for the size.
+uintptr
+runtime·roundupsize(uintptr size)
+{
+	if(size < MaxSmallSize) {
+		if(size <= 1024-8)
+			return runtime·class_to_size[runtime·size_to_class8[(size+7)>>3]];
+		else
+			return runtime·class_to_size[runtime·size_to_class128[(size-1024+127) >> 7]];
+	}
+	if(size + PageSize < size)
+		return size;
+	return ROUND(size, PageSize);
+}
diff --git a/src/pkg/runtime/netpoll.goc b/src/pkg/runtime/netpoll.goc
index d27bef1..7b3d16d 100644
--- a/src/pkg/runtime/netpoll.goc
+++ b/src/pkg/runtime/netpoll.goc
@@ -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 windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
@@ -19,21 +19,46 @@ package net
 // An implementation must call the following function to denote that the pd is ready.
 // void runtime·netpollready(G **gpp, PollDesc *pd, int32 mode);
 
+// PollDesc contains 2 binary semaphores, rg and wg, to park reader and writer
+// goroutines respectively. The semaphore can be in the following states:
+// READY - io readiness notification is pending;
+//         a goroutine consumes the notification by changing the state to nil.
+// WAIT - a goroutine prepares to park on the semaphore, but not yet parked;
+//        the goroutine commits to park by changing the state to G pointer,
+//        or, alternatively, concurrent io notification changes the state to READY,
+//        or, alternatively, concurrent timeout/close changes the state to nil.
+// G pointer - the goroutine is blocked on the semaphore;
+//             io notification or timeout/close changes the state to READY or nil respectively
+//             and unparks the goroutine.
+// nil - nothing of the above.
 #define READY ((G*)1)
+#define WAIT  ((G*)2)
+
+enum
+{
+	PollBlockSize	= 4*1024,
+};
 
 struct PollDesc
 {
 	PollDesc* link;	// in pollcache, protected by pollcache.Lock
+
+	// The lock protects pollOpen, pollSetDeadline, pollUnblock and deadlineimpl operations.
+	// This fully covers seq, rt and wt variables. fd is constant throughout the PollDesc lifetime.
+	// pollReset, pollWait, pollWaitCanceled and runtime·netpollready (IO rediness notification)
+	// proceed w/o taking the lock. So closing, rg, rd, wg and wd are manipulated
+	// in a lock-free way by all operations.
 	Lock;		// protectes the following fields
 	uintptr	fd;
 	bool	closing;
 	uintptr	seq;	// protects from stale timers and ready notifications
-	G*	rg;	// G waiting for read or READY (binary semaphore)
+	G*	rg;	// READY, WAIT, G waiting for read or nil
 	Timer	rt;	// read deadline timer (set if rt.fv != nil)
 	int64	rd;	// read deadline
-	G*	wg;	// the same for writes
-	Timer	wt;
-	int64	wd;
+	G*	wg;	// READY, WAIT, G waiting for write or nil
+	Timer	wt;	// write deadline timer
+	int64	wd;	// write deadline
+	void*	user;	// user settable cookie
 };
 
 static struct
@@ -47,7 +72,7 @@ static struct
 	// seq is incremented when deadlines are changed or descriptor is reused.
 } pollcache;
 
-static bool	netpollblock(PollDesc*, int32);
+static bool	netpollblock(PollDesc*, int32, bool);
 static G*	netpollunblock(PollDesc*, int32, bool);
 static void	deadline(int64, Eface);
 static void	readDeadline(int64, Eface);
@@ -59,6 +84,11 @@ static FuncVal deadlineFn	= {(void(*)(void))deadline};
 static FuncVal readDeadlineFn	= {(void(*)(void))readDeadline};
 static FuncVal writeDeadlineFn	= {(void(*)(void))writeDeadline};
 
+// runtimeNano returns the current value of the runtime clock in nanoseconds.
+func runtimeNano() (ns int64) {
+	ns = runtime·nanotime();
+}
+
 func runtime_pollServerInit() {
 	runtime·netpollinit();
 }
@@ -97,7 +127,6 @@ func runtime_pollClose(pd *PollDesc) {
 }
 
 func runtime_pollReset(pd *PollDesc, mode int) (err int) {
-	runtime·lock(pd);
 	err = checkerr(pd, mode);
 	if(err)
 		goto ret;
@@ -106,14 +135,15 @@ func runtime_pollReset(pd *PollDesc, mode int) (err int) {
 	else if(mode == 'w')
 		pd->wg = nil;
 ret:
-	runtime·unlock(pd);
 }
 
 func runtime_pollWait(pd *PollDesc, mode int) (err int) {
-	runtime·lock(pd);
 	err = checkerr(pd, mode);
 	if(err == 0) {
-		while(!netpollblock(pd, mode)) {
+		// As for now only Solaris uses level-triggered IO.
+		if(Solaris)
+			runtime·netpollarm(pd, mode);
+		while(!netpollblock(pd, mode, false)) {
 			err = checkerr(pd, mode);
 			if(err != 0)
 				break;
@@ -122,15 +152,13 @@ func runtime_pollWait(pd *PollDesc, mode int) (err int) {
 			// Pretend it has not happened and retry.
 		}
 	}
-	runtime·unlock(pd);
 }
 
 func runtime_pollWaitCanceled(pd *PollDesc, mode int) {
-	runtime·lock(pd);
-	// wait for ioready, ignore closing or timeouts.
-	while(!netpollblock(pd, mode))
+	// This function is used only on windows after a failed attempt to cancel
+	// a pending async IO operation. Wait for ioready, ignore closing or timeouts.
+	while(!netpollblock(pd, mode, true))
 		;
-	runtime·unlock(pd);
 }
 
 func runtime_pollSetDeadline(pd *PollDesc, d int64, mode int) {
@@ -185,7 +213,7 @@ func runtime_pollSetDeadline(pd *PollDesc, d int64, mode int) {
 	}
 	// If we set the new deadline in the past, unblock currently pending IO if any.
 	rg = nil;
-	wg = nil;
+	runtime·atomicstorep(&wg, nil);  // full memory barrier between stores to rd/wd and load of rg/wg in netpollunblock
 	if(pd->rd < 0)
 		rg = netpollunblock(pd, 'r', false);
 	if(pd->wd < 0)
@@ -205,6 +233,7 @@ func runtime_pollUnblock(pd *PollDesc) {
 		runtime·throw("runtime_pollUnblock: already closing");
 	pd->closing = true;
 	pd->seq++;
+	runtime·atomicstorep(&rg, nil);  // full memory barrier between store to closing and read of rg/wg in netpollunblock
 	rg = netpollunblock(pd, 'r', false);
 	wg = netpollunblock(pd, 'w', false);
 	if(pd->rt.fv) {
@@ -228,6 +257,30 @@ runtime·netpollfd(PollDesc *pd)
 	return pd->fd;
 }
 
+void**
+runtime·netpolluser(PollDesc *pd)
+{
+	return &pd->user;
+}
+
+bool
+runtime·netpollclosing(PollDesc *pd)
+{
+	return pd->closing;
+}
+
+void
+runtime·netpolllock(PollDesc *pd)
+{
+	runtime·lock(pd);
+}
+
+void
+runtime·netpollunlock(PollDesc *pd)
+{
+	runtime·unlock(pd);
+}
+
 // make pd ready, newly runnable goroutines (if any) are enqueued info gpp list
 void
 runtime·netpollready(G **gpp, PollDesc *pd, int32 mode)
@@ -235,12 +288,10 @@ runtime·netpollready(G **gpp, PollDesc *pd, int32 mode)
 	G *rg, *wg;
 
 	rg = wg = nil;
-	runtime·lock(pd);
 	if(mode == 'r' || mode == 'r'+'w')
 		rg = netpollunblock(pd, 'r', true);
 	if(mode == 'w' || mode == 'r'+'w')
 		wg = netpollunblock(pd, 'w', true);
-	runtime·unlock(pd);
 	if(rg) {
 		rg->schedlink = *gpp;
 		*gpp = rg;
@@ -261,51 +312,75 @@ checkerr(PollDesc *pd, int32 mode)
 	return 0;
 }
 
+static bool
+blockcommit(G *gp, G **gpp)
+{
+	return runtime·casp(gpp, WAIT, gp);
+}
+
 // returns true if IO is ready, or false if timedout or closed
+// waitio - wait only for completed IO, ignore errors
 static bool
-netpollblock(PollDesc *pd, int32 mode)
+netpollblock(PollDesc *pd, int32 mode, bool waitio)
 {
-	G **gpp;
+	G **gpp, *old;
 
 	gpp = &pd->rg;
 	if(mode == 'w')
 		gpp = &pd->wg;
-	if(*gpp == READY) {
-		*gpp = nil;
-		return true;
+
+	// set the gpp semaphore to WAIT
+	for(;;) {
+		old = *gpp;
+		if(old == READY) {
+			*gpp = nil;
+			return true;
+		}
+		if(old != nil)
+			runtime·throw("netpollblock: double wait");
+		if(runtime·casp(gpp, nil, WAIT))
+			break;
 	}
-	if(*gpp != nil)
-		runtime·throw("netpollblock: double wait");
-	*gpp = g;
-	runtime·park(runtime·unlock, &pd->Lock, "IO wait");
-	runtime·lock(pd);
-	if(g->param)
-		return true;
-	return false;
+
+	// need to recheck error states after setting gpp to WAIT
+	// this is necessary because runtime_pollUnblock/runtime_pollSetDeadline/deadlineimpl
+	// do the opposite: store to closing/rd/wd, membarrier, load of rg/wg
+	if(waitio || checkerr(pd, mode) == 0)
+		runtime·park((bool(*)(G*, void*))blockcommit, gpp, "IO wait");
+	// be careful to not lose concurrent READY notification
+	old = runtime·xchgp(gpp, nil);
+	if(old > WAIT)
+		runtime·throw("netpollblock: corrupted state");
+	return old == READY;
 }
 
 static G*
 netpollunblock(PollDesc *pd, int32 mode, bool ioready)
 {
-	G **gpp, *old;
+	G **gpp, *old, *new;
 
 	gpp = &pd->rg;
 	if(mode == 'w')
 		gpp = &pd->wg;
-	if(*gpp == READY)
-		return nil;
-	if(*gpp == nil) {
-		// Only set READY for ioready. runtime_pollWait
-		// will check for timeout/cancel before waiting.
+
+	for(;;) {
+		old = *gpp;
+		if(old == READY)
+			return nil;
+		if(old == nil && !ioready) {
+			// Only set READY for ioready. runtime_pollWait
+			// will check for timeout/cancel before waiting.
+			return nil;
+		}
+		new = nil;
 		if(ioready)
-			*gpp = READY;
-		return nil;
+			new = READY;
+		if(runtime·casp(gpp, old, new))
+			break;
 	}
-	old = *gpp;
-	// pass unblock reason onto blocked g
-	old->param = (void*)ioready;
-	*gpp = nil;
-	return old;
+	if(old > WAIT)
+		return old;  // must be G*
+	return nil;
 }
 
 static void
@@ -331,14 +406,14 @@ deadlineimpl(int64 now, Eface arg, bool read, bool write)
 		if(pd->rd <= 0 || pd->rt.fv == nil)
 			runtime·throw("deadlineimpl: inconsistent read deadline");
 		pd->rd = -1;
-		pd->rt.fv = nil;
+		runtime·atomicstorep(&pd->rt.fv, nil);  // full memory barrier between store to rd and load of rg in netpollunblock
 		rg = netpollunblock(pd, 'r', false);
 	}
 	if(write) {
 		if(pd->wd <= 0 || (pd->wt.fv == nil && !read))
 			runtime·throw("deadlineimpl: inconsistent write deadline");
 		pd->wd = -1;
-		pd->wt.fv = nil;
+		runtime·atomicstorep(&pd->wt.fv, nil);  // full memory barrier between store to wd and load of wg in netpollunblock
 		wg = netpollunblock(pd, 'w', false);
 	}
 	runtime·unlock(pd);
@@ -374,7 +449,7 @@ allocPollDesc(void)
 
 	runtime·lock(&pollcache);
 	if(pollcache.first == nil) {
-		n = PageSize/sizeof(*pd);
+		n = PollBlockSize/sizeof(*pd);
 		if(n == 0)
 			n = 1;
 		// Must be in non-GC memory because can be referenced
diff --git a/src/pkg/runtime/netpoll_epoll.c b/src/pkg/runtime/netpoll_epoll.c
index 885ac5e..9ea5e1a 100644
--- a/src/pkg/runtime/netpoll_epoll.c
+++ b/src/pkg/runtime/netpoll_epoll.c
@@ -52,6 +52,13 @@ runtime·netpollclose(uintptr fd)
 	return -res;
 }
 
+void
+runtime·netpollarm(PollDesc* pd, int32 mode)
+{
+	USED(pd, mode);
+	runtime·throw("unused");
+}
+
 // polls for ready network connections
 // returns list of goroutines that become runnable
 G*
diff --git a/src/pkg/runtime/netpoll_kqueue.c b/src/pkg/runtime/netpoll_kqueue.c
index afc8d68..171346c 100644
--- a/src/pkg/runtime/netpoll_kqueue.c
+++ b/src/pkg/runtime/netpoll_kqueue.c
@@ -59,6 +59,13 @@ runtime·netpollclose(uintptr fd)
 	return 0;
 }
 
+void
+runtime·netpollarm(PollDesc* pd, int32 mode)
+{
+	USED(pd, mode);
+	runtime·throw("unused");
+}
+
 // Polls for ready network connections.
 // Returns list of goroutines that become runnable.
 G*
diff --git a/src/pkg/runtime/netpoll_nacl.c b/src/pkg/runtime/netpoll_nacl.c
new file mode 100644
index 0000000..b75753a
--- /dev/null
+++ b/src/pkg/runtime/netpoll_nacl.c
@@ -0,0 +1,37 @@
+// 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 "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+// Fake network poller for NaCl.
+// Should never be used, because NaCl network connections do not honor "SetNonblock".
+
+void
+runtime·netpollinit(void)
+{
+}
+
+int32
+runtime·netpollopen(uintptr fd, PollDesc *pd)
+{
+	USED(fd);
+	USED(pd);
+	return 0;
+}
+
+int32
+runtime·netpollclose(uintptr fd)
+{
+	USED(fd);
+	return 0;
+}
+
+G*
+runtime·netpoll(bool block)
+{
+	USED(block);
+	return nil;
+}
diff --git a/src/pkg/runtime/netpoll_solaris.c b/src/pkg/runtime/netpoll_solaris.c
new file mode 100644
index 0000000..a2631a8
--- /dev/null
+++ b/src/pkg/runtime/netpoll_solaris.c
@@ -0,0 +1,268 @@
+// 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 "runtime.h"
+#include "arch_GOARCH.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+// Solaris runtime-integrated network poller.
+// 
+// Solaris uses event ports for scalable network I/O. Event
+// ports are level-triggered, unlike epoll and kqueue which
+// can be configured in both level-triggered and edge-triggered
+// mode. Level triggering means we have to keep track of a few things
+// ourselves. After we receive an event for a file descriptor,
+// it's our responsibility to ask again to be notified for future
+// events for that descriptor. When doing this we must keep track of
+// what kind of events the goroutines are currently interested in,
+// for example a fd may be open both for reading and writing.
+// 
+// A description of the high level operation of this code
+// follows. Networking code will get a file descriptor by some means
+// and will register it with the netpolling mechanism by a code path
+// that eventually calls runtime·netpollopen. runtime·netpollopen
+// calls port_associate with an empty event set. That means that we
+// will not receive any events at this point. The association needs
+// to be done at this early point because we need to process the I/O
+// readiness notification at some point in the future. If I/O becomes
+// ready when nobody is listening, when we finally care about it,
+// nobody will tell us anymore.
+// 
+// Beside calling runtime·netpollopen, the networking code paths
+// will call runtime·netpollarm each time goroutines are interested
+// in doing network I/O. Because now we know what kind of I/O we
+// are interested in (reading/writting), we can call port_associate
+// passing the correct type of event set (POLLIN/POLLOUT). As we made
+// sure to have already associated the file descriptor with the port,
+// when we now call port_associate, we will unblock the main poller
+// loop (in runtime·netpoll) right away if the socket is actually
+// ready for I/O.
+// 
+// The main poller loop runs in its own thread waiting for events
+// using port_getn. When an event happens, it will tell the scheduler
+// about it using runtime·netpollready. Besides doing this, it must
+// also re-associate the events that were not part of this current
+// notification with the file descriptor. Failing to do this would
+// mean each notification will prevent concurrent code using the
+// same file descriptor in parallel.
+// 
+// The logic dealing with re-associations is encapsulated in
+// runtime·netpollupdate. This function takes care to associate the
+// descriptor only with the subset of events that were previously
+// part of the association, except the one that just happened. We
+// can't re-associate with that right away, because event ports
+// are level triggered so it would cause a busy loop. Instead, that
+// association is effected only by the runtime·netpollarm code path,
+// when Go code actually asks for I/O.
+// 
+// The open and arming mechanisms are serialized using the lock
+// inside PollDesc. This is required because the netpoll loop runs
+// asynchonously in respect to other Go code and by the time we get
+// to call port_associate to update the association in the loop, the
+// file descriptor might have been closed and reopened already. The
+// lock allows runtime·netpollupdate to be called synchronously from
+// the loop thread while preventing other threads operating to the
+// same PollDesc, so once we unblock in the main loop, until we loop
+// again we know for sure we are always talking about the same file
+// descriptor and can safely access the data we want (the event set).
+
+#pragma dynimport libc·fcntl fcntl "libc.so"
+#pragma dynimport libc·port_create port_create "libc.so"
+#pragma dynimport libc·port_associate port_associate "libc.so"
+#pragma dynimport libc·port_dissociate port_dissociate "libc.so"
+#pragma dynimport libc·port_getn port_getn "libc.so"
+extern uintptr libc·fcntl;
+extern uintptr libc·port_create;
+extern uintptr libc·port_associate;
+extern uintptr libc·port_dissociate;
+extern uintptr libc·port_getn;
+
+#define errno (*m->perrno)
+
+int32
+runtime·fcntl(int32 fd, int32 cmd, uintptr arg)
+{
+	return runtime·sysvicall6(libc·fcntl, 3,
+	    (uintptr)fd, (uintptr)cmd, (uintptr)arg);
+}
+
+int32
+runtime·port_create(void)
+{
+	return runtime·sysvicall6(libc·port_create, 0);
+}
+
+int32
+runtime·port_associate(int32 port, int32 source, uintptr object, int32 events, uintptr user)
+{
+	return runtime·sysvicall6(libc·port_associate,
+	    5, (uintptr)port, (uintptr)source, object, (uintptr)events, user);
+}
+
+int32
+runtime·port_dissociate(int32 port, int32 source, uintptr object)
+{
+	return runtime·sysvicall6(libc·port_dissociate,
+	    3, (uintptr)port, (uintptr)source, object);
+}
+
+int32
+runtime·port_getn(int32 port, PortEvent *evs, uint32 max, uint32 *nget, Timespec *timeout)
+{
+	return runtime·sysvicall6(libc·port_getn, 5, (uintptr)port,
+	    (uintptr)evs, (uintptr)max, (uintptr)nget, (uintptr)timeout);
+}
+
+static int32 portfd = -1;
+
+void
+runtime·netpollinit(void)
+{
+	if((portfd = runtime·port_create()) >= 0) {
+		runtime·fcntl(portfd, F_SETFD, FD_CLOEXEC);
+		return;
+	}
+
+	runtime·printf("netpollinit: failed to create port (%d)\n", errno);
+	runtime·throw("netpollinit: failed to create port");
+}
+
+int32
+runtime·netpollopen(uintptr fd, PollDesc *pd)
+{
+	int32 r;
+
+	runtime·netpolllock(pd);
+	// We don't register for any specific type of events yet, that's
+	// netpollarm's job. We merely ensure we call port_associate before
+	// asynchonous connect/accept completes, so when we actually want
+	// to do any I/O, the call to port_associate (from netpollarm,
+	// with the interested event set) will unblock port_getn right away
+	// because of the I/O readiness notification.
+	*runtime·netpolluser(pd) = 0;
+	r = runtime·port_associate(portfd, PORT_SOURCE_FD, fd, 0, (uintptr)pd);
+	runtime·netpollunlock(pd);
+	return r;
+}
+
+int32
+runtime·netpollclose(uintptr fd)
+{
+	return runtime·port_dissociate(portfd, PORT_SOURCE_FD, fd);
+}
+
+// Updates the association with a new set of interested events. After
+// this call, port_getn will return one and only one event for that
+// particular descriptor, so this function needs to be called again.
+void
+runtime·netpollupdate(PollDesc* pd, uint32 set, uint32 clear)
+{
+	uint32 *ep, old, events;
+	uintptr fd = runtime·netpollfd(pd);
+	ep = (uint32*)runtime·netpolluser(pd);
+
+	if(runtime·netpollclosing(pd))
+		return;
+
+	old = *ep;
+	events = (old & ~clear) | set;
+	if(old == events)
+		return;
+
+	if(events && runtime·port_associate(portfd, PORT_SOURCE_FD, fd, events, (uintptr)pd) != 0) {
+		runtime·printf("netpollupdate: failed to associate (%d)\n", errno);
+		runtime·throw("netpollupdate: failed to associate");
+	} 
+	*ep = events;
+}
+
+// subscribe the fd to the port such that port_getn will return one event.
+void
+runtime·netpollarm(PollDesc* pd, int32 mode)
+{
+	runtime·netpolllock(pd);
+	switch(mode) {
+	case 'r':
+		runtime·netpollupdate(pd, POLLIN, 0);
+		break;
+	case 'w':
+		runtime·netpollupdate(pd, POLLOUT, 0);
+		break;
+	default:
+		runtime·throw("netpollarm: bad mode");
+	}
+	runtime·netpollunlock(pd);
+}
+
+// polls for ready network connections
+// returns list of goroutines that become runnable
+G*
+runtime·netpoll(bool block)
+{
+	static int32 lasterr;
+	PortEvent events[128], *ev;
+	PollDesc *pd;
+	int32 i, mode, clear;
+	uint32 n;
+	Timespec *wait = nil, zero;
+	G *gp;
+
+	if(portfd == -1)
+		return (nil);
+
+	if(!block) {
+		zero.tv_sec = 0;
+		zero.tv_nsec = 0;
+		wait = &zero;
+	}
+
+retry:
+	n = 1;
+	if(runtime·port_getn(portfd, events, nelem(events), &n, wait) < 0) {
+		if(errno != EINTR && errno != lasterr) {
+			lasterr = errno;
+			runtime·printf("runtime: port_getn on fd %d failed with %d\n", portfd, errno);
+		}
+		goto retry;
+	}
+
+	gp = nil;
+	for(i = 0; i < n; i++) {
+		ev = &events[i];
+
+		if(ev->portev_events == 0)
+			continue;
+		pd = (PollDesc *)ev->portev_user;
+
+		mode = 0;
+		clear = 0;
+		if(ev->portev_events & (POLLIN|POLLHUP|POLLERR)) {
+			mode += 'r';
+			clear |= POLLIN;
+		}
+		if(ev->portev_events & (POLLOUT|POLLHUP|POLLERR)) {
+			mode += 'w';
+			clear |= POLLOUT;
+		}
+		// To effect edge-triggered events, we need to be sure to
+		// update our association with whatever events were not
+		// set with the event. For example if we are registered
+		// for POLLIN|POLLOUT, and we get POLLIN, besides waking
+		// the goroutine interested in POLLIN we have to not forget
+		// about the one interested in POLLOUT.
+		if(clear != 0) {
+			runtime·netpolllock(pd);
+			runtime·netpollupdate(pd, 0, clear);
+			runtime·netpollunlock(pd);
+		}
+
+		if(mode)
+			runtime·netpollready(&gp, pd, mode);
+	}
+
+	if(block && gp == nil)
+		goto retry;
+	return gp;
+}
diff --git a/src/pkg/runtime/netpoll_windows.c b/src/pkg/runtime/netpoll_windows.c
index b510a41..f3cd15c 100644
--- a/src/pkg/runtime/netpoll_windows.c
+++ b/src/pkg/runtime/netpoll_windows.c
@@ -72,6 +72,13 @@ runtime·netpollclose(uintptr fd)
 	return 0;
 }
 
+void
+runtime·netpollarm(PollDesc* pd, int32 mode)
+{
+	USED(pd, mode);
+	runtime·throw("unused");
+}
+
 // Polls for completed network IO.
 // Returns list of goroutines that become runnable.
 G*
@@ -94,13 +101,17 @@ retry:
 		n = nelem(entries) / runtime·gomaxprocs;
 		if(n < 8)
 			n = 8;
+		if(block)
+			m->blocked = true;
 		if(runtime·stdcall(runtime·GetQueuedCompletionStatusEx, 6, iocphandle, entries, (uintptr)n, &n, (uintptr)wait, (uintptr)0) == 0) {
+			m->blocked = false;
 			errno = runtime·getlasterror();
 			if(!block && errno == WAIT_TIMEOUT)
 				return nil;
 			runtime·printf("netpoll: GetQueuedCompletionStatusEx failed (errno=%d)\n", errno);
 			runtime·throw("netpoll: GetQueuedCompletionStatusEx failed");
 		}
+		m->blocked = false;
 		for(i = 0; i < n; i++) {
 			op = entries[i].op;
 			errno = 0;
@@ -113,7 +124,10 @@ retry:
 		op = nil;
 		errno = 0;
 		qty = 0;
+		if(block)
+			m->blocked = true;
 		if(runtime·stdcall(runtime·GetQueuedCompletionStatus, 5, iocphandle, &qty, &key, &op, (uintptr)wait) == 0) {
+			m->blocked = false;
 			errno = runtime·getlasterror();
 			if(!block && errno == WAIT_TIMEOUT)
 				return nil;
@@ -123,6 +137,7 @@ retry:
 			}
 			// dequeued failed IO packet, so report that
 		}
+		m->blocked = false;
 		handlecompletion(&gp, op, errno, qty);
 	}
 	if(block && gp == nil)
diff --git a/src/pkg/runtime/norace_test.go b/src/pkg/runtime/norace_test.go
index a3d5b00..3b17187 100644
--- a/src/pkg/runtime/norace_test.go
+++ b/src/pkg/runtime/norace_test.go
@@ -9,7 +9,6 @@ package runtime_test
 
 import (
 	"runtime"
-	"sync/atomic"
 	"testing"
 )
 
@@ -31,28 +30,17 @@ func BenchmarkSyscallExcessWork(b *testing.B) {
 }
 
 func benchmarkSyscall(b *testing.B, work, excess int) {
-	const CallsPerSched = 1000
-	procs := runtime.GOMAXPROCS(-1) * excess
-	N := int32(b.N / CallsPerSched)
-	c := make(chan bool, procs)
-	for p := 0; p < procs; p++ {
-		go func() {
-			foo := 42
-			for atomic.AddInt32(&N, -1) >= 0 {
-				runtime.Gosched()
-				for g := 0; g < CallsPerSched; g++ {
-					runtime.Entersyscall()
-					for i := 0; i < work; i++ {
-						foo *= 2
-						foo /= 2
-					}
-					runtime.Exitsyscall()
-				}
+	b.SetParallelism(excess)
+	b.RunParallel(func(pb *testing.PB) {
+		foo := 42
+		for pb.Next() {
+			runtime.Entersyscall()
+			for i := 0; i < work; i++ {
+				foo *= 2
+				foo /= 2
 			}
-			c <- foo == 42
-		}()
-	}
-	for p := 0; p < procs; p++ {
-		<-c
-	}
+			runtime.Exitsyscall()
+		}
+		_ = foo
+	})
 }
diff --git a/src/pkg/runtime/os_darwin.c b/src/pkg/runtime/os_darwin.c
index 9eb1b46..33a2df9 100644
--- a/src/pkg/runtime/os_darwin.c
+++ b/src/pkg/runtime/os_darwin.c
@@ -59,6 +59,7 @@ runtime·osinit(void)
 void
 runtime·get_random_data(byte **rnd, int32 *rnd_len)
 {
+	#pragma dataflag NOPTR
 	static byte urandom_data[HashRandomBytes];
 	int32 fd;
 	fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
@@ -434,9 +435,12 @@ runtime·mach_semrelease(uint32 sem)
 void
 runtime·sigpanic(void)
 {
+	if(!runtime·canpanic(g))
+		runtime·throw("unexpected signal during runtime execution");
+
 	switch(g->sig) {
 	case SIGBUS:
-		if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+		if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
 			if(g->sigpc == 0)
 				runtime·panicstring("call of nil func value");
 			runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -444,7 +448,7 @@ runtime·sigpanic(void)
 		runtime·printf("unexpected fault address %p\n", g->sigcode1);
 		runtime·throw("fault");
 	case SIGSEGV:
-		if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+		if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
 			if(g->sigpc == 0)
 				runtime·panicstring("call of nil func value");
 			runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -517,3 +521,9 @@ runtime·signalstack(byte *p, int32 n)
 		st.ss_flags = SS_DISABLE;
 	runtime·sigaltstack(&st, nil);
 }
+
+void
+runtime·unblocksignals(void)
+{
+	runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
+}
diff --git a/src/pkg/runtime/os_darwin.h b/src/pkg/runtime/os_darwin.h
index b4f49e0..91a405f 100644
--- a/src/pkg/runtime/os_darwin.h
+++ b/src/pkg/runtime/os_darwin.h
@@ -23,6 +23,7 @@ int32	runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
 
 typedef uint32 Sigset;
 void	runtime·sigprocmask(int32, Sigset*, Sigset*);
+void	runtime·unblocksignals(void);
 
 struct Sigaction;
 void	runtime·sigaction(uintptr, struct Sigaction*, struct Sigaction*);
@@ -39,4 +40,3 @@ void	runtime·setitimer(int32, Itimerval*, Itimerval*);
 #define	SIG_BLOCK 1
 #define	SIG_UNBLOCK 2
 #define	SIG_SETMASK 3
-
diff --git a/src/pkg/runtime/os_dragonfly.c b/src/pkg/runtime/os_dragonfly.c
index cf427b7..e7fd2cc 100644
--- a/src/pkg/runtime/os_dragonfly.c
+++ b/src/pkg/runtime/os_dragonfly.c
@@ -122,6 +122,7 @@ runtime·osinit(void)
 void
 runtime·get_random_data(byte **rnd, int32 *rnd_len)
 {
+	#pragma dataflag NOPTR
 	static byte urandom_data[HashRandomBytes];
 	int32 fd;
 	fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
@@ -169,9 +170,12 @@ runtime·unminit(void)
 void
 runtime·sigpanic(void)
 {
+	if(!runtime·canpanic(g))
+		runtime·throw("unexpected signal during runtime execution");
+
 	switch(g->sig) {
 	case SIGBUS:
-		if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+		if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
 			if(g->sigpc == 0)
 				runtime·panicstring("call of nil func value");
 			runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -179,7 +183,7 @@ runtime·sigpanic(void)
 		runtime·printf("unexpected fault address %p\n", g->sigcode1);
 		runtime·throw("fault");
 	case SIGSEGV:
-		if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+		if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
 			if(g->sigpc == 0)
 				runtime·panicstring("call of nil func value");
 			runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -280,3 +284,9 @@ runtime·signalstack(byte *p, int32 n)
 		st.ss_flags = SS_DISABLE;
 	runtime·sigaltstack(&st, nil);
 }
+
+void
+runtime·unblocksignals(void)
+{
+	runtime·sigprocmask(&sigset_none, nil);
+}
diff --git a/src/pkg/runtime/os_dragonfly.h b/src/pkg/runtime/os_dragonfly.h
index ebbd0eb..fddeede 100644
--- a/src/pkg/runtime/os_dragonfly.h
+++ b/src/pkg/runtime/os_dragonfly.h
@@ -12,6 +12,7 @@ void	runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
 struct	sigaction;
 void	runtime·sigaction(int32, struct sigaction*, struct sigaction*);
 void	runtime·sigprocmask(Sigset *, Sigset *);
+void	runtime·unblocksignals(void);
 void	runtime·setitimer(int32, Itimerval*, Itimerval*);
 int32	runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
 
diff --git a/src/pkg/runtime/os_freebsd.c b/src/pkg/runtime/os_freebsd.c
index 042097b..02b1347 100644
--- a/src/pkg/runtime/os_freebsd.c
+++ b/src/pkg/runtime/os_freebsd.c
@@ -50,7 +50,7 @@ runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
 	Timespec ts;
 
 	if(ns < 0) {
-		ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT_UINT, val, nil, nil);
+		ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT_UINT_PRIVATE, val, nil, nil);
 		if(ret >= 0 || ret == -EINTR)
 			return;
 		goto fail;
@@ -58,7 +58,7 @@ runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
 	// NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system.
 	ts.tv_nsec = 0;
 	ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec);
-	ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT_UINT, val, nil, &ts);
+	ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT_UINT_PRIVATE, val, nil, &ts);
 	if(ret >= 0 || ret == -EINTR)
 		return;
 
@@ -78,7 +78,7 @@ runtime·futexwakeup(uint32 *addr, uint32 cnt)
 {
 	int32 ret;
 
-	ret = runtime·sys_umtx_op(addr, UMTX_OP_WAKE, cnt, nil, nil);
+	ret = runtime·sys_umtx_op(addr, UMTX_OP_WAKE_PRIVATE, cnt, nil, nil);
 	if(ret >= 0)
 		return;
 
@@ -130,6 +130,7 @@ runtime·osinit(void)
 void
 runtime·get_random_data(byte **rnd, int32 *rnd_len)
 {
+	#pragma dataflag NOPTR
 	static byte urandom_data[HashRandomBytes];
 	int32 fd;
 	fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
@@ -177,9 +178,12 @@ runtime·unminit(void)
 void
 runtime·sigpanic(void)
 {
+	if(!runtime·canpanic(g))
+		runtime·throw("unexpected signal during runtime execution");
+
 	switch(g->sig) {
 	case SIGBUS:
-		if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+		if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
 			if(g->sigpc == 0)
 				runtime·panicstring("call of nil func value");
 			runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -187,7 +191,7 @@ runtime·sigpanic(void)
 		runtime·printf("unexpected fault address %p\n", g->sigcode1);
 		runtime·throw("fault");
 	case SIGSEGV:
-		if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+		if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
 			if(g->sigpc == 0)
 				runtime·panicstring("call of nil func value");
 			runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -288,3 +292,9 @@ runtime·signalstack(byte *p, int32 n)
 		st.ss_flags = SS_DISABLE;
 	runtime·sigaltstack(&st, nil);
 }
+
+void
+runtime·unblocksignals(void)
+{
+	runtime·sigprocmask(&sigset_none, nil);
+}
diff --git a/src/pkg/runtime/os_freebsd.h b/src/pkg/runtime/os_freebsd.h
index c1853e6..4b2c253 100644
--- a/src/pkg/runtime/os_freebsd.h
+++ b/src/pkg/runtime/os_freebsd.h
@@ -12,6 +12,7 @@ void	runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
 struct	sigaction;
 void	runtime·sigaction(int32, struct sigaction*, struct sigaction*);
 void	runtime·sigprocmask(Sigset *, Sigset *);
+void	runtime·unblocksignals(void);
 void	runtime·setitimer(int32, Itimerval*, Itimerval*);
 int32	runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
 
diff --git a/src/pkg/runtime/os_linux.c b/src/pkg/runtime/os_linux.c
index cb45fe8..8a94524 100644
--- a/src/pkg/runtime/os_linux.c
+++ b/src/pkg/runtime/os_linux.c
@@ -218,9 +218,12 @@ runtime·unminit(void)
 void
 runtime·sigpanic(void)
 {
+	if(!runtime·canpanic(g))
+		runtime·throw("unexpected signal during runtime execution");
+
 	switch(g->sig) {
 	case SIGBUS:
-		if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+		if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
 			if(g->sigpc == 0)
 				runtime·panicstring("call of nil func value");
 			runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -228,7 +231,7 @@ runtime·sigpanic(void)
 		runtime·printf("unexpected fault address %p\n", g->sigcode1);
 		runtime·throw("fault");
 	case SIGSEGV:
-		if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+		if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
 			if(g->sigpc == 0)
 				runtime·panicstring("call of nil func value");
 			runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -331,3 +334,9 @@ runtime·signalstack(byte *p, int32 n)
 		st.ss_flags = SS_DISABLE;
 	runtime·sigaltstack(&st, nil);
 }
+
+void
+runtime·unblocksignals(void)
+{
+	runtime·rtsigprocmask(SIG_SETMASK, &sigset_none, nil, sizeof sigset_none);
+}
diff --git a/src/pkg/runtime/os_linux.h b/src/pkg/runtime/os_linux.h
index b2d3f6f..d4b1902 100644
--- a/src/pkg/runtime/os_linux.h
+++ b/src/pkg/runtime/os_linux.h
@@ -28,6 +28,7 @@ struct Sigset
 	uint32 mask[2];
 };
 void	runtime·rtsigprocmask(int32, Sigset*, Sigset*, int32);
+void	runtime·unblocksignals(void);
 #define SIG_SETMASK 2
 
 #define RLIMIT_AS 9
diff --git a/src/pkg/runtime/os_linux_arm.c b/src/pkg/runtime/os_linux_arm.c
index 570b3f0..aad08b9 100644
--- a/src/pkg/runtime/os_linux_arm.c
+++ b/src/pkg/runtime/os_linux_arm.c
@@ -16,7 +16,7 @@
 static uint32 runtime·randomNumber;
 uint8  runtime·armArch = 6;	// we default to ARMv6
 uint32 runtime·hwcap;	// set by setup_auxv
-uint8  runtime·goarm;	// set by 5l
+extern uint8  runtime·goarm;	// set by 5l
 
 void
 runtime·checkgoarm(void)
diff --git a/src/pkg/runtime/os_nacl.c b/src/pkg/runtime/os_nacl.c
new file mode 100644
index 0000000..3196e2c
--- /dev/null
+++ b/src/pkg/runtime/os_nacl.c
@@ -0,0 +1,278 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "arch_GOARCH.h"
+#include "../../cmd/ld/textflag.h"
+#include "stack.h"
+
+int8 *goos = "nacl";
+extern SigTab runtime·sigtab[];
+
+void runtime·sigtramp(void);
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+void
+runtime·mpreinit(M *mp)
+{
+	mp->gsignal = runtime·malg(32*1024);	// OS X wants >=8K, Linux >=2K
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+void
+runtime·minit(void)
+{
+	int32 ret;
+
+	// Initialize signal handling
+	ret = runtime·nacl_exception_stack((byte*)m->gsignal->stackguard - StackGuard, 32*1024);
+	if(ret < 0)
+		runtime·printf("runtime: nacl_exception_stack: error %d\n", -ret);
+
+	ret = runtime·nacl_exception_handler(runtime·sigtramp, nil);
+	if(ret < 0)
+		runtime·printf("runtime: nacl_exception_handler: error %d\n", -ret);
+}
+
+// Called from dropm to undo the effect of an minit.
+void
+runtime·unminit(void)
+{
+}
+
+int8 runtime·sigtrampf[] = "runtime: signal at PC=%X AX=%X CX=%X DX=%X BX=%X DI=%X R15=%X *SP=%X\n";
+int8 runtime·sigtrampp[] = "runtime: sigtramp";
+
+extern byte runtime·tls0[];
+
+void
+runtime·osinit(void)
+{
+	runtime·ncpu = 1;
+	m->procid = 2;
+//runtime·nacl_exception_handler(runtime·sigtramp, nil);
+}
+
+void
+runtime·crash(void)
+{
+	*(int32*)0 = 0;
+}
+
+void
+runtime·get_random_data(byte **rnd, int32 *rnd_len)
+{
+	*rnd = nil;
+	*rnd_len = 0;
+}
+
+void
+runtime·goenvs(void)
+{
+	runtime·goenvs_unix();
+}
+
+void
+runtime·initsig(void)
+{
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·usleep(uint32 us)
+{
+	Timespec ts;
+	
+	ts.tv_sec = us/1000000;
+	ts.tv_nsec = (us%1000000)*1000;
+	runtime·nacl_nanosleep(&ts, nil);
+}
+
+void runtime·mstart_nacl(void);
+
+void
+runtime·newosproc(M *mp, void *stk)
+{
+	int32 ret;
+	void **tls;
+
+	tls = (void**)mp->tls;
+	tls[0] = mp->g0;
+	tls[1] = mp;
+	ret = runtime·nacl_thread_create(runtime·mstart_nacl, stk, tls+2, 0);
+	if(ret < 0) {
+		runtime·printf("nacl_thread_create: error %d\n", -ret);
+		runtime·throw("newosproc");
+	}
+}
+
+uintptr
+runtime·semacreate(void)
+{
+	int32 mu, cond;
+	
+	mu = runtime·nacl_mutex_create(0);
+	if(mu < 0) {
+		runtime·printf("nacl_mutex_create: error %d\n", -mu);
+		runtime·throw("semacreate");
+	}
+	cond = runtime·nacl_cond_create(0);
+	if(cond < 0) {
+		runtime·printf("nacl_cond_create: error %d\n", -cond);
+		runtime·throw("semacreate");
+	}
+	m->waitsemalock = mu;
+	return cond; // assigned to m->waitsema
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·semasleep(int64 ns)
+{
+	int32 ret;
+	
+	ret = runtime·nacl_mutex_lock(m->waitsemalock);
+	if(ret < 0) {
+		//runtime·printf("nacl_mutex_lock: error %d\n", -ret);
+		runtime·throw("semasleep");
+	}
+	if(m->waitsemacount > 0) {
+		m->waitsemacount = 0;
+		runtime·nacl_mutex_unlock(m->waitsemalock);
+		return 0;
+	}
+
+	while(m->waitsemacount == 0) {
+		if(ns < 0) {
+			ret = runtime·nacl_cond_wait(m->waitsema, m->waitsemalock);
+			if(ret < 0) {
+				//runtime·printf("nacl_cond_wait: error %d\n", -ret);
+				runtime·throw("semasleep");
+			}
+		} else {
+			Timespec ts;
+			
+			ns += runtime·nanotime();
+			ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec);
+			ret = runtime·nacl_cond_timed_wait_abs(m->waitsema, m->waitsemalock, &ts);
+			if(ret == -ETIMEDOUT) {
+				runtime·nacl_mutex_unlock(m->waitsemalock);
+				return -1;
+			}
+			if(ret < 0) {
+				//runtime·printf("nacl_cond_timed_wait_abs: error %d\n", -ret);
+				runtime·throw("semasleep");
+			}
+		}
+	}
+			
+	m->waitsemacount = 0;
+	runtime·nacl_mutex_unlock(m->waitsemalock);
+	return 0;
+}
+
+void
+runtime·semawakeup(M *mp)
+{
+	int32 ret;
+	
+	ret = runtime·nacl_mutex_lock(mp->waitsemalock);
+	if(ret < 0) {
+		//runtime·printf("nacl_mutex_lock: error %d\n", -ret);
+		runtime·throw("semawakeup");
+	}
+	if(mp->waitsemacount != 0) {
+		//runtime·printf("semawakeup: double wakeup\n");
+		runtime·throw("semawakeup");
+	}
+	mp->waitsemacount = 1;
+	runtime·nacl_cond_signal(mp->waitsema);
+	runtime·nacl_mutex_unlock(mp->waitsemalock);
+}
+
+void
+os·sigpipe(void)
+{
+	runtime·throw("too many writes on closed pipe");
+}
+
+uintptr
+runtime·memlimit(void)
+{
+	runtime·printf("memlimit\n");
+	return 0;
+}
+
+#pragma dataflag NOPTR
+static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g.  No stack split.
+#pragma textflag NOSPLIT
+void
+runtime·badsignal2(void)
+{
+	runtime·write(2, badsignal, sizeof badsignal - 1);
+	runtime·exit(2);
+}
+
+void	runtime·madvise(byte*, uintptr, int32) { }
+void runtime·munmap(byte*, uintptr) {}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+	USED(hz);
+}
+
+void
+runtime·sigdisable(uint32)
+{
+}
+
+void
+runtime·sigenable(uint32)
+{
+}
+
+void
+runtime·closeonexec(int32)
+{
+}
+
+void
+runtime·sigpanic(void)
+{
+	if(!runtime·canpanic(g))
+		runtime·throw("unexpected signal during runtime execution");
+
+	// Native Client only invokes the exception handler for memory faults.
+	g->sig = SIGSEGV;
+	if(g->sigpc == 0)
+		runtime·panicstring("call of nil func value");
+	runtime·panicstring("invalid memory address or nil pointer dereference");
+}
+
+uint32 runtime·writelock; // test-and-set spin lock for runtime.write
+
+/*
+An attempt at IRT. Doesn't work. See end of sys_nacl_amd64.s.
+
+void (*runtime·nacl_irt_query)(void);
+
+int8 runtime·nacl_irt_basic_v0_1_str[] = "nacl-irt-basic-0.1";
+void *runtime·nacl_irt_basic_v0_1[6]; // exit, gettod, clock, nanosleep, sched_yield, sysconf
+int32 runtime·nacl_irt_basic_v0_1_size = sizeof(runtime·nacl_irt_basic_v0_1);
+
+int8 runtime·nacl_irt_memory_v0_3_str[] = "nacl-irt-memory-0.3";
+void *runtime·nacl_irt_memory_v0_3[3]; // mmap, munmap, mprotect
+int32 runtime·nacl_irt_memory_v0_3_size = sizeof(runtime·nacl_irt_memory_v0_3);
+
+int8 runtime·nacl_irt_thread_v0_1_str[] = "nacl-irt-thread-0.1";
+void *runtime·nacl_irt_thread_v0_1[3]; // thread_create, thread_exit, thread_nice
+int32 runtime·nacl_irt_thread_v0_1_size = sizeof(runtime·nacl_irt_thread_v0_1);
+*/
\ No newline at end of file
diff --git a/src/pkg/runtime/os_nacl.h b/src/pkg/runtime/os_nacl.h
new file mode 100644
index 0000000..7c9d9c2
--- /dev/null
+++ b/src/pkg/runtime/os_nacl.h
@@ -0,0 +1,162 @@
+enum {
+	NSIG = 32,
+	SI_USER = 1,
+
+	// native_client/src/trusted/service_runtime/include/sys/errno.h
+	// The errors are mainly copied from Linux.
+	EPERM = 1,  /* Operation not permitted */
+	ENOENT = 2,  /* No such file or directory */
+	ESRCH = 3,  /* No such process */
+	EINTR = 4,  /* Interrupted system call */
+	EIO = 5,  /* I/O error */
+	ENXIO = 6,  /* No such device or address */
+	E2BIG = 7,  /* Argument list too long */
+	ENOEXEC = 8,  /* Exec format error */
+	EBADF = 9,  /* Bad file number */
+	ECHILD = 10,  /* No child processes */
+	EAGAIN = 11,  /* Try again */
+	ENOMEM = 12,  /* Out of memory */
+	EACCES = 13,  /* Permission denied */
+	EFAULT = 14,  /* Bad address */
+	EBUSY = 16,  /* Device or resource busy */
+	EEXIST = 17,  /* File exists */
+	EXDEV = 18,  /* Cross-device link */
+	ENODEV = 19,  /* No such device */
+	ENOTDIR = 20,  /* Not a directory */
+	EISDIR = 21,  /* Is a directory */
+	EINVAL = 22,  /* Invalid argument */
+	ENFILE = 23,  /* File table overflow */
+	EMFILE = 24,  /* Too many open files */
+	ENOTTY = 25,  /* Not a typewriter */
+	EFBIG = 27,  /* File too large */
+	ENOSPC = 28,  /* No space left on device */
+	ESPIPE = 29,  /* Illegal seek */
+	EROFS = 30,  /* Read-only file system */
+	EMLINK = 31,  /* Too many links */
+	EPIPE = 32,  /* Broken pipe */
+	ENAMETOOLONG = 36,  /* File name too long */
+	ENOSYS = 38,  /* Function not implemented */
+	EDQUOT = 122, /* Quota exceeded */
+	EDOM = 33,   /* Math arg out of domain of func */
+	ERANGE = 34, /* Math result not representable */
+	EDEADLK = 35,  /* Deadlock condition */
+	ENOLCK = 37, /* No record locks available */
+	ENOTEMPTY = 39,  /* Directory not empty */
+	ELOOP = 40,  /* Too many symbolic links */
+	ENOMSG = 42, /* No message of desired type */
+	EIDRM = 43,  /* Identifier removed */
+	ECHRNG = 44, /* Channel number out of range */
+	EL2NSYNC = 45, /* Level 2 not synchronized */
+	EL3HLT = 46, /* Level 3 halted */
+	EL3RST = 47, /* Level 3 reset */
+	ELNRNG = 48, /* Link number out of range */
+	EUNATCH = 49,  /* Protocol driver not attached */
+	ENOCSI = 50, /* No CSI structure available */
+	EL2HLT = 51, /* Level 2 halted */
+	EBADE = 52,  /* Invalid exchange */
+	EBADR = 53,  /* Invalid request descriptor */
+	EXFULL = 54, /* Exchange full */
+	ENOANO = 55, /* No anode */
+	EBADRQC = 56,  /* Invalid request code */
+	EBADSLT = 57,  /* Invalid slot */
+	EDEADLOCK = EDEADLK,  /* File locking deadlock error */
+	EBFONT = 59, /* Bad font file fmt */
+	ENOSTR = 60, /* Device not a stream */
+	ENODATA = 61,  /* No data (for no delay io) */
+	ETIME = 62,  /* Timer expired */
+	ENOSR = 63,  /* Out of streams resources */
+	ENONET = 64, /* Machine is not on the network */
+	ENOPKG = 65, /* Package not installed */
+	EREMOTE = 66,  /* The object is remote */
+	ENOLINK = 67,  /* The link has been severed */
+	EADV = 68,   /* Advertise error */
+	ESRMNT = 69, /* Srmount error */
+	ECOMM = 70,  /* Communication error on send */
+	EPROTO = 71, /* Protocol error */
+	EMULTIHOP = 72,  /* Multihop attempted */
+	EDOTDOT = 73,  /* Cross mount point (not really error) */
+	EBADMSG = 74,  /* Trying to read unreadable message */
+	EOVERFLOW = 75, /* Value too large for defined data type */
+	ENOTUNIQ = 76, /* Given log. name not unique */
+	EBADFD = 77, /* f.d. invalid for this operation */
+	EREMCHG = 78,  /* Remote address changed */
+	ELIBACC = 79,  /* Can't access a needed shared lib */
+	ELIBBAD = 80,  /* Accessing a corrupted shared lib */
+	ELIBSCN = 81,  /* .lib section in a.out corrupted */
+	ELIBMAX = 82,  /* Attempting to link in too many libs */
+	ELIBEXEC = 83, /* Attempting to exec a shared library */
+	EILSEQ = 84,
+	EUSERS = 87,
+	ENOTSOCK = 88,  /* Socket operation on non-socket */
+	EDESTADDRREQ = 89,  /* Destination address required */
+	EMSGSIZE = 90,    /* Message too long */
+	EPROTOTYPE = 91,  /* Protocol wrong type for socket */
+	ENOPROTOOPT = 92, /* Protocol not available */
+	EPROTONOSUPPORT = 93, /* Unknown protocol */
+	ESOCKTNOSUPPORT = 94, /* Socket type not supported */
+	EOPNOTSUPP = 95, /* Operation not supported on transport endpoint */
+	EPFNOSUPPORT = 96, /* Protocol family not supported */
+	EAFNOSUPPORT = 97, /* Address family not supported by protocol family */
+	EADDRINUSE = 98,    /* Address already in use */
+	EADDRNOTAVAIL = 99, /* Address not available */
+	ENETDOWN = 100,    /* Network interface is not configured */
+	ENETUNREACH = 101,   /* Network is unreachable */
+	ENETRESET = 102,
+	ECONNABORTED = 103,  /* Connection aborted */
+	ECONNRESET = 104,  /* Connection reset by peer */
+	ENOBUFS = 105, /* No buffer space available */
+	EISCONN = 106,   /* Socket is already connected */
+	ENOTCONN = 107,    /* Socket is not connected */
+	ESHUTDOWN = 108, /* Can't send after socket shutdown */
+	ETOOMANYREFS = 109,
+	ETIMEDOUT = 110,   /* Connection timed out */
+	ECONNREFUSED = 111,  /* Connection refused */
+	EHOSTDOWN = 112,   /* Host is down */
+	EHOSTUNREACH = 113,  /* Host is unreachable */
+	EALREADY = 114,    /* Socket already connected */
+	EINPROGRESS = 115,   /* Connection already in progress */
+	ESTALE = 116,
+	ENOTSUP = EOPNOTSUPP,   /* Not supported */
+	ENOMEDIUM = 123,   /* No medium (in tape drive) */
+	ECANCELED = 125, /* Operation canceled. */
+	ELBIN = 2048,  /* Inode is remote (not really error) */
+	EFTYPE = 2049,  /* Inappropriate file type or format */
+	ENMFILE = 2050,  /* No more files */
+	EPROCLIM = 2051,
+	ENOSHARE = 2052,  /* No such host or network path */
+	ECASECLASH = 2053,  /* Filename exists with different case */
+	EWOULDBLOCK = EAGAIN,      /* Operation would block */
+
+	// native_client/src/trusted/service_runtime/include/bits/mman.h.
+	// NOTE: DO NOT USE native_client/src/shared/imc/nacl_imc_c.h.
+	// Those MAP_*values are different from these.
+	PROT_NONE	= 0x0,
+	PROT_READ	= 0x1,
+	PROT_WRITE	= 0x2,
+	PROT_EXEC	= 0x4,
+
+	MAP_SHARED	= 0x1,
+	MAP_PRIVATE	= 0x2,
+	MAP_FIXED	= 0x10,
+	MAP_ANON	= 0x20,
+};
+typedef byte* kevent_udata;
+
+int32	runtime·nacl_exception_stack(byte*, int32);
+int32	runtime·nacl_exception_handler(void*, void*);
+int32	runtime·nacl_sem_create(int32);
+int32	runtime·nacl_sem_wait(int32);
+int32	runtime·nacl_sem_post(int32);
+int32	runtime·nacl_mutex_create(int32);
+int32	runtime·nacl_mutex_lock(int32);
+int32	runtime·nacl_mutex_trylock(int32);
+int32	runtime·nacl_mutex_unlock(int32);
+int32	runtime·nacl_cond_create(int32);
+int32	runtime·nacl_cond_wait(int32, int32);
+int32	runtime·nacl_cond_signal(int32);
+int32	runtime·nacl_cond_broadcast(int32);
+int32	runtime·nacl_cond_timed_wait_abs(int32, int32, Timespec*);
+int32	runtime·nacl_thread_create(void*, void*, void*, void*);
+int32	runtime·nacl_nanosleep(Timespec*, Timespec*);
+
+void	runtime·sigpanic(void);
diff --git a/src/pkg/runtime/os_netbsd.c b/src/pkg/runtime/os_netbsd.c
index a49dca2..93229bf 100644
--- a/src/pkg/runtime/os_netbsd.c
+++ b/src/pkg/runtime/os_netbsd.c
@@ -188,6 +188,7 @@ runtime·osinit(void)
 void
 runtime·get_random_data(byte **rnd, int32 *rnd_len)
 {
+	#pragma dataflag NOPTR
 	static byte urandom_data[HashRandomBytes];
 	int32 fd;
 	fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
@@ -237,9 +238,12 @@ runtime·unminit(void)
 void
 runtime·sigpanic(void)
 {
+	if(!runtime·canpanic(g))
+		runtime·throw("unexpected signal during runtime execution");
+
 	switch(g->sig) {
 	case SIGBUS:
-		if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+		if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
 			if(g->sigpc == 0)
 				runtime·panicstring("call of nil func value");
 			runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -247,7 +251,7 @@ runtime·sigpanic(void)
 		runtime·printf("unexpected fault address %p\n", g->sigcode1);
 		runtime·throw("fault");
 	case SIGSEGV:
-		if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+		if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
 			if(g->sigpc == 0)
 				runtime·panicstring("call of nil func value");
 			runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -326,3 +330,9 @@ runtime·signalstack(byte *p, int32 n)
 		st.ss_flags = SS_DISABLE;
 	runtime·sigaltstack(&st, nil);
 }
+
+void
+runtime·unblocksignals(void)
+{
+	runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
+}
diff --git a/src/pkg/runtime/os_netbsd.h b/src/pkg/runtime/os_netbsd.h
index 55743c8..16e9833 100644
--- a/src/pkg/runtime/os_netbsd.h
+++ b/src/pkg/runtime/os_netbsd.h
@@ -18,6 +18,7 @@ void	runtime·setitimer(int32, Itimerval*, Itimerval*);
 void	runtime·sigaction(int32, struct sigaction*, struct sigaction*);
 void	runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
 void	runtime·sigprocmask(int32, Sigset*, Sigset*);
+void	runtime·unblocksignals(void);
 int32	runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
 extern void runtime·lwp_tramp(void);
 
diff --git a/src/pkg/runtime/os_openbsd.c b/src/pkg/runtime/os_openbsd.c
index 18377a0..08a290a 100644
--- a/src/pkg/runtime/os_openbsd.c
+++ b/src/pkg/runtime/os_openbsd.c
@@ -82,7 +82,7 @@ runtime·semasleep(int64 ns)
 				// NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system.
 				ts.tv_nsec = 0;
 				ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec);
-				runtime·thrsleep(&m->waitsemacount, CLOCK_REALTIME, &ts, &m->waitsemalock, nil);
+				runtime·thrsleep(&m->waitsemacount, CLOCK_MONOTONIC, &ts, &m->waitsemalock, nil);
 			}
 			// reacquire lock
 			while(runtime·xchg(&m->waitsemalock, 1))
@@ -167,6 +167,7 @@ runtime·osinit(void)
 void
 runtime·get_random_data(byte **rnd, int32 *rnd_len)
 {
+	#pragma dataflag NOPTR
 	static byte urandom_data[HashRandomBytes];
 	int32 fd;
 	fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
@@ -214,9 +215,12 @@ runtime·unminit(void)
 void
 runtime·sigpanic(void)
 {
+	if(!runtime·canpanic(g))
+		runtime·throw("unexpected signal during runtime execution");
+
 	switch(g->sig) {
 	case SIGBUS:
-		if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
+		if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
 			if(g->sigpc == 0)
 				runtime·panicstring("call of nil func value");
 			runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -224,7 +228,7 @@ runtime·sigpanic(void)
 		runtime·printf("unexpected fault address %p\n", g->sigcode1);
 		runtime·throw("fault");
 	case SIGSEGV:
-		if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
+		if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
 			if(g->sigpc == 0)
 				runtime·panicstring("call of nil func value");
 			runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -300,3 +304,9 @@ runtime·signalstack(byte *p, int32 n)
 		st.ss_flags = SS_DISABLE;
 	runtime·sigaltstack(&st, nil);
 }
+
+void
+runtime·unblocksignals(void)
+{
+	runtime·sigprocmask(SIG_SETMASK, sigset_none);
+}
diff --git a/src/pkg/runtime/os_openbsd.h b/src/pkg/runtime/os_openbsd.h
index 4746b31..bbfde39 100644
--- a/src/pkg/runtime/os_openbsd.h
+++ b/src/pkg/runtime/os_openbsd.h
@@ -18,6 +18,7 @@ void	runtime·setitimer(int32, Itimerval*, Itimerval*);
 void	runtime·sigaction(int32, struct sigaction*, struct sigaction*);
 void	runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
 Sigset	runtime·sigprocmask(int32, Sigset);
+void	runtime·unblocksignals(void);
 int32	runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
 
 #define	NSIG 33
diff --git a/src/pkg/runtime/os_plan9.c b/src/pkg/runtime/os_plan9.c
index 07db2c3..14d4fae 100644
--- a/src/pkg/runtime/os_plan9.c
+++ b/src/pkg/runtime/os_plan9.c
@@ -102,8 +102,18 @@ runtime·crash(void)
 void
 runtime·get_random_data(byte **rnd, int32 *rnd_len)
 {
-	*rnd = nil;
-	*rnd_len = 0;
+	static byte random_data[HashRandomBytes];
+	int32 fd;
+
+	fd = runtime·open("/dev/random", 0 /* O_RDONLY */, 0);
+	if(runtime·read(fd, random_data, HashRandomBytes) == HashRandomBytes) {
+		*rnd = random_data;
+		*rnd_len = HashRandomBytes;
+	} else {
+		*rnd = nil;
+		*rnd_len = 0;
+	}
+	runtime·close(fd);
 }
 
 void
@@ -183,13 +193,15 @@ runtime·itoa(int32 n, byte *p, uint32 len)
 void
 runtime·goexitsall(int8 *status)
 {
+	int8 buf[ERRMAX];
 	M *mp;
 	int32 pid;
 
+	runtime·snprintf((byte*)buf, sizeof buf, "go: exit %s", status);
 	pid = getpid();
 	for(mp=runtime·atomicloadp(&runtime·allm); mp; mp=mp->alllink)
 		if(mp->procid != pid)
-			runtime·postnote(mp->procid, status);
+			runtime·postnote(mp->procid, buf);
 }
 
 int32
@@ -271,6 +283,8 @@ runtime·semasleep(int64 ns)
 
 	if(ns >= 0) {
 		ms = runtime·timediv(ns, 1000000, nil);
+		if(ms == 0)
+			ms = 1;
 		ret = runtime·plan9_tsemacquire(&m->waitsemacount, ms);
 		if(ret == 1)
 			return 0;  // success
@@ -295,15 +309,82 @@ os·sigpipe(void)
 	runtime·throw("too many writes on closed pipe");
 }
 
+static int64
+atolwhex(byte *p)
+{
+	int64 n;
+	int32 f;
+
+	n = 0;
+	f = 0;
+	while(*p == ' ' || *p == '\t')
+		p++;
+	if(*p == '-' || *p == '+') {
+		if(*p++ == '-')
+			f = 1;
+		while(*p == ' ' || *p == '\t')
+			p++;
+	}
+	if(p[0] == '0' && p[1]) {
+		if(p[1] == 'x' || p[1] == 'X') {
+			p += 2;
+			for(;;) {
+				if('0' <= *p && *p <= '9')
+					n = n*16 + *p++ - '0';
+				else if('a' <= *p && *p <= 'f')
+					n = n*16 + *p++ - 'a' + 10;
+				else if('A' <= *p && *p <= 'F')
+					n = n*16 + *p++ - 'A' + 10;
+				else
+					break;
+			}
+		} else
+			while('0' <= *p && *p <= '7')
+				n = n*8 + *p++ - '0';
+	} else
+		while('0' <= *p && *p <= '9')
+			n = n*10 + *p++ - '0';
+	if(f)
+		n = -n;
+	return n;
+}
+
 void
 runtime·sigpanic(void)
 {
-	if(g->sigpc == 0)
-		runtime·panicstring("call of nil func value");
-	runtime·panicstring(m->notesig);
-
-	if(g->sig == 1 || g->sig == 2)
+	byte *p;
+
+	if(!runtime·canpanic(g))
+		runtime·throw("unexpected signal during runtime execution");
+
+	switch(g->sig) {
+	case SIGRFAULT:
+	case SIGWFAULT:
+		p = runtime·strstr((byte*)m->notesig, (byte*)"addr=")+5;
+		g->sigcode1 = atolwhex(p);
+		if(g->sigcode1 < 0x1000 || g->paniconfault) {
+			if(g->sigpc == 0)
+				runtime·panicstring("call of nil func value");
+			runtime·panicstring("invalid memory address or nil pointer dereference");
+		}
+		runtime·printf("unexpected fault address %p\n", g->sigcode1);
 		runtime·throw("fault");
+		break;
+	case SIGTRAP:
+		if(g->paniconfault)
+			runtime·panicstring("invalid memory address or nil pointer dereference");
+		runtime·throw(m->notesig);
+		break;
+	case SIGINTDIV:
+		runtime·panicstring("integer divide by zero");
+		break;
+	case SIGFLOAT:
+		runtime·panicstring("floating point error");
+		break;
+	default:
+		runtime·panicstring(m->notesig);
+		break;
+	}
 }
 
 int32
@@ -313,9 +394,9 @@ runtime·read(int32 fd, void *buf, int32 nbytes)
 }
 
 int32
-runtime·write(int32 fd, void *buf, int32 nbytes)
+runtime·write(uintptr fd, void *buf, int32 nbytes)
 {
-	return runtime·pwrite(fd, buf, nbytes, -1LL);
+	return runtime·pwrite((int32)fd, buf, nbytes, -1LL);
 }
 
 uintptr
diff --git a/src/pkg/runtime/os_plan9.h b/src/pkg/runtime/os_plan9.h
index f0474cd..00ea836 100644
--- a/src/pkg/runtime/os_plan9.h
+++ b/src/pkg/runtime/os_plan9.h
@@ -78,5 +78,12 @@ struct Tos {
 	/* top of stack is here */
 };
 
-#define	NSIG	5	/* number of signals in runtime·SigTab array */
+#define	NSIG	14	/* number of signals in runtime·SigTab array */
 #define	ERRMAX	128	/* max length of note string */
+
+/* Notes in runtime·sigtab that are handled by runtime·sigpanic. */
+#define	SIGRFAULT	2
+#define	SIGWFAULT	3
+#define	SIGINTDIV	4
+#define	SIGFLOAT	5
+#define	SIGTRAP		6
diff --git a/src/pkg/runtime/os_plan9_386.c b/src/pkg/runtime/os_plan9_386.c
index 0844d72..80d711f 100644
--- a/src/pkg/runtime/os_plan9_386.c
+++ b/src/pkg/runtime/os_plan9_386.c
@@ -10,71 +10,80 @@
 void
 runtime·dumpregs(Ureg *u)
 {
-	runtime·printf("ax	%X\n", u->ax);
-	runtime·printf("bx	%X\n", u->bx);
-	runtime·printf("cx	%X\n", u->cx);
-	runtime·printf("dx	%X\n", u->dx);
-	runtime·printf("di	%X\n", u->di);
-	runtime·printf("si	%X\n", u->si);
-	runtime·printf("bp	%X\n", u->bp);
-	runtime·printf("sp	%X\n", u->sp);
-	runtime·printf("pc	%X\n", u->pc);
-	runtime·printf("flags	%X\n", u->flags);
-	runtime·printf("cs	%X\n", u->cs);
-	runtime·printf("fs	%X\n", u->fs);
-	runtime·printf("gs	%X\n", u->gs);
+	runtime·printf("ax	%x\n", u->ax);
+	runtime·printf("bx	%x\n", u->bx);
+	runtime·printf("cx	%x\n", u->cx);
+	runtime·printf("dx	%x\n", u->dx);
+	runtime·printf("di	%x\n", u->di);
+	runtime·printf("si	%x\n", u->si);
+	runtime·printf("bp	%x\n", u->bp);
+	runtime·printf("sp	%x\n", u->sp);
+	runtime·printf("pc	%x\n", u->pc);
+	runtime·printf("flags	%x\n", u->flags);
+	runtime·printf("cs	%x\n", u->cs);
+	runtime·printf("fs	%x\n", u->fs);
+	runtime·printf("gs	%x\n", u->gs);
 }
 
 int32
-runtime·sighandler(void *v, int8 *s, G *gp)
+runtime·sighandler(void *v, int8 *note, G *gp)
 {
+	uintptr *sp;
+	SigTab *t;
 	bool crash;
 	Ureg *ureg;
-	uintptr *sp;
-	SigTab *sig, *nsig;
-	intgo len, i;
+	intgo len, n;
+	int32 sig, flags;
 
-	if(!s)
-		return NCONT;
-			
-	len = runtime·findnull((byte*)s);
-	if(len <= 4 || runtime·mcmp((byte*)s, (byte*)"sys:", 4) != 0)
-		return NDFLT;
-
-	nsig = nil;
-	sig = runtime·sigtab;
-	for(i=0; i < NSIG; i++) {
-		if(runtime·strstr((byte*)s, (byte*)sig->name)) {
-			nsig = sig;
+	ureg = (Ureg*)v;
+
+	// The kernel will never pass us a nil note or ureg so we probably
+	// made a mistake somewhere in runtime·sigtramp.
+	if(ureg == nil || note == nil) {
+		runtime·printf("sighandler: ureg %p note %p\n", ureg, note);
+		goto Throw;
+	}
+
+	// Check that the note is no more than ERRMAX bytes (including
+	// the trailing NUL). We should never receive a longer note.
+	len = runtime·findnull((byte*)note);
+	if(len > ERRMAX-1) {
+		runtime·printf("sighandler: note is longer than ERRMAX\n");
+		goto Throw;
+	}
+
+	// See if the note matches one of the patterns in runtime·sigtab.
+	// Notes that do not match any pattern can be handled at a higher
+	// level by the program but will otherwise be ignored.
+	flags = SigNotify;
+	for(sig = 0; sig < nelem(runtime·sigtab); sig++) {
+		t = &runtime·sigtab[sig];
+		n = runtime·findnull((byte*)t->name);
+		if(len < n)
+			continue;
+		if(runtime·strncmp((byte*)note, (byte*)t->name, n) == 0) {
+			flags = t->flags;
 			break;
 		}
-		sig++;
 	}
 
-	if(nsig == nil)
-		return NDFLT;
-
-	ureg = v;
-	if(nsig->flags & SigPanic) {
-		if(gp == nil || m->notesig == 0)
-			goto Throw;
+	if(flags & SigGoExit)
+		runtime·exits(note+9); // Strip "go: exit " prefix.
 
-		// Save error string from sigtramp's stack,
-		// into gsignal->sigcode0, so we can reliably
-		// access it from the panic routines.
-		if(len > ERRMAX)
-			len = ERRMAX;
-		runtime·memmove((void*)m->notesig, (void*)s, len);
+	if(flags & SigPanic) {
+		// Copy the error string from sigtramp's stack into m->notesig so
+		// we can reliably access it from the panic routines.
+		runtime·memmove(m->notesig, note, len+1);
 
-		gp->sig = i;
+		gp->sig = sig;
 		gp->sigpc = ureg->pc;
 
-		// Only push runtime·sigpanic if ureg->pc != 0.
-		// If ureg->pc == 0, probably panicked because of a
-		// call to a nil func.  Not pushing that onto sp will
-		// make the trace look like a call to runtime·sigpanic instead.
-		// (Otherwise the trace will end at runtime·sigpanic and we
-		// won't get to see who faulted.)
+		// Only push runtime·sigpanic if PC != 0.
+		//
+		// If PC == 0, probably panicked because of a call to a nil func.
+		// Not pushing that onto SP will make the trace look like a call
+		// to runtime·sigpanic instead. (Otherwise the trace will end at
+		// runtime·sigpanic and we won't get to see who faulted).
 		if(ureg->pc != 0) {
 			sp = (uintptr*)ureg->sp;
 			*--sp = ureg->pc;
@@ -84,34 +93,42 @@ runtime·sighandler(void *v, int8 *s, G *gp)
 		return NCONT;
 	}
 
-	if(!(nsig->flags & SigThrow))
-		return NDFLT;
+	if(flags & SigNotify) {
+		// TODO(ality): See if os/signal wants it.
+		//if(runtime·sigsend(...))
+		//	return NCONT;
+	}
+	if(flags & SigKill)
+		goto Exit;
+	if(!(flags & SigThrow))
+		return NCONT;
 
 Throw:
 	m->throwing = 1;
 	m->caughtsig = gp;
 	runtime·startpanic();
 
-	runtime·printf("%s\n", s);
-	runtime·printf("PC=%X\n", ureg->pc);
+	runtime·printf("%s\n", note);
+	runtime·printf("PC=%x\n", ureg->pc);
 	runtime·printf("\n");
 
 	if(runtime·gotraceback(&crash)) {
+		runtime·goroutineheader(gp);
 		runtime·traceback(ureg->pc, ureg->sp, 0, gp);
 		runtime·tracebackothers(gp);
+		runtime·printf("\n");
 		runtime·dumpregs(ureg);
 	}
 	
 	if(crash)
 		runtime·crash();
 
-	runtime·goexitsall("");
-	runtime·exits(s);
-
-	return 0;
+Exit:
+	runtime·goexitsall(note);
+	runtime·exits(note);
+	return NDFLT; // not reached
 }
 
-
 void
 runtime·sigenable(uint32 sig)
 {
diff --git a/src/pkg/runtime/os_plan9_amd64.c b/src/pkg/runtime/os_plan9_amd64.c
index 58822ff..a4e5ba8 100644
--- a/src/pkg/runtime/os_plan9_amd64.c
+++ b/src/pkg/runtime/os_plan9_amd64.c
@@ -34,55 +34,64 @@ runtime·dumpregs(Ureg *u)
 }
 
 int32
-runtime·sighandler(void *v, int8 *s, G *gp)
+runtime·sighandler(void *v, int8 *note, G *gp)
 {
+	uintptr *sp;
+	SigTab *t;
 	bool crash;
 	Ureg *ureg;
-	uintptr *sp;
-	SigTab *sig, *nsig;
-	intgo i, len;
+	intgo len, n;
+	int32 sig, flags;
 
-	if(!s)
-		return NCONT;
-			
-	len = runtime·findnull((byte*)s);
-	if(len <= 4 || runtime·mcmp((byte*)s, (byte*)"sys:", 4) != 0)
-		return NDFLT;
-
-	nsig = nil;
-	sig = runtime·sigtab;
-	for(i=0; i < NSIG; i++) {
-		if(runtime·strstr((byte*)s, (byte*)sig->name)) {
-			nsig = sig;
+	ureg = (Ureg*)v;
+
+	// The kernel will never pass us a nil note or ureg so we probably
+	// made a mistake somewhere in runtime·sigtramp.
+	if(ureg == nil || note == nil) {
+		runtime·printf("sighandler: ureg %p note %p\n", ureg, note);
+		goto Throw;
+	}
+
+	// Check that the note is no more than ERRMAX bytes (including
+	// the trailing NUL). We should never receive a longer note.
+	len = runtime·findnull((byte*)note);
+	if(len > ERRMAX-1) {
+		runtime·printf("sighandler: note is longer than ERRMAX\n");
+		goto Throw;
+	}
+
+	// See if the note matches one of the patterns in runtime·sigtab.
+	// Notes that do not match any pattern can be handled at a higher
+	// level by the program but will otherwise be ignored.
+	flags = SigNotify;
+	for(sig = 0; sig < nelem(runtime·sigtab); sig++) {
+		t = &runtime·sigtab[sig];
+		n = runtime·findnull((byte*)t->name);
+		if(len < n)
+			continue;
+		if(runtime·strncmp((byte*)note, (byte*)t->name, n) == 0) {
+			flags = t->flags;
 			break;
 		}
-		sig++;
 	}
 
-	if(nsig == nil)
-		return NDFLT;
-
-	ureg = v;
-	if(nsig->flags & SigPanic) {
-		if(gp == nil || m->notesig == 0)
-			goto Throw;
+	if(flags & SigGoExit)
+		runtime·exits(note+9); // Strip "go: exit " prefix.
 
-		// Save error string from sigtramp's stack,
-		// into gsignal->sigcode0, so we can reliably
-		// access it from the panic routines.
-		if(len > ERRMAX)
-			len = ERRMAX;
-		runtime·memmove((void*)m->notesig, (void*)s, len);
+	if(flags & SigPanic) {
+		// Copy the error string from sigtramp's stack into m->notesig so
+		// we can reliably access it from the panic routines.
+		runtime·memmove(m->notesig, note, len+1);
 
-		gp->sig = i;
+		gp->sig = sig;
 		gp->sigpc = ureg->ip;
 
-		// Only push runtime·sigpanic if ureg->ip != 0.
-		// If ureg->ip == 0, probably panicked because of a
-		// call to a nil func.  Not pushing that onto sp will
-		// make the trace look like a call to runtime·sigpanic instead.
-		// (Otherwise the trace will end at runtime·sigpanic and we
-		// won't get to see who faulted.)
+		// Only push runtime·sigpanic if PC != 0.
+		//
+		// If PC == 0, probably panicked because of a call to a nil func.
+		// Not pushing that onto SP will make the trace look like a call
+		// to runtime·sigpanic instead. (Otherwise the trace will end at
+		// runtime·sigpanic and we won't get to see who faulted).
 		if(ureg->ip != 0) {
 			sp = (uintptr*)ureg->sp;
 			*--sp = ureg->ip;
@@ -92,31 +101,40 @@ runtime·sighandler(void *v, int8 *s, G *gp)
 		return NCONT;
 	}
 
-	if(!(nsig->flags & SigThrow))
-		return NDFLT;
+	if(flags & SigNotify) {
+		// TODO(ality): See if os/signal wants it.
+		//if(runtime·sigsend(...))
+		//	return NCONT;
+	}
+	if(flags & SigKill)
+		goto Exit;
+	if(!(flags & SigThrow))
+		return NCONT;
 
 Throw:
 	m->throwing = 1;
 	m->caughtsig = gp;
 	runtime·startpanic();
 
-	runtime·printf("%s\n", s);
+	runtime·printf("%s\n", note);
 	runtime·printf("PC=%X\n", ureg->ip);
 	runtime·printf("\n");
 
 	if(runtime·gotraceback(&crash)) {
+		runtime·goroutineheader(gp);
 		runtime·traceback(ureg->ip, ureg->sp, 0, gp);
 		runtime·tracebackothers(gp);
+		runtime·printf("\n");
 		runtime·dumpregs(ureg);
 	}
 	
 	if(crash)
 		runtime·crash();
 
-	runtime·goexitsall("");
-	runtime·exits(s);
-
-	return 0;
+Exit:
+	runtime·goexitsall(note);
+	runtime·exits(note);
+	return NDFLT; // not reached
 }
 
 void
diff --git a/src/pkg/runtime/os_solaris.c b/src/pkg/runtime/os_solaris.c
new file mode 100644
index 0000000..c6bbea3
--- /dev/null
+++ b/src/pkg/runtime/os_solaris.c
@@ -0,0 +1,583 @@
+// 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.
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "signal_unix.h"
+#include "stack.h"
+#include "../../cmd/ld/textflag.h"
+
+#pragma dynexport end _end
+#pragma dynexport etext _etext
+#pragma dynexport edata _edata
+
+#pragma dynimport libc·___errno ___errno "libc.so"
+#pragma dynimport libc·clock_gettime clock_gettime "libc.so"
+#pragma dynimport libc·close close "libc.so"
+#pragma dynimport libc·exit exit "libc.so"
+#pragma dynimport libc·fstat fstat "libc.so"
+#pragma dynimport libc·getcontext getcontext "libc.so"
+#pragma dynimport libc·getrlimit getrlimit "libc.so"
+#pragma dynimport libc·malloc malloc "libc.so"
+#pragma dynimport libc·mmap mmap "libc.so"
+#pragma dynimport libc·munmap munmap "libc.so"
+#pragma dynimport libc·open open "libc.so"
+#pragma dynimport libc·pthread_attr_destroy pthread_attr_destroy "libc.so"
+#pragma dynimport libc·pthread_attr_getstack pthread_attr_getstack "libc.so"
+#pragma dynimport libc·pthread_attr_init pthread_attr_init "libc.so"
+#pragma dynimport libc·pthread_attr_setdetachstate pthread_attr_setdetachstate "libc.so"
+#pragma dynimport libc·pthread_attr_setstack pthread_attr_setstack "libc.so"
+#pragma dynimport libc·pthread_create pthread_create "libc.so"
+#pragma dynimport libc·raise raise "libc.so"
+#pragma dynimport libc·read read "libc.so"
+#pragma dynimport libc·select select "libc.so"
+#pragma dynimport libc·sched_yield sched_yield "libc.so"
+#pragma dynimport libc·sem_init sem_init "libc.so"
+#pragma dynimport libc·sem_post sem_post "libc.so"
+#pragma dynimport libc·sem_reltimedwait_np sem_reltimedwait_np "libc.so"
+#pragma dynimport libc·sem_wait sem_wait "libc.so"
+#pragma dynimport libc·setitimer setitimer "libc.so"
+#pragma dynimport libc·sigaction sigaction "libc.so"
+#pragma dynimport libc·sigaltstack sigaltstack "libc.so"
+#pragma dynimport libc·sigprocmask sigprocmask "libc.so"
+#pragma dynimport libc·sysconf sysconf "libc.so"
+#pragma dynimport libc·usleep usleep "libc.so"
+#pragma dynimport libc·write write "libc.so"
+
+extern uintptr libc·___errno;
+extern uintptr libc·clock_gettime;
+extern uintptr libc·close;
+extern uintptr libc·exit;
+extern uintptr libc·fstat;
+extern uintptr libc·getcontext;
+extern uintptr libc·getrlimit;
+extern uintptr libc·malloc;
+extern uintptr libc·mmap;
+extern uintptr libc·munmap;
+extern uintptr libc·open;
+extern uintptr libc·pthread_attr_destroy;
+extern uintptr libc·pthread_attr_getstack;
+extern uintptr libc·pthread_attr_init;
+extern uintptr libc·pthread_attr_setdetachstate;
+extern uintptr libc·pthread_attr_setstack;
+extern uintptr libc·pthread_create;
+extern uintptr libc·raise;
+extern uintptr libc·read;
+extern uintptr libc·sched_yield;
+extern uintptr libc·select;
+extern uintptr libc·sem_init;
+extern uintptr libc·sem_post;
+extern uintptr libc·sem_reltimedwait_np;
+extern uintptr libc·sem_wait;
+extern uintptr libc·setitimer;
+extern uintptr libc·sigaction;
+extern uintptr libc·sigaltstack;
+extern uintptr libc·sigprocmask;
+extern uintptr libc·sysconf;
+extern uintptr libc·usleep;
+extern uintptr libc·write;
+
+void	runtime·getcontext(Ucontext *context);
+int32	runtime·pthread_attr_destroy(PthreadAttr* attr);
+int32	runtime·pthread_attr_init(PthreadAttr* attr);
+int32	runtime·pthread_attr_getstack(PthreadAttr* attr, void** addr, uint64* size);
+int32	runtime·pthread_attr_setdetachstate(PthreadAttr* attr, int32 state);
+int32	runtime·pthread_attr_setstack(PthreadAttr* attr, void* addr, uint64 size);
+int32	runtime·pthread_create(Pthread* thread, PthreadAttr* attr, void(*fn)(void), void *arg);
+uint32	runtime·tstart_sysvicall(M *newm);
+int32	runtime·sem_init(SemT* sem, int32 pshared, uint32 value);
+int32	runtime·sem_post(SemT* sem);
+int32	runtime·sem_reltimedwait_np(SemT* sem, Timespec* timeout);
+int32	runtime·sem_wait(SemT* sem);
+int64	runtime·sysconf(int32 name);
+
+extern SigTab runtime·sigtab[];
+static Sigset sigset_none;
+static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, };
+
+// Calling sysvcall on os stack.
+#pragma textflag NOSPLIT
+uintptr
+runtime·sysvicall6(uintptr fn, int32 count, ...)
+{
+	runtime·memclr((byte*)&m->scratch, sizeof(m->scratch));
+	m->libcall.fn = (void*)fn;
+	m->libcall.n = (uintptr)count;
+	for(;count; count--)
+		m->scratch.v[count - 1] = *((uintptr*)&count + count);
+	m->libcall.args = (uintptr*)&m->scratch.v[0];
+	runtime·asmcgocall(runtime·asmsysvicall6, &m->libcall);
+	return m->libcall.r1;
+}
+
+static int32
+getncpu(void) 
+{
+	int32 n;
+	
+	n = (int32)runtime·sysconf(_SC_NPROCESSORS_ONLN);
+	if(n < 1)
+		return 1;
+	return n;
+}
+
+void
+runtime·osinit(void)
+{
+	runtime·ncpu = getncpu(); 
+}
+
+void
+runtime·newosproc(M *mp, void *stk)
+{
+	PthreadAttr attr;
+	Sigset oset;
+	Pthread tid;
+	int32 ret;
+
+	USED(stk);
+	if(runtime·pthread_attr_init(&attr) != 0)
+		runtime·throw("pthread_attr_init");
+	if(runtime·pthread_attr_setstack(&attr, 0, 0x200000) != 0)
+		runtime·throw("pthread_attr_setstack");
+	if(runtime·pthread_attr_getstack(&attr, (void**)&mp->g0->stackbase, &mp->g0->stacksize) != 0)
+		runtime·throw("pthread_attr_getstack");	
+	if(runtime·pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
+		runtime·throw("pthread_attr_setdetachstate");
+
+	// Disable signals during create, so that the new thread starts
+	// with signals disabled.  It will enable them in minit.
+	runtime·sigprocmask(SIG_SETMASK, &sigset_all, &oset);
+	ret = runtime·pthread_create(&tid, &attr, (void (*)(void))runtime·tstart_sysvicall, mp);
+	runtime·sigprocmask(SIG_SETMASK, &oset, nil);
+	if(ret != 0) {
+		runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), ret);
+		runtime·throw("runtime.newosproc");
+	}
+}
+
+void
+runtime·get_random_data(byte **rnd, int32 *rnd_len)
+{
+	#pragma dataflag NOPTR
+	static byte urandom_data[HashRandomBytes];
+	int32 fd;
+	fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
+	if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
+		*rnd = urandom_data;
+		*rnd_len = HashRandomBytes;
+	} else {
+		*rnd = nil;
+		*rnd_len = 0;
+	}
+	runtime·close(fd);
+}
+
+void
+runtime·goenvs(void)
+{
+	runtime·goenvs_unix();
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+void
+runtime·mpreinit(M *mp)
+{
+	mp->gsignal = runtime·malg(32*1024);
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+void
+runtime·minit(void)
+{
+	runtime·asmcgocall(runtime·miniterrno, (void *)libc·___errno);
+	// Initialize signal handling
+	runtime·signalstack((byte*)m->gsignal->stackguard - StackGuard, 32*1024);
+	runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
+}
+
+// Called from dropm to undo the effect of an minit.
+void
+runtime·unminit(void)
+{
+	runtime·signalstack(nil, 0);
+}
+
+void
+runtime·sigpanic(void)
+{
+	if(!runtime·canpanic(g))
+		runtime·throw("unexpected signal during runtime execution");
+
+	switch(g->sig) {
+	case SIGBUS:
+		if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000 || g->paniconfault) {
+			if(g->sigpc == 0)
+				runtime·panicstring("call of nil func value");
+			runtime·panicstring("invalid memory address or nil pointer dereference");
+		}
+		runtime·printf("unexpected fault address %p\n", g->sigcode1);
+		runtime·throw("fault");
+	case SIGSEGV:
+		if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000 || g->paniconfault) {
+			if(g->sigpc == 0)
+				runtime·panicstring("call of nil func value");
+			runtime·panicstring("invalid memory address or nil pointer dereference");
+		}
+		runtime·printf("unexpected fault address %p\n", g->sigcode1);
+		runtime·throw("fault");
+	case SIGFPE:
+		switch(g->sigcode0) {
+		case FPE_INTDIV:
+			runtime·panicstring("integer divide by zero");
+		case FPE_INTOVF:
+			runtime·panicstring("integer overflow");
+		}
+		runtime·panicstring("floating point error");
+	}
+	runtime·panicstring(runtime·sigtab[g->sig].name);
+}
+
+uintptr
+runtime·memlimit(void)
+{
+	Rlimit rl;
+	extern byte text[], end[];
+	uintptr used;
+	
+	if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
+		return 0;
+	if(rl.rlim_cur >= 0x7fffffff)
+		return 0;
+
+	// Estimate our VM footprint excluding the heap.
+	// Not an exact science: use size of binary plus
+	// some room for thread stacks.
+	used = end - text + (64<<20);
+	if(used >= rl.rlim_cur)
+		return 0;
+
+	// If there's not at least 16 MB left, we're probably
+	// not going to be able to do much.  Treat as no limit.
+	rl.rlim_cur -= used;
+	if(rl.rlim_cur < (16<<20))
+		return 0;
+
+	return rl.rlim_cur - used;
+}
+
+void
+runtime·setprof(bool on)
+{
+	USED(on);
+}
+
+extern void runtime·sigtramp(void);
+
+void
+runtime·setsig(int32 i, GoSighandler *fn, bool restart)
+{
+	Sigaction sa;
+
+	runtime·memclr((byte*)&sa, sizeof sa);
+	sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+	if(restart)
+		sa.sa_flags |= SA_RESTART;
+	sa.sa_mask.__sigbits[0] = ~(uint32)0;
+	sa.sa_mask.__sigbits[1] = ~(uint32)0;
+	sa.sa_mask.__sigbits[2] = ~(uint32)0;
+	sa.sa_mask.__sigbits[3] = ~(uint32)0;
+	if(fn == runtime·sighandler)
+		fn = (void*)runtime·sigtramp;
+	*((void**)&sa._funcptr[0]) = (void*)fn;
+	runtime·sigaction(i, &sa, nil);
+}
+
+GoSighandler*
+runtime·getsig(int32 i)
+{
+	Sigaction sa;
+
+	runtime·memclr((byte*)&sa, sizeof sa);
+	runtime·sigaction(i, nil, &sa);
+	if(*((void**)&sa._funcptr[0]) == runtime·sigtramp)
+		return runtime·sighandler;
+	return *((void**)&sa._funcptr[0]);
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+	StackT st;
+
+	st.ss_sp = (void*)p;
+	st.ss_size = n;
+	st.ss_flags = 0;
+	if(p == nil)
+		st.ss_flags = SS_DISABLE;
+	runtime·sigaltstack(&st, nil);
+}
+
+void
+runtime·unblocksignals(void)
+{
+	runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
+}
+
+#pragma textflag NOSPLIT
+uintptr
+runtime·semacreate(void)
+{
+	SemT* sem;
+
+	// Call libc's malloc rather than runtime·malloc.  This will
+	// allocate space on the C heap.  We can't call runtime·malloc
+	// here because it could cause a deadlock.
+	m->libcall.fn = (void*)libc·malloc;
+	m->libcall.n = 1;
+	runtime·memclr((byte*)&m->scratch, sizeof(m->scratch));
+	m->scratch.v[0] = (uintptr)sizeof(*sem);
+	m->libcall.args = (uintptr*)&m->scratch;
+	runtime·asmcgocall(runtime·asmsysvicall6, &m->libcall);
+	sem = (void*)m->libcall.r1;
+	if(runtime·sem_init(sem, 0, 0) != 0)
+		runtime·throw("sem_init");
+	return (uintptr)sem;
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·semasleep(int64 ns)
+{
+	if(ns >= 0) {
+		m->ts.tv_sec = ns / 1000000000LL;
+		m->ts.tv_nsec = ns % 1000000000LL;
+
+		m->libcall.fn = (void*)libc·sem_reltimedwait_np;
+		m->libcall.n = 2;
+		runtime·memclr((byte*)&m->scratch, sizeof(m->scratch));
+		m->scratch.v[0] = m->waitsema;
+		m->scratch.v[1] = (uintptr)&m->ts;
+		m->libcall.args = (uintptr*)&m->scratch;
+		runtime·asmcgocall(runtime·asmsysvicall6, &m->libcall);
+		if(*m->perrno != 0) {
+			if(*m->perrno == ETIMEDOUT || *m->perrno == EAGAIN || *m->perrno == EINTR)
+				return -1;
+			runtime·throw("sem_reltimedwait_np");
+		}
+		return 0;
+	}
+	for(;;) {
+		m->libcall.fn = (void*)libc·sem_wait;
+		m->libcall.n = 1;
+		runtime·memclr((byte*)&m->scratch, sizeof(m->scratch));
+		m->scratch.v[0] = m->waitsema;
+		m->libcall.args = (uintptr*)&m->scratch;
+		runtime·asmcgocall(runtime·asmsysvicall6, &m->libcall);
+		if(m->libcall.r1 == 0)
+			break;
+		if(*m->perrno == EINTR) 
+			continue;
+		runtime·throw("sem_wait");
+	}
+	return 0;
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·semawakeup(M *mp)
+{
+	SemT* sem = (SemT*)mp->waitsema;
+	if(runtime·sem_post(sem) != 0)
+		runtime·throw("sem_post");
+}
+
+int32
+runtime·close(int32 fd)
+{
+	return runtime·sysvicall6(libc·close, 1, (uintptr)fd);
+}
+
+void
+runtime·exit(int32 r)
+{
+	runtime·sysvicall6(libc·exit, 1, (uintptr)r);
+}
+
+/* int32 */ void
+runtime·getcontext(Ucontext* context)
+{
+	runtime·sysvicall6(libc·getcontext, 1, (uintptr)context);
+}
+
+int32
+runtime·getrlimit(int32 res, Rlimit* rlp)
+{
+	return runtime·sysvicall6(libc·getrlimit, 2, (uintptr)res, (uintptr)rlp);
+}
+
+uint8*
+runtime·mmap(byte* addr, uintptr len, int32 prot, int32 flags, int32 fildes, uint32 off)
+{
+	return (uint8*)runtime·sysvicall6(libc·mmap, 6, (uintptr)addr, (uintptr)len, (uintptr)prot, (uintptr)flags, (uintptr)fildes, (uintptr)off);
+}
+
+void
+runtime·munmap(byte* addr, uintptr len)
+{
+	runtime·sysvicall6(libc·munmap, 2, (uintptr)addr, (uintptr)len);
+}
+
+extern int64 runtime·nanotime1(void);
+#pragma textflag NOSPLIT
+int64
+runtime·nanotime(void)
+{
+	return runtime·sysvicall6((uintptr)runtime·nanotime1, 0);
+}
+
+void
+time·now(int64 sec, int32 usec)
+{
+	int64 ns;
+
+	ns = runtime·nanotime();
+	sec = ns / 1000000000LL;
+	usec = ns - sec * 1000000000LL;
+	FLUSH(&sec);
+	FLUSH(&usec);
+}
+
+int32
+runtime·open(int8* path, int32 oflag, int32 mode)
+{
+	return runtime·sysvicall6(libc·open, 3, (uintptr)path, (uintptr)oflag, (uintptr)mode);
+}
+
+int32
+runtime·pthread_attr_destroy(PthreadAttr* attr)
+{
+	return runtime·sysvicall6(libc·pthread_attr_destroy, 1, (uintptr)attr);
+}
+
+int32
+runtime·pthread_attr_getstack(PthreadAttr* attr, void** addr, uint64* size)
+{
+	return runtime·sysvicall6(libc·pthread_attr_getstack, 3, (uintptr)attr, (uintptr)addr, (uintptr)size);
+}
+
+int32
+runtime·pthread_attr_init(PthreadAttr* attr)
+{
+	return runtime·sysvicall6(libc·pthread_attr_init, 1, (uintptr)attr);
+}
+
+int32
+runtime·pthread_attr_setdetachstate(PthreadAttr* attr, int32 state)
+{
+	return runtime·sysvicall6(libc·pthread_attr_setdetachstate, 2, (uintptr)attr, (uintptr)state);
+}
+
+int32
+runtime·pthread_attr_setstack(PthreadAttr* attr, void* addr, uint64 size)
+{
+	return runtime·sysvicall6(libc·pthread_attr_setstack, 3, (uintptr)attr, (uintptr)addr, (uintptr)size);
+}
+
+int32
+runtime·pthread_create(Pthread* thread, PthreadAttr* attr, void(*fn)(void), void *arg)
+{
+	return runtime·sysvicall6(libc·pthread_create, 4, (uintptr)thread, (uintptr)attr, (uintptr)fn, (uintptr)arg);
+}
+
+/* int32 */ void
+runtime·raise(int32 sig)
+{
+	runtime·sysvicall6(libc·raise, 1, (uintptr)sig);
+}
+
+int32
+runtime·read(int32 fd, void* buf, int32 nbyte)
+{
+	return runtime·sysvicall6(libc·read, 3, (uintptr)fd, (uintptr)buf, (uintptr)nbyte);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·sem_init(SemT* sem, int32 pshared, uint32 value)
+{
+	return runtime·sysvicall6(libc·sem_init, 3, (uintptr)sem, (uintptr)pshared, (uintptr)value);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·sem_post(SemT* sem)
+{
+	return runtime·sysvicall6(libc·sem_post, 1, (uintptr)sem);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·sem_reltimedwait_np(SemT* sem, Timespec* timeout)
+{
+	return runtime·sysvicall6(libc·sem_reltimedwait_np, 2, (uintptr)sem, (uintptr)timeout);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·sem_wait(SemT* sem)
+{
+	return runtime·sysvicall6(libc·sem_wait, 1, (uintptr)sem);
+}
+
+/* int32 */ void
+runtime·setitimer(int32 which, Itimerval* value, Itimerval* ovalue)
+{
+	runtime·sysvicall6(libc·setitimer, 3, (uintptr)which, (uintptr)value, (uintptr)ovalue);
+}
+
+/* int32 */ void
+runtime·sigaction(int32 sig, struct Sigaction* act, struct Sigaction* oact)
+{
+	runtime·sysvicall6(libc·sigaction, 3, (uintptr)sig, (uintptr)act, (uintptr)oact);
+}
+
+/* int32 */ void
+runtime·sigaltstack(Sigaltstack* ss, Sigaltstack* oss)
+{
+	runtime·sysvicall6(libc·sigaltstack, 2, (uintptr)ss, (uintptr)oss);
+}
+
+/* int32 */ void
+runtime·sigprocmask(int32 how, Sigset* set, Sigset* oset)
+{
+	runtime·sysvicall6(libc·sigprocmask, 3, (uintptr)how, (uintptr)set, (uintptr)oset);
+}
+
+int64
+runtime·sysconf(int32 name)
+{
+	return runtime·sysvicall6(libc·sysconf, 1, (uintptr)name);
+}
+
+void
+runtime·usleep(uint32 us)
+{
+	runtime·sysvicall6(libc·usleep, 1, (uintptr)us);
+}
+
+int32
+runtime·write(uintptr fd, void* buf, int32 nbyte)
+{
+	return runtime·sysvicall6(libc·write, 3, (uintptr)fd, (uintptr)buf, (uintptr)nbyte);
+}
+
+void
+runtime·osyield(void)
+{
+	runtime·sysvicall6(libc·sched_yield, 0);
+}
diff --git a/src/pkg/runtime/os_solaris.h b/src/pkg/runtime/os_solaris.h
new file mode 100644
index 0000000..f3fae5d
--- /dev/null
+++ b/src/pkg/runtime/os_solaris.h
@@ -0,0 +1,51 @@
+// 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.
+
+#define SS_DISABLE 2
+
+#define SIG_BLOCK 1
+#define SIG_UNBLOCK 2
+#define SIG_SETMASK 3
+
+typedef uintptr kevent_udata;
+
+struct sigaction;
+
+void	runtime·sigpanic(void);
+
+void	runtime·setitimer(int32, Itimerval*, Itimerval*);
+void	runtime·sigaction(int32, struct Sigaction*, struct Sigaction*);
+void	runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
+void	runtime·sigprocmask(int32, Sigset*, Sigset*);
+void	runtime·unblocksignals(void);
+int32	runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
+
+#define	NSIG 73 /* number of signals in runtime·SigTab array */
+#define	SI_USER	0
+
+void	runtime·raisesigpipe(void);
+void	runtime·setsig(int32, void(*)(int32, Siginfo*, void*, G*), bool);
+void	runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp);
+void	runtime·sigpanic(void);
+
+#define _UC_SIGMASK	0x01
+#define _UC_CPU		0x04
+
+#define RLIMIT_AS 10
+typedef struct Rlimit Rlimit;
+struct Rlimit {
+	int64   rlim_cur;
+	int64   rlim_max;
+};
+int32   runtime·getrlimit(int32, Rlimit*);
+
+// Call a library function with SysV conventions,
+// and switch to os stack during the call.
+#pragma	varargck	countpos	runtime·sysvicall6	2
+#pragma	varargck	type		runtime·sysvicall6	uintptr
+#pragma	varargck	type		runtime·sysvicall6	int32
+void	runtime·asmsysvicall6(void *c);
+uintptr	runtime·sysvicall6(uintptr fn, int32 count, ...);
+
+void	runtime·miniterrno(void *fn);
diff --git a/src/pkg/runtime/os_windows.c b/src/pkg/runtime/os_windows.c
index c3e296a..0dd44ed 100644
--- a/src/pkg/runtime/os_windows.c
+++ b/src/pkg/runtime/os_windows.c
@@ -8,6 +8,7 @@
 #include "os_GOOS.h"
 #include "../../cmd/ld/textflag.h"
 
+#pragma dynimport runtime·AddVectoredExceptionHandler AddVectoredExceptionHandler "kernel32.dll"
 #pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll"
 #pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll"
 #pragma dynimport runtime·CreateThread CreateThread "kernel32.dll"
@@ -26,20 +27,20 @@
 #pragma dynimport runtime·GetThreadContext GetThreadContext "kernel32.dll"
 #pragma dynimport runtime·LoadLibrary LoadLibraryW "kernel32.dll"
 #pragma dynimport runtime·LoadLibraryA LoadLibraryA "kernel32.dll"
+#pragma dynimport runtime·NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll"
 #pragma dynimport runtime·ResumeThread ResumeThread "kernel32.dll"
 #pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll"
 #pragma dynimport runtime·SetEvent SetEvent "kernel32.dll"
+#pragma dynimport runtime·SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll"
 #pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll"
 #pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll"
 #pragma dynimport runtime·Sleep Sleep "kernel32.dll"
 #pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll"
-#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll"
 #pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll"
 #pragma dynimport runtime·WriteFile WriteFile "kernel32.dll"
-#pragma dynimport runtime·NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll"
-
-extern void *runtime·NtWaitForSingleObject;
+#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll"
 
+extern void *runtime·AddVectoredExceptionHandler;
 extern void *runtime·CloseHandle;
 extern void *runtime·CreateEvent;
 extern void *runtime·CreateThread;
@@ -58,19 +59,25 @@ extern void *runtime·GetSystemTimeAsFileTime;
 extern void *runtime·GetThreadContext;
 extern void *runtime·LoadLibrary;
 extern void *runtime·LoadLibraryA;
+extern void *runtime·NtWaitForSingleObject;
 extern void *runtime·ResumeThread;
 extern void *runtime·SetConsoleCtrlHandler;
 extern void *runtime·SetEvent;
+extern void *runtime·SetProcessPriorityBoost;
 extern void *runtime·SetThreadPriority;
 extern void *runtime·SetWaitableTimer;
 extern void *runtime·Sleep;
 extern void *runtime·SuspendThread;
-extern void *runtime·timeBeginPeriod;
 extern void *runtime·WaitForSingleObject;
 extern void *runtime·WriteFile;
+extern void *runtime·timeBeginPeriod;
 
 void *runtime·GetQueuedCompletionStatusEx;
 
+extern uintptr runtime·externalthreadhandlerp;
+void runtime·externalthreadhandler(void);
+void runtime·sigtramp(void);
+
 static int32
 getproccount(void)
 {
@@ -84,25 +91,22 @@ void
 runtime·osinit(void)
 {
 	void *kernel32;
-	void *SetProcessPriorityBoost;
 
-	// -1 = current process, -2 = current thread
-	runtime·stdcall(runtime·DuplicateHandle, 7,
-		(uintptr)-1, (uintptr)-2, (uintptr)-1, &m->thread,
-		(uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS);
+	runtime·externalthreadhandlerp = (uintptr)runtime·externalthreadhandler;
+
+	runtime·stdcall(runtime·AddVectoredExceptionHandler, 2, (uintptr)1, (uintptr)runtime·sigtramp);
 	runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, (uintptr)1);
 	runtime·stdcall(runtime·timeBeginPeriod, 1, (uintptr)1);
 	runtime·ncpu = getproccount();
+	
+	// Windows dynamic priority boosting assumes that a process has different types
+	// of dedicated threads -- GUI, IO, computational, etc. Go processes use
+	// equivalent threads that all do a mix of GUI, IO, computations, etc.
+	// In such context dynamic priority boosting does nothing but harm, so we turn it off.
+	runtime·stdcall(runtime·SetProcessPriorityBoost, 2, (uintptr)-1, (uintptr)1);
 
 	kernel32 = runtime·stdcall(runtime·LoadLibraryA, 1, "kernel32.dll");
 	if(kernel32 != nil) {
-		// Windows dynamic priority boosting assumes that a process has different types
-		// of dedicated threads -- GUI, IO, computational, etc. Go processes use
-		// equivalent threads that all do a mix of GUI, IO, computations, etc.
-		// In such context dynamic priority boosting does nothing but harm, so we turn it off.
-		SetProcessPriorityBoost = runtime·stdcall(runtime·GetProcAddress, 2, kernel32, "SetProcessPriorityBoost");
-		if(SetProcessPriorityBoost != nil)  // supported since Windows XP
-			runtime·stdcall(SetProcessPriorityBoost, 2, (uintptr)-1, (uintptr)1);
 		runtime·GetQueuedCompletionStatusEx = runtime·stdcall(runtime·GetProcAddress, 2, kernel32, "GetQueuedCompletionStatusEx");
 	}
 }
@@ -162,7 +166,7 @@ runtime·exit(int32 code)
 }
 
 int32
-runtime·write(int32 fd, void *buf, int32 n)
+runtime·write(uintptr fd, void *buf, int32 n)
 {
 	void *handle;
 	uint32 written;
@@ -176,7 +180,9 @@ runtime·write(int32 fd, void *buf, int32 n)
 		handle = runtime·stdcall(runtime·GetStdHandle, 1, (uintptr)-12);
 		break;
 	default:
-		return -1;
+		// assume fd is real windows handle.
+		handle = (void*)fd;
+		break;
 	}
 	runtime·stdcall(runtime·WriteFile, 5, handle, buf, (uintptr)n, &written, (uintptr)0);
 	return written;
@@ -229,7 +235,6 @@ runtime·newosproc(M *mp, void *stk)
 		runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror());
 		runtime·throw("runtime.newosproc");
 	}
-	runtime·atomicstorep(&mp->thread, thandle);
 }
 
 // Called to initialize a new m (including the bootstrap m).
@@ -245,14 +250,19 @@ runtime·mpreinit(M *mp)
 void
 runtime·minit(void)
 {
-	runtime·install_exception_handler();
+	void *thandle;
+
+	// -1 = current process, -2 = current thread
+	runtime·stdcall(runtime·DuplicateHandle, 7,
+		(uintptr)-1, (uintptr)-2, (uintptr)-1, &thandle,
+		(uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS);
+	runtime·atomicstorep(&m->thread, thandle);
 }
 
 // Called from dropm to undo the effect of an minit.
 void
 runtime·unminit(void)
 {
-	runtime·remove_exception_handler();
 }
 
 #pragma textflag NOSPLIT
@@ -285,11 +295,20 @@ time·now(int64 sec, int32 usec)
 void *
 runtime·stdcall(void *fn, int32 count, ...)
 {
-	m->wincall.fn = fn;
-	m->wincall.n = count;
-	m->wincall.args = (uintptr*)&count + 1;
-	runtime·asmcgocall(runtime·asmstdcall, &m->wincall);
-	return (void*)m->wincall.r1;
+	m->libcall.fn = fn;
+	m->libcall.n = count;
+	m->libcall.args = (uintptr*)&count + 1;
+	if(m->profilehz != 0) {
+		// leave pc/sp for cpu profiler
+		m->libcallg = g;
+		m->libcallpc = (uintptr)runtime·getcallerpc(&fn);
+		// sp must be the last, because once async cpu profiler finds
+		// all three values to be non-zero, it will use them
+		m->libcallsp = (uintptr)runtime·getcallersp(&fn);
+	}
+	runtime·asmcgocall(runtime·asmstdcall, &m->libcall);
+	m->libcallsp = 0;
+	return (void*)m->libcall.r1;
 }
 
 extern void runtime·usleep1(uint32);
@@ -329,9 +348,12 @@ runtime·issigpanic(uint32 code)
 void
 runtime·sigpanic(void)
 {
+	if(!runtime·canpanic(g))
+		runtime·throw("unexpected signal during runtime execution");
+
 	switch(g->sig) {
 	case EXCEPTION_ACCESS_VIOLATION:
-		if(g->sigcode1 < 0x1000) {
+		if(g->sigcode1 < 0x1000 || g->paniconfault) {
 			if(g->sigpc == 0)
 				runtime·panicstring("call of nil func value");
 			runtime·panicstring("invalid memory address or nil pointer dereference");
@@ -352,8 +374,6 @@ runtime·sigpanic(void)
 	runtime·throw("fault");
 }
 
-extern void *runtime·sigtramp;
-
 void
 runtime·initsig(void)
 {
@@ -383,7 +403,7 @@ runtime·ctrlhandler1(uint32 type)
 	return 0;
 }
 
-extern void runtime·dosigprof(Context *r, G *gp);
+extern void runtime·dosigprof(Context *r, G *gp, M *mp);
 extern void runtime·profileloop(void);
 static void *profiletimer;
 
@@ -402,13 +422,11 @@ profilem(M *mp)
 		tls = runtime·tls0;
 	gp = *(G**)tls;
 
-	if(gp != nil && gp != mp->g0 && gp->status != Gsyscall) {
-		// align Context to 16 bytes
-		r = (Context*)((uintptr)(&rbuf[15]) & ~15);
-		r->ContextFlags = CONTEXT_CONTROL;
-		runtime·stdcall(runtime·GetThreadContext, 2, mp->thread, r);
-		runtime·dosigprof(r, gp);
-	}
+	// align Context to 16 bytes
+	r = (Context*)((uintptr)(&rbuf[15]) & ~15);
+	r->ContextFlags = CONTEXT_CONTROL;
+	runtime·stdcall(runtime·GetThreadContext, 2, mp->thread, r);
+	runtime·dosigprof(r, gp, mp);
 }
 
 void
@@ -425,10 +443,13 @@ runtime·profileloop1(void)
 		allm = runtime·atomicloadp(&runtime·allm);
 		for(mp = allm; mp != nil; mp = mp->alllink) {
 			thread = runtime·atomicloadp(&mp->thread);
-			if(thread == nil)
+			// Do not profile threads blocked on Notes,
+			// this includes idle worker threads,
+			// idle timer thread, idle heap scavenger, etc.
+			if(thread == nil || mp->profilehz == 0 || mp->blocked)
 				continue;
 			runtime·stdcall(runtime·SuspendThread, 1, thread);
-			if(mp->profilehz != 0)
+			if(mp->profilehz != 0 && !mp->blocked)
 				profilem(mp);
 			runtime·stdcall(runtime·ResumeThread, 1, thread);
 		}
diff --git a/src/pkg/runtime/os_windows_386.c b/src/pkg/runtime/os_windows_386.c
index c377e5b..c36a001 100644
--- a/src/pkg/runtime/os_windows_386.c
+++ b/src/pkg/runtime/os_windows_386.c
@@ -24,16 +24,47 @@ runtime·dumpregs(Context *r)
 	runtime·printf("gs      %x\n", r->SegGs);
 }
 
+#define DBG_PRINTEXCEPTION_C 0x40010006
+
+// Called by sigtramp from Windows VEH handler.
+// Return value signals whether the exception has been handled (-1)
+// or should be made available to other handlers in the chain (0).
 uint32
 runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
 {
 	bool crash;
 	uintptr *sp;
+	extern byte text[], etext[];
+
+	if(info->ExceptionCode == DBG_PRINTEXCEPTION_C) {
+		// This exception is intended to be caught by debuggers.
+		// There is a not-very-informational message like
+		// "Invalid parameter passed to C runtime function"
+		// sitting at info->ExceptionInformation[0] (a wchar_t*),
+		// with length info->ExceptionInformation[1].
+		// The default behavior is to ignore this exception,
+		// but somehow returning 0 here (meaning keep going)
+		// makes the program crash instead. Maybe Windows has no
+		// other handler registered? In any event, ignore it.
+		return -1;
+	}
+
+	// Only handle exception if executing instructions in Go binary
+	// (not Windows library code). 
+	if(r->Eip < (uint32)text || (uint32)etext < r->Eip)
+		return 0;
 
 	switch(info->ExceptionCode) {
 	case EXCEPTION_BREAKPOINT:
-		r->Eip--;	// because 8l generates 2 bytes for INT3
-		return 1;
+		// It is unclear whether this is needed, unclear whether it
+		// would work, and unclear how to test it. Leave out for now.
+		// This only handles breakpoint instructions written in the
+		// assembly sources, not breakpoints set by a debugger, and
+		// there are very few of the former.
+		//
+		// r->Eip--;	// because 8l generates 2 bytes for INT3
+		// return 0;
+		break;
 	}
 
 	if(gp != nil && runtime·issigpanic(info->ExceptionCode)) {
@@ -58,15 +89,15 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
 			r->Esp = (uintptr)sp;
 		}
 		r->Eip = (uintptr)runtime·sigpanic;
-		return 0;
+		return -1;
 	}
 
 	if(runtime·panicking)	// traceback already printed
 		runtime·exit(2);
 	runtime·panicking = 1;
 
-	runtime·printf("Exception %x %p %p\n", info->ExceptionCode,
-		info->ExceptionInformation[0], info->ExceptionInformation[1]);
+	runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode,
+		info->ExceptionInformation[0], info->ExceptionInformation[1], r->Eip);
 
 	runtime·printf("PC=%x\n", r->Eip);
 	if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
@@ -84,9 +115,8 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
 	if(crash)
 		runtime·crash();
 
-
 	runtime·exit(2);
-	return 0;
+	return -1; // not reached
 }
 
 void
@@ -102,7 +132,7 @@ runtime·sigdisable(uint32 sig)
 }
 
 void
-runtime·dosigprof(Context *r, G *gp)
+runtime·dosigprof(Context *r, G *gp, M *mp)
 {
-	runtime·sigprof((uint8*)r->Eip, (uint8*)r->Esp, nil, gp);
+	runtime·sigprof((uint8*)r->Eip, (uint8*)r->Esp, nil, gp, mp);
 }
diff --git a/src/pkg/runtime/os_windows_amd64.c b/src/pkg/runtime/os_windows_amd64.c
index 97c48fe..7fb973c 100644
--- a/src/pkg/runtime/os_windows_amd64.c
+++ b/src/pkg/runtime/os_windows_amd64.c
@@ -32,15 +32,44 @@ runtime·dumpregs(Context *r)
 	runtime·printf("gs      %X\n", (uint64)r->SegGs);
 }
 
+#define DBG_PRINTEXCEPTION_C 0x40010006
+
+// Called by sigtramp from Windows VEH handler.
+// Return value signals whether the exception has been handled (-1)
+// or should be made available to other handlers in the chain (0).
 uint32
 runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
 {
 	bool crash;
 	uintptr *sp;
+	extern byte text[], etext[];
+
+	if(info->ExceptionCode == DBG_PRINTEXCEPTION_C) {
+		// This exception is intended to be caught by debuggers.
+		// There is a not-very-informational message like
+		// "Invalid parameter passed to C runtime function"
+		// sitting at info->ExceptionInformation[0] (a wchar_t*),
+		// with length info->ExceptionInformation[1].
+		// The default behavior is to ignore this exception,
+		// but somehow returning 0 here (meaning keep going)
+		// makes the program crash instead. Maybe Windows has no
+		// other handler registered? In any event, ignore it.
+		return -1;
+	}
+
+	// Only handle exception if executing instructions in Go binary
+	// (not Windows library code). 
+	if(r->Rip < (uint64)text || (uint64)etext < r->Rip)
+		return 0;
 
 	switch(info->ExceptionCode) {
 	case EXCEPTION_BREAKPOINT:
-		return 1;
+		// It is unclear whether this is needed, unclear whether it
+		// would work, and unclear how to test it. Leave out for now.
+		// This only handles breakpoint instructions written in the
+		// assembly sources, not breakpoints set by a debugger, and
+		// there are very few of the former.
+		break;
 	}
 
 	if(gp != nil && runtime·issigpanic(info->ExceptionCode)) {
@@ -65,15 +94,16 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
 			r->Rsp = (uintptr)sp;
 		}
 		r->Rip = (uintptr)runtime·sigpanic;
-		return 0;
+		return -1;
 	}
 
 	if(runtime·panicking)	// traceback already printed
 		runtime·exit(2);
 	runtime·panicking = 1;
 
-	runtime·printf("Exception %x %p %p\n", info->ExceptionCode,
-		info->ExceptionInformation[0], info->ExceptionInformation[1]);
+	runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode,
+		info->ExceptionInformation[0], info->ExceptionInformation[1], r->Rip);
+
 
 	runtime·printf("PC=%X\n", r->Rip);
 	if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
@@ -92,7 +122,7 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
 		runtime·crash();
 
 	runtime·exit(2);
-	return 0;
+	return -1; // not reached
 }
 
 void
@@ -108,7 +138,7 @@ runtime·sigdisable(uint32 sig)
 }
 
 void
-runtime·dosigprof(Context *r, G *gp)
+runtime·dosigprof(Context *r, G *gp, M *mp)
 {
-	runtime·sigprof((uint8*)r->Rip, (uint8*)r->Rsp, nil, gp);
+	runtime·sigprof((uint8*)r->Rip, (uint8*)r->Rsp, nil, gp, mp);
 }
diff --git a/src/pkg/runtime/panic.c b/src/pkg/runtime/panic.c
index 8227a44..f577b37 100644
--- a/src/pkg/runtime/panic.c
+++ b/src/pkg/runtime/panic.c
@@ -13,108 +13,63 @@
 uint32 runtime·panicking;
 static Lock paniclk;
 
-enum
-{
-	DeferChunkSize = 2048
-};
+// Each P holds pool for defers with arg sizes 8, 24, 40, 56 and 72 bytes.
+// Memory block is 40 (24 for 32 bits) bytes larger due to Defer header.
+// This maps exactly to malloc size classes.
+
+// defer size class for arg size sz
+#define DEFERCLASS(sz) (((sz)+7)>>4)
+// total size of memory block for defer with arg size sz
+#define TOTALSIZE(sz) (sizeof(Defer) - sizeof(((Defer*)nil)->args) + ROUND(sz, sizeof(uintptr)))
 
-// Allocate a Defer, usually as part of the larger frame of deferred functions.
-// Each defer must be released with both popdefer and freedefer.
+// Allocate a Defer, usually using per-P pool.
+// Each defer must be released with freedefer.
 static Defer*
 newdefer(int32 siz)
 {
-	int32 total;
-	DeferChunk *c;
+	int32 total, sc;
 	Defer *d;
-	
-	c = g->dchunk;
-	total = sizeof(*d) + ROUND(siz, sizeof(uintptr)) - sizeof(d->args);
-	if(c == nil || total > DeferChunkSize - c->off) {
-		if(total > DeferChunkSize / 2) {
-			// Not worth putting in any chunk.
-			// Allocate a separate block.
-			d = runtime·malloc(total);
-			d->siz = siz;
-			d->special = 1;
-			d->free = 1;
-			d->link = g->defer;
-			g->defer = d;
-			return d;
-		}
-
-		// Cannot fit in current chunk.
-		// Switch to next chunk, allocating if necessary.
-		c = g->dchunknext;
-		if(c == nil)
-			c = runtime·malloc(DeferChunkSize);
-		c->prev = g->dchunk;
-		c->off = sizeof(*c);
-		g->dchunk = c;
-		g->dchunknext = nil;
+	P *p;
+
+	d = nil;
+	sc = DEFERCLASS(siz);
+	if(sc < nelem(p->deferpool)) {
+		p = m->p;
+		d = p->deferpool[sc];
+		if(d)
+			p->deferpool[sc] = d->link;
+	}
+	if(d == nil) {
+		// deferpool is empty or just a big defer
+		total = TOTALSIZE(siz);
+		d = runtime·malloc(total);
 	}
-
-	d = (Defer*)((byte*)c + c->off);
-	c->off += total;
 	d->siz = siz;
 	d->special = 0;
-	d->free = 0;
 	d->link = g->defer;
 	g->defer = d;
-	return d;	
-}
-
-// Pop the current defer from the defer stack.
-// Its contents are still valid until the goroutine begins executing again.
-// In particular it is safe to call reflect.call(d->fn, d->argp, d->siz) after
-// popdefer returns.
-static void
-popdefer(void)
-{
-	Defer *d;
-	DeferChunk *c;
-	int32 total;
-	
-	d = g->defer;
-	if(d == nil)
-		runtime·throw("runtime: popdefer nil");
-	g->defer = d->link;
-	if(d->special) {
-		// Nothing else to do.
-		return;
-	}
-	total = sizeof(*d) + ROUND(d->siz, sizeof(uintptr)) - sizeof(d->args);
-	c = g->dchunk;
-	if(c == nil || (byte*)d+total != (byte*)c+c->off)
-		runtime·throw("runtime: popdefer phase error");
-	c->off -= total;
-	if(c->off == sizeof(*c)) {
-		// Chunk now empty, so pop from stack.
-		// Save in dchunknext both to help with pingponging between frames
-		// and to make sure d is still valid on return.
-		if(g->dchunknext != nil)
-			runtime·free(g->dchunknext);
-		g->dchunknext = c;
-		g->dchunk = c->prev;
-	}
+	return d;
 }
 
 // Free the given defer.
-// For defers in the per-goroutine chunk this just clears the saved arguments.
-// For large defers allocated on the heap, this frees them.
 // The defer cannot be used after this call.
 static void
 freedefer(Defer *d)
 {
-	int32 total;
+	int32 sc;
+	P *p;
 
-	if(d->special) {
-		if(d->free)
-			runtime·free(d);
-	} else {
-		// Wipe out any possible pointers in argp/pc/fn/args.
-		total = sizeof(*d) + ROUND(d->siz, sizeof(uintptr)) - sizeof(d->args);
-		runtime·memclr((byte*)d, total);
-	}
+	if(d->special)
+		return;
+	sc = DEFERCLASS(d->siz);
+	if(sc < nelem(p->deferpool)) {
+		p = m->p;
+		d->link = p->deferpool[sc];
+		p->deferpool[sc] = d;
+		// No need to wipe out pointers in argp/pc/fn/args,
+		// because we empty the pool before GC.
+	} else
+		runtime·free(d);
 }
 
 // Create a new deferred function fn with siz bytes of arguments.
@@ -157,14 +112,12 @@ runtime·deferproc(int32 siz, FuncVal *fn, ...)
 // is called again and again until there are no more deferred functions.
 // Cannot split the stack because we reuse the caller's frame to
 // call the deferred function.
-//
-// The ... in the prototype keeps the compiler from declaring
-// an argument frame size. deferreturn is a very special function,
-// and if the runtime ever asks for its frame size, that means
-// the traceback routines are probably broken.
+
+// The single argument isn't actually used - it just has its address
+// taken so it can be matched against pending defers.
 #pragma textflag NOSPLIT
 void
-runtime·deferreturn(uintptr arg0, ...)
+runtime·deferreturn(uintptr arg0)
 {
 	Defer *d;
 	byte *argp;
@@ -184,7 +137,7 @@ runtime·deferreturn(uintptr arg0, ...)
 	m->locks++;
 	runtime·memmove(argp, d->args, d->siz);
 	fn = d->fn;
-	popdefer();
+	g->defer = d->link;
 	freedefer(d);
 	m->locks--;
 	if(m->locks == 0 && g->preempt)
@@ -192,6 +145,37 @@ runtime·deferreturn(uintptr arg0, ...)
 	runtime·jmpdefer(fn, argp);
 }
 
+// Ensure that defer arg sizes that map to the same defer size class
+// also map to the same malloc size class.
+void
+runtime·testdefersizes(void)
+{
+	P *p;
+	int32 i, siz, defersc, mallocsc;
+	int32 map[nelem(p->deferpool)];
+
+	for(i=0; i<nelem(p->deferpool); i++)
+		map[i] = -1;
+	for(i=0;; i++) {
+		defersc = DEFERCLASS(i);
+		if(defersc >= nelem(p->deferpool))
+			break;
+		siz = TOTALSIZE(i);
+		mallocsc = runtime·SizeToClass(siz);
+		siz = runtime·class_to_size[mallocsc];
+		// runtime·printf("defer class %d: arg size %d, block size %d(%d)\n", defersc, i, siz, mallocsc);
+		if(map[defersc] < 0) {
+			map[defersc] = mallocsc;
+			continue;
+		}
+		if(map[defersc] != mallocsc) {
+			runtime·printf("bad defer size class: i=%d siz=%d mallocsc=%d/%d\n",
+				i, siz, map[defersc], mallocsc);
+			runtime·throw("bad defer size class");
+		}
+	}
+}
+
 // Run all deferred functions for the current goroutine.
 static void
 rundefer(void)
@@ -199,8 +183,8 @@ rundefer(void)
 	Defer *d;
 
 	while((d = g->defer) != nil) {
-		popdefer();
-		reflect·call(d->fn, (byte*)d->args, d->siz);
+		g->defer = d->link;
+		reflect·call(d->fn, (byte*)d->args, d->siz, d->siz);
 		freedefer(d);
 	}
 }
@@ -221,37 +205,65 @@ printpanics(Panic *p)
 }
 
 static void recovery(G*);
+static void abortpanic(Panic*);
+static FuncVal abortpanicV = { (void(*)(void))abortpanic };
 
 // The implementation of the predeclared function panic.
 void
 runtime·panic(Eface e)
 {
-	Defer *d;
-	Panic *p;
+	Defer *d, dabort;
+	Panic p;
 	void *pc, *argp;
-	
-	p = runtime·mal(sizeof *p);
-	p->arg = e;
-	p->link = g->panic;
-	p->stackbase = g->stackbase;
-	g->panic = p;
+
+	runtime·memclr((byte*)&p, sizeof p);
+	p.arg = e;
+	p.link = g->panic;
+	p.stackbase = g->stackbase;
+	g->panic = &p;
+
+	dabort.fn = &abortpanicV;
+	dabort.siz = sizeof(&p);
+	dabort.args[0] = &p;
+	dabort.argp = NoArgs;
+	dabort.special = true;
 
 	for(;;) {
 		d = g->defer;
 		if(d == nil)
 			break;
 		// take defer off list in case of recursive panic
-		popdefer();
-		g->ispanic = true;	// rock for newstack, where reflect.newstackcall ends up
+		g->defer = d->link;
+		g->ispanic = true;	// rock for runtime·newstack, where runtime·newstackcall ends up
 		argp = d->argp;
 		pc = d->pc;
+
+		// The deferred function may cause another panic,
+		// so newstackcall may not return. Set up a defer
+		// to mark this panic aborted if that happens.
+		dabort.link = g->defer;
+		g->defer = &dabort;
+		p.defer = d;
+
 		runtime·newstackcall(d->fn, (byte*)d->args, d->siz);
+
+		// Newstackcall did not panic. Remove dabort.
+		if(g->defer != &dabort)
+			runtime·throw("bad defer entry in panic");
+		g->defer = dabort.link;
+
 		freedefer(d);
-		if(p->recovered) {
-			g->panic = p->link;
+		if(p.recovered) {
+			g->panic = p.link;
+			// Aborted panics are marked but remain on the g->panic list.
+			// Recovery will unwind the stack frames containing their Panic structs.
+			// Remove them from the list and free the associated defers.
+			while(g->panic && g->panic->aborted) {
+				freedefer(g->panic->defer);
+				g->panic = g->panic->link;
+			}
 			if(g->panic == nil)	// must be done with signal
 				g->sig = 0;
-			runtime·free(p);
 			// Pass information about recovering frame to recovery.
 			g->sigcode0 = (uintptr)argp;
 			g->sigcode1 = (uintptr)pc;
@@ -263,7 +275,14 @@ runtime·panic(Eface e)
 	// ran out of deferred calls - old-school panic now
 	runtime·startpanic();
 	printpanics(g->panic);
-	runtime·dopanic(0);
+	runtime·dopanic(0);	// should not return
+	runtime·exit(1);	// not reached
+}
+
+static void
+abortpanic(Panic *p)
+{
+	p->aborted = true;
 }
 
 // Unwind the stack after a deferred function calls recover
@@ -320,10 +339,7 @@ runtime·unwindstack(G *gp, byte *sp)
 		gp->stackbase = top->stackbase;
 		gp->stackguard = top->stackguard;
 		gp->stackguard0 = gp->stackguard;
-		if(top->free != 0) {
-			gp->stacksize -= top->free;
-			runtime·stackfree(stk, top->free);
-		}
+		runtime·stackfree(gp, stk, top);
 	}
 
 	if(sp != nil && (sp < (byte*)gp->stackguard - StackGuard || (byte*)gp->stackbase < sp)) {
@@ -337,10 +353,11 @@ runtime·unwindstack(G *gp, byte *sp)
 // find the stack segment of its caller.
 #pragma textflag NOSPLIT
 void
-runtime·recover(byte *argp, Eface ret)
+runtime·recover(byte *argp, GoOutput retbase, ...)
 {
 	Panic *p;
 	Stktop *top;
+	Eface *ret;
 
 	// Must be an unrecovered panic in progress.
 	// Must be on a stack segment created for a deferred call during a panic.
@@ -351,16 +368,16 @@ runtime·recover(byte *argp, Eface ret)
 	// do not count as official calls to adjust what we consider the top frame
 	// while they are active on the stack. The linker emits adjustments of
 	// g->panicwrap in the prologue and epilogue of functions marked as wrappers.
+	ret = (Eface*)&retbase;
 	top = (Stktop*)g->stackbase;
 	p = g->panic;
 	if(p != nil && !p->recovered && top->panic && argp == (byte*)top - top->argsize - g->panicwrap) {
 		p->recovered = 1;
-		ret = p->arg;
+		*ret = p->arg;
 	} else {
-		ret.type = nil;
-		ret.data = nil;
+		ret->type = nil;
+		ret->data = nil;
 	}
-	FLUSH(&ret);
 }
 
 void
@@ -371,18 +388,34 @@ runtime·startpanic(void)
 		m->mallocing = 1; // tell rest of panic not to try to malloc
 	} else if(m->mcache == nil) // can happen if called from signal handler or throw
 		m->mcache = runtime·allocmcache();
-	if(m->dying) {
+	switch(m->dying) {
+	case 0:
+		m->dying = 1;
+		if(g != nil)
+			g->writebuf = nil;
+		runtime·xadd(&runtime·panicking, 1);
+		runtime·lock(&paniclk);
+		if(runtime·debug.schedtrace > 0 || runtime·debug.scheddetail > 0)
+			runtime·schedtrace(true);
+		runtime·freezetheworld();
+		return;
+	case 1:
+		// Something failed while panicing, probably the print of the
+		// argument to panic().  Just print a stack trace and exit.
+		m->dying = 2;
 		runtime·printf("panic during panic\n");
+		runtime·dopanic(0);
 		runtime·exit(3);
+	case 2:
+		// This is a genuine bug in the runtime, we couldn't even
+		// print the stack trace successfully.
+		m->dying = 3;
+		runtime·printf("stack trace unavailable\n");
+		runtime·exit(4);
+	default:
+		// Can't even print!  Just exit.
+		runtime·exit(5);
 	}
-	m->dying = 1;
-	if(g != nil)
-		g->writebuf = nil;
-	runtime·xadd(&runtime·panicking, 1);
-	runtime·lock(&paniclk);
-	if(runtime·debug.schedtrace > 0 || runtime·debug.scheddetail > 0)
-		runtime·schedtrace(true);
-	runtime·freezetheworld();
 }
 
 void
@@ -453,6 +486,29 @@ runtime·throwinit(void)
 	runtime·throw("recursive call during initialization - linker skew");
 }
 
+bool
+runtime·canpanic(G *gp)
+{
+	byte g;
+
+	USED(&g);  // don't use global g, it points to gsignal
+
+	// Is it okay for gp to panic instead of crashing the program?
+	// Yes, as long as it is running Go code, not runtime code,
+	// and not stuck in a system call.
+	if(gp == nil || gp != m->curg)
+		return false;
+	if(m->locks-m->softfloat != 0 || m->mallocing != 0 || m->throwing != 0 || m->gcing != 0 || m->dying != 0)
+		return false;
+	if(gp->status != Grunning || gp->syscallsp != 0)
+		return false;
+#ifdef GOOS_windows
+	if(m->libcallsp != 0)
+		return false;
+#endif
+	return true;
+}
+
 void
 runtime·throw(int8 *s)
 {
@@ -470,6 +526,16 @@ runtime·panicstring(int8 *s)
 {
 	Eface err;
 
+	// m->softfloat is set during software floating point,
+	// which might cause a fault during a memory load.
+	// It increments m->locks to avoid preemption.
+	// If we're panicking, the software floating point frames
+	// will be unwound, so decrement m->locks as they would.
+	if(m->softfloat) {
+		m->locks--;
+		m->softfloat = 0;
+	}
+
 	if(m->mallocing) {
 		runtime·printf("panic: %s\n", s);
 		runtime·throw("panic during malloc");
@@ -478,6 +544,10 @@ runtime·panicstring(int8 *s)
 		runtime·printf("panic: %s\n", s);
 		runtime·throw("panic during gc");
 	}
+	if(m->locks) {
+		runtime·printf("panic: %s\n", s);
+		runtime·throw("panic holding locks");
+	}
 	runtime·newErrorCString(s, &err);
 	runtime·panic(err);
 }
@@ -488,3 +558,9 @@ runtime·Goexit(void)
 	rundefer();
 	runtime·goexit();
 }
+
+void
+runtime·panicdivide(void)
+{
+	runtime·panicstring("integer divide by zero");
+}
diff --git a/src/pkg/runtime/parfor.c b/src/pkg/runtime/parfor.c
index ceaac8b..4706e0a 100644
--- a/src/pkg/runtime/parfor.c
+++ b/src/pkg/runtime/parfor.c
@@ -33,15 +33,6 @@ runtime·parforalloc(uint32 nthrmax)
 	return desc;
 }
 
-// For testing from Go
-// func parforalloc2(nthrmax uint32) *ParFor
-void
-runtime·parforalloc2(uint32 nthrmax, ParFor *desc)
-{
-	desc = runtime·parforalloc(nthrmax);
-	FLUSH(&desc);
-}
-
 void
 runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32))
 {
@@ -75,14 +66,6 @@ runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait,
 	}
 }
 
-// For testing from Go
-// func parforsetup2(desc *ParFor, nthr, n uint32, ctx *byte, wait bool, body func(*ParFor, uint32))
-void
-runtime·parforsetup2(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void *body)
-{
-	runtime·parforsetup(desc, nthr, n, ctx, wait, *(void(**)(ParFor*, uint32))body);
-}
-
 void
 runtime·parfordo(ParFor *desc)
 {
@@ -207,13 +190,10 @@ exit:
 	me->nsleep = 0;
 }
 
-// For testing from Go
-// func parforiters(desc *ParFor, tid uintptr) (uintptr, uintptr)
+// For testing from Go.
 void
-runtime·parforiters(ParFor *desc, uintptr tid, uintptr start, uintptr end)
+runtime·parforiters(ParFor *desc, uintptr tid, uintptr *start, uintptr *end)
 {
-	start = (uint32)desc->thr[tid].pos;
-	end = (uint32)(desc->thr[tid].pos>>32);
-	FLUSH(&start);
-	FLUSH(&end);
+	*start = (uint32)desc->thr[tid].pos;
+	*end = (uint32)(desc->thr[tid].pos>>32);
 }
diff --git a/src/pkg/runtime/pprof/pprof.go b/src/pkg/runtime/pprof/pprof.go
index 3b84285..26aa0b8 100644
--- a/src/pkg/runtime/pprof/pprof.go
+++ b/src/pkg/runtime/pprof/pprof.go
@@ -20,7 +20,7 @@ import (
 	"text/tabwriter"
 )
 
-// BUG(rsc): Profiles are incomplete and inaccuate on NetBSD, OpenBSD, and OS X.
+// BUG(rsc): Profiles are incomplete and inaccurate on NetBSD and OS X.
 // See http://golang.org/issue/6047 for details.
 
 // A Profile is a collection of stack traces showing the call sequences
diff --git a/src/pkg/runtime/pprof/pprof_test.go b/src/pkg/runtime/pprof/pprof_test.go
index eb76b93..aba538e 100644
--- a/src/pkg/runtime/pprof/pprof_test.go
+++ b/src/pkg/runtime/pprof/pprof_test.go
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build !nacl
+
 package pprof_test
 
 import (
@@ -138,7 +140,11 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
 		t.Logf("no CPU profile samples collected")
 		ok = false
 	}
-	min := total / uintptr(len(have)) / 3
+	// We'd like to check a reasonable minimum, like
+	// total / len(have) / smallconstant, but this test is
+	// pretty flaky (see bug 7095).  So we'll just test to
+	// make sure we got at least one sample.
+	min := uintptr(1)
 	for i, name := range need {
 		if have[i] < min {
 			t.Logf("%s has %d samples out of %d, want at least %d, ideally %d", name, have[i], total, min, total/uintptr(len(have)))
@@ -189,9 +195,6 @@ func TestCPUProfileWithFork(t *testing.T) {
 // If it did, it would see inconsistent state and would either record an incorrect stack
 // or crash because the stack was malformed.
 func TestGoroutineSwitch(t *testing.T) {
-	if runtime.GOOS == "windows" {
-		t.Skip("flaky test; see http://golang.org/issue/6417")
-	}
 	// How much to try. These defaults take about 1 seconds
 	// on a 2012 MacBook Pro. The ones in short mode take
 	// about 0.1 seconds.
@@ -217,7 +220,7 @@ func TestGoroutineSwitch(t *testing.T) {
 			// exists to record a PC without a traceback. Those are okay.
 			if len(stk) == 2 {
 				f := runtime.FuncForPC(stk[1])
-				if f != nil && f.Name() == "System" {
+				if f != nil && (f.Name() == "System" || f.Name() == "ExternalCode") {
 					return
 				}
 			}
@@ -264,9 +267,9 @@ func TestMathBigDivide(t *testing.T) {
 
 // Operating systems that are expected to fail the tests. See issue 6047.
 var badOS = map[string]bool{
-	"darwin":  true,
-	"netbsd":  true,
-	"openbsd": true,
+	"darwin": true,
+	"netbsd": true,
+	"plan9":  true,
 }
 
 func TestBlockProfile(t *testing.T) {
@@ -278,31 +281,31 @@ func TestBlockProfile(t *testing.T) {
 	tests := [...]TestCase{
 		{"chan recv", blockChanRecv, `
 [0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
-#	0x[0-9,a-f]+	runtime\.chanrecv1\+0x[0-9,a-f]+	.*/src/pkg/runtime/chan.c:[0-9]+
+#	0x[0-9,a-f]+	runtime\.chanrecv1\+0x[0-9,a-f]+	.*/src/pkg/runtime/chan.goc:[0-9]+
 #	0x[0-9,a-f]+	runtime/pprof_test\.blockChanRecv\+0x[0-9,a-f]+	.*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
 #	0x[0-9,a-f]+	runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+	.*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
 `},
 		{"chan send", blockChanSend, `
 [0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
-#	0x[0-9,a-f]+	runtime\.chansend1\+0x[0-9,a-f]+	.*/src/pkg/runtime/chan.c:[0-9]+
+#	0x[0-9,a-f]+	runtime\.chansend1\+0x[0-9,a-f]+	.*/src/pkg/runtime/chan.goc:[0-9]+
 #	0x[0-9,a-f]+	runtime/pprof_test\.blockChanSend\+0x[0-9,a-f]+	.*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
 #	0x[0-9,a-f]+	runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+	.*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
 `},
 		{"chan close", blockChanClose, `
 [0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
-#	0x[0-9,a-f]+	runtime\.chanrecv1\+0x[0-9,a-f]+	.*/src/pkg/runtime/chan.c:[0-9]+
+#	0x[0-9,a-f]+	runtime\.chanrecv1\+0x[0-9,a-f]+	.*/src/pkg/runtime/chan.goc:[0-9]+
 #	0x[0-9,a-f]+	runtime/pprof_test\.blockChanClose\+0x[0-9,a-f]+	.*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
 #	0x[0-9,a-f]+	runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+	.*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
 `},
 		{"select recv async", blockSelectRecvAsync, `
 [0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
-#	0x[0-9,a-f]+	runtime\.selectgo\+0x[0-9,a-f]+	.*/src/pkg/runtime/chan.c:[0-9]+
+#	0x[0-9,a-f]+	runtime\.selectgo\+0x[0-9,a-f]+	.*/src/pkg/runtime/chan.goc:[0-9]+
 #	0x[0-9,a-f]+	runtime/pprof_test\.blockSelectRecvAsync\+0x[0-9,a-f]+	.*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
 #	0x[0-9,a-f]+	runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+	.*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
 `},
 		{"select send sync", blockSelectSendSync, `
 [0-9]+ [0-9]+ @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
-#	0x[0-9,a-f]+	runtime\.selectgo\+0x[0-9,a-f]+	.*/src/pkg/runtime/chan.c:[0-9]+
+#	0x[0-9,a-f]+	runtime\.selectgo\+0x[0-9,a-f]+	.*/src/pkg/runtime/chan.goc:[0-9]+
 #	0x[0-9,a-f]+	runtime/pprof_test\.blockSelectSendSync\+0x[0-9,a-f]+	.*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
 #	0x[0-9,a-f]+	runtime/pprof_test\.TestBlockProfile\+0x[0-9,a-f]+	.*/src/pkg/runtime/pprof/pprof_test.go:[0-9]+
 `},
diff --git a/src/pkg/runtime/print.c b/src/pkg/runtime/print.c
index 8de3ae4..a04708f 100644
--- a/src/pkg/runtime/print.c
+++ b/src/pkg/runtime/print.c
@@ -63,67 +63,85 @@ runtime·printf(int8 *s, ...)
 	vprintf(s, arg);
 }
 
+#pragma textflag NOSPLIT
+int32
+runtime·snprintf(byte *buf, int32 n, int8 *s, ...)
+{
+	byte *arg;
+	int32 m;
+
+	arg = (byte*)(&s+1);
+	g->writebuf = buf;
+	g->writenbuf = n-1;
+	vprintf(s, arg);
+	*g->writebuf = '\0';
+	m = g->writebuf - buf;
+	g->writenbuf = 0;
+	g->writebuf = nil;
+	return m;
+}
+
 // Very simple printf.  Only for debugging prints.
 // Do not add to this without checking with Rob.
 static void
 vprintf(int8 *s, byte *base)
 {
 	int8 *p, *lp;
-	uintptr arg, narg;
+	uintptr arg, siz;
 	byte *v;
 
 	//runtime·lock(&debuglock);
 
 	lp = p = s;
-	arg = 0;
+	arg = (uintptr)base;
 	for(; *p; p++) {
 		if(*p != '%')
 			continue;
 		if(p > lp)
 			gwrite(lp, p-lp);
 		p++;
-		narg = 0;
+		siz = 0;
 		switch(*p) {
 		case 't':
 		case 'c':
-			narg = arg + 1;
+			siz = 1;
 			break;
 		case 'd':	// 32-bit
 		case 'x':
 			arg = ROUND(arg, 4);
-			narg = arg + 4;
+			siz = 4;
 			break;
 		case 'D':	// 64-bit
 		case 'U':
 		case 'X':
 		case 'f':
-			arg = ROUND(arg, sizeof(uintptr));
-			narg = arg + 8;
+			arg = ROUND(arg, sizeof(uintreg));
+			siz = 8;
 			break;
 		case 'C':
-			arg = ROUND(arg, sizeof(uintptr));
-			narg = arg + 16;
+			arg = ROUND(arg, sizeof(uintreg));
+			siz = 16;
 			break;
 		case 'p':	// pointer-sized
 		case 's':
 			arg = ROUND(arg, sizeof(uintptr));
-			narg = arg + sizeof(uintptr);
+			siz = sizeof(uintptr);
 			break;
 		case 'S':	// pointer-aligned but bigger
 			arg = ROUND(arg, sizeof(uintptr));
-			narg = arg + sizeof(String);
+			siz = sizeof(String);
 			break;
 		case 'a':	// pointer-aligned but bigger
 			arg = ROUND(arg, sizeof(uintptr));
-			narg = arg + sizeof(Slice);
+			siz = sizeof(Slice);
 			break;
 		case 'i':	// pointer-aligned but bigger
 		case 'e':
 			arg = ROUND(arg, sizeof(uintptr));
-			narg = arg + sizeof(Eface);
+			siz = sizeof(Eface);
 			break;
 		}
-		v = base+arg;
+		v = (byte*)arg;
 		switch(*p) {
 		case 'a':
 			runtime·printslice(*(Slice*)v);
@@ -171,7 +189,7 @@ vprintf(int8 *s, byte *base)
 			runtime·printhex(*(uint64*)v);
 			break;
 		}
-		arg = narg;
+		arg += siz;
 		lp = p+1;
 	}
 	if(p > lp)
@@ -236,7 +254,10 @@ runtime·printfloat(float64 v)
 	n = 7;	// digits printed
 	e = 0;	// exp
 	s = 0;	// sign
-	if(v != 0) {
+	if(v == 0) {
+		if(1/v == runtime·neginf)
+			s = 1;
+	} else {
 		// sign
 		if(v < 0) {
 			v = -v;
@@ -345,7 +366,7 @@ runtime·printhex(uint64 v)
 void
 runtime·printpointer(void *p)
 {
-	runtime·printhex((uint64)p);
+	runtime·printhex((uintptr)p);
 }
 
 void
@@ -370,11 +391,3 @@ runtime·printnl(void)
 {
 	gwrite("\n", 1);
 }
-
-void
-runtime·typestring(Eface e, String s)
-{
-	s = *e.type->string;
-	FLUSH(&s);
-}
-
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index ed3e1e7..914a02e 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -58,17 +58,23 @@ struct Sched {
 	int32	profilehz;	// cpu profiling rate
 };
 
-// The max value of GOMAXPROCS.
-// There are no fundamental restrictions on the value.
-enum { MaxGomaxprocs = 1<<8 };
+enum
+{
+	// The max value of GOMAXPROCS.
+	// There are no fundamental restrictions on the value.
+	MaxGomaxprocs = 1<<8,
+
+	// Number of goroutine ids to grab from runtime·sched.goidgen to local per-P cache at once.
+	// 16 seems to provide enough amortization, but other than that it's mostly arbitrary number.
+	GoidCacheBatch = 16,
+};
 
 Sched	runtime·sched;
 int32	runtime·gomaxprocs;
 uint32	runtime·needextram;
 bool	runtime·iscgo;
 M	runtime·m0;
-G	runtime·g0;	 // idle goroutine for m0
-G*	runtime·allg;
+G	runtime·g0;	// idle goroutine for m0
 G*	runtime·lastg;
 M*	runtime·allm;
 M*	runtime·extram;
@@ -76,10 +82,15 @@ int8*	runtime·goos;
 int32	runtime·ncpu;
 static int32	newprocs;
 
+static	Lock allglock;	// the following vars are protected by this lock or by stoptheworld
+G**	runtime·allg;
+uintptr runtime·allglen;
+static	uintptr allgcap;
+
 void runtime·mstart(void);
 static void runqput(P*, G*);
 static G* runqget(P*);
-static void runqgrow(P*);
+static bool runqputslow(P*, G*, uint32, uint32);
 static G* runqsteal(P*, P*);
 static void mput(M*);
 static M* mget(void);
@@ -106,6 +117,7 @@ static void gfput(P*, G*);
 static G* gfget(P*);
 static void gfpurge(P*);
 static void globrunqput(G*);
+static void globrunqputbatch(G*, G*, int32);
 static G* globrunqget(P*, int32);
 static P* pidleget(void);
 static void pidleput(P*);
@@ -114,6 +126,7 @@ static bool preemptall(void);
 static bool preemptone(P*);
 static bool exitsyscallfast(void);
 static bool haveexperiment(int8*);
+static void allgadd(G*);
 
 // The bootstrap sequence is:
 //
@@ -131,9 +144,9 @@ runtime·schedinit(void)
 	Eface i;
 
 	runtime·sched.maxmcount = 10000;
-	runtime·precisestack = haveexperiment("precisestack");
+	runtime·precisestack = true; // haveexperiment("precisestack");
 
-	runtime·mprofinit();
+	runtime·symtabinit();
 	runtime·mallocinit();
 	mcommoninit(m);
 	
@@ -142,14 +155,15 @@ runtime·schedinit(void)
 	// in a fault during a garbage collection, it will not
 	// need to allocated memory.
 	runtime·newErrorCString(0, &i);
+	
+	// Initialize the cached gotraceback value, since
+	// gotraceback calls getenv, which mallocs on Plan 9.
+	runtime·gotraceback(nil);
 
 	runtime·goargs();
 	runtime·goenvs();
 	runtime·parsedebugvars();
 
-	// Allocate internal symbol table representation now, we need it for GC anyway.
-	runtime·symtabinit();
-
 	runtime·sched.lastpoll = runtime·nanotime();
 	procs = 1;
 	p = runtime·getenv("GOMAXPROCS");
@@ -161,6 +175,11 @@ runtime·schedinit(void)
 	runtime·allp = runtime·malloc((MaxGomaxprocs+1)*sizeof(runtime·allp[0]));
 	procresize(procs);
 
+	runtime·copystack = runtime·precisestack;
+	p = runtime·getenv("GOCOPYSTACK");
+	if(p != nil && !runtime·strcmp(p, (byte*)"0"))
+		runtime·copystack = false;
+
 	mstats.enablegc = 1;
 
 	if(raceenabled)
@@ -175,6 +194,15 @@ static FuncVal scavenger = {runtime·MHeap_Scavenger};
 static FuncVal initDone = { runtime·unlockOSThread };
 
 // The main goroutine.
+// Note: C frames in general are not copyable during stack growth, for two reasons:
+//   1) We don't know where in a frame to find pointers to other stack locations.
+//   2) There's no guarantee that globals or heap values do not point into the frame.
+//
+// The C frame for runtime.main is copyable, because:
+//   1) There are no pointers to other stack locations in the frame
+//      (d.fn points at a global, d.link is nil, d.argp is -1).
+//   2) The only pointer into this frame is from the defer chain,
+//      which is explicitly handled during stack copying.
 void
 runtime·main(void)
 {
@@ -202,9 +230,8 @@ runtime·main(void)
 	d.fn = &initDone;
 	d.siz = 0;
 	d.link = g->defer;
-	d.argp = (void*)-1;
+	d.argp = NoArgs;
 	d.special = true;
-	d.free = false;
 	g->defer = &d;
 
 	if(m != &runtime·m0)
@@ -237,6 +264,7 @@ void
 runtime·goroutineheader(G *gp)
 {
 	int8 *status;
+	int64 waitfor;
 
 	switch(gp->status) {
 	case Gidle:
@@ -261,7 +289,16 @@ runtime·goroutineheader(G *gp)
 		status = "???";
 		break;
 	}
-	runtime·printf("goroutine %D [%s]:\n", gp->goid, status);
+
+	// approx time the G is blocked, in minutes
+	waitfor = 0;
+	if((gp->status == Gwaiting || gp->status == Gsyscall) && gp->waitsince != 0)
+		waitfor = (runtime·nanotime() - gp->waitsince) / (60LL*1000*1000*1000);
+
+	if(waitfor < 1)
+		runtime·printf("goroutine %D [%s]:\n", gp->goid, status);
+	else
+		runtime·printf("goroutine %D [%s, %D minutes]:\n", gp->goid, status, waitfor);
 }
 
 void
@@ -269,6 +306,7 @@ runtime·tracebackothers(G *me)
 {
 	G *gp;
 	int32 traceback;
+	uintptr i;
 
 	traceback = runtime·gotraceback(nil);
 	
@@ -279,7 +317,9 @@ runtime·tracebackothers(G *me)
 		runtime·traceback(~(uintptr)0, ~(uintptr)0, 0, gp);
 	}
 
-	for(gp = runtime·allg; gp != nil; gp = gp->alllink) {
+	runtime·lock(&allglock);
+	for(i = 0; i < runtime·allglen; i++) {
+		gp = runtime·allg[i];
 		if(gp == me || gp == m->curg || gp->status == Gdead)
 			continue;
 		if(gp->issystem && traceback < 2)
@@ -292,6 +332,7 @@ runtime·tracebackothers(G *me)
 		} else
 			runtime·traceback(~(uintptr)0, ~(uintptr)0, 0, gp);
 	}
+	runtime·unlock(&allglock);
 }
 
 static void
@@ -562,15 +603,6 @@ runtime·starttheworld(void)
 void
 runtime·mstart(void)
 {
-#ifdef GOOS_windows
-#ifdef GOARCH_386
-	// It is used by windows-386 only. Unfortunately, seh needs
-	// to be located on os stack, and mstart runs on os stack
-	// for both m0 and m.
-	SEH seh;
-#endif
-#endif
-
 	if(g != m->g0)
 		runtime·throw("bad runtime·mstart");
 
@@ -580,11 +612,6 @@ runtime·mstart(void)
 	runtime·gosave(&m->g0->sched);
 	m->g0->sched.pc = (uintptr)-1;  // make sure it is never used
 	m->g0->stackguard = m->g0->stackguard0;  // cgo sets only stackguard0, copy it to stackguard
-#ifdef GOOS_windows
-#ifdef GOARCH_386
-	m->seh = &seh;
-#endif
-#endif
 	runtime·asminit();
 	runtime·minit();
 
@@ -620,6 +647,7 @@ struct CgoThreadStart
 {
 	M *m;
 	G *g;
+	uintptr *tls;
 	void (*fn)(void);
 };
 
@@ -643,9 +671,9 @@ runtime·allocm(P *p)
 	mp = runtime·cnew(mtype);
 	mcommoninit(mp);
 
-	// In case of cgo, pthread_create will make us a stack.
+	// In case of cgo or Solaris, pthread_create will make us a stack.
 	// Windows will layout sched stack on OS stack.
-	if(runtime·iscgo || Windows)
+	if(runtime·iscgo || Solaris || Windows)
 		mp->g0 = runtime·malg(-1);
 	else
 		mp->g0 = runtime·malg(8192);
@@ -659,6 +687,21 @@ runtime·allocm(P *p)
 	return mp;
 }
 
+static G*
+allocg(void)
+{
+	G *gp;
+	static Type *gtype;
+	
+	if(gtype == nil) {
+		Eface e;
+		runtime·gc_g_ptr(&e);
+		gtype = ((PtrType*)e.type)->elem;
+	}
+	gp = runtime·cnew(gtype);
+	return gp;
+}
+
 static M* lockextra(bool nilokay);
 static void unlockextra(M*);
 
@@ -735,16 +778,6 @@ runtime·needm(byte x)
 	g->stackguard = (uintptr)(&x - 32*1024);
 	g->stackguard0 = g->stackguard;
 
-#ifdef GOOS_windows
-#ifdef GOARCH_386
-	// On windows/386, we need to put an SEH frame (two words)
-	// somewhere on the current stack. We are called from cgocallback_gofunc
-	// and we know that it will leave two unused words below m->curg->sched.sp.
-	// Use those.
-	m->seh = (SEH*)((uintptr*)&x + 1);
-#endif
-#endif
-
 	// Initialize this thread to use the m.
 	runtime·asminit();
 	runtime·minit();
@@ -783,13 +816,7 @@ runtime·newextram(void)
 	if(raceenabled)
 		gp->racectx = runtime·racegostart(runtime·newextram);
 	// put on allg for garbage collector
-	runtime·lock(&runtime·sched);
-	if(runtime·lastg == nil)
-		runtime·allg = gp;
-	else
-		runtime·lastg->alllink = gp;
-	runtime·lastg = gp;
-	runtime·unlock(&runtime·sched);
+	allgadd(gp);
 
 	// Add m to the extra list.
 	mnext = lockextra(true);
@@ -828,12 +855,6 @@ runtime·dropm(void)
 	// Undo whatever initialization minit did during needm.
 	runtime·unminit();
 
-#ifdef GOOS_windows
-#ifdef GOARCH_386
-	m->seh = nil;  // reset dangling typed pointer
-#endif
-#endif
-
 	// Clear m and g, and return m to the extra list.
 	// After the call to setmg we can only call nosplit functions.
 	mp = m;
@@ -904,6 +925,7 @@ newm(void(*fn)(void), P *p)
 			runtime·throw("_cgo_thread_start missing");
 		ts.m = mp;
 		ts.g = mp->g0;
+		ts.tls = mp->tls;
 		ts.fn = runtime·mstart;
 		runtime·asmcgocall(_cgo_thread_start, &ts);
 		return;
@@ -948,7 +970,7 @@ mspinning(void)
 }
 
 // Schedules some M to run the p (creates an M if necessary).
-// If p==nil, tries to get an idle P, if no idle P's returns false.
+// If p==nil, tries to get an idle P, if no idle P's does nothing.
 static void
 startm(P *p, bool spinning)
 {
@@ -1112,6 +1134,7 @@ execute(G *gp)
 		runtime·throw("execute: bad g status");
 	}
 	gp->status = Grunning;
+	gp->waitsince = 0;
 	gp->preempt = false;
 	gp->stackguard0 = gp->stackguard;
 	m->p->schedtick++;
@@ -1140,6 +1163,8 @@ top:
 		gcstopm();
 		goto top;
 	}
+	if(runtime·fingwait && runtime·fingwake && (gp = runtime·wakefing()) != nil)
+		runtime·ready(gp);
 	// local runq
 	gp = runqget(m->p);
 	if(gp)
@@ -1331,28 +1356,52 @@ top:
 	execute(gp);
 }
 
-// Puts the current goroutine into a waiting state and unlocks the lock.
-// The goroutine can be made runnable again by calling runtime·ready(gp).
+// Puts the current goroutine into a waiting state and calls unlockf.
+// If unlockf returns false, the goroutine is resumed.
 void
-runtime·park(void(*unlockf)(Lock*), Lock *lock, int8 *reason)
+runtime·park(bool(*unlockf)(G*, void*), void *lock, int8 *reason)
 {
+	if(g->status != Grunning)
+		runtime·throw("bad g status");
 	m->waitlock = lock;
 	m->waitunlockf = unlockf;
 	g->waitreason = reason;
 	runtime·mcall(park0);
 }
 
+static bool
+parkunlock(G *gp, void *lock)
+{
+	USED(gp);
+	runtime·unlock(lock);
+	return true;
+}
+
+// Puts the current goroutine into a waiting state and unlocks the lock.
+// The goroutine can be made runnable again by calling runtime·ready(gp).
+void
+runtime·parkunlock(Lock *lock, int8 *reason)
+{
+	runtime·park(parkunlock, lock, reason);
+}
+
 // runtime·park continuation on g0.
 static void
 park0(G *gp)
 {
+	bool ok;
+
 	gp->status = Gwaiting;
 	gp->m = nil;
 	m->curg = nil;
 	if(m->waitunlockf) {
-		m->waitunlockf(m->waitlock);
+		ok = m->waitunlockf(gp, m->waitlock);
 		m->waitunlockf = nil;
 		m->waitlock = nil;
+		if(!ok) {
+			gp->status = Grunnable;
+			execute(gp);  // Schedule it back, never returns.
+		}
 	}
 	if(m->lockedg) {
 		stoplockedm();
@@ -1365,6 +1414,8 @@ park0(G *gp)
 void
 runtime·gosched(void)
 {
+	if(g->status != Grunning)
+		runtime·throw("bad g status");
 	runtime·mcall(runtime·gosched0);
 }
 
@@ -1393,6 +1444,8 @@ runtime·gosched0(G *gp)
 void
 runtime·goexit(void)
 {
+	if(g->status != Grunning)
+		runtime·throw("bad g status");
 	if(raceenabled)
 		runtime·racegoend();
 	runtime·mcall(goexit0);
@@ -1405,6 +1458,13 @@ goexit0(G *gp)
 	gp->status = Gdead;
 	gp->m = nil;
 	gp->lockedm = nil;
+	gp->paniconfault = 0;
+	gp->defer = nil; // should be true already but just in case.
+	gp->panic = nil; // non-nil for Goexit during panic. points at stack-allocated data.
+	gp->writenbuf = 0;
+	gp->writebuf = nil;
+	gp->waitreason = nil;
+	gp->param = nil;
 	m->curg = nil;
 	m->lockedg = nil;
 	if(m->locked & ~LockExternal) {
@@ -1535,6 +1595,7 @@ runtime·exitsyscall(void)
 	if(g->isbackground)  // do not consider blocked scavenger for deadlock detection
 		incidlelocked(-1);
 
+	g->waitsince = 0;
 	if(exitsyscallfast()) {
 		// There's a cpu for us, so we can run.
 		m->p->syscalltick++;
@@ -1640,6 +1701,7 @@ exitsyscall0(G *gp)
 }
 
 // Called from syscall package before fork.
+#pragma textflag NOSPLIT
 void
 syscall·runtime_BeforeFork(void)
 {
@@ -1648,14 +1710,28 @@ syscall·runtime_BeforeFork(void)
 	m->locks++;
 	if(m->profilehz != 0)
 		runtime·resetcpuprofiler(0);
+
+	// This function is called before fork in syscall package.
+	// Code between fork and exec must not allocate memory nor even try to grow stack.
+	// Here we spoil g->stackguard to reliably detect any attempts to grow stack.
+	// runtime_AfterFork will undo this in parent process, but not in child.
+	m->forkstackguard = g->stackguard;
+	g->stackguard0 = StackPreempt-1;
+	g->stackguard = StackPreempt-1;
 }
 
 // Called from syscall package after fork in parent.
+#pragma textflag NOSPLIT
 void
 syscall·runtime_AfterFork(void)
 {
 	int32 hz;
 
+	// See the comment in runtime_BeforeFork.
+	g->stackguard0 = m->forkstackguard;
+	g->stackguard = m->forkstackguard;
+	m->forkstackguard = 0;
+
 	hz = runtime·sched.profilehz;
 	if(hz != 0)
 		runtime·resetcpuprofiler(hz);
@@ -1669,7 +1745,13 @@ syscall·runtime_AfterFork(void)
 static void
 mstackalloc(G *gp)
 {
-	gp->param = runtime·stackalloc((uintptr)gp->param);
+	G *newg;
+	uintptr size;
+
+	newg = (G*)gp->param;
+	size = newg->stacksize;
+	newg->stacksize = 0;
+	gp->param = runtime·stackalloc(newg, size);
 	runtime·gogo(&gp->sched);
 }
 
@@ -1685,24 +1767,24 @@ runtime·malg(int32 stacksize)
 		runtime·throw("runtime: bad stack.h");
 	}
 
-	newg = runtime·malloc(sizeof(G));
+	newg = allocg();
 	if(stacksize >= 0) {
+		stacksize = runtime·round2(StackSystem + stacksize);
 		if(g == m->g0) {
 			// running on scheduler stack already.
-			stk = runtime·stackalloc(StackSystem + stacksize);
+			stk = runtime·stackalloc(newg, stacksize);
 		} else {
 			// have to call stackalloc on scheduler stack.
-			g->param = (void*)(StackSystem + stacksize);
+			newg->stacksize = stacksize;
+			g->param = newg;
 			runtime·mcall(mstackalloc);
 			stk = g->param;
 			g->param = nil;
 		}
-		newg->stacksize = StackSystem + stacksize;
 		newg->stack0 = (uintptr)stk;
 		newg->stackguard = (uintptr)stk + StackGuard;
 		newg->stackguard0 = newg->stackguard;
-		newg->stackbase = (uintptr)stk + StackSystem + stacksize - sizeof(Stktop);
-		runtime·memclr((byte*)newg->stackbase, sizeof(Stktop));
+		newg->stackbase = (uintptr)stk + stacksize - sizeof(Stktop);
 	}
 	return newg;
 }
@@ -1736,9 +1818,14 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp
 {
 	byte *sp;
 	G *newg;
+	P *p;
 	int32 siz;
 
 //runtime·printf("newproc1 %p %p narg=%d nret=%d\n", fn->fn, argp, narg, nret);
+	if(fn == nil) {
+		m->throwing = -1;  // do not dump full stacks
+		runtime·throw("go of nil func value");
+	}
 	m->locks++;  // disable preemption because it can be holding p in a local var
 	siz = narg + nret;
 	siz = (siz+7) & ~7;
@@ -1750,18 +1837,13 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp
 	if(siz > StackMin - 1024)
 		runtime·throw("runtime.newproc: function arguments too large for new goroutine");
 
-	if((newg = gfget(m->p)) != nil) {
+	p = m->p;
+	if((newg = gfget(p)) != nil) {
 		if(newg->stackguard - StackGuard != newg->stack0)
 			runtime·throw("invalid stack in newg");
 	} else {
 		newg = runtime·malg(StackMin);
-		runtime·lock(&runtime·sched);
-		if(runtime·lastg == nil)
-			runtime·allg = newg;
-		else
-			runtime·lastg->alllink = newg;
-		runtime·lastg = newg;
-		runtime·unlock(&runtime·sched);
+		allgadd(newg);
 	}
 
 	sp = (byte*)newg->stackbase;
@@ -1780,11 +1862,15 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp
 	runtime·gostartcallfn(&newg->sched, fn);
 	newg->gopc = (uintptr)callerpc;
 	newg->status = Grunnable;
-	newg->goid = runtime·xadd64(&runtime·sched.goidgen, 1);
+	if(p->goidcache == p->goidcacheend) {
+		p->goidcache = runtime·xadd64(&runtime·sched.goidgen, GoidCacheBatch);
+		p->goidcacheend = p->goidcache + GoidCacheBatch;
+	}
+	newg->goid = p->goidcache++;
 	newg->panicwrap = 0;
 	if(raceenabled)
 		newg->racectx = runtime·racegostart((void*)callerpc);
-	runqput(m->p, newg);
+	runqput(p, newg);
 
 	if(runtime·atomicload(&runtime·sched.npidle) != 0 && runtime·atomicload(&runtime·sched.nmspinning) == 0 && fn->fn != runtime·main)  // TODO: fast atomic
 		wakep();
@@ -1794,13 +1880,56 @@ runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerp
 	return newg;
 }
 
+static void
+allgadd(G *gp)
+{
+	G **new;
+	uintptr cap;
+
+	runtime·lock(&allglock);
+	if(runtime·allglen >= allgcap) {
+		cap = 4096/sizeof(new[0]);
+		if(cap < 2*allgcap)
+			cap = 2*allgcap;
+		new = runtime·malloc(cap*sizeof(new[0]));
+		if(new == nil)
+			runtime·throw("runtime: cannot allocate memory");
+		if(runtime·allg != nil) {
+			runtime·memmove(new, runtime·allg, runtime·allglen*sizeof(new[0]));
+			runtime·free(runtime·allg);
+		}
+		runtime·allg = new;
+		allgcap = cap;
+	}
+	runtime·allg[runtime·allglen++] = gp;
+	runtime·unlock(&allglock);
+}
+
 // Put on gfree list.
 // If local list is too long, transfer a batch to the global list.
 static void
 gfput(P *p, G *gp)
 {
+	uintptr stksize;
+	Stktop *top;
+
 	if(gp->stackguard - StackGuard != gp->stack0)
 		runtime·throw("invalid stack in gfput");
+	stksize = gp->stackbase + sizeof(Stktop) - gp->stack0;
+	if(stksize != gp->stacksize) {
+		runtime·printf("runtime: bad stacksize, goroutine %D, remain=%d, last=%d\n",
+			gp->goid, (int32)gp->stacksize, (int32)stksize);
+		runtime·throw("gfput: bad stacksize");
+	}
+	top = (Stktop*)gp->stackbase;
+	if(top->malloced) {
+		// non-standard stack size - free it.
+		runtime·stackfree(gp, (void*)gp->stack0, top);
+		gp->stack0 = 0;
+		gp->stackguard = 0;
+		gp->stackguard0 = 0;
+		gp->stackbase = 0;
+	}
 	gp->schedlink = p->gfree;
 	p->gfree = gp;
 	p->gfreecnt++;
@@ -1823,6 +1952,7 @@ static G*
 gfget(P *p)
 {
 	G *gp;
+	byte *stk;
 
 retry:
 	gp = p->gfree;
@@ -1841,6 +1971,23 @@ retry:
 	if(gp) {
 		p->gfree = gp->schedlink;
 		p->gfreecnt--;
+
+		if(gp->stack0 == 0) {
+			// Stack was deallocated in gfput.  Allocate a new one.
+			if(g == m->g0) {
+				stk = runtime·stackalloc(gp, FixedStack);
+			} else {
+				gp->stacksize = FixedStack;
+				g->param = gp;
+				runtime·mcall(mstackalloc);
+				stk = g->param;
+				g->param = nil;
+			}
+			gp->stack0 = (uintptr)stk;
+			gp->stackbase = (uintptr)stk + FixedStack - sizeof(Stktop);
+			gp->stackguard = (uintptr)stk + StackGuard;
+			gp->stackguard0 = gp->stackguard;
+		}
 	}
 	return gp;
 }
@@ -1963,39 +2110,26 @@ runtime·lockedOSThread(void)
 	return g->lockedm != nil && m->lockedg != nil;
 }
 
-// for testing of callbacks
-void
-runtime·golockedOSThread(bool ret)
-{
-	ret = runtime·lockedOSThread();
-	FLUSH(&ret);
-}
-
-void
-runtime·NumGoroutine(intgo ret)
-{
-	ret = runtime·gcount();
-	FLUSH(&ret);
-}
-
 int32
 runtime·gcount(void)
 {
 	G *gp;
 	int32 n, s;
+	uintptr i;
 
 	n = 0;
-	runtime·lock(&runtime·sched);
+	runtime·lock(&allglock);
 	// TODO(dvyukov): runtime.NumGoroutine() is O(N).
 	// We do not want to increment/decrement centralized counter in newproc/goexit,
 	// just to make runtime.NumGoroutine() faster.
 	// Compromise solution is to introduce per-P counters of active goroutines.
-	for(gp = runtime·allg; gp; gp = gp->alllink) {
+	for(i = 0; i < runtime·allglen; i++) {
+		gp = runtime·allg[i];
 		s = gp->status;
 		if(s == Grunnable || s == Grunning || s == Gsyscall || s == Gwaiting)
 			n++;
 	}
-	runtime·unlock(&runtime·sched);
+	runtime·unlock(&allglock);
 	return n;
 }
 
@@ -2032,25 +2166,30 @@ static struct {
 	uintptr pcbuf[100];
 } prof;
 
-static void
-System(void)
-{
-}
+static void System(void) {}
+static void ExternalCode(void) {}
+static void GC(void) {}
+extern byte etext[];
 
 // Called if we receive a SIGPROF signal.
 void
-runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp)
+runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp)
 {
 	int32 n;
 	bool traceback;
+	// Do not use global m in this function, use mp instead.
+	// On windows one m is sending reports about all the g's, so m means a wrong thing.
+	byte m;
+
+	m = 0;
+	USED(m);
 
 	if(prof.fn == nil || prof.hz == 0)
 		return;
-	traceback = true;
-	// Windows does profiling in a dedicated thread w/o m.
-	if(!Windows && (m == nil || m->mcache == nil))
-		traceback = false;
-	
+
+	// Profiling runs concurrently with GC, so it must not allocate.
+	mp->mallocing++;
+
 	// Define that a "user g" is a user-created goroutine, and a "system g"
 	// is one that is m->g0 or m->gsignal. We've only made sure that we
 	// can unwind user g's, so exclude the system g's.
@@ -2123,36 +2262,55 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp)
 	// To recap, there are no constraints on the assembly being used for the
 	// transition. We simply require that g and SP match and that the PC is not
 	// in runtime.gogo.
-	//
-	// On Windows, one m is sending reports about all the g's, so gp == m->curg
-	// is not a useful comparison. The profilem function in os_windows.c has
-	// already checked that gp is a user g.
-	if(gp == nil ||
-	   (!Windows && gp != m->curg) ||
+	traceback = true;
+	if(gp == nil || gp != mp->curg ||
 	   (uintptr)sp < gp->stackguard - StackGuard || gp->stackbase < (uintptr)sp ||
 	   ((uint8*)runtime·gogo <= pc && pc < (uint8*)runtime·gogo + RuntimeGogoBytes))
 		traceback = false;
 
-	// Race detector calls asmcgocall w/o entersyscall/exitsyscall,
-	// we can not currently unwind through asmcgocall.
-	if(m != nil && m->racecall)
-		traceback = false;
-
 	runtime·lock(&prof);
 	if(prof.fn == nil) {
 		runtime·unlock(&prof);
+		mp->mallocing--;
 		return;
 	}
 	n = 0;
 	if(traceback)
 		n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr, gp, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil, false);
 	if(!traceback || n <= 0) {
-		n = 2;
-		prof.pcbuf[0] = (uintptr)pc;
-		prof.pcbuf[1] = (uintptr)System + 1;
+		// Normal traceback is impossible or has failed.
+		// See if it falls into several common cases.
+		n = 0;
+		if(mp->ncgo > 0 && mp->curg != nil &&
+			mp->curg->syscallpc != 0 && mp->curg->syscallsp != 0) {
+			// Cgo, we can't unwind and symbolize arbitrary C code,
+			// so instead collect Go stack that leads to the cgo call.
+			// This is especially important on windows, since all syscalls are cgo calls.
+			n = runtime·gentraceback(mp->curg->syscallpc, mp->curg->syscallsp, 0, mp->curg, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil, false);
+		}
+#ifdef GOOS_windows
+		if(n == 0 && mp->libcallg != nil && mp->libcallpc != 0 && mp->libcallsp != 0) {
+			// Libcall, i.e. runtime syscall on windows.
+			// Collect Go stack that leads to the call.
+			n = runtime·gentraceback(mp->libcallpc, mp->libcallsp, 0, mp->libcallg, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil, false);
+		}
+#endif
+		if(n == 0) {
+			// If all of the above has failed, account it against abstract "System" or "GC".
+			n = 2;
+			// "ExternalCode" is better than "etext".
+			if((uintptr)pc > (uintptr)etext)
+				pc = (byte*)ExternalCode + PCQuantum;
+			prof.pcbuf[0] = (uintptr)pc;
+			if(mp->gcing || mp->helpgc)
+				prof.pcbuf[1] = (uintptr)GC + PCQuantum;
+			else
+				prof.pcbuf[1] = (uintptr)System + PCQuantum;
+		}
 	}
 	prof.fn(prof.pcbuf, n);
 	runtime·unlock(&prof);
+	mp->mallocing--;
 }
 
 // Arrange to call fn with a traceback hz times a second.
@@ -2195,6 +2353,7 @@ static void
 procresize(int32 new)
 {
 	int32 i, old;
+	bool empty;
 	G *gp;
 	P *p;
 
@@ -2216,27 +2375,42 @@ procresize(int32 new)
 			else
 				p->mcache = runtime·allocmcache();
 		}
-		if(p->runq == nil) {
-			p->runqsize = 128;
-			p->runq = (G**)runtime·mallocgc(p->runqsize*sizeof(G*), 0, FlagNoInvokeGC);
-		}
 	}
 
 	// redistribute runnable G's evenly
-	for(i = 0; i < old; i++) {
-		p = runtime·allp[i];
-		while(gp = runqget(p))
-			globrunqput(gp);
+	// collect all runnable goroutines in global queue preserving FIFO order
+	// FIFO order is required to ensure fairness even during frequent GCs
+	// see http://golang.org/issue/7126
+	empty = false;
+	while(!empty) {
+		empty = true;
+		for(i = 0; i < old; i++) {
+			p = runtime·allp[i];
+			if(p->runqhead == p->runqtail)
+				continue;
+			empty = false;
+			// pop from tail of local queue
+			p->runqtail--;
+			gp = p->runq[p->runqtail%nelem(p->runq)];
+			// push onto head of global queue
+			gp->schedlink = runtime·sched.runqhead;
+			runtime·sched.runqhead = gp;
+			if(runtime·sched.runqtail == nil)
+				runtime·sched.runqtail = gp;
+			runtime·sched.runqsize++;
+		}
 	}
+	// fill local queues with at most nelem(p->runq)/2 goroutines
 	// start at 1 because current M already executes some G and will acquire allp[0] below,
 	// so if we have a spare G we want to put it into allp[1].
-	for(i = 1; runtime·sched.runqhead; i++) {
+	for(i = 1; i < new * nelem(p->runq)/2 && runtime·sched.runqsize > 0; i++) {
 		gp = runtime·sched.runqhead;
 		runtime·sched.runqhead = gp->schedlink;
+		if(runtime·sched.runqhead == nil)
+			runtime·sched.runqtail = nil;
+		runtime·sched.runqsize--;
 		runqput(runtime·allp[i%new], gp);
 	}
-	runtime·sched.runqtail = nil;
-	runtime·sched.runqsize = 0;
 
 	// free unused P's
 	for(i = new; i < old; i++) {
@@ -2318,30 +2492,41 @@ checkdead(void)
 {
 	G *gp;
 	int32 run, grunning, s;
+	uintptr i;
 
 	// -1 for sysmon
 	run = runtime·sched.mcount - runtime·sched.nmidle - runtime·sched.nmidlelocked - 1;
 	if(run > 0)
 		return;
+	// If we are dying because of a signal caught on an already idle thread,
+	// freezetheworld will cause all running threads to block.
+	// And runtime will essentially enter into deadlock state,
+	// except that there is a thread that will call runtime·exit soon.
+	if(runtime·panicking > 0)
+		return;
 	if(run < 0) {
-		runtime·printf("checkdead: nmidle=%d nmidlelocked=%d mcount=%d\n",
+		runtime·printf("runtime: checkdead: nmidle=%d nmidlelocked=%d mcount=%d\n",
 			runtime·sched.nmidle, runtime·sched.nmidlelocked, runtime·sched.mcount);
 		runtime·throw("checkdead: inconsistent counts");
 	}
 	grunning = 0;
-	for(gp = runtime·allg; gp; gp = gp->alllink) {
+	runtime·lock(&allglock);
+	for(i = 0; i < runtime·allglen; i++) {
+		gp = runtime·allg[i];
 		if(gp->isbackground)
 			continue;
 		s = gp->status;
 		if(s == Gwaiting)
 			grunning++;
 		else if(s == Grunnable || s == Grunning || s == Gsyscall) {
-			runtime·printf("checkdead: find g %D in status %d\n", gp->goid, s);
+			runtime·unlock(&allglock);
+			runtime·printf("runtime: checkdead: find g %D in status %d\n", gp->goid, s);
 			runtime·throw("checkdead: runnable g");
 		}
 	}
+	runtime·unlock(&allglock);
 	if(grunning == 0)  // possible if main goroutine calls runtime·Goexit()
-		runtime·exit(0);
+		runtime·throw("no goroutines (main called runtime.Goexit) - deadlock!");
 	m->throwing = -1;  // do not dump full stacks
 	runtime·throw("all goroutines are asleep - deadlock!");
 }
@@ -2418,6 +2603,7 @@ struct Pdesc
 	uint32	syscalltick;
 	int64	syscallwhen;
 };
+#pragma dataflag NOPTR
 static Pdesc pdesc[MaxGomaxprocs];
 
 static uint32
@@ -2436,16 +2622,19 @@ retake(int64 now)
 		pd = &pdesc[i];
 		s = p->status;
 		if(s == Psyscall) {
-			// Retake P from syscall if it's there for more than 1 sysmon tick (20us).
-			// But only if there is other work to do.
+			// Retake P from syscall if it's there for more than 1 sysmon tick (at least 20us).
 			t = p->syscalltick;
 			if(pd->syscalltick != t) {
 				pd->syscalltick = t;
 				pd->syscallwhen = now;
 				continue;
 			}
+			// On the one hand we don't want to retake Ps if there is no other work to do,
+			// but on the other hand we want to retake them eventually
+			// because they can prevent the sysmon thread from deep sleep.
 			if(p->runqhead == p->runqtail &&
-				runtime·atomicload(&runtime·sched.nmspinning) + runtime·atomicload(&runtime·sched.npidle) > 0)
+				runtime·atomicload(&runtime·sched.nmspinning) + runtime·atomicload(&runtime·sched.npidle) > 0 &&
+				pd->syscallwhen + 10*1000*1000 > now)
 				continue;
 			// Need to decrement number of idle locked M's
 			// (pretending that one more is running) before the CAS.
@@ -2525,7 +2714,8 @@ runtime·schedtrace(bool detailed)
 	static int64 starttime;
 	int64 now;
 	int64 id1, id2, id3;
-	int32 i, q, t, h, s;
+	int32 i, t, h;
+	uintptr gi;
 	int8 *fmt;
 	M *mp, *lockedm;
 	G *gp, *lockedg;
@@ -2552,15 +2742,11 @@ runtime·schedtrace(bool detailed)
 		if(p == nil)
 			continue;
 		mp = p->m;
-		t = p->runqtail;
-		h = p->runqhead;
-		s = p->runqsize;
-		q = t - h;
-		if(q < 0)
-			q += s;
+		h = runtime·atomicload(&p->runqhead);
+		t = runtime·atomicload(&p->runqtail);
 		if(detailed)
-			runtime·printf("  P%d: status=%d schedtick=%d syscalltick=%d m=%d runqsize=%d/%d gfreecnt=%d\n",
-				i, p->status, p->schedtick, p->syscalltick, mp ? mp->id : -1, q, s, p->gfreecnt);
+			runtime·printf("  P%d: status=%d schedtick=%d syscalltick=%d m=%d runqsize=%d gfreecnt=%d\n",
+				i, p->status, p->schedtick, p->syscalltick, mp ? mp->id : -1, t-h, p->gfreecnt);
 		else {
 			// In non-detailed mode format lengths of per-P run queues as:
 			// [len1 len2 len3 len4]
@@ -2571,7 +2757,7 @@ runtime·schedtrace(bool detailed)
 				fmt = " [%d";
 			else if(i == runtime·gomaxprocs-1)
 				fmt = " %d]\n";
-			runtime·printf(fmt, q);
+			runtime·printf(fmt, t-h);
 		}
 	}
 	if(!detailed) {
@@ -2592,18 +2778,21 @@ runtime·schedtrace(bool detailed)
 		if(lockedg)
 			id3 = lockedg->goid;
 		runtime·printf("  M%d: p=%D curg=%D mallocing=%d throwing=%d gcing=%d"
-			" locks=%d dying=%d helpgc=%d spinning=%d lockedg=%D\n",
+			" locks=%d dying=%d helpgc=%d spinning=%d blocked=%d lockedg=%D\n",
 			mp->id, id1, id2,
 			mp->mallocing, mp->throwing, mp->gcing, mp->locks, mp->dying, mp->helpgc,
-			mp->spinning, id3);
+			mp->spinning, m->blocked, id3);
 	}
-	for(gp = runtime·allg; gp; gp = gp->alllink) {
+	runtime·lock(&allglock);
+	for(gi = 0; gi < runtime·allglen; gi++) {
+		gp = runtime·allg[gi];
 		mp = gp->m;
 		lockedm = gp->lockedm;
 		runtime·printf("  G%D: status=%d(%s) m=%d lockedm=%d\n",
 			gp->goid, gp->status, gp->waitreason, mp ? mp->id : -1,
 			lockedm ? lockedm->id : -1);
 	}
+	runtime·unlock(&allglock);
 	runtime·unlock(&runtime·sched);
 }
 
@@ -2646,6 +2835,20 @@ globrunqput(G *gp)
 	runtime·sched.runqsize++;
 }
 
+// Put a batch of runnable goroutines on the global runnable queue.
+// Sched must be locked.
+static void
+globrunqputbatch(G *ghead, G *gtail, int32 n)
+{
+	gtail->schedlink = nil;
+	if(runtime·sched.runqtail)
+		runtime·sched.runqtail->schedlink = ghead;
+	else
+		runtime·sched.runqhead = ghead;
+	runtime·sched.runqtail = gtail;
+	runtime·sched.runqsize += n;
+}
+
 // Try get a batch of G's from the global runnable queue.
 // Sched must be locked.
 static G*
@@ -2661,6 +2864,8 @@ globrunqget(P *p, int32 max)
 		n = runtime·sched.runqsize;
 	if(max > 0 && n > max)
 		n = max;
+	if(n > nelem(p->runq)/2)
+		n = nelem(p->runq)/2;
 	runtime·sched.runqsize -= n;
 	if(runtime·sched.runqsize == 0)
 		runtime·sched.runqtail = nil;
@@ -2700,78 +2905,98 @@ pidleget(void)
 	return p;
 }
 
-// Put g on local runnable queue.
-// TODO(dvyukov): consider using lock-free queue.
+// Try to put g on local runnable queue.
+// If it's full, put onto global queue.
+// Executed only by the owner P.
 static void
 runqput(P *p, G *gp)
 {
-	int32 h, t, s;
+	uint32 h, t;
 
-	runtime·lock(p);
 retry:
-	h = p->runqhead;
+	h = runtime·atomicload(&p->runqhead);  // load-acquire, synchronize with consumers
 	t = p->runqtail;
-	s = p->runqsize;
-	if(t == h-1 || (h == 0 && t == s-1)) {
-		runqgrow(p);
-		goto retry;
+	if(t - h < nelem(p->runq)) {
+		p->runq[t%nelem(p->runq)] = gp;
+		runtime·atomicstore(&p->runqtail, t+1);  // store-release, makes the item available for consumption
+		return;
 	}
-	p->runq[t++] = gp;
-	if(t == s)
-		t = 0;
-	p->runqtail = t;
-	runtime·unlock(p);
+	if(runqputslow(p, gp, h, t))
+		return;
+	// the queue is not full, now the put above must suceed
+	goto retry;
+}
+
+// Put g and a batch of work from local runnable queue on global queue.
+// Executed only by the owner P.
+static bool
+runqputslow(P *p, G *gp, uint32 h, uint32 t)
+{
+	G *batch[nelem(p->runq)/2+1];
+	uint32 n, i;
+
+	// First, grab a batch from local queue.
+	n = t-h;
+	n = n/2;
+	if(n != nelem(p->runq)/2)
+		runtime·throw("runqputslow: queue is not full");
+	for(i=0; i<n; i++)
+		batch[i] = p->runq[(h+i)%nelem(p->runq)];
+	if(!runtime·cas(&p->runqhead, h, h+n))  // cas-release, commits consume
+		return false;
+	batch[n] = gp;
+	// Link the goroutines.
+	for(i=0; i<n; i++)
+		batch[i]->schedlink = batch[i+1];
+	// Now put the batch on global queue.
+	runtime·lock(&runtime·sched);
+	globrunqputbatch(batch[0], batch[n], n+1);
+	runtime·unlock(&runtime·sched);
+	return true;
 }
 
 // Get g from local runnable queue.
+// Executed only by the owner P.
 static G*
 runqget(P *p)
 {
 	G *gp;
-	int32 t, h, s;
+	uint32 t, h;
 
-	if(p->runqhead == p->runqtail)
-		return nil;
-	runtime·lock(p);
-	h = p->runqhead;
-	t = p->runqtail;
-	s = p->runqsize;
-	if(t == h) {
-		runtime·unlock(p);
-		return nil;
+	for(;;) {
+		h = runtime·atomicload(&p->runqhead);  // load-acquire, synchronize with other consumers
+		t = p->runqtail;
+		if(t == h)
+			return nil;
+		gp = p->runq[h%nelem(p->runq)];
+		if(runtime·cas(&p->runqhead, h, h+1))  // cas-release, commits consume
+			return gp;
 	}
-	gp = p->runq[h++];
-	if(h == s)
-		h = 0;
-	p->runqhead = h;
-	runtime·unlock(p);
-	return gp;
 }
 
-// Grow local runnable queue.
-// TODO(dvyukov): consider using fixed-size array
-// and transfer excess to the global list (local queue can grow way too big).
-static void
-runqgrow(P *p)
+// Grabs a batch of goroutines from local runnable queue.
+// batch array must be of size nelem(p->runq)/2. Returns number of grabbed goroutines.
+// Can be executed by any P.
+static uint32
+runqgrab(P *p, G **batch)
 {
-	G **q;
-	int32 s, t, h, t2;
+	uint32 t, h, n, i;
 
-	h = p->runqhead;
-	t = p->runqtail;
-	s = p->runqsize;
-	t2 = 0;
-	q = runtime·malloc(2*s*sizeof(*q));
-	while(t != h) {
-		q[t2++] = p->runq[h++];
-		if(h == s)
-			h = 0;
+	for(;;) {
+		h = runtime·atomicload(&p->runqhead);  // load-acquire, synchronize with other consumers
+		t = runtime·atomicload(&p->runqtail);  // load-acquire, synchronize with the producer
+		n = t-h;
+		n = n - n/2;
+		if(n == 0)
+			break;
+		if(n > nelem(p->runq)/2)  // read inconsistent h and t
+			continue;
+		for(i=0; i<n; i++)
+			batch[i] = p->runq[(h+i)%nelem(p->runq)];
+		if(runtime·cas(&p->runqhead, h, h+n))  // cas-release, commits consume
+			break;
 	}
-	runtime·free(p->runq);
-	p->runq = q;
-	p->runqhead = 0;
-	p->runqtail = t2;
-	p->runqsize = 2*s;
+	return n;
 }
 
 // Steal half of elements from local runnable queue of p2
@@ -2780,57 +3005,24 @@ runqgrow(P *p)
 static G*
 runqsteal(P *p, P *p2)
 {
-	G *gp, *gp1;
-	int32 t, h, s, t2, h2, s2, c, i;
+	G *gp;
+	G *batch[nelem(p->runq)/2];
+	uint32 t, h, n, i;
 
-	if(p2->runqhead == p2->runqtail)
+	n = runqgrab(p2, batch);
+	if(n == 0)
 		return nil;
-	// sort locks to prevent deadlocks
-	if(p < p2)
-		runtime·lock(p);
-	runtime·lock(p2);
-	if(p2->runqhead == p2->runqtail) {
-		runtime·unlock(p2);
-		if(p < p2)
-			runtime·unlock(p);
-		return nil;
-	}
-	if(p >= p2)
-		runtime·lock(p);
-	// now we've locked both queues and know the victim is not empty
-	h = p->runqhead;
+	n--;
+	gp = batch[n];
+	if(n == 0)
+		return gp;
+	h = runtime·atomicload(&p->runqhead);  // load-acquire, synchronize with consumers
 	t = p->runqtail;
-	s = p->runqsize;
-	h2 = p2->runqhead;
-	t2 = p2->runqtail;
-	s2 = p2->runqsize;
-	gp = p2->runq[h2++];  // return value
-	if(h2 == s2)
-		h2 = 0;
-	// steal roughly half
-	if(t2 > h2)
-		c = (t2 - h2) / 2;
-	else
-		c = (s2 - h2 + t2) / 2;
-	// copy
-	for(i = 0; i != c; i++) {
-		// the target queue is full?
-		if(t == h-1 || (h == 0 && t == s-1))
-			break;
-		// the victim queue is empty?
-		if(t2 == h2)
-			break;
-		gp1 = p2->runq[h2++];
-		if(h2 == s2)
-			h2 = 0;
-		p->runq[t++] = gp1;
-		if(t == s)
-			t = 0;
-	}
-	p->runqtail = t;
-	p2->runqhead = h2;
-	runtime·unlock(p2);
-	runtime·unlock(p);
+	if(t - h + n >= nelem(p->runq))
+		runtime·throw("runqsteal: runq overflow");
+	for(i=0; i<n; i++, t++)
+		p->runq[t%nelem(p->runq)] = batch[i];
+	runtime·atomicstore(&p->runqtail, t);  // store-release, makes the item available for consumption
 	return gp;
 }
 
@@ -2838,14 +3030,10 @@ void
 runtime·testSchedLocalQueue(void)
 {
 	P p;
-	G gs[1000];
+	G gs[nelem(p.runq)];
 	int32 i, j;
 
 	runtime·memclr((byte*)&p, sizeof(p));
-	p.runqsize = 1;
-	p.runqhead = 0;
-	p.runqtail = 0;
-	p.runq = runtime·malloc(p.runqsize*sizeof(*p.runq));
 
 	for(i = 0; i < nelem(gs); i++) {
 		if(runqget(&p) != nil)
@@ -2867,20 +3055,11 @@ void
 runtime·testSchedLocalQueueSteal(void)
 {
 	P p1, p2;
-	G gs[1000], *gp;
+	G gs[nelem(p1.runq)], *gp;
 	int32 i, j, s;
 
 	runtime·memclr((byte*)&p1, sizeof(p1));
-	p1.runqsize = 1;
-	p1.runqhead = 0;
-	p1.runqtail = 0;
-	p1.runq = runtime·malloc(p1.runqsize*sizeof(*p1.runq));
-
 	runtime·memclr((byte*)&p2, sizeof(p2));
-	p2.runqsize = nelem(gs);
-	p2.runqhead = 0;
-	p2.runqtail = 0;
-	p2.runq = runtime·malloc(p2.runqsize*sizeof(*p2.runq));
 
 	for(i = 0; i < nelem(gs); i++) {
 		for(j = 0; j < i; j++) {
@@ -2914,6 +3093,7 @@ runtime·testSchedLocalQueueSteal(void)
 }
 
 extern void runtime·morestack(void);
+uintptr runtime·externalthreadhandlerp;
 
 // Does f mark the top of a goroutine stack?
 bool
@@ -2924,18 +3104,21 @@ runtime·topofstack(Func *f)
 		f->entry == (uintptr)runtime·mcall ||
 		f->entry == (uintptr)runtime·morestack ||
 		f->entry == (uintptr)runtime·lessstack ||
-		f->entry == (uintptr)_rt0_go;
+		f->entry == (uintptr)_rt0_go ||
+		(runtime·externalthreadhandlerp != 0 && f->entry == runtime·externalthreadhandlerp);
 }
 
-void
-runtime∕debug·setMaxThreads(intgo in, intgo out)
+int32
+runtime·setmaxthreads(int32 in)
 {
+	int32 out;
+
 	runtime·lock(&runtime·sched);
 	out = runtime·sched.maxmcount;
 	runtime·sched.maxmcount = in;
 	checkmcount();
 	runtime·unlock(&runtime·sched);
-	FLUSH(&out);
+	return out;
 }
 
 static int8 experiment[] = GOEXPERIMENT; // defined in zaexperiment.h
diff --git a/src/pkg/runtime/proc.p b/src/pkg/runtime/proc.p
deleted file mode 100644
index f0b46de..0000000
--- a/src/pkg/runtime/proc.p
+++ /dev/null
@@ -1,526 +0,0 @@
-// 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.
-
-/*
-model for proc.c as of 2011/07/22.
-
-takes 4900 seconds to explore 1189070 states
-with G=3, var_gomaxprocs=1
-on a Core i7 L640 2.13 GHz Lenovo X201s.
-
-rm -f proc.p.trail pan.* pan
-spin -a proc.p
-gcc -DSAFETY -DREACH -DMEMLIM'='4000 -o pan pan.c
-pan -w28 -n -i -m500000
-test -f proc.p.trail && pan -r proc.p.trail
-*/
-
-/*
- * scheduling parameters
- */
-
-/*
- * the number of goroutines G doubles as the maximum
- * number of OS threads; the max is reachable when all
- * the goroutines are blocked in system calls.
- */
-#define G 3
-
-/*
- * whether to allow gomaxprocs to vary during execution.
- * enabling this checks the scheduler even when code is
- * calling GOMAXPROCS, but it also slows down the verification
- * by about 10x.
- */
-#define var_gomaxprocs 1  /* allow gomaxprocs to vary */
-
-/* gomaxprocs */
-#if var_gomaxprocs
-byte gomaxprocs = 3;
-#else
-#define gomaxprocs 3
-#endif
-
-/* queue of waiting M's: sched_mhead[:mwait] */
-byte mwait;
-byte sched_mhead[G];
-
-/* garbage collector state */
-bit gc_lock, gcwaiting;
-
-/* goroutines sleeping, waiting to run */
-byte gsleep, gwait;
-
-/* scheduler state */
-bit sched_lock;
-bit sched_stopped;
-bit atomic_gwaiting, atomic_waitstop;
-byte atomic_mcpu, atomic_mcpumax;
-
-/* M struct fields - state for handing off g to m. */
-bit m_waitnextg[G];
-bit m_havenextg[G];
-bit m_nextg[G];
-
-/*
- * opt_atomic/opt_dstep mark atomic/deterministics
- * sequences that are marked only for reasons of
- * optimization, not for correctness of the algorithms.
- *
- * in general any code that runs while holding the
- * schedlock and does not refer to or modify the atomic_*
- * fields can be marked atomic/dstep without affecting
- * the usefulness of the model.  since we trust the lock
- * implementation, what we really want to test is the
- * interleaving of the atomic fast paths with entersyscall
- * and exitsyscall.
- */
-#define opt_atomic atomic
-#define opt_dstep d_step
-
-/* locks */
-inline lock(x) {
-	d_step { x == 0; x = 1 }
-}
-
-inline unlock(x) {
-	d_step { assert x == 1; x = 0 }
-}
-
-/* notes */
-inline noteclear(x) {
-	x = 0
-}
-
-inline notesleep(x) {
-	x == 1
-}
-
-inline notewakeup(x) {
-	opt_dstep { assert x == 0; x = 1 }
-}
-
-/*
- * scheduler
- */
-inline schedlock() {
-	lock(sched_lock)
-}
-
-inline schedunlock() {
-	unlock(sched_lock)
-}
-
-/*
- * canaddmcpu is like the C function but takes
- * an extra argument to include in the test, to model
- * "cannget() && canaddmcpu()" as "canaddmcpu(cangget())"
- */
-inline canaddmcpu(g) {
-	d_step {
-		g && atomic_mcpu < atomic_mcpumax;
-		atomic_mcpu++;
-	}
-}
-
-/*
- * gput is like the C function.
- * instead of tracking goroutines explicitly we
- * maintain only the count of the number of
- * waiting goroutines.
- */
-inline gput() {
-	/* omitted: lockedm, idlem concerns */
-	opt_dstep {
-		gwait++;
-		if
-		:: gwait == 1 ->
-			atomic_gwaiting = 1
-		:: else
-		fi
-	}
-}
-
-/*
- * cangget is a macro so it can be passed to
- * canaddmcpu (see above).
- */
-#define cangget()  (gwait>0)
-
-/*
- * gget is like the C function.
- */
-inline gget() {
-	opt_dstep {
-		assert gwait > 0;
-		gwait--;
-		if
-		:: gwait == 0 ->
-			atomic_gwaiting = 0
-		:: else
-		fi
-	}
-}
-
-/*
- * mput is like the C function.
- * here we do keep an explicit list of waiting M's,
- * so that we know which ones can be awakened.
- * we use _pid-1 because the monitor is proc 0.
- */
-inline mput() {
-	opt_dstep {
-		sched_mhead[mwait] = _pid - 1;
-		mwait++
-	}
-}
-
-/*
- * mnextg is like the C function mnextg(m, g).
- * it passes an unspecified goroutine to m to start running.
- */
-inline mnextg(m) {
-	opt_dstep {
-		m_nextg[m] = 1;
-		if
-		:: m_waitnextg[m] ->
-			m_waitnextg[m] = 0;
-			notewakeup(m_havenextg[m])
-		:: else
-		fi
-	}
-}
-
-/*
- * mgetnextg handles the main m handoff in matchmg.
- * it is like mget() || new M followed by mnextg(m, g),
- * but combined to avoid a local variable.
- * unlike the C code, a new M simply assumes it is
- * running a g instead of using the mnextg coordination
- * to obtain one.
- */
-inline mgetnextg() {
-	opt_atomic {
-		if
-		:: mwait > 0 ->
-			mwait--;
-			mnextg(sched_mhead[mwait]);
-			sched_mhead[mwait] = 0;
-		:: else ->
-			run mstart();
-		fi
-	}
-}
-
-/*
- * nextgandunlock is like the C function.
- * it pulls a g off the queue or else waits for one.
- */
-inline nextgandunlock() {
-	assert atomic_mcpu <= G;
-
-	if
-	:: m_nextg[_pid-1] ->
-		m_nextg[_pid-1] = 0;
-		schedunlock();
-	:: canaddmcpu(!m_nextg[_pid-1] && cangget()) ->
-		gget();
-		schedunlock();
-	:: else ->
-		opt_dstep {
-			mput();
-			m_nextg[_pid-1] = 0;
-			m_waitnextg[_pid-1] = 1;
-			noteclear(m_havenextg[_pid-1]);
-		}
-		if
-		:: atomic_waitstop && atomic_mcpu <= atomic_mcpumax ->
-			atomic_waitstop = 0;
-			notewakeup(sched_stopped)
-		:: else
-		fi;
-		schedunlock();
-		opt_dstep {
-			notesleep(m_havenextg[_pid-1]);
-			assert m_nextg[_pid-1];
-			m_nextg[_pid-1] = 0;
-		}
-	fi
-}
-
-/*
- * stoptheworld is like the C function.
- */
-inline stoptheworld() {
-	schedlock();
-	gcwaiting = 1;
-	atomic_mcpumax = 1;
-	do
-	:: d_step { atomic_mcpu > 1 ->
-		noteclear(sched_stopped);
-		assert !atomic_waitstop;
-		atomic_waitstop = 1 }
-		schedunlock();
-		notesleep(sched_stopped);
-		schedlock();
-	:: else ->
-		break
-	od;
-	schedunlock();
-}
-
-/*
- * starttheworld is like the C function.
- */
-inline starttheworld() {
-	schedlock();
-	gcwaiting = 0;
-	atomic_mcpumax = gomaxprocs;
-	matchmg();
-	schedunlock();
-}
-
-/*
- * matchmg is like the C function.
- */
-inline matchmg() {
-	do
-	:: canaddmcpu(cangget()) ->
-		gget();
-		mgetnextg();
-	:: else -> break
-	od
-}
-
-/*
- * ready is like the C function.
- * it puts a g on the run queue.
- */
-inline ready() {
-	schedlock();
-	gput()
-	matchmg()
-	schedunlock()
-}
-
-/*
- * schedule simulates the C scheduler.
- * it assumes that there is always a goroutine
- * running already, and the goroutine has entered
- * the scheduler for an unspecified reason,
- * either to yield or to block.
- */
-inline schedule() {
-	schedlock();
-
-	mustsched = 0;
-	atomic_mcpu--;
-	assert atomic_mcpu <= G;
-	if
-	:: skip ->
-		// goroutine yields, still runnable
-		gput();
-	:: gsleep+1 < G ->
-		// goroutine goes to sleep (but there is another that can wake it)
-		gsleep++
-	fi;
-
-	// Find goroutine to run.
-	nextgandunlock()
-}
-
-/*
- * schedpend is > 0 if a goroutine is about to committed to
- * entering the scheduler but has not yet done so.
- * Just as we don't test for the undesirable conditions when a
- * goroutine is in the scheduler, we don't test for them when
- * a goroutine will be in the scheduler shortly.
- * Modeling this state lets us replace mcpu cas loops with
- * simpler mcpu atomic adds.
- */
-byte schedpend;
-
-/*
- * entersyscall is like the C function.
- */
-inline entersyscall() {
-	bit willsched;
-
-	/*
-	 * Fast path.  Check all the conditions tested during schedlock/schedunlock
-	 * below, and if we can get through the whole thing without stopping, run it
-	 * in one atomic cas-based step.
-	 */
-	atomic {
-		atomic_mcpu--;
-		if
-		:: atomic_gwaiting ->
-			skip
-		:: atomic_waitstop && atomic_mcpu <= atomic_mcpumax ->
-			skip
-		:: else ->
-			goto Lreturn_entersyscall;
-		fi;
-		willsched = 1;
-		schedpend++;
-	}
-
-	/*
-	 * Normal path.
-	 */
-	schedlock()
-	opt_dstep {
-		if
-		:: willsched ->
-			schedpend--;
-			willsched = 0
-		:: else
-		fi
-	}
-	if
-	:: atomic_gwaiting ->
-		matchmg()
-	:: else
-	fi;
-	if
-	:: atomic_waitstop && atomic_mcpu <= atomic_mcpumax ->
-		atomic_waitstop = 0;
-		notewakeup(sched_stopped)
-	:: else
-	fi;
-	schedunlock();
-Lreturn_entersyscall:
-	skip
-}
-
-/*
- * exitsyscall is like the C function.
- */
-inline exitsyscall() {
-	/*
-	 * Fast path.  If there's a cpu available, use it.
-	 */
-	atomic {
-		// omitted profilehz check
-		atomic_mcpu++;
-		if
-		:: atomic_mcpu >= atomic_mcpumax ->
-			skip
-		:: else ->
-			goto Lreturn_exitsyscall
-		fi
-	}
-
-	/*
-	 * Normal path.
-	 */
-	schedlock();
-	d_step {
-		if
-		:: atomic_mcpu <= atomic_mcpumax ->
-			skip
-		:: else ->
-			mustsched = 1
-		fi
-	}
-	schedunlock()
-Lreturn_exitsyscall:
-	skip
-}
-
-#if var_gomaxprocs
-inline gomaxprocsfunc() {
-	schedlock();
-	opt_atomic {
-		if
-		:: gomaxprocs != 1 -> gomaxprocs = 1
-		:: gomaxprocs != 2 -> gomaxprocs = 2
-		:: gomaxprocs != 3 -> gomaxprocs = 3
-		fi;
-	}
-	if
-	:: gcwaiting != 0 ->
-		assert atomic_mcpumax == 1
-	:: else ->
-		atomic_mcpumax = gomaxprocs;
-		if
-		:: atomic_mcpu > gomaxprocs ->
-			mustsched = 1
-		:: else ->
-			matchmg()
-		fi
-	fi;
-	schedunlock();
-}
-#endif
-
-/*
- * mstart is the entry point for a new M.
- * our model of an M is always running some
- * unspecified goroutine.
- */
-proctype mstart() {
-	/*
-	 * mustsched is true if the goroutine must enter the
-	 * scheduler instead of continuing to execute.
-	 */
-	bit mustsched;
-
-	do
-	:: skip ->
-		// goroutine reschedules.
-		schedule()
-	:: !mustsched ->
-		// goroutine does something.
-		if
-		:: skip ->
-			// goroutine executes system call
-			entersyscall();
-			exitsyscall()
-		:: atomic { gsleep > 0; gsleep-- } ->
-			// goroutine wakes another goroutine
-			ready()
-		:: lock(gc_lock) ->
-			// goroutine runs a garbage collection
-			stoptheworld();
-			starttheworld();
-			unlock(gc_lock)
-#if var_gomaxprocs
-		:: skip ->
-			// goroutine picks a new gomaxprocs
-			gomaxprocsfunc()
-#endif
-		fi
-	od;
-
-	assert 0;
-}
-
-/*
- * monitor initializes the scheduler state
- * and then watches for impossible conditions.
- */
-active proctype monitor() {
-	opt_dstep {
-		byte i = 1;
-		do
-		:: i < G ->
-			gput();
-			i++
-		:: else -> break
-		od;
-		atomic_mcpu = 1;
-		atomic_mcpumax = 1;
-	}
-	run mstart();
-
-	do
-	// Should never have goroutines waiting with procs available.
-	:: !sched_lock && schedpend==0 && gwait > 0 && atomic_mcpu < atomic_mcpumax ->
-		assert 0
-	// Should never have gc waiting for stop if things have already stopped.
-	:: !sched_lock && schedpend==0 && atomic_waitstop && atomic_mcpu <= atomic_mcpumax ->
-		assert 0
-	od
-}
diff --git a/src/pkg/runtime/proc_test.go b/src/pkg/runtime/proc_test.go
index dd70ed9..5be3551 100644
--- a/src/pkg/runtime/proc_test.go
+++ b/src/pkg/runtime/proc_test.go
@@ -244,6 +244,49 @@ func TestPreemptionGC(t *testing.T) {
 	atomic.StoreUint32(&stop, 1)
 }
 
+func TestGCFairness(t *testing.T) {
+	output := executeTest(t, testGCFairnessSource, nil)
+	want := "OK\n"
+	if output != want {
+		t.Fatalf("want %s, got %s\n", want, output)
+	}
+}
+
+const testGCFairnessSource = `
+package main
+
+import (
+	"fmt"
+	"os"
+	"runtime"
+	"time"
+)
+
+func main() {
+	runtime.GOMAXPROCS(1)
+	f, err := os.Open("/dev/null")
+	if os.IsNotExist(err) {
+		// This test tests what it is intended to test only if writes are fast.
+		// If there is no /dev/null, we just don't execute the test.
+		fmt.Println("OK")
+		return
+	}
+	if err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+	for i := 0; i < 2; i++ {
+		go func() {
+			for {
+				f.Write([]byte("."))
+			}
+		}()
+	}
+	time.Sleep(10 * time.Millisecond)
+	fmt.Println("OK")
+}
+`
+
 func stackGrowthRecursive(i int) {
 	var pad [128]uint64
 	if i != 0 && pad[0] == 0 {
@@ -327,24 +370,11 @@ func TestSchedLocalQueueSteal(t *testing.T) {
 }
 
 func benchmarkStackGrowth(b *testing.B, rec int) {
-	const CallsPerSched = 1000
-	procs := runtime.GOMAXPROCS(-1)
-	N := int32(b.N / CallsPerSched)
-	c := make(chan bool, procs)
-	for p := 0; p < procs; p++ {
-		go func() {
-			for atomic.AddInt32(&N, -1) >= 0 {
-				runtime.Gosched()
-				for g := 0; g < CallsPerSched; g++ {
-					stackGrowthRecursive(rec)
-				}
-			}
-			c <- true
-		}()
-	}
-	for p := 0; p < procs; p++ {
-		<-c
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			stackGrowthRecursive(rec)
+		}
+	})
 }
 
 func BenchmarkStackGrowth(b *testing.B) {
diff --git a/src/pkg/runtime/race.c b/src/pkg/runtime/race.c
index 6ee55be..eb0be7f 100644
--- a/src/pkg/runtime/race.c
+++ b/src/pkg/runtime/race.c
@@ -9,178 +9,96 @@
 #include "arch_GOARCH.h"
 #include "malloc.h"
 #include "race.h"
-#include "../../cmd/ld/textflag.h"
-
-void runtime∕race·Initialize(uintptr *racectx);
-void runtime∕race·MapShadow(void *addr, uintptr size);
-void runtime∕race·Finalize(void);
-void runtime∕race·FinalizerGoroutine(uintptr racectx);
-void runtime∕race·Read(uintptr racectx, void *addr, void *pc);
-void runtime∕race·Write(uintptr racectx, void *addr, void *pc);
-void runtime∕race·ReadRange(uintptr racectx, void *addr, uintptr sz, void *pc);
-void runtime∕race·WriteRange(uintptr racectx, void *addr, uintptr sz, void *pc);
-void runtime∕race·FuncEnter(uintptr racectx, void *pc);
-void runtime∕race·FuncExit(uintptr racectx);
-void runtime∕race·Malloc(uintptr racectx, void *p, uintptr sz, void *pc);
-void runtime∕race·Free(void *p);
-void runtime∕race·GoStart(uintptr racectx, uintptr *chracectx, void *pc);
-void runtime∕race·GoEnd(uintptr racectx);
-void runtime∕race·Acquire(uintptr racectx, void *addr);
-void runtime∕race·Release(uintptr racectx, void *addr);
-void runtime∕race·ReleaseMerge(uintptr racectx, void *addr);
+#include "type.h"
+#include "typekind.h"
+
+// Race runtime functions called via runtime·racecall.
+void __tsan_init(void);
+void __tsan_fini(void);
+void __tsan_map_shadow(void);
+void __tsan_finalizer_goroutine(void);
+void __tsan_go_start(void);
+void __tsan_go_end(void);
+void __tsan_malloc(void);
+void __tsan_acquire(void);
+void __tsan_release(void);
+void __tsan_release_merge(void);
+
+// Mimic what cmd/cgo would do.
+#pragma cgo_import_static __tsan_init
+#pragma cgo_import_static __tsan_fini
+#pragma cgo_import_static __tsan_map_shadow
+#pragma cgo_import_static __tsan_finalizer_goroutine
+#pragma cgo_import_static __tsan_go_start
+#pragma cgo_import_static __tsan_go_end
+#pragma cgo_import_static __tsan_malloc
+#pragma cgo_import_static __tsan_acquire
+#pragma cgo_import_static __tsan_release
+#pragma cgo_import_static __tsan_release_merge
+
+// These are called from race_amd64.s.
+#pragma cgo_import_static __tsan_read
+#pragma cgo_import_static __tsan_read_pc
+#pragma cgo_import_static __tsan_read_range
+#pragma cgo_import_static __tsan_write
+#pragma cgo_import_static __tsan_write_pc
+#pragma cgo_import_static __tsan_write_range
+#pragma cgo_import_static __tsan_func_enter
+#pragma cgo_import_static __tsan_func_exit
 
 extern byte noptrdata[];
 extern byte enoptrbss[];
+  
+// start/end of heap for race_amd64.s
+uintptr runtime·racearenastart;
+uintptr runtime·racearenaend;
 
-static bool onstack(uintptr argp);
+void runtime·racefuncenter(void *callpc);
+void runtime·racefuncexit(void);
+void runtime·racereadrangepc1(void *addr, uintptr sz, void *pc);
+void runtime·racewriterangepc1(void *addr, uintptr sz, void *pc);
+void runtime·racesymbolizethunk(void*);
 
-// We set m->racecall around all calls into race library to trigger fast path in cgocall.
-// Also we increment m->locks to disable preemption and potential rescheduling
-// to ensure that we reset m->racecall on the correct m.
+// racecall allows calling an arbitrary function f from C race runtime
+// with up to 4 uintptr arguments.
+void runtime·racecall(void(*f)(void), ...);
 
 uintptr
 runtime·raceinit(void)
 {
 	uintptr racectx, start, size;
 
-	m->racecall = true;
-	m->locks++;
-	runtime∕race·Initialize(&racectx);
+	// cgo is required to initialize libc, which is used by race runtime
+	if(!runtime·iscgo)
+		runtime·throw("raceinit: race build must use cgo");
+	runtime·racecall(__tsan_init, &racectx, runtime·racesymbolizethunk);
 	// Round data segment to page boundaries, because it's used in mmap().
 	start = (uintptr)noptrdata & ~(PageSize-1);
 	size = ROUND((uintptr)enoptrbss - start, PageSize);
-	runtime∕race·MapShadow((void*)start, size);
-	m->locks--;
-	m->racecall = false;
+	runtime·racecall(__tsan_map_shadow, start, size);
 	return racectx;
 }
 
 void
 runtime·racefini(void)
 {
-	m->racecall = true;
-	m->locks++;
-	runtime∕race·Finalize();
-	m->locks--;
-	m->racecall = false;
+	runtime·racecall(__tsan_fini);
 }
 
 void
 runtime·racemapshadow(void *addr, uintptr size)
 {
-	m->racecall = true;
-	m->locks++;
-	runtime∕race·MapShadow(addr, size);
-	m->locks--;
-	m->racecall = false;
-}
-
-// Called from instrumented code.
-// If we split stack, getcallerpc() can return runtime·lessstack().
-#pragma textflag NOSPLIT
-void
-runtime·racewrite(uintptr addr)
-{
-	if(!onstack(addr)) {
-		m->racecall = true;
-		m->locks++;
-		runtime∕race·Write(g->racectx, (void*)addr, runtime·getcallerpc(&addr));
-		m->locks--;
-		m->racecall = false;
-	}
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racewriterange(uintptr addr, uintptr sz)
-{
-	if(!onstack(addr)) {
-		m->racecall = true;
-		m->locks++;
-		runtime∕race·WriteRange(g->racectx, (void*)addr, sz, runtime·getcallerpc(&addr));
-		m->locks--;
-		m->racecall = false;
-	}
-}
-
-// Called from instrumented code.
-// If we split stack, getcallerpc() can return runtime·lessstack().
-#pragma textflag NOSPLIT
-void
-runtime·raceread(uintptr addr)
-{
-	if(!onstack(addr)) {
-		m->racecall = true;
-		m->locks++;
-		runtime∕race·Read(g->racectx, (void*)addr, runtime·getcallerpc(&addr));
-		m->locks--;
-		m->racecall = false;
-	}
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racereadrange(uintptr addr, uintptr sz)
-{
-	if(!onstack(addr)) {
-		m->racecall = true;
-		m->locks++;
-		runtime∕race·ReadRange(g->racectx, (void*)addr, sz, runtime·getcallerpc(&addr));
-		m->locks--;
-		m->racecall = false;
-	}
-}
-
-// Called from runtime·racefuncenter (assembly).
-#pragma textflag NOSPLIT
-void
-runtime·racefuncenter1(uintptr pc)
-{
-	// If the caller PC is lessstack, use slower runtime·callers
-	// to walk across the stack split to find the real caller.
-	if(pc == (uintptr)runtime·lessstack)
-		runtime·callers(2, &pc, 1);
-
-	m->racecall = true;
-	m->locks++;
-	runtime∕race·FuncEnter(g->racectx, (void*)pc);
-	m->locks--;
-	m->racecall = false;
-}
-
-// Called from instrumented code.
-#pragma textflag NOSPLIT
-void
-runtime·racefuncexit(void)
-{
-	m->racecall = true;
-	m->locks++;
-	runtime∕race·FuncExit(g->racectx);
-	m->locks--;
-	m->racecall = false;
+	if(runtime·racearenastart == 0)
+		runtime·racearenastart = (uintptr)addr;
+	if(runtime·racearenaend < (uintptr)addr+size)
+		runtime·racearenaend = (uintptr)addr+size;
+	runtime·racecall(__tsan_map_shadow, addr, size);
 }
 
 void
 runtime·racemalloc(void *p, uintptr sz)
 {
-	// use m->curg because runtime·stackalloc() is called from g0
-	if(m->curg == nil)
-		return;
-	m->racecall = true;
-	m->locks++;
-	runtime∕race·Malloc(m->curg->racectx, p, sz, /* unused pc */ 0);
-	m->locks--;
-	m->racecall = false;
-}
-
-void
-runtime·racefree(void *p)
-{
-	m->racecall = true;
-	m->locks++;
-	runtime∕race·Free(p);
-	m->locks--;
-	m->racecall = false;
+	runtime·racecall(__tsan_malloc, p, sz);
 }
 
 uintptr
@@ -188,96 +106,58 @@ runtime·racegostart(void *pc)
 {
 	uintptr racectx;
 
-	m->racecall = true;
-	m->locks++;
-	runtime∕race·GoStart(g->racectx, &racectx, pc);
-	m->locks--;
-	m->racecall = false;
+	runtime·racecall(__tsan_go_start, g->racectx, &racectx, pc);
 	return racectx;
 }
 
 void
 runtime·racegoend(void)
 {
-	m->racecall = true;
-	m->locks++;
-	runtime∕race·GoEnd(g->racectx);
-	m->locks--;
-	m->racecall = false;
-}
-
-static void
-memoryaccess(void *addr, uintptr callpc, uintptr pc, bool write)
-{
-	uintptr racectx;
-
-	if(!onstack((uintptr)addr)) {
-		m->racecall = true;
-		m->locks++;
-		racectx = g->racectx;
-		if(callpc) {
-			if(callpc == (uintptr)runtime·lessstack)
-				runtime·callers(3, &callpc, 1);
-			runtime∕race·FuncEnter(racectx, (void*)callpc);
-		}
-		if(write)
-			runtime∕race·Write(racectx, addr, (void*)pc);
-		else
-			runtime∕race·Read(racectx, addr, (void*)pc);
-		if(callpc)
-			runtime∕race·FuncExit(racectx);
-		m->locks--;
-		m->racecall = false;
-	}
+	runtime·racecall(__tsan_go_end, g->racectx);
 }
 
 void
-runtime·racewritepc(void *addr, void *callpc, void *pc)
+runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc)
 {
-	memoryaccess(addr, (uintptr)callpc, (uintptr)pc, true);
+	if(callpc != nil)
+		runtime·racefuncenter(callpc);
+	runtime·racewriterangepc1(addr, sz, pc);
+	if(callpc != nil)
+		runtime·racefuncexit();
 }
 
 void
-runtime·racereadpc(void *addr, void *callpc, void *pc)
+runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc)
 {
-	memoryaccess(addr, (uintptr)callpc, (uintptr)pc, false);
+	if(callpc != nil)
+		runtime·racefuncenter(callpc);
+	runtime·racereadrangepc1(addr, sz, pc);
+	if(callpc != nil)
+		runtime·racefuncexit();
 }
 
-static void
-rangeaccess(void *addr, uintptr size, uintptr callpc, uintptr pc, bool write)
+void
+runtime·racewriteobjectpc(void *addr, Type *t, void *callpc, void *pc)
 {
-	uintptr racectx;
+	uint8 kind;
 
-	if(!onstack((uintptr)addr)) {
-		m->racecall = true;
-		m->locks++;
-		racectx = g->racectx;
-		if(callpc) {
-			if(callpc == (uintptr)runtime·lessstack)
-				runtime·callers(3, &callpc, 1);
-			runtime∕race·FuncEnter(racectx, (void*)callpc);
-		}
-		if(write)
-			runtime∕race·WriteRange(racectx, addr, size, (void*)pc);
-		else
-			runtime∕race·ReadRange(racectx, addr, size, (void*)pc);
-		if(callpc)
-			runtime∕race·FuncExit(racectx);
-		m->locks--;
-		m->racecall = false;
-	}
+	kind = t->kind & ~KindNoPointers;
+	if(kind == KindArray || kind == KindStruct)
+		runtime·racewriterangepc(addr, t->size, callpc, pc);
+	else
+		runtime·racewritepc(addr, callpc, pc);
 }
 
 void
-runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc)
+runtime·racereadobjectpc(void *addr, Type *t, void *callpc, void *pc)
 {
-	rangeaccess(addr, sz, (uintptr)callpc, (uintptr)pc, true);
-}
+	uint8 kind;
 
-void
-runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc)
-{
-	rangeaccess(addr, sz, (uintptr)callpc, (uintptr)pc, false);
+	kind = t->kind & ~KindNoPointers;
+	if(kind == KindArray || kind == KindStruct)
+		runtime·racereadrangepc(addr, t->size, callpc, pc);
+	else
+		runtime·racereadpc(addr, callpc, pc);
 }
 
 void
@@ -291,11 +171,7 @@ runtime·raceacquireg(G *gp, void *addr)
 {
 	if(g->raceignore)
 		return;
-	m->racecall = true;
-	m->locks++;
-	runtime∕race·Acquire(gp->racectx, addr);
-	m->locks--;
-	m->racecall = false;
+	runtime·racecall(__tsan_acquire, gp->racectx, addr);
 }
 
 void
@@ -309,11 +185,7 @@ runtime·racereleaseg(G *gp, void *addr)
 {
 	if(g->raceignore)
 		return;
-	m->racecall = true;
-	m->locks++;
-	runtime∕race·Release(gp->racectx, addr);
-	m->locks--;
-	m->racecall = false;
+	runtime·racecall(__tsan_release, gp->racectx, addr);
 }
 
 void
@@ -327,21 +199,13 @@ runtime·racereleasemergeg(G *gp, void *addr)
 {
 	if(g->raceignore)
 		return;
-	m->racecall = true;
-	m->locks++;
-	runtime∕race·ReleaseMerge(gp->racectx, addr);
-	m->locks--;
-	m->racecall = false;
+	runtime·racecall(__tsan_release_merge, gp->racectx, addr);
 }
 
 void
 runtime·racefingo(void)
 {
-	m->racecall = true;
-	m->locks++;
-	runtime∕race·FinalizerGoroutine(g->racectx);
-	m->locks--;
-	m->racecall = false;
+	runtime·racecall(__tsan_finalizer_goroutine, g->racectx);
 }
 
 // func RaceAcquire(addr unsafe.Pointer)
@@ -379,38 +243,6 @@ runtime·RaceSemrelease(uint32 *s)
 	runtime·semrelease(s);
 }
 
-// func RaceRead(addr unsafe.Pointer)
-#pragma textflag NOSPLIT
-void
-runtime·RaceRead(void *addr)
-{
-	memoryaccess(addr, 0, (uintptr)runtime·getcallerpc(&addr), false);
-}
-
-// func RaceWrite(addr unsafe.Pointer)
-#pragma textflag NOSPLIT
-void
-runtime·RaceWrite(void *addr)
-{
-	memoryaccess(addr, 0, (uintptr)runtime·getcallerpc(&addr), true);
-}
-
-// func RaceReadRange(addr unsafe.Pointer, len int)
-#pragma textflag NOSPLIT
-void
-runtime·RaceReadRange(void *addr, intgo len)
-{
-	rangeaccess(addr, len, 0, (uintptr)runtime·getcallerpc(&addr), false);
-}
-
-// func RaceWriteRange(addr unsafe.Pointer, len int)
-#pragma textflag NOSPLIT
-void
-runtime·RaceWriteRange(void *addr, intgo len)
-{
-	rangeaccess(addr, len, 0, (uintptr)runtime·getcallerpc(&addr), true);
-}
-
 // func RaceDisable()
 void
 runtime·RaceDisable(void)
@@ -425,14 +257,36 @@ runtime·RaceEnable(void)
 	g->raceignore--;
 }
 
-static bool
-onstack(uintptr argp)
+typedef struct SymbolizeContext SymbolizeContext;
+struct SymbolizeContext
+{
+	uintptr	pc;
+	int8*	func;
+	int8*	file;
+	uintptr	line;
+	uintptr	off;
+	uintptr	res;
+};
+
+// Callback from C into Go, runs on g0.
+void
+runtime·racesymbolize(SymbolizeContext *ctx)
 {
-	// noptrdata, data, bss, noptrbss
-	// the layout is in ../../cmd/ld/data.c
-	if((byte*)argp >= noptrdata && (byte*)argp < enoptrbss)
-		return false;
-	if((byte*)argp >= runtime·mheap.arena_start && (byte*)argp < runtime·mheap.arena_used)
-		return false;
-	return true;
+	Func *f;
+	String file;
+
+	f = runtime·findfunc(ctx->pc);
+	if(f == nil) {
+		ctx->func = "??";
+		ctx->file = "-";
+		ctx->line = 0;
+		ctx->off = ctx->pc;
+		ctx->res = 1;
+		return;
+	}
+	ctx->func = runtime·funcname(f);
+	ctx->line = runtime·funcline(f, ctx->pc, &file);
+	ctx->file = (int8*)file.str;  // assume zero-terminated
+	ctx->off = ctx->pc - f->entry;
+	ctx->res = 1;
 }
diff --git a/src/pkg/runtime/race.h b/src/pkg/runtime/race.h
index f7aa99d..fee31e0 100644
--- a/src/pkg/runtime/race.h
+++ b/src/pkg/runtime/race.h
@@ -17,13 +17,14 @@ void	runtime·racefini(void);
 
 void	runtime·racemapshadow(void *addr, uintptr size);
 void	runtime·racemalloc(void *p, uintptr sz);
-void	runtime·racefree(void *p);
 uintptr	runtime·racegostart(void *pc);
 void	runtime·racegoend(void);
 void	runtime·racewritepc(void *addr, void *callpc, void *pc);
 void	runtime·racereadpc(void *addr, void *callpc, void *pc);
 void	runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc);
 void	runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc);
+void	runtime·racereadobjectpc(void *addr, Type *t, void *callpc, void *pc);
+void	runtime·racewriteobjectpc(void *addr, Type *t, void *callpc, void *pc);
 void	runtime·racefingo(void);
 void	runtime·raceacquire(void *addr);
 void	runtime·raceacquireg(G *gp, void *addr);
diff --git a/src/pkg/runtime/race/README b/src/pkg/runtime/race/README
index 0b73bd8..7856406 100644
--- a/src/pkg/runtime/race/README
+++ b/src/pkg/runtime/race/README
@@ -9,4 +9,4 @@ $ ./buildgo.sh
 
 Tested with gcc 4.6.1 and 4.7.0.  On Windows it's built with 64-bit MinGW.
 
-Current runtime is built on rev 191161.
+Current runtime is built on rev 203116.
diff --git a/src/pkg/runtime/race/race.go b/src/pkg/runtime/race/race.go
index 5b44bde..e53cacf 100644
--- a/src/pkg/runtime/race/race.go
+++ b/src/pkg/runtime/race/race.go
@@ -6,116 +6,10 @@
 
 package race
 
-/*
-void __tsan_init(void **racectx);
-void __tsan_fini(void);
-void __tsan_map_shadow(void *addr, void *size);
-void __tsan_go_start(void *racectx, void **chracectx, void *pc);
-void __tsan_go_end(void *racectx);
-void __tsan_read(void *racectx, void *addr, void *pc);
-void __tsan_write(void *racectx, void *addr, void *pc);
-void __tsan_read_range(void *racectx, void *addr, long sz, long step, void *pc);
-void __tsan_write_range(void *racectx, void *addr, long sz, long step, void *pc);
-void __tsan_func_enter(void *racectx, void *pc);
-void __tsan_func_exit(void *racectx);
-void __tsan_malloc(void *racectx, void *p, long sz, void *pc);
-void __tsan_free(void *p);
-void __tsan_acquire(void *racectx, void *addr);
-void __tsan_release(void *racectx, void *addr);
-void __tsan_release_merge(void *racectx, void *addr);
-void __tsan_finalizer_goroutine(void *racectx);
-*/
-import "C"
-
-import (
-	"runtime"
-	"unsafe"
-)
-
-func Initialize(racectx *uintptr) {
-	C.__tsan_init((*unsafe.Pointer)(unsafe.Pointer(racectx)))
-}
-
-func Finalize() {
-	C.__tsan_fini()
-}
-
-func MapShadow(addr, size uintptr) {
-	C.__tsan_map_shadow(unsafe.Pointer(addr), unsafe.Pointer(size))
-}
-
-func FinalizerGoroutine(racectx uintptr) {
-	C.__tsan_finalizer_goroutine(unsafe.Pointer(racectx))
-}
-
-func Read(racectx uintptr, addr, pc uintptr) {
-	C.__tsan_read(unsafe.Pointer(racectx), unsafe.Pointer(addr), unsafe.Pointer(pc))
-}
-
-func Write(racectx uintptr, addr, pc uintptr) {
-	C.__tsan_write(unsafe.Pointer(racectx), unsafe.Pointer(addr), unsafe.Pointer(pc))
-}
-
-func ReadRange(racectx uintptr, addr, sz, pc uintptr) {
-	C.__tsan_read_range(unsafe.Pointer(racectx), unsafe.Pointer(addr),
-		C.long(sz), 0 /*step is unused*/, unsafe.Pointer(pc))
-}
-
-func WriteRange(racectx uintptr, addr, sz, pc uintptr) {
-	C.__tsan_write_range(unsafe.Pointer(racectx), unsafe.Pointer(addr),
-		C.long(sz), 0 /*step is unused*/, unsafe.Pointer(pc))
-}
+// This file merely ensures that we link in runtime/cgo in race build,
+// this is turn ensures that runtime uses pthread_create to create threads.
+// The prebuilt race runtime lives in race_GOOS_GOARCH.syso.
+// Calls to the runtime are done directly from src/pkg/runtime/race.c.
 
-func FuncEnter(racectx uintptr, pc uintptr) {
-	C.__tsan_func_enter(unsafe.Pointer(racectx), unsafe.Pointer(pc))
-}
-
-func FuncExit(racectx uintptr) {
-	C.__tsan_func_exit(unsafe.Pointer(racectx))
-}
-
-func Malloc(racectx uintptr, p, sz, pc uintptr) {
-	C.__tsan_malloc(unsafe.Pointer(racectx), unsafe.Pointer(p), C.long(sz), unsafe.Pointer(pc))
-}
-
-func Free(p uintptr) {
-	C.__tsan_free(unsafe.Pointer(p))
-}
-
-func GoStart(racectx uintptr, chracectx *uintptr, pc uintptr) {
-	C.__tsan_go_start(unsafe.Pointer(racectx), (*unsafe.Pointer)(unsafe.Pointer(chracectx)), unsafe.Pointer(pc))
-}
-
-func GoEnd(racectx uintptr) {
-	C.__tsan_go_end(unsafe.Pointer(racectx))
-}
-
-func Acquire(racectx uintptr, addr uintptr) {
-	C.__tsan_acquire(unsafe.Pointer(racectx), unsafe.Pointer(addr))
-}
-
-func Release(racectx uintptr, addr uintptr) {
-	C.__tsan_release(unsafe.Pointer(racectx), unsafe.Pointer(addr))
-}
-
-func ReleaseMerge(racectx uintptr, addr uintptr) {
-	C.__tsan_release_merge(unsafe.Pointer(racectx), unsafe.Pointer(addr))
-}
-
-//export __tsan_symbolize
-func __tsan_symbolize(pc uintptr, fun, file **C.char, line, off *C.int) C.int {
-	f := runtime.FuncForPC(pc)
-	if f == nil {
-		*fun = C.CString("??")
-		*file = C.CString("-")
-		*line = 0
-		*off = C.int(pc)
-		return 1
-	}
-	fi, l := f.FileLine(pc)
-	*fun = C.CString(f.Name())
-	*file = C.CString(fi)
-	*line = C.int(l)
-	*off = C.int(pc - f.Entry())
-	return 1
-}
+// void __race_unused_func(void);
+import "C"
diff --git a/src/pkg/runtime/race/race_darwin_amd64.syso b/src/pkg/runtime/race/race_darwin_amd64.syso
index 96a43c9..249a878 100644
Binary files a/src/pkg/runtime/race/race_darwin_amd64.syso and b/src/pkg/runtime/race/race_darwin_amd64.syso differ
diff --git a/src/pkg/runtime/race/race_linux_amd64.syso b/src/pkg/runtime/race/race_linux_amd64.syso
index 50bde96..8120484 100644
Binary files a/src/pkg/runtime/race/race_linux_amd64.syso and b/src/pkg/runtime/race/race_linux_amd64.syso differ
diff --git a/src/pkg/runtime/race/race_test.go b/src/pkg/runtime/race/race_test.go
index 4776ae2..7e0ee86 100644
--- a/src/pkg/runtime/race/race_test.go
+++ b/src/pkg/runtime/race/race_test.go
@@ -44,7 +44,7 @@ func TestRace(t *testing.T) {
 	if err != nil {
 		t.Fatalf("Failed to run tests: %v\n%v", err, string(testOutput))
 	}
-	reader := bufio.NewReader(bytes.NewBuffer(testOutput))
+	reader := bufio.NewReader(bytes.NewReader(testOutput))
 
 	funcName := ""
 	var tsanLog []string
@@ -155,3 +155,18 @@ func runTests() ([]byte, error) {
 	cmd.Env = append(cmd.Env, `GORACE="suppress_equal_stacks=0 suppress_equal_addresses=0 exitcode=0"`)
 	return cmd.CombinedOutput()
 }
+
+func TestIssue8102(t *testing.T) {
+	// If this compiles with -race, the test passes.
+	type S struct {
+		x interface{}
+		i int
+	}
+	c := make(chan int)
+	a := [2]*int{}
+	for ; ; c <- *a[S{}.i] {
+		if t != nil {
+			break
+		}
+	}
+}
diff --git a/src/pkg/runtime/race/race_windows_amd64.syso b/src/pkg/runtime/race/race_windows_amd64.syso
index 46eb127..67db40f 100644
Binary files a/src/pkg/runtime/race/race_windows_amd64.syso and b/src/pkg/runtime/race/race_windows_amd64.syso differ
diff --git a/src/pkg/runtime/race/testdata/chan_test.go b/src/pkg/runtime/race/testdata/chan_test.go
index 614ba4a..4a3d529 100644
--- a/src/pkg/runtime/race/testdata/chan_test.go
+++ b/src/pkg/runtime/race/testdata/chan_test.go
@@ -347,6 +347,119 @@ func TestRaceChanSendSelectClose(t *testing.T) {
 	<-compl
 }
 
+func TestRaceSelectReadWriteAsync(t *testing.T) {
+	done := make(chan bool)
+	x := 0
+	c1 := make(chan int, 10)
+	c2 := make(chan int, 10)
+	c3 := make(chan int)
+	c2 <- 1
+	go func() {
+		select {
+		case c1 <- x: // read of x races with...
+		case c3 <- 1:
+		}
+		done <- true
+	}()
+	select {
+	case x = <-c2: // ... write to x here
+	case c3 <- 1:
+	}
+	<-done
+}
+
+func TestRaceSelectReadWriteSync(t *testing.T) {
+	done := make(chan bool)
+	x := 0
+	c1 := make(chan int)
+	c2 := make(chan int)
+	c3 := make(chan int)
+	// make c1 and c2 ready for communication
+	go func() {
+		<-c1
+	}()
+	go func() {
+		c2 <- 1
+	}()
+	go func() {
+		select {
+		case c1 <- x: // read of x races with...
+		case c3 <- 1:
+		}
+		done <- true
+	}()
+	select {
+	case x = <-c2: // ... write to x here
+	case c3 <- 1:
+	}
+	<-done
+}
+
+func TestNoRaceSelectReadWriteAsync(t *testing.T) {
+	done := make(chan bool)
+	x := 0
+	c1 := make(chan int)
+	c2 := make(chan int)
+	go func() {
+		select {
+		case c1 <- x: // read of x does not race with...
+		case c2 <- 1:
+		}
+		done <- true
+	}()
+	select {
+	case x = <-c1: // ... write to x here
+	case c2 <- 1:
+	}
+	<-done
+}
+
+func TestRaceChanReadWriteAsync(t *testing.T) {
+	done := make(chan bool)
+	c1 := make(chan int, 10)
+	c2 := make(chan int, 10)
+	c2 <- 10
+	x := 0
+	go func() {
+		c1 <- x // read of x races with...
+		done <- true
+	}()
+	x = <-c2 // ... write to x here
+	<-done
+}
+
+func TestRaceChanReadWriteSync(t *testing.T) {
+	done := make(chan bool)
+	c1 := make(chan int)
+	c2 := make(chan int)
+	// make c1 and c2 ready for communication
+	go func() {
+		<-c1
+	}()
+	go func() {
+		c2 <- 10
+	}()
+	x := 0
+	go func() {
+		c1 <- x // read of x races with...
+		done <- true
+	}()
+	x = <-c2 // ... write to x here
+	<-done
+}
+
+func TestNoRaceChanReadWriteAsync(t *testing.T) {
+	done := make(chan bool)
+	c1 := make(chan int, 10)
+	x := 0
+	go func() {
+		c1 <- x // read of x does not race with...
+		done <- true
+	}()
+	x = <-c1 // ... write to x here
+	<-done
+}
+
 func TestNoRaceProducerConsumerUnbuffered(t *testing.T) {
 	type Task struct {
 		f    func()
@@ -454,20 +567,6 @@ func TestRaceChanCloseLen(t *testing.T) {
 	v = 2
 }
 
-func TestRaceChanSameCell(t *testing.T) {
-	c := make(chan int, 1)
-	v := 0
-	go func() {
-		v = 1
-		c <- 42
-		<-c
-	}()
-	time.Sleep(1e7)
-	c <- 43
-	<-c
-	_ = v
-}
-
 func TestRaceChanCloseSend(t *testing.T) {
 	compl := make(chan bool, 1)
 	c := make(chan int, 10)
@@ -478,3 +577,83 @@ func TestRaceChanCloseSend(t *testing.T) {
 	c <- 0
 	<-compl
 }
+
+func TestNoRaceChanMutex(t *testing.T) {
+	done := make(chan struct{})
+	mtx := make(chan struct{}, 1)
+	data := 0
+	go func() {
+		mtx <- struct{}{}
+		data = 42
+		<-mtx
+		done <- struct{}{}
+	}()
+	mtx <- struct{}{}
+	data = 43
+	<-mtx
+	<-done
+}
+
+func TestNoRaceSelectMutex(t *testing.T) {
+	done := make(chan struct{})
+	mtx := make(chan struct{}, 1)
+	aux := make(chan bool)
+	data := 0
+	go func() {
+		select {
+		case mtx <- struct{}{}:
+		case <-aux:
+		}
+		data = 42
+		select {
+		case <-mtx:
+		case <-aux:
+		}
+		done <- struct{}{}
+	}()
+	select {
+	case mtx <- struct{}{}:
+	case <-aux:
+	}
+	data = 43
+	select {
+	case <-mtx:
+	case <-aux:
+	}
+	<-done
+}
+
+func TestRaceChanSem(t *testing.T) {
+	done := make(chan struct{})
+	mtx := make(chan bool, 2)
+	data := 0
+	go func() {
+		mtx <- true
+		data = 42
+		<-mtx
+		done <- struct{}{}
+	}()
+	mtx <- true
+	data = 43
+	<-mtx
+	<-done
+}
+
+func TestNoRaceChanWaitGroup(t *testing.T) {
+	const N = 10
+	chanWg := make(chan bool, N/2)
+	data := make([]int, N)
+	for i := 0; i < N; i++ {
+		chanWg <- true
+		go func(i int) {
+			data[i] = 42
+			<-chanWg
+		}(i)
+	}
+	for i := 0; i < cap(chanWg); i++ {
+		chanWg <- true
+	}
+	for i := 0; i < N; i++ {
+		_ = data[i]
+	}
+}
diff --git a/src/pkg/runtime/race/testdata/finalizer_test.go b/src/pkg/runtime/race/testdata/finalizer_test.go
index 2b26076..222cbf6 100644
--- a/src/pkg/runtime/race/testdata/finalizer_test.go
+++ b/src/pkg/runtime/race/testdata/finalizer_test.go
@@ -14,16 +14,16 @@ import (
 func TestNoRaceFin(t *testing.T) {
 	c := make(chan bool)
 	go func() {
-		x := new(int)
-		runtime.SetFinalizer(x, func(x *int) {
-			*x = 42
+		x := new(string)
+		runtime.SetFinalizer(x, func(x *string) {
+			*x = "foo"
 		})
-		*x = 66
+		*x = "bar"
 		c <- true
 	}()
 	<-c
 	runtime.GC()
-	time.Sleep(1e8)
+	time.Sleep(100 * time.Millisecond)
 }
 
 var finVar struct {
@@ -34,8 +34,8 @@ var finVar struct {
 func TestNoRaceFinGlobal(t *testing.T) {
 	c := make(chan bool)
 	go func() {
-		x := new(int)
-		runtime.SetFinalizer(x, func(x *int) {
+		x := new(string)
+		runtime.SetFinalizer(x, func(x *string) {
 			finVar.Lock()
 			finVar.cnt++
 			finVar.Unlock()
@@ -44,7 +44,7 @@ func TestNoRaceFinGlobal(t *testing.T) {
 	}()
 	<-c
 	runtime.GC()
-	time.Sleep(1e8)
+	time.Sleep(100 * time.Millisecond)
 	finVar.Lock()
 	finVar.cnt++
 	finVar.Unlock()
@@ -54,14 +54,14 @@ func TestRaceFin(t *testing.T) {
 	c := make(chan bool)
 	y := 0
 	go func() {
-		x := new(int)
-		runtime.SetFinalizer(x, func(x *int) {
+		x := new(string)
+		runtime.SetFinalizer(x, func(x *string) {
 			y = 42
 		})
 		c <- true
 	}()
 	<-c
 	runtime.GC()
-	time.Sleep(1e8)
+	time.Sleep(100 * time.Millisecond)
 	y = 66
 }
diff --git a/src/pkg/runtime/race/testdata/map_test.go b/src/pkg/runtime/race/testdata/map_test.go
index 35db8db..98e2a5f 100644
--- a/src/pkg/runtime/race/testdata/map_test.go
+++ b/src/pkg/runtime/race/testdata/map_test.go
@@ -159,3 +159,82 @@ func TestRaceMapVariable3(t *testing.T) {
 	m = make(map[int]int)
 	<-ch
 }
+
+type Big struct {
+	x [17]int32
+}
+
+func TestRaceMapLookupPartKey(t *testing.T) {
+	k := &Big{}
+	m := make(map[Big]bool)
+	ch := make(chan bool, 1)
+	go func() {
+		k.x[8] = 1
+		ch <- true
+	}()
+	_ = m[*k]
+	<-ch
+}
+
+func TestRaceMapLookupPartKey2(t *testing.T) {
+	k := &Big{}
+	m := make(map[Big]bool)
+	ch := make(chan bool, 1)
+	go func() {
+		k.x[8] = 1
+		ch <- true
+	}()
+	_, _ = m[*k]
+	<-ch
+}
+func TestRaceMapDeletePartKey(t *testing.T) {
+	k := &Big{}
+	m := make(map[Big]bool)
+	ch := make(chan bool, 1)
+	go func() {
+		k.x[8] = 1
+		ch <- true
+	}()
+	delete(m, *k)
+	<-ch
+}
+
+func TestRaceMapInsertPartKey(t *testing.T) {
+	k := &Big{}
+	m := make(map[Big]bool)
+	ch := make(chan bool, 1)
+	go func() {
+		k.x[8] = 1
+		ch <- true
+	}()
+	m[*k] = true
+	<-ch
+}
+
+func TestRaceMapInsertPartVal(t *testing.T) {
+	v := &Big{}
+	m := make(map[int]Big)
+	ch := make(chan bool, 1)
+	go func() {
+		v.x[8] = 1
+		ch <- true
+	}()
+	m[1] = *v
+	<-ch
+}
+
+// Test for issue 7561.
+func TestRaceMapAssignMultipleReturn(t *testing.T) {
+	connect := func() (int, error) { return 42, nil }
+	conns := make(map[int][]int)
+	conns[1] = []int{0}
+	ch := make(chan bool, 1)
+	var err error
+	go func() {
+		conns[1][0], err = connect()
+		ch <- true
+	}()
+	x := conns[1][0]
+	_ = x
+	<-ch
+}
diff --git a/src/pkg/runtime/race/testdata/mop_test.go b/src/pkg/runtime/race/testdata/mop_test.go
index b0b6656..14591b1 100644
--- a/src/pkg/runtime/race/testdata/mop_test.go
+++ b/src/pkg/runtime/race/testdata/mop_test.go
@@ -1933,3 +1933,25 @@ func TestRaceMethodThunk4(t *testing.T) {
 	*(*int)(d.Base) = 42
 	<-done
 }
+
+func TestNoRaceTinyAlloc(t *testing.T) {
+	const P = 4
+	const N = 1e6
+	var tinySink *byte
+	done := make(chan bool)
+	for p := 0; p < P; p++ {
+		go func() {
+			for i := 0; i < N; i++ {
+				var b byte
+				if b != 0 {
+					tinySink = &b // make it heap allocated
+				}
+				b = 42
+			}
+			done <- true
+		}()
+	}
+	for p := 0; p < P; p++ {
+		<-done
+	}
+}
diff --git a/src/pkg/runtime/race0.c b/src/pkg/runtime/race0.c
index b74b035..eddb0be 100644
--- a/src/pkg/runtime/race0.c
+++ b/src/pkg/runtime/race0.c
@@ -111,12 +111,6 @@ runtime·racemalloc(void *p, uintptr sz)
 	USED(sz);
 }
 
-void
-runtime·racefree(void *p)
-{
-	USED(p);
-}
-
 uintptr
 runtime·racegostart(void *pc)
 {
diff --git a/src/pkg/runtime/race_amd64.s b/src/pkg/runtime/race_amd64.s
index a33b77a..d60cf89 100644
--- a/src/pkg/runtime/race_amd64.s
+++ b/src/pkg/runtime/race_amd64.s
@@ -4,13 +4,241 @@
 
 // +build race
 
+#include "zasm_GOOS_GOARCH.h"
+#include "funcdata.h"
 #include "../../cmd/ld/textflag.h"
 
+// The following thunks allow calling the gcc-compiled race runtime directly
+// from Go code without going all the way through cgo.
+// First, it's much faster (up to 50% speedup for real Go programs).
+// Second, it eliminates race-related special cases from cgocall and scheduler.
+// Third, in long-term it will allow to remove cyclic runtime/race dependency on cmd/go.
+
+// A brief recap of the amd64 calling convention.
+// Arguments are passed in DI, SI, DX, CX, R8, R9, the rest is on stack.
+// Callee-saved registers are: BX, BP, R12-R15.
+// SP must be 16-byte aligned.
+// On Windows:
+// Arguments are passed in CX, DX, R8, R9, the rest is on stack.
+// Callee-saved registers are: BX, BP, DI, SI, R12-R15.
+// SP must be 16-byte aligned. Windows also requires "stack-backing" for the 4 register arguments:
+// http://msdn.microsoft.com/en-us/library/ms235286.aspx
+// We do not do this, because it seems to be intended for vararg/unprototyped functions.
+// Gcc-compiled race runtime does not try to use that space.
+
+#ifdef GOOS_windows
+#define RARG0 CX
+#define RARG1 DX
+#define RARG2 R8
+#define RARG3 R9
+#else
+#define RARG0 DI
+#define RARG1 SI
+#define RARG2 DX
+#define RARG3 CX
+#endif
+
+// func runtime·raceread(addr uintptr)
+// Called from instrumented code.
+TEXT	runtime·raceread(SB), NOSPLIT, $0-8
+	MOVQ	addr+0(FP), RARG1
+	MOVQ	(SP), RARG2
+	// void __tsan_read(ThreadState *thr, void *addr, void *pc);
+	MOVQ	$__tsan_read(SB), AX
+	JMP	racecalladdr<>(SB)
+
+// func runtime·RaceRead(addr uintptr)
+TEXT	runtime·RaceRead(SB), NOSPLIT, $0-8
+	// This needs to be a tail call, because raceread reads caller pc.
+	JMP	runtime·raceread(SB)
+
+// void runtime·racereadpc(void *addr, void *callpc, void *pc)
+TEXT	runtime·racereadpc(SB), NOSPLIT, $0-24
+	MOVQ	addr+0(FP), RARG1
+	MOVQ	callpc+8(FP), RARG2
+	MOVQ	pc+16(FP), RARG3
+	// void __tsan_read_pc(ThreadState *thr, void *addr, void *callpc, void *pc);
+	MOVQ	$__tsan_read_pc(SB), AX
+	JMP	racecalladdr<>(SB)
+
+// func runtime·racewrite(addr uintptr)
+// Called from instrumented code.
+TEXT	runtime·racewrite(SB), NOSPLIT, $0-8
+	MOVQ	addr+0(FP), RARG1
+	MOVQ	(SP), RARG2
+	// void __tsan_write(ThreadState *thr, void *addr, void *pc);
+	MOVQ	$__tsan_write(SB), AX
+	JMP	racecalladdr<>(SB)
+
+// func runtime·RaceWrite(addr uintptr)
+TEXT	runtime·RaceWrite(SB), NOSPLIT, $0-8
+	// This needs to be a tail call, because racewrite reads caller pc.
+	JMP	runtime·racewrite(SB)
+
+// void runtime·racewritepc(void *addr, void *callpc, void *pc)
+TEXT	runtime·racewritepc(SB), NOSPLIT, $0-24
+	MOVQ	addr+0(FP), RARG1
+	MOVQ	callpc+8(FP), RARG2
+	MOVQ	cp+16(FP), RARG3
+	// void __tsan_write_pc(ThreadState *thr, void *addr, void *callpc, void *pc);
+	MOVQ	$__tsan_write_pc(SB), AX
+	JMP	racecalladdr<>(SB)
+
+// func runtime·racereadrange(addr, size uintptr)
+// Called from instrumented code.
+TEXT	runtime·racereadrange(SB), NOSPLIT, $0-16
+	MOVQ	addr+0(FP), RARG1
+	MOVQ	size+8(FP), RARG2
+	MOVQ	(SP), RARG3
+	// void __tsan_read_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+	MOVQ	$__tsan_read_range(SB), AX
+	JMP	racecalladdr<>(SB)
+
+// func runtime·RaceReadRange(addr, size uintptr)
+TEXT	runtime·RaceReadRange(SB), NOSPLIT, $0-16
+	// This needs to be a tail call, because racereadrange reads caller pc.
+	JMP	runtime·racereadrange(SB)
+
+// void runtime·racereadrangepc1(void *addr, uintptr sz, void *pc)
+TEXT	runtime·racereadrangepc1(SB), NOSPLIT, $0-24
+	MOVQ	addr+0(FP), RARG1
+	MOVQ	size+8(FP), RARG2
+	MOVQ	pc+16(FP), RARG3
+	// void __tsan_read_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+	MOVQ	$__tsan_read_range(SB), AX
+	JMP	racecalladdr<>(SB)
+
+// func runtime·racewriterange(addr, size uintptr)
+// Called from instrumented code.
+TEXT	runtime·racewriterange(SB), NOSPLIT, $0-16
+	MOVQ	addr+0(FP), RARG1
+	MOVQ	size+8(FP), RARG2
+	MOVQ	(SP), RARG3
+	// void __tsan_write_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+	MOVQ	$__tsan_write_range(SB), AX
+	JMP	racecalladdr<>(SB)
+
+// func runtime·RaceWriteRange(addr, size uintptr)
+TEXT	runtime·RaceWriteRange(SB), NOSPLIT, $0-16
+	// This needs to be a tail call, because racewriterange reads caller pc.
+	JMP	runtime·racewriterange(SB)
+
+// void runtime·racewriterangepc1(void *addr, uintptr sz, void *pc)
+TEXT	runtime·racewriterangepc1(SB), NOSPLIT, $0-24
+	MOVQ	addr+0(FP), RARG1
+	MOVQ	size+8(FP), RARG2
+	MOVQ	pc+16(FP), RARG3
+	// void __tsan_write_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+	MOVQ	$__tsan_write_range(SB), AX
+	JMP	racecalladdr<>(SB)
+
+// If addr (RARG1) is out of range, do nothing.
+// Otherwise, setup goroutine context and invoke racecall. Other arguments already set.
+TEXT	racecalladdr<>(SB), NOSPLIT, $0-0
+	get_tls(R12)
+	MOVQ	g(R12), R14
+	MOVQ	g_racectx(R14), RARG0	// goroutine context
+	// Check that addr is within [arenastart, arenaend) or within [noptrdata, enoptrbss).
+	CMPQ	RARG1, runtime·racearenastart(SB)
+	JB	racecalladdr_data
+	CMPQ	RARG1, runtime·racearenaend(SB)
+	JB	racecalladdr_call
+racecalladdr_data:
+	CMPQ	RARG1, $noptrdata(SB)
+	JB	racecalladdr_ret
+	CMPQ	RARG1, $enoptrbss(SB)
+	JAE	racecalladdr_ret
+racecalladdr_call:
+	MOVQ	AX, AX		// w/o this 6a miscompiles this function
+	JMP	racecall<>(SB)
+racecalladdr_ret:
+	RET
+
 // func runtime·racefuncenter(pc uintptr)
-TEXT	runtime·racefuncenter(SB), NOSPLIT, $16-8
-	MOVQ	DX, saved-8(SP) // save function entry context (for closures)
-	MOVQ	pc+0(FP), DX
-	MOVQ	DX, arg-16(SP)
-	CALL	runtime·racefuncenter1(SB)
-	MOVQ	saved-8(SP), DX
+// Called from instrumented code.
+TEXT	runtime·racefuncenter(SB), NOSPLIT, $0-8
+	MOVQ	DX, R15		// save function entry context (for closures)
+	get_tls(R12)
+	MOVQ	g(R12), R14
+	MOVQ	g_racectx(R14), RARG0	// goroutine context
+	MOVQ	callpc+0(FP), RARG1
+	// void __tsan_func_enter(ThreadState *thr, void *pc);
+	MOVQ	$__tsan_func_enter(SB), AX
+	CALL	racecall<>(SB)
+	MOVQ	R15, DX	// restore function entry context
+	RET
+
+// func runtime·racefuncexit()
+// Called from instrumented code.
+TEXT	runtime·racefuncexit(SB), NOSPLIT, $0-0
+	get_tls(R12)
+	MOVQ	g(R12), R14
+	MOVQ	g_racectx(R14), RARG0	// goroutine context
+	// void __tsan_func_exit(ThreadState *thr);
+	MOVQ	$__tsan_func_exit(SB), AX
+	JMP	racecall<>(SB)
+
+// void runtime·racecall(void(*f)(...), ...)
+// Calls C function f from race runtime and passes up to 4 arguments to it.
+// The arguments are never heap-object-preserving pointers, so we pretend there are no arguments.
+TEXT	runtime·racecall(SB), NOSPLIT, $0-0
+	MOVQ	fn+0(FP), AX
+	MOVQ	arg0+8(FP), RARG0
+	MOVQ	arg1+16(FP), RARG1
+	MOVQ	arg2+24(FP), RARG2
+	MOVQ	arg3+32(FP), RARG3
+	JMP	racecall<>(SB)
+
+// Switches SP to g0 stack and calls (AX). Arguments already set.
+TEXT	racecall<>(SB), NOSPLIT, $0-0
+	get_tls(R12)
+	MOVQ	m(R12), R13
+	MOVQ	g(R12), R14
+	// Switch to g0 stack.
+	MOVQ	SP, R12		// callee-saved, preserved across the CALL
+	MOVQ	m_g0(R13), R10
+	CMPQ	R10, R14
+	JE	racecall_cont	// already on g0
+	MOVQ	(g_sched+gobuf_sp)(R10), SP
+racecall_cont:
+	ANDQ	$~15, SP	// alignment for gcc ABI
+	CALL	AX
+	MOVQ	R12, SP
+	RET
+
+// C->Go callback thunk that allows to call runtime·racesymbolize from C code.
+// Direct Go->C race call has only switched SP, finish g->g0 switch by setting correct g.
+// The overall effect of Go->C->Go call chain is similar to that of mcall.
+TEXT	runtime·racesymbolizethunk(SB), NOSPLIT, $56-8
+	// Save callee-saved registers (Go code won't respect that).
+	// This is superset of darwin/linux/windows registers.
+	PUSHQ	BX
+	PUSHQ	BP
+	PUSHQ	DI
+	PUSHQ	SI
+	PUSHQ	R12
+	PUSHQ	R13
+	PUSHQ	R14
+	PUSHQ	R15
+	// Set g = g0.
+	get_tls(R12)
+	MOVQ	m(R12), R13
+	MOVQ	m_g0(R13), R14
+	MOVQ	R14, g(R12)	// g = m->g0
+	MOVQ	RARG0, 0(SP)	// func arg
+	CALL	runtime·racesymbolize(SB)
+	// All registers are smashed after Go code, reload.
+	get_tls(R12)
+	MOVQ	m(R12), R13
+	MOVQ	m_curg(R13), R14
+	MOVQ	R14, g(R12)	// g = m->curg
+	// Restore callee-saved registers.
+	POPQ	R15
+	POPQ	R14
+	POPQ	R13
+	POPQ	R12
+	POPQ	SI
+	POPQ	DI
+	POPQ	BP
+	POPQ	BX
 	RET
diff --git a/src/pkg/runtime/rdebug.goc b/src/pkg/runtime/rdebug.goc
new file mode 100644
index 0000000..042b30a
--- /dev/null
+++ b/src/pkg/runtime/rdebug.goc
@@ -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 runtime∕debug
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+#include "stack.h"
+
+func setMaxStack(in int) (out int) {
+	out = runtime·maxstacksize;
+	runtime·maxstacksize = in;
+}
+
+func setGCPercent(in int) (out int) {
+	out = runtime·setgcpercent(in);
+}
+
+func setMaxThreads(in int) (out int) {
+	out = runtime·setmaxthreads(in);
+}
+
+func SetPanicOnFault(enabled bool) (old bool) {
+	old = g->paniconfault;
+	g->paniconfault = enabled;
+}
diff --git a/src/pkg/runtime/rt0_freebsd_arm.s b/src/pkg/runtime/rt0_freebsd_arm.s
index d110876..56219f8 100644
--- a/src/pkg/runtime/rt0_freebsd_arm.s
+++ b/src/pkg/runtime/rt0_freebsd_arm.s
@@ -11,3 +11,8 @@ TEXT _rt0_arm_freebsd(SB),NOSPLIT,$-4
 	MOVW	$4(R13), R1		// argv
 	MOVM.DB.W [R0-R1], (R13)
 	B	_rt0_go(SB)
+
+TEXT main(SB),NOSPLIT,$-4
+	MOVM.DB.W [R0-R1], (R13)
+	MOVW	$_rt0_go(SB), R4
+	B		(R4)
diff --git a/src/pkg/runtime/rt0_nacl_386.s b/src/pkg/runtime/rt0_nacl_386.s
new file mode 100644
index 0000000..8b71354
--- /dev/null
+++ b/src/pkg/runtime/rt0_nacl_386.s
@@ -0,0 +1,22 @@
+// 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 "../../cmd/ld/textflag.h"
+
+// NaCl entry has:
+//	0(FP) - arg block == SP+8
+//	4(FP) - cleanup function pointer, always 0
+//	8(FP) - envc
+//	12(FP) - argc
+//	16(FP) - argv, then 0, then envv, then 0, then auxv
+TEXT _rt0_386_nacl(SB),NOSPLIT,$8
+	MOVL	argc+12(FP), AX
+	LEAL	argv+16(FP), BX
+	MOVL	AX, 0(SP)
+	MOVL	BX, 4(SP)
+	CALL	main(SB)
+	INT	$3
+
+TEXT main(SB),NOSPLIT,$0
+	JMP	_rt0_go(SB)
diff --git a/src/pkg/runtime/rt0_nacl_amd64p32.s b/src/pkg/runtime/rt0_nacl_amd64p32.s
new file mode 100644
index 0000000..502d2e2
--- /dev/null
+++ b/src/pkg/runtime/rt0_nacl_amd64p32.s
@@ -0,0 +1,30 @@
+// 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 "../../cmd/ld/textflag.h"
+
+// NaCl entry on 32-bit x86 has DI pointing at the arg block, which contains:
+//
+//	0(DI) - cleanup function pointer, always 0
+//	4(DI) - envc
+//	8(DI) - argc
+//	12(DI) - argv, then 0, then envv, then 0, then auxv
+// NaCl entry here is almost the same, except that there
+// is no saved caller PC, so 0(FP) is -8(FP) and so on. 
+TEXT _rt0_amd64p32_nacl(SB),NOSPLIT,$16
+	MOVL	DI, 0(SP)
+	CALL	runtime·nacl_sysinfo(SB)
+	MOVL	0(SP), DI
+	MOVL	8(DI), AX
+	LEAL	12(DI), BX
+	MOVL	AX, 0(SP)
+	MOVL	BX, 4(SP)
+	CALL	main(SB)
+	INT	$3
+
+TEXT main(SB),NOSPLIT,$0
+	// Uncomment for fake time like on Go Playground.
+	//MOVQ	$1257894000000000000, AX
+	//MOVQ	AX, runtime·timens(SB)
+	JMP	_rt0_go(SB)
diff --git a/src/pkg/runtime/rt0_solaris_amd64.s b/src/pkg/runtime/rt0_solaris_amd64.s
new file mode 100644
index 0000000..4aca991
--- /dev/null
+++ b/src/pkg/runtime/rt0_solaris_amd64.s
@@ -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.
+
+#include "../../cmd/ld/textflag.h"
+
+TEXT _rt0_amd64_solaris(SB),NOSPLIT,$-8
+	LEAQ	8(SP), SI // argv
+	MOVQ	0(SP), DI // argc
+	MOVQ	$main(SB), AX
+	JMP	AX
+
+TEXT main(SB),NOSPLIT,$-8
+	MOVQ	$_rt0_go(SB), AX
+	JMP	AX
+
+DATA runtime·issolaris(SB)/4, $1
+GLOBL runtime·issolaris(SB), $4
diff --git a/src/pkg/runtime/runtime-gdb.py b/src/pkg/runtime/runtime-gdb.py
index e704f4c..eedac7c 100644
--- a/src/pkg/runtime/runtime-gdb.py
+++ b/src/pkg/runtime/runtime-gdb.py
@@ -15,10 +15,14 @@ path to this file based on the path to the runtime package.
 #      circumventing the pretty print triggering.
 
 
-import sys, re
-
-print >>sys.stderr, "Loading Go Runtime support."
-
+from __future__ import print_function
+import re
+import sys
+
+print("Loading Go Runtime support.", file=sys.stderr)
+#http://python3porting.com/differences.html
+if sys.version > '3':
+	xrange = range
 # allow to manually reload while developing
 goobjfile = gdb.current_objfile() or gdb.objfiles()[0]
 goobjfile.pretty_printers = []
@@ -27,6 +31,7 @@ goobjfile.pretty_printers = []
 #  Pretty Printers
 #
 
+
 class StringTypePrinter:
 	"Pretty print Go strings."
 
@@ -61,8 +66,8 @@ class SliceTypePrinter:
 		if self.val["len"] > self.val["cap"]:
 			return
 		ptr = self.val["array"]
-		for idx in range(self.val["len"]):
-			yield ('[%d]' % idx, (ptr + idx).dereference())
+		for idx in range(int(self.val["len"])):
+			yield ('[{0}]'.format(idx), (ptr + idx).dereference())
 
 
 class MapTypePrinter:
@@ -72,7 +77,7 @@ class MapTypePrinter:
 	to inspect their contents with this pretty printer.
 	"""
 
-	pattern = re.compile(r'^struct hash<.*>$')
+	pattern = re.compile(r'^map\[.*\].*$')
 
 	def __init__(self, val):
 		self.val = val
@@ -90,14 +95,15 @@ class MapTypePrinter:
 		flags = self.val['flags']
 		inttype = self.val['hash0'].type
 		cnt = 0
-		for bucket in xrange(2 ** B):
+		for bucket in xrange(2 ** int(B)):
 			bp = buckets + bucket
 			if oldbuckets:
 				oldbucket = bucket & (2 ** (B - 1) - 1)
 				oldbp = oldbuckets + oldbucket
 				oldb = oldbp.dereference()
-				if (oldb['overflow'].cast(inttype) & 1) == 0: # old bucket not evacuated yet
-					if bucket >= 2 ** (B - 1): continue   # already did old bucket
+				if (oldb['overflow'].cast(inttype) & 1) == 0:  # old bucket not evacuated yet
+					if bucket >= 2 ** (B - 1):
+						continue    # already did old bucket
 					bp = oldbp
 			while bp:
 				b = bp.dereference()
@@ -109,11 +115,12 @@ class MapTypePrinter:
 							k = k.dereference()
 						if flags & 2:
 							v = v.dereference()
-						yield '%d' % cnt, k
-						yield '%d' % (cnt + 1), v
+						yield str(cnt), k
+						yield str(cnt + 1), v
 						cnt += 2
 				bp = b['overflow']
 
+
 class ChanTypePrinter:
 	"""Pretty print chan[T] types.
 
@@ -138,7 +145,7 @@ class ChanTypePrinter:
 		ptr = (self.val.address + 1).cast(et.pointer())
 		for i in range(self.val["qcount"]):
 			j = (self.val["recvx"] + i) % self.val["dataqsiz"]
-			yield ('[%d]' % i, (ptr + j).dereference())
+			yield ('[{0}]'.format(i), (ptr + j).dereference())
 
 
 #
@@ -150,11 +157,11 @@ def makematcher(klass):
 		try:
 			if klass.pattern.match(str(val.type)):
 				return klass(val)
-		except:
+		except Exception:
 			pass
 	return matcher
 
-goobjfile.pretty_printers.extend([makematcher(k) for k in vars().values() if hasattr(k, 'pattern')])
+goobjfile.pretty_printers.extend([makematcher(var) for var in vars().values() if hasattr(var, 'pattern')])
 
 #
 #  For reference, this is what we're trying to do:
@@ -169,34 +176,35 @@ goobjfile.pretty_printers.extend([makematcher(k) for k in vars().values() if has
 
 def is_iface(val):
 	try:
-		return str(val['tab'].type) == "struct runtime.itab *" \
-		      and str(val['data'].type) == "void *"
-	except:
+		return str(val['tab'].type) == "struct runtime.itab *" and str(val['data'].type) == "void *"
+	except gdb.error:
 		pass
 
+
 def is_eface(val):
 	try:
-		return str(val['_type'].type) == "struct runtime._type *" \
-		      and str(val['data'].type) == "void *"
-	except:
+		return str(val['_type'].type) == "struct runtime._type *" and str(val['data'].type) == "void *"
+	except gdb.error:
 		pass
 
+
 def lookup_type(name):
 	try:
 		return gdb.lookup_type(name)
-	except:
+	except gdb.error:
 		pass
 	try:
 		return gdb.lookup_type('struct ' + name)
-	except:
+	except gdb.error:
 		pass
 	try:
 		return gdb.lookup_type('struct ' + name[1:]).pointer()
-	except:
+	except gdb.error:
 		pass
 
 _rctp_type = gdb.lookup_type("struct runtime.rtype").pointer()
 
+
 def iface_commontype(obj):
 	if is_iface(obj):
 		go_type_ptr = obj['tab']['_type']
@@ -204,9 +212,9 @@ def iface_commontype(obj):
 		go_type_ptr = obj['_type']
 	else:
 		return
-	
+
 	return go_type_ptr.cast(_rctp_type).dereference()
-	
+
 
 def iface_dtype(obj):
 	"Decode type of the data field of an eface or iface struct."
@@ -221,7 +229,7 @@ def iface_dtype(obj):
 	dynamic_gdb_type = lookup_type(dtype_name)
 	if dynamic_gdb_type is None:
 		return
-	
+
 	type_size = int(dynamic_go_type['size'])
 	uintptr_size = int(dynamic_go_type['size'].type.sizeof)	 # size is itself an uintptr
 	if type_size > uintptr_size:
@@ -229,6 +237,7 @@ def iface_dtype(obj):
 
 	return dynamic_gdb_type
 
+
 def iface_dtype_name(obj):
 	"Decode type name of the data field of an eface or iface struct."
 
@@ -254,15 +263,15 @@ class IfacePrinter:
 			return 0x0
 		try:
 			dtype = iface_dtype(self.val)
-		except:
+		except Exception:
 			return "<bad dynamic type>"
 
 		if dtype is None:  # trouble looking up, print something reasonable
-			return "(%s)%s" % (iface_dtype_name(self.val), self.val['data'])
+			return "({0}){0}".format(iface_dtype_name(self.val), self.val['data'])
 
 		try:
 			return self.val['data'].cast(dtype).dereference()
-		except:
+		except Exception:
 			pass
 		return self.val['data'].cast(dtype)
 
@@ -277,16 +286,14 @@ goobjfile.pretty_printers.append(ifacematcher)
 #  Convenience Functions
 #
 
+
 class GoLenFunc(gdb.Function):
 	"Length of strings, slices, maps or channels"
 
-	how = ((StringTypePrinter, 'len'),
-	       (SliceTypePrinter, 'len'),
-	       (MapTypePrinter, 'count'),
-	       (ChanTypePrinter, 'qcount'))
+	how = ((StringTypePrinter, 'len'), (SliceTypePrinter, 'len'), (MapTypePrinter, 'count'), (ChanTypePrinter, 'qcount'))
 
 	def __init__(self):
-		super(GoLenFunc, self).__init__("len")
+		gdb.Function.__init__(self, "len")
 
 	def invoke(self, obj):
 		typename = str(obj.type)
@@ -294,14 +301,14 @@ class GoLenFunc(gdb.Function):
 			if klass.pattern.match(typename):
 				return obj[fld]
 
+
 class GoCapFunc(gdb.Function):
 	"Capacity of slices or channels"
 
-	how = ((SliceTypePrinter, 'cap'),
-	       (ChanTypePrinter, 'dataqsiz'))
+	how = ((SliceTypePrinter, 'cap'), (ChanTypePrinter, 'dataqsiz'))
 
 	def __init__(self):
-		super(GoCapFunc, self).__init__("cap")
+		gdb.Function.__init__(self, "cap")
 
 	def invoke(self, obj):
 		typename = str(obj.type)
@@ -309,6 +316,7 @@ class GoCapFunc(gdb.Function):
 			if klass.pattern.match(typename):
 				return obj[fld]
 
+
 class DTypeFunc(gdb.Function):
 	"""Cast Interface values to their dynamic type.
 
@@ -316,12 +324,12 @@ class DTypeFunc(gdb.Function):
 	"""
 
 	def __init__(self):
-		super(DTypeFunc, self).__init__("dtype")
+		gdb.Function.__init__(self, "dtype")
 
 	def invoke(self, obj):
 		try:
 			return obj['data'].cast(iface_dtype(obj))
-		except:
+		except gdb.error:
 			pass
 		return obj
 
@@ -331,6 +339,7 @@ class DTypeFunc(gdb.Function):
 
 sts = ('idle', 'runnable', 'running', 'syscall', 'waiting', 'moribund', 'dead', 'recovery')
 
+
 def linked_list(ptr, linkfield):
 	while ptr:
 		yield ptr
@@ -341,29 +350,47 @@ class GoroutinesCmd(gdb.Command):
 	"List all goroutines."
 
 	def __init__(self):
-		super(GoroutinesCmd, self).__init__("info goroutines", gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
+		gdb.Command.__init__(self, "info goroutines", gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
 
-	def invoke(self, arg, from_tty):
+	def invoke(self, _arg, _from_tty):
 		# args = gdb.string_to_argv(arg)
 		vp = gdb.lookup_type('void').pointer()
 		for ptr in linked_list(gdb.parse_and_eval("'runtime.allg'"), 'alllink'):
-			if ptr['status'] == 6:	# 'gdead'
+			if ptr['status'] == 6:  # 'gdead'
 				continue
 			s = ' '
 			if ptr['m']:
 				s = '*'
 			pc = ptr['sched']['pc'].cast(vp)
-			sp = ptr['sched']['sp'].cast(vp)
-			blk = gdb.block_for_pc(long((pc)))
-			print s, ptr['goid'], "%8s" % sts[long((ptr['status']))], blk.function
+			# python2 will not cast pc (type void*) to an int cleanly
+			# instead python2 and python3 work with the hex string representation
+			# of the void pointer which we can parse back into an int.
+			# int(pc) will not work.
+			try:
+				#python3 / newer versions of gdb
+				pc = int(pc)
+			except gdb.error:
+				pc = int(str(pc), 16)
+			blk = gdb.block_for_pc(pc)
+			print(s, ptr['goid'], "{0:8s}".format(sts[int(ptr['status'])]), blk.function)
+
 
 def find_goroutine(goid):
+	"""
+	find_goroutine attempts to find the goroutine identified by goid.
+	It returns a touple of gdv.Value's representing the stack pointer
+	and program counter pointer for the goroutine.
+
+	@param int goid
+
+	@return tuple (gdb.Value, gdb.Value)
+	"""
 	vp = gdb.lookup_type('void').pointer()
 	for ptr in linked_list(gdb.parse_and_eval("'runtime.allg'"), 'alllink'):
-		if ptr['status'] == 6:	# 'gdead'
+		if ptr['status'] == 6:  # 'gdead'
 			continue
 		if ptr['goid'] == goid:
-			return [ptr['sched'][x].cast(vp) for x in 'pc', 'sp']
+			return (ptr['sched'][x].cast(vp) for x in ('pc', 'sp'))
 	return None, None
 
 
@@ -380,20 +407,25 @@ class GoroutineCmd(gdb.Command):
 	"""
 
 	def __init__(self):
-		super(GoroutineCmd, self).__init__("goroutine", gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
+		gdb.Command.__init__(self, "goroutine", gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
 
-	def invoke(self, arg, from_tty):
+	def invoke(self, arg, _from_tty):
 		goid, cmd = arg.split(None, 1)
 		goid = gdb.parse_and_eval(goid)
 		pc, sp = find_goroutine(int(goid))
 		if not pc:
-			print "No such goroutine: ", goid
+			print("No such goroutine: ", goid)
 			return
+		try:
+			#python3 / newer versions of gdb
+			pc = int(pc)
+		except gdb.error:
+			pc = int(str(pc), 16)
 		save_frame = gdb.selected_frame()
 		gdb.parse_and_eval('$save_pc = $pc')
 		gdb.parse_and_eval('$save_sp = $sp')
-		gdb.parse_and_eval('$pc = 0x%x' % long(pc))
-		gdb.parse_and_eval('$sp = 0x%x' % long(sp))
+		gdb.parse_and_eval('$pc = {0}'.format(str(pc)))
+		gdb.parse_and_eval('$sp = {0}'.format(str(sp)))
 		try:
 			gdb.execute(cmd)
 		finally:
@@ -406,31 +438,33 @@ class GoIfaceCmd(gdb.Command):
 	"Print Static and dynamic interface types"
 
 	def __init__(self):
-		super(GoIfaceCmd, self).__init__("iface", gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL)
+		gdb.Command.__init__(self, "iface", gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL)
 
-	def invoke(self, arg, from_tty):
+	def invoke(self, arg, _from_tty):
 		for obj in gdb.string_to_argv(arg):
 			try:
 				#TODO fix quoting for qualified variable names
-				obj = gdb.parse_and_eval("%s" % obj)
-			except Exception, e:
-				print "Can't parse ", obj, ": ", e
+				obj = gdb.parse_and_eval(str(obj))
+			except Exception as e:
+				print("Can't parse ", obj, ": ", e)
 				continue
 
 			if obj['data'] == 0:
 				dtype = "nil"
 			else:
 				dtype = iface_dtype(obj)
-				
+
 			if dtype is None:
-				print "Not an interface: ", obj.type
+				print("Not an interface: ", obj.type)
 				continue
 
-			print "%s: %s" % (obj.type, dtype)
+			print("{0}: {1}".format(obj.type, dtype))
 
 # TODO: print interface's methods and dynamic type's func pointers thereof.
-#rsc: "to find the number of entries in the itab's Fn field look at itab.inter->numMethods
-#i am sure i have the names wrong but look at the interface type and its method count"
+#rsc: "to find the number of entries in the itab's Fn field look at
+# itab.inter->numMethods
+# i am sure i have the names wrong but look at the interface type
+# and its method count"
 # so Itype will start with a commontype which has kind = interface
 
 #
diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c
index ab9fed8..3a4f719 100644
--- a/src/pkg/runtime/runtime.c
+++ b/src/pkg/runtime/runtime.c
@@ -3,6 +3,7 @@
 // license that can be found in the LICENSE file.
 
 #include "runtime.h"
+#include "stack.h"
 #include "arch_GOARCH.h"
 #include "../../cmd/ld/textflag.h"
 
@@ -10,13 +11,12 @@ enum {
 	maxround = sizeof(uintptr),
 };
 
-/*
- * We assume that all architectures turn faults and the like
- * into apparent calls to runtime.sigpanic.  If we see a "call"
- * to runtime.sigpanic, we do not back up the PC to find the
- * line number of the CALL instruction, because there is no CALL.
- */
-void	runtime·sigpanic(void);
+// Keep a cached value to make gotraceback fast,
+// since we call it on every call to gentraceback.
+// The cached value is a uint32 in which the low bit
+// is the "crash" setting and the top 31 bits are the
+// gotraceback value.
+static uint32 traceback_cache = ~(uint32)0;
 
 // The GOTRACEBACK environment variable controls the
 // behavior of a Go program that is crashing and exiting.
@@ -28,18 +28,28 @@ int32
 runtime·gotraceback(bool *crash)
 {
 	byte *p;
+	uint32 x;
 
 	if(crash != nil)
 		*crash = false;
-	p = runtime·getenv("GOTRACEBACK");
-	if(p == nil || p[0] == '\0')
-		return 1;	// default is on
-	if(runtime·strcmp(p, (byte*)"crash") == 0) {
-		if(crash != nil)
-			*crash = true;
-		return 2;	// extra information
+	if(m->traceback != 0)
+		return m->traceback;
+	x = runtime·atomicload(&traceback_cache);
+	if(x == ~(uint32)0) {
+		p = runtime·getenv("GOTRACEBACK");
+		if(p == nil)
+			p = (byte*)"";
+		if(p[0] == '\0')
+			x = 1<<1;
+		else if(runtime·strcmp(p, (byte*)"crash") == 0)
+			x = (2<<1) | 1;
+		else
+			x = runtime·atoi(p)<<1;	
+		runtime·atomicstore(&traceback_cache, x);
 	}
-	return runtime·atoi(p);
+	if(crash != nil)
+		*crash = x&1;
+	return x>>1;
 }
 
 int32
@@ -87,6 +97,7 @@ runtime·args(int32 c, uint8 **v)
 }
 
 int32 runtime·isplan9;
+int32 runtime·issolaris;
 int32 runtime·iswindows;
 
 // Information about what cpu features are available.
@@ -127,16 +138,8 @@ runtime·goenvs_unix(void)
 	syscall·envs.array = (byte*)s;
 	syscall·envs.len = n;
 	syscall·envs.cap = n;
-}
 
-void
-runtime·getgoroot(String out)
-{
-	byte *p;
-
-	p = runtime·getenv("GOROOT");
-	out = runtime·gostringnocopy(p);
-	FLUSH(&out);
+	traceback_cache = ~(uint32)0;
 }
 
 int32
@@ -273,62 +276,9 @@ runtime·check(void)
 		runtime·throw("float32nan3");
 
 	TestAtomic64();
-}
-
-void
-runtime·Caller(intgo skip, uintptr retpc, String retfile, intgo retline, bool retbool)
-{
-	Func *f, *g;
-	uintptr pc;
-	uintptr rpc[2];
-
-	/*
-	 * Ask for two PCs: the one we were asked for
-	 * and what it called, so that we can see if it
-	 * "called" sigpanic.
-	 */
-	retpc = 0;
-	if(runtime·callers(1+skip-1, rpc, 2) < 2) {
-		retfile = runtime·emptystring;
-		retline = 0;
-		retbool = false;
-	} else if((f = runtime·findfunc(rpc[1])) == nil) {
-		retfile = runtime·emptystring;
-		retline = 0;
-		retbool = true;  // have retpc at least
-	} else {
-		retpc = rpc[1];
-		pc = retpc;
-		g = runtime·findfunc(rpc[0]);
-		if(pc > f->entry && (g == nil || g->entry != (uintptr)runtime·sigpanic))
-			pc--;
-		retline = runtime·funcline(f, pc, &retfile);
-		retbool = true;
-	}
-	FLUSH(&retpc);
-	FLUSH(&retfile);
-	FLUSH(&retline);
-	FLUSH(&retbool);
-}
 
-void
-runtime·Callers(intgo skip, Slice pc, intgo retn)
-{
-	// runtime.callers uses pc.array==nil as a signal
-	// to print a stack trace.  Pick off 0-length pc here
-	// so that we don't let a nil pc slice get to it.
-	if(pc.len == 0)
-		retn = 0;
-	else
-		retn = runtime·callers(skip, (uintptr*)pc.array, pc.len);
-	FLUSH(&retn);
-}
-
-void
-runtime·FuncForPC(uintptr pc, void *retf)
-{
-	retf = runtime·findfunc(pc);
-	FLUSH(&retf);
+	if(FixedStack != runtime·round2(FixedStack))
+		runtime·throw("FixedStack is not power-of-2");
 }
 
 uint32
@@ -374,22 +324,18 @@ runtime·tickspersecond(void)
 	return res;
 }
 
-void
-runtime∕pprof·runtime_cyclesPerSecond(int64 res)
-{
-	res = runtime·tickspersecond();
-	FLUSH(&res);
-}
-
 DebugVars	runtime·debug;
 
 static struct {
 	int8*	name;
 	int32*	value;
 } dbgvar[] = {
+	{"allocfreetrace", &runtime·debug.allocfreetrace},
+	{"efence", &runtime·debug.efence},
 	{"gctrace", &runtime·debug.gctrace},
-	{"schedtrace", &runtime·debug.schedtrace},
+	{"gcdead", &runtime·debug.gcdead},
 	{"scheddetail", &runtime·debug.scheddetail},
+	{"schedtrace", &runtime·debug.schedtrace},
 };
 
 void
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index f7c2adb..5115503 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -28,6 +28,12 @@ typedef	int32		intgo; // Go's int
 typedef	uint32		uintgo; // Go's uint
 #endif
 
+#ifdef _64BITREG
+typedef	uint64		uintreg;
+#else
+typedef	uint32		uintreg;
+#endif
+
 /*
  * get rid of C types
  * the / / / forces a syntax error immediately,
@@ -66,17 +72,17 @@ typedef	struct	Itab		Itab;
 typedef	struct	InterfaceType	InterfaceType;
 typedef	struct	Eface		Eface;
 typedef	struct	Type		Type;
+typedef	struct	PtrType		PtrType;
 typedef	struct	ChanType		ChanType;
 typedef	struct	MapType		MapType;
 typedef	struct	Defer		Defer;
-typedef	struct	DeferChunk	DeferChunk;
 typedef	struct	Panic		Panic;
 typedef	struct	Hmap		Hmap;
+typedef	struct	Hiter			Hiter;
 typedef	struct	Hchan		Hchan;
 typedef	struct	Complex64	Complex64;
 typedef	struct	Complex128	Complex128;
-typedef	struct	WinCall		WinCall;
-typedef	struct	SEH		SEH;
+typedef	struct	LibCall		LibCall;
 typedef	struct	WinCallbackContext	WinCallbackContext;
 typedef	struct	Timers		Timers;
 typedef	struct	Timer		Timer;
@@ -93,10 +99,10 @@ typedef	struct	DebugVars	DebugVars;
  *
  * "extern register" is a special storage class implemented by 6c, 8c, etc.
  * On the ARM, it is an actual register; elsewhere it is a slot in thread-
- * local storage indexed by a segment register. See zasmhdr in
+ * local storage indexed by a pseudo-register TLS. See zasmhdr in
  * src/cmd/dist/buildruntime.c for details, and be aware that the linker may
  * make further OS-specific changes to the compiler's output. For example,
- * 6l/linux rewrites 0(GS) as -16(FS).
+ * 6l/linux rewrites 0(TLS) as -16(FS).
  *
  * Every C file linked into a Go program must include runtime.h so that the
  * C compiler (6c, 8c, etc.) knows to avoid other uses of these dedicated
@@ -208,8 +214,8 @@ struct	Gobuf
 	uintptr	sp;
 	uintptr	pc;
 	G*	g;
-	uintptr	ret;
 	void*	ctxt;
+	uintreg	ret;
 	uintptr	lr;
 };
 struct	GCStats
@@ -223,7 +229,7 @@ struct	GCStats
 	uint64	nsleep;
 };
 
-struct	WinCall
+struct	LibCall
 {
 	void	(*fn)(void*);
 	uintptr	n;	// number of parameters
@@ -232,17 +238,14 @@ struct	WinCall
 	uintptr	r2;
 	uintptr	err;	// error number
 };
-struct	SEH
-{
-	void*	prev;
-	void*	handler;
-};
+
 // describes how to handle callback
 struct	WinCallbackContext
 {
 	void*	gobody;		// Go function to call
 	uintptr	argsize;	// callback arguments size (in bytes)
 	uintptr	restorestack;	// adjust stack on return by (in bytes) (386 only)
+	bool	cleanstack;
 };
 
 struct	G
@@ -251,7 +254,6 @@ struct	G
 	uintptr	stackguard0;	// cannot move - also known to linker, libmach, runtime/cgo
 	uintptr	stackbase;	// cannot move - also known to libmach, runtime/cgo
 	uint32	panicwrap;	// cannot move - also known to linker
-	uint32	selgen;		// valid sudog pointer
 	Defer*	defer;
 	Panic*	panic;
 	Gobuf	sched;
@@ -262,24 +264,23 @@ struct	G
 	uintptr	stackguard;	// same as stackguard0, but not set to StackPreempt
 	uintptr	stack0;
 	uintptr	stacksize;
-	G*	alllink;	// on allg
 	void*	param;		// passed parameter on wakeup
 	int16	status;
 	int64	goid;
+	int64	waitsince;	// approx time when the G become blocked
 	int8*	waitreason;	// if status==Gwaiting
 	G*	schedlink;
 	bool	ispanic;
 	bool	issystem;	// do not output in stack dump
 	bool	isbackground;	// ignore in deadlock detector
 	bool	preempt;	// preemption signal, duplicates stackguard0 = StackPreempt
+	bool	paniconfault;	// panic (instead of crash) on unexpected fault address
 	int8	raceignore;	// ignore race detection events
 	M*	m;		// for debuggers, but offset not hard-coded
 	M*	lockedm;
 	int32	sig;
 	int32	writenbuf;
 	byte*	writebuf;
-	DeferChunk*	dchunk;
-	DeferChunk*	dchunknext;
 	uintptr	sigcode0;
 	uintptr	sigcode1;
 	uintptr	sigpc;
@@ -287,6 +288,7 @@ struct	G
 	uintptr	racectx;
 	uintptr	end[];
 };
+
 struct	M
 {
 	G*	g0;		// goroutine with scheduling stack
@@ -295,8 +297,8 @@ struct	M
 
 	// Fields not known to debuggers.
 	uint32	moreframesize;	// size arguments to morestack
-	uint32	moreargsize;
-	uintptr	cret;		// return value from C
+	uint32	moreargsize;	// known by amd64 asm to follow moreframesize
+	uintreg	cret;		// return value from C
 	uint64	procid;		// for debuggers, but offset not hard-coded
 	G*	gsignal;	// signal-handling G
 	uintptr	tls[4];		// thread-local storage (for x86 extern register)
@@ -310,10 +312,12 @@ struct	M
 	int32	throwing;
 	int32	gcing;
 	int32	locks;
+	int32	softfloat;
 	int32	dying;
 	int32	profilehz;
 	int32	helpgc;
-	bool	spinning;
+	bool	spinning;	// M is out of work and is actively looking for work
+	bool	blocked;	// M is blocked on a Note
 	uint32	fastrand;
 	uint64	ncgocall;	// number of cgo calls in total
 	int32	ncgo;		// number of cgo calls currently in progress
@@ -338,23 +342,37 @@ struct	M
 	uint32	waitsemacount;
 	uint32	waitsemalock;
 	GCStats	gcstats;
-	bool	racecall;
 	bool	needextram;
-	void	(*waitunlockf)(Lock*);
+	uint8	traceback;
+	bool	(*waitunlockf)(G*, void*);
 	void*	waitlock;
-
-	uintptr	settype_buf[1024];
-	uintptr	settype_bufsize;
-
+	uintptr	forkstackguard;
 #ifdef GOOS_windows
 	void*	thread;		// thread handle
-	WinCall	wincall;
+	// these are here because they are too large to be on the stack
+	// of low-level NOSPLIT functions.
+	LibCall	libcall;
+	uintptr	libcallpc;	// for cpu profiler
+	uintptr	libcallsp;
+	G*	libcallg;
+#endif
+#ifdef GOOS_solaris
+	int32*	perrno; 	// pointer to TLS errno
+	// these are here because they are too large to be on the stack
+	// of low-level NOSPLIT functions.
+	LibCall	libcall;
+	struct {
+		int64	tv_sec;
+		int64	tv_nsec;
+	} ts;
+	struct {
+		uintptr v[6];
+	} scratch;
 #endif
 #ifdef GOOS_plan9
 	int8*	notesig;
 	byte*	errstr;
 #endif
-	SEH*	seh;
 	uintptr	end[];
 };
 
@@ -369,12 +387,16 @@ struct P
 	uint32	syscalltick;	// incremented on every system call
 	M*	m;		// back-link to associated M (nil if idle)
 	MCache*	mcache;
+	Defer*	deferpool[5];	// pool of available Defer structs of different sizes (see panic.c)
+
+	// Cache of goroutine ids, amortizes accesses to runtime·sched.goidgen.
+	uint64	goidcache;
+	uint64	goidcacheend;
 
 	// Queue of runnable goroutines.
-	G**	runq;
-	int32	runqhead;
-	int32	runqtail;
-	int32	runqsize;
+	uint32	runqhead;
+	uint32	runqtail;
+	G*	runq[256];
 
 	// Available G's (status == Gdead)
 	G*	gfree;
@@ -406,8 +428,8 @@ struct	Stktop
 	uint32	panicwrap;
 
 	uint8*	argp;	// pointer to arguments in old frame
-	uintptr	free;	// if free>0, call stackfree using free as size
 	bool	panic;	// is this frame the top of a panic?
+	bool	malloced;
 };
 struct	SigTab
 {
@@ -423,6 +445,7 @@ enum
 	SigDefault = 1<<4,	// if the signal isn't explicitly requested, don't monitor it
 	SigHandling = 1<<5,	// our signal handler is registered
 	SigIgnored = 1<<6,	// the signal was ignored before we registered for it
+	SigGoExit = 1<<7,	// cause all runtime procs to exit (only used on Plan 9).
 };
 
 // Layout of in-memory per-function information prepared by linker
@@ -456,6 +479,16 @@ struct	Itab
 	void	(*fun[])(void);
 };
 
+#ifdef GOOS_nacl
+enum {
+   NaCl = 1,
+};
+#else
+enum {
+   NaCl = 0,
+};
+#endif
+
 #ifdef GOOS_windows
 enum {
    Windows = 1
@@ -465,6 +498,15 @@ enum {
    Windows = 0
 };
 #endif
+#ifdef GOOS_solaris
+enum {
+   Solaris = 1
+};
+#else
+enum {
+   Solaris = 0
+};
+#endif
 
 struct	Timers
 {
@@ -480,6 +522,8 @@ struct	Timers
 
 // Package time knows the layout of this structure.
 // If this struct changes, adjust ../time/sleep.go:/runtimeTimer.
+// For GOOS=nacl, package syscall knows the layout of this structure.
+// If this struct changes, adjust ../syscall/net_nacl.go:/runtimeTimer.
 struct	Timer
 {
 	int32	i;	// heap index
@@ -533,12 +577,16 @@ struct CgoMal
 // Holds variables parsed from GODEBUG env var.
 struct DebugVars
 {
+	int32	allocfreetrace;
+	int32	efence;
 	int32	gctrace;
-	int32	schedtrace;
+	int32	gcdead;
 	int32	scheddetail;
+	int32	schedtrace;
 };
 
 extern bool runtime·precisestack;
+extern bool runtime·copystack;
 
 /*
  * defined macros
@@ -548,13 +596,13 @@ extern bool runtime·precisestack;
 #define	nelem(x)	(sizeof(x)/sizeof((x)[0]))
 #define	nil		((void*)0)
 #define	offsetof(s,m)	(uint32)(&(((s*)0)->m))
-#define	ROUND(x, n)	(((x)+(n)-1)&~((n)-1)) /* all-caps to mark as macro: it evaluates n twice */
+#define	ROUND(x, n)	(((x)+(n)-1)&~(uintptr)((n)-1)) /* all-caps to mark as macro: it evaluates n twice */
 
 /*
  * known to compiler
  */
 enum {
-	Structrnd = sizeof(uintptr)
+	Structrnd = sizeof(uintreg),
 };
 
 /*
@@ -648,7 +696,6 @@ struct Defer
 {
 	int32	siz;
 	bool	special;	// not part of defer frame
-	bool	free;		// if special, free when done
 	byte*	argp;		// where args were copied from
 	byte*	pc;
 	FuncVal*	fn;
@@ -656,11 +703,10 @@ struct Defer
 	void*	args[1];	// padded to actual size
 };
 
-struct DeferChunk
-{
-	DeferChunk	*prev;
-	uintptr	off;
-};
+// argp used in Defer structs when there is no argp.
+// TODO(rsc): Maybe we could use nil instead, but we've always used -1
+// and I don't want to change this days before the Go 1.3 release.
+#define NoArgs ((byte*)-1)
 
 /*
  * panics
@@ -670,7 +716,9 @@ struct Panic
 	Eface	arg;		// argument to panic
 	uintptr	stackbase;	// g->stackbase in panic
 	Panic*	link;		// link to earlier panic
+	Defer*	defer;		// current executing defer
 	bool	recovered;	// whether this panic is over
+	bool	aborted;	// the panic was aborted
 };
 
 /*
@@ -681,6 +729,7 @@ struct Stkframe
 {
 	Func*	fn;	// function being run
 	uintptr	pc;	// program counter within fn
+	uintptr	continpc;	// program counter where execution can continue, or 0 if not
 	uintptr	lr;	// program counter at caller aka link register
 	uintptr	sp;	// stack pointer at pc
 	uintptr	fp;	// stack pointer at caller aka frame pointer
@@ -689,18 +738,24 @@ struct Stkframe
 	uintptr	arglen;	// number of bytes at argp
 };
 
-int32	runtime·gentraceback(uintptr, uintptr, uintptr, G*, int32, uintptr*, int32, void(*)(Stkframe*, void*), void*, bool);
+int32	runtime·gentraceback(uintptr, uintptr, uintptr, G*, int32, uintptr*, int32, bool(*)(Stkframe*, void*), void*, bool);
 void	runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G* gp);
 void	runtime·tracebackothers(G*);
 bool	runtime·haszeroargs(uintptr pc);
 bool	runtime·topofstack(Func*);
+enum
+{
+	// The maximum number of frames we print for a traceback
+	TracebackMaxFrames = 100,
+};
 
 /*
  * external data
  */
 extern	String	runtime·emptystring;
 extern	uintptr runtime·zerobase;
-extern	G*	runtime·allg;
+extern	G**	runtime·allg;
+extern	uintptr runtime·allglen;
 extern	G*	runtime·lastg;
 extern	M*	runtime·allm;
 extern	P**	runtime·allp;
@@ -722,6 +777,7 @@ extern	uintptr	runtime·maxstacksize;
  * common functions and data
  */
 int32	runtime·strcmp(byte*, byte*);
+int32	runtime·strncmp(byte*, byte*, uintptr);
 byte*	runtime·strstr(byte*, byte*);
 intgo	runtime·findnull(byte*);
 intgo	runtime·findnullw(uint16*);
@@ -729,11 +785,33 @@ void	runtime·dump(byte*, int32);
 int32	runtime·runetochar(byte*, int32);
 int32	runtime·charntorune(int32*, uint8*, int32);
 
+
 /*
- * very low level c-called
- */
+ * This macro is used when writing C functions
+ * called as if they were Go functions.
+ * Passed the address of a result before a return statement,
+ * it makes sure the result has been flushed to memory
+ * before the return.
+ *
+ * It is difficult to write such functions portably, because
+ * of the varying requirements on the alignment of the
+ * first output value. Almost all code should write such
+ * functions in .goc files, where goc2c (part of cmd/dist)
+ * can arrange the correct alignment for the target system.
+ * Goc2c also takes care of conveying to the garbage collector
+ * which parts of the argument list are inputs vs outputs.
+ *
+ * Therefore, do NOT use this macro if at all possible.
+ */ 
 #define FLUSH(x)	USED(x)
 
+/*
+ * GoOutput is a type with the same alignment requirements as the
+ * initial output argument from a Go function. Only for use in cases
+ * where using goc2c is not possible. See comment on FLUSH above.
+ */
+typedef uint64 GoOutput;
+
 void	runtime·gogo(Gobuf*);
 void	runtime·gostartcall(Gobuf*, void(*)(void), void*);
 void	runtime·gostartcallfn(Gobuf*, FuncVal*);
@@ -745,8 +823,10 @@ void	runtime·goenvs_unix(void);
 void*	runtime·getu(void);
 void	runtime·throw(int8*);
 void	runtime·panicstring(int8*);
+bool	runtime·canpanic(G*);
 void	runtime·prints(int8*);
 void	runtime·printf(int8*, ...);
+int32	runtime·snprintf(byte*, int32, int8*, ...);
 byte*	runtime·mchr(byte*, byte, byte*);
 int32	runtime·mcmp(byte*, byte*, uintptr);
 void	runtime·memmove(void*, void*, uintptr);
@@ -764,24 +844,9 @@ int32	runtime·gotraceback(bool *crash);
 void	runtime·goroutineheader(G*);
 int32	runtime·open(int8*, int32, int32);
 int32	runtime·read(int32, void*, int32);
-int32	runtime·write(int32, void*, int32);
+int32	runtime·write(uintptr, void*, int32); // use uintptr to accommodate windows.
 int32	runtime·close(int32);
 int32	runtime·mincore(void*, uintptr, byte*);
-bool	runtime·cas(uint32*, uint32, uint32);
-bool	runtime·cas64(uint64*, uint64, uint64);
-bool	runtime·casp(void**, void*, void*);
-// Don't confuse with XADD x86 instruction,
-// this one is actually 'addx', that is, add-and-fetch.
-uint32	runtime·xadd(uint32 volatile*, int32);
-uint64	runtime·xadd64(uint64 volatile*, int64);
-uint32	runtime·xchg(uint32 volatile*, uint32);
-uint64	runtime·xchg64(uint64 volatile*, uint64);
-uint32	runtime·atomicload(uint32 volatile*);
-void	runtime·atomicstore(uint32 volatile*, uint32);
-void	runtime·atomicstore64(uint64 volatile*, uint64);
-uint64	runtime·atomicload64(uint64 volatile*);
-void*	runtime·atomicloadp(void* volatile*);
-void	runtime·atomicstorep(void* volatile*, void*);
 void	runtime·jmpdefer(FuncVal*, void*);
 void	runtime·exit1(int32);
 void	runtime·ready(G*);
@@ -802,12 +867,12 @@ int32	runtime·funcarglen(Func*, uintptr);
 int32	runtime·funcspdelta(Func*, uintptr);
 int8*	runtime·funcname(Func*);
 int32	runtime·pcdatavalue(Func*, int32, uintptr);
-void*	runtime·stackalloc(uint32);
-void	runtime·stackfree(void*, uintptr);
+void*	runtime·stackalloc(G*, uint32);
+void	runtime·stackfree(G*, void*, Stktop*);
+void	runtime·shrinkstack(G*);
 MCache*	runtime·allocmcache(void);
 void	runtime·freemcache(MCache*);
 void	runtime·mallocinit(void);
-void	runtime·mprofinit(void);
 bool	runtime·ifaceeq_c(Iface, Iface);
 bool	runtime·efaceeq_c(Eface, Eface);
 uintptr	runtime·ifacehash(Iface, uintptr);
@@ -822,15 +887,35 @@ void	runtime·mcall(void(*)(G*));
 uint32	runtime·fastrand1(void);
 void	runtime·rewindmorestack(Gobuf*);
 int32	runtime·timediv(int64, int32, int32*);
+int32	runtime·round2(int32 x); // round x up to a power of 2.
+
+// atomic operations
+bool	runtime·cas(uint32*, uint32, uint32);
+bool	runtime·cas64(uint64*, uint64, uint64);
+bool	runtime·casp(void**, void*, void*);
+// Don't confuse with XADD x86 instruction,
+// this one is actually 'addx', that is, add-and-fetch.
+uint32	runtime·xadd(uint32 volatile*, int32);
+uint64	runtime·xadd64(uint64 volatile*, int64);
+uint32	runtime·xchg(uint32 volatile*, uint32);
+uint64	runtime·xchg64(uint64 volatile*, uint64);
+void*	runtime·xchgp(void* volatile*, void*);
+uint32	runtime·atomicload(uint32 volatile*);
+void	runtime·atomicstore(uint32 volatile*, uint32);
+void	runtime·atomicstore64(uint64 volatile*, uint64);
+uint64	runtime·atomicload64(uint64 volatile*);
+void*	runtime·atomicloadp(void* volatile*);
+void	runtime·atomicstorep(void* volatile*, void*);
 
-void runtime·setmg(M*, G*);
-void runtime·newextram(void);
+void	runtime·setmg(M*, G*);
+void	runtime·newextram(void);
 void	runtime·exit(int32);
 void	runtime·breakpoint(void);
 void	runtime·gosched(void);
 void	runtime·gosched0(G*);
 void	runtime·schedtrace(bool);
-void	runtime·park(void(*)(Lock*), Lock*, int8*);
+void	runtime·park(bool(*)(G*, void*), void*, int8*);
+void	runtime·parkunlock(Lock*, int8*);
 void	runtime·tsleep(int64, int8*);
 M*	runtime·newm(void);
 void	runtime·goexit(void);
@@ -841,12 +926,13 @@ void	runtime·exitsyscall(void);
 G*	runtime·newproc1(FuncVal*, byte*, int32, int32, void*);
 bool	runtime·sigsend(int32 sig);
 int32	runtime·callers(int32, uintptr*, int32);
-int64	runtime·nanotime(void);
+int64	runtime·nanotime(void);	// monotonic time
+int64	runtime·unixnanotime(void); // real time, can skip
 void	runtime·dopanic(int32);
 void	runtime·startpanic(void);
 void	runtime·freezetheworld(void);
 void	runtime·unwindstack(G*, byte*);
-void	runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp);
+void	runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp);
 void	runtime·resetcpuprofiler(int32);
 void	runtime·setcpuprofilerate(void(*)(uintptr*, int32), int32);
 void	runtime·usleep(uint32);
@@ -862,10 +948,19 @@ int32	runtime·netpollopen(uintptr, PollDesc*);
 int32   runtime·netpollclose(uintptr);
 void	runtime·netpollready(G**, PollDesc*, int32);
 uintptr	runtime·netpollfd(PollDesc*);
+void	runtime·netpollarm(PollDesc*, int32);
+void**	runtime·netpolluser(PollDesc*);
+bool	runtime·netpollclosing(PollDesc*);
+void	runtime·netpolllock(PollDesc*);
+void	runtime·netpollunlock(PollDesc*);
 void	runtime·crash(void);
 void	runtime·parsedebugvars(void);
 void	_rt0_go(void);
 void*	runtime·funcdata(Func*, int32);
+int32	runtime·setmaxthreads(int32);
+G*	runtime·timejump(void);
+void	runtime·iterate_itabs(void (*callback)(Itab*));
+void	runtime·iterate_finq(void (*callback)(FuncVal*, byte*, uintptr, Type*, PtrType*));
 
 #pragma	varargck	argpos	runtime·printf	1
 #pragma	varargck	type	"c"	int32
@@ -954,13 +1049,7 @@ LFNode*	runtime·lfstackpop(uint64 *head);
 ParFor*	runtime·parforalloc(uint32 nthrmax);
 void	runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32));
 void	runtime·parfordo(ParFor *desc);
-
-/*
- * This is consistent across Linux and BSD.
- * If a new OS is added that is different, move this to
- * $GOOS/$GOARCH/defs.h.
- */
-#define EACCES		13
+void	runtime·parforiters(ParFor*, uintptr, uintptr*, uintptr*);
 
 /*
  * low level C-called
@@ -992,10 +1081,11 @@ void	runtime·printhex(uint64);
 void	runtime·printslice(Slice);
 void	runtime·printcomplex(Complex128);
 void	runtime·newstackcall(FuncVal*, byte*, uint32);
-void	reflect·call(FuncVal*, byte*, uint32);
+void	reflect·call(FuncVal*, byte*, uint32, uint32);
 void	runtime·panic(Eface);
 void	runtime·panicindex(void);
 void	runtime·panicslice(void);
+void	runtime·panicdivide(void);
 
 /*
  * runtime c-called (but written in Go)
@@ -1036,16 +1126,8 @@ void	runtime·procyield(uint32);
 void	runtime·osyield(void);
 void	runtime·lockOSThread(void);
 void	runtime·unlockOSThread(void);
+bool	runtime·lockedOSThread(void);
 
-void	runtime·mapassign(MapType*, Hmap*, byte*, byte*);
-void	runtime·mapaccess(MapType*, Hmap*, byte*, byte*, bool*);
-void	runtime·mapiternext(struct hash_iter*);
-bool	runtime·mapiterkey(struct hash_iter*, void*);
-Hmap*	runtime·makemap_c(MapType*, int64);
-
-Hchan*	runtime·makechan_c(ChanType*, int64);
-void	runtime·chansend(ChanType*, Hchan*, byte*, bool*, void*);
-void	runtime·chanrecv(ChanType*, Hchan*, byte*, bool*, bool*);
 bool	runtime·showframe(Func*, G*);
 void	runtime·printcreatedby(G*);
 
diff --git a/src/pkg/runtime/runtime1.goc b/src/pkg/runtime/runtime1.goc
index d2c38df..c6f6b62 100644
--- a/src/pkg/runtime/runtime1.goc
+++ b/src/pkg/runtime/runtime1.goc
@@ -4,6 +4,8 @@
 
 package runtime
 #include "runtime.h"
+#include "arch_GOARCH.h"
+#include "type.h"
 
 func GOMAXPROCS(n int) (ret int) {
 	ret = runtime·gomaxprocsfunc(n);
@@ -12,3 +14,115 @@ func GOMAXPROCS(n int) (ret int) {
 func NumCPU() (ret int) {
 	ret = runtime·ncpu;
 }
+
+func NumCgoCall() (ret int64) {
+	M *mp;
+
+	ret = 0;
+	for(mp=runtime·atomicloadp(&runtime·allm); mp; mp=mp->alllink)
+		ret += mp->ncgocall;
+}
+
+func newParFor(nthrmax uint32) (desc *ParFor) {
+	desc = runtime·parforalloc(nthrmax);
+}
+
+func parForSetup(desc *ParFor, nthr uint32, n uint32, ctx *byte, wait bool, body *byte) {
+	runtime·parforsetup(desc, nthr, n, ctx, wait, *(void(**)(ParFor*, uint32))body);
+}
+
+func parForDo(desc *ParFor) {
+	runtime·parfordo(desc);
+}
+
+func parForIters(desc *ParFor, tid uintptr) (start uintptr, end uintptr) {
+	runtime·parforiters(desc, tid, &start, &end);
+}
+
+func gogoBytes() (x int32) {
+	x = RuntimeGogoBytes;
+}
+
+func typestring(e Eface) (s String) {
+	s = *e.type->string;
+}
+
+func golockedOSThread() (ret bool) {
+	ret = runtime·lockedOSThread();
+}
+
+func NumGoroutine() (ret int) {
+	ret = runtime·gcount();
+}
+
+func getgoroot() (out String) {
+	byte *p;
+
+	p = runtime·getenv("GOROOT");
+	out = runtime·gostringnocopy(p);
+}
+
+/*
+ * We assume that all architectures turn faults and the like
+ * into apparent calls to runtime.sigpanic.  If we see a "call"
+ * to runtime.sigpanic, we do not back up the PC to find the
+ * line number of the CALL instruction, because there is no CALL.
+ */
+void	runtime·sigpanic(void);
+
+func Caller(skip int) (retpc uintptr, retfile String, retline int, retbool bool) {
+	Func *f, *g;
+	uintptr pc;
+	uintptr rpc[2];
+
+	/*
+	 * Ask for two PCs: the one we were asked for
+	 * and what it called, so that we can see if it
+	 * "called" sigpanic.
+	 */
+	retpc = 0;
+	if(runtime·callers(1+skip-1, rpc, 2) < 2) {
+		retfile = runtime·emptystring;
+		retline = 0;
+		retbool = false;
+	} else if((f = runtime·findfunc(rpc[1])) == nil) {
+		retfile = runtime·emptystring;
+		retline = 0;
+		retbool = true;  // have retpc at least
+	} else {
+		retpc = rpc[1];
+		pc = retpc;
+		g = runtime·findfunc(rpc[0]);
+		if(pc > f->entry && (g == nil || g->entry != (uintptr)runtime·sigpanic))
+			pc--;
+		retline = runtime·funcline(f, pc, &retfile);
+		retbool = true;
+	}
+}
+
+func Callers(skip int, pc Slice) (retn int) {
+	// runtime.callers uses pc.array==nil as a signal
+	// to print a stack trace.  Pick off 0-length pc here
+	// so that we don't let a nil pc slice get to it.
+	if(pc.len == 0)
+		retn = 0;
+	else
+		retn = runtime·callers(skip, (uintptr*)pc.array, pc.len);
+}
+
+func runtime∕pprof·runtime_cyclesPerSecond() (res int64) {
+	res = runtime·tickspersecond();
+}
+
+func sync·runtime_procPin() (p int) {
+	M *mp;
+
+	mp = m;
+	// Disable preemption.
+	mp->locks++;
+	p = mp->p->id;
+}
+
+func sync·runtime_procUnpin() {
+	m->locks--;
+}
diff --git a/src/pkg/runtime/runtime_test.go b/src/pkg/runtime/runtime_test.go
index de6e549..5a9f52f 100644
--- a/src/pkg/runtime/runtime_test.go
+++ b/src/pkg/runtime/runtime_test.go
@@ -10,9 +10,11 @@ import (
 	"os"
 	"os/exec"
 	. "runtime"
+	"runtime/debug"
 	"strconv"
 	"strings"
 	"testing"
+	"unsafe"
 )
 
 var errf error
@@ -93,6 +95,10 @@ func BenchmarkDeferMany(b *testing.B) {
 // The value reported will include the padding between runtime.gogo and the
 // next function in memory. That's fine.
 func TestRuntimeGogoBytes(t *testing.T) {
+	if GOOS == "nacl" {
+		t.Skip("skipping on nacl")
+	}
+
 	dir, err := ioutil.TempDir("", "go-build")
 	if err != nil {
 		t.Fatalf("failed to create temp directory: %v", err)
@@ -104,7 +110,7 @@ func TestRuntimeGogoBytes(t *testing.T) {
 		t.Fatalf("building hello world: %v\n%s", err, out)
 	}
 
-	out, err = exec.Command("go", "tool", "nm", "-S", dir+"/hello").CombinedOutput()
+	out, err = exec.Command("go", "tool", "nm", "-size", dir+"/hello").CombinedOutput()
 	if err != nil {
 		t.Fatalf("go tool nm: %v\n%s", err, out)
 	}
@@ -122,3 +128,77 @@ func TestRuntimeGogoBytes(t *testing.T) {
 
 	t.Fatalf("go tool nm did not report size for runtime.gogo")
 }
+
+// golang.org/issue/7063
+func TestStopCPUProfilingWithProfilerOff(t *testing.T) {
+	SetCPUProfileRate(0)
+}
+
+// Addresses to test for faulting behavior.
+// This is less a test of SetPanicOnFault and more a check that
+// the operating system and the runtime can process these faults
+// correctly. That is, we're indirectly testing that without SetPanicOnFault
+// these would manage to turn into ordinary crashes.
+// Note that these are truncated on 32-bit systems, so the bottom 32 bits
+// of the larger addresses must themselves be invalid addresses.
+// We might get unlucky and the OS might have mapped one of these
+// addresses, but probably not: they're all in the first page, very high
+// adderesses that normally an OS would reserve for itself, or malformed
+// addresses. Even so, we might have to remove one or two on different
+// systems. We will see.
+
+var faultAddrs = []uint64{
+	// low addresses
+	0,
+	1,
+	0xfff,
+	// high (kernel) addresses
+	// or else malformed.
+	0xffffffffffffffff,
+	0xfffffffffffff001,
+	// no 0xffffffffffff0001; 0xffff0001 is mapped for 32-bit user space on OS X
+	// no 0xfffffffffff00001; 0xfff00001 is mapped for 32-bit user space sometimes on Linux
+	0xffffffffff000001,
+	0xfffffffff0000001,
+	0xffffffff00000001,
+	0xfffffff000000001,
+	0xffffff0000000001,
+	0xfffff00000000001,
+	0xffff000000000001,
+	0xfff0000000000001,
+	0xff00000000000001,
+	0xf000000000000001,
+	0x8000000000000001,
+}
+
+func TestSetPanicOnFault(t *testing.T) {
+	// This currently results in a fault in the signal trampoline on
+	// dragonfly/386 - see issue 7421.
+	if GOOS == "dragonfly" && GOARCH == "386" {
+		t.Skip("skipping test on dragonfly/386")
+	}
+
+	old := debug.SetPanicOnFault(true)
+	defer debug.SetPanicOnFault(old)
+
+	for _, addr := range faultAddrs {
+		testSetPanicOnFault(t, uintptr(addr))
+	}
+}
+
+func testSetPanicOnFault(t *testing.T, addr uintptr) {
+	if GOOS == "nacl" {
+		t.Skip("nacl doesn't seem to fault on high addresses")
+	}
+
+	defer func() {
+		if err := recover(); err == nil {
+			t.Fatalf("did not find error in recover")
+		}
+	}()
+
+	var p *int
+	p = (*int)(unsafe.Pointer(addr))
+	println(*p)
+	t.Fatalf("still here - should have faulted on address %#x", addr)
+}
diff --git a/src/pkg/runtime/runtime_unix_test.go b/src/pkg/runtime/runtime_unix_test.go
new file mode 100644
index 0000000..963de8c
--- /dev/null
+++ b/src/pkg/runtime/runtime_unix_test.go
@@ -0,0 +1,56 @@
+// 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.
+
+// Only works on systems with syscall.Close.
+// We need a fast system call to provoke the race,
+// and Close(-1) is nearly universally fast.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd plan9
+
+package runtime_test
+
+import (
+	"runtime"
+	"sync"
+	"sync/atomic"
+	"syscall"
+	"testing"
+)
+
+func TestGoroutineProfile(t *testing.T) {
+	// GoroutineProfile used to use the wrong starting sp for
+	// goroutines coming out of system calls, causing possible
+	// crashes.
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(100))
+
+	var stop uint32
+	defer atomic.StoreUint32(&stop, 1) // in case of panic
+
+	var wg sync.WaitGroup
+	for i := 0; i < 4; i++ {
+		wg.Add(1)
+		go func() {
+			for atomic.LoadUint32(&stop) == 0 {
+				syscall.Close(-1)
+			}
+			wg.Done()
+		}()
+	}
+
+	max := 10000
+	if testing.Short() {
+		max = 100
+	}
+	stk := make([]runtime.StackRecord, 100)
+	for n := 0; n < max; n++ {
+		_, ok := runtime.GoroutineProfile(stk)
+		if !ok {
+			t.Fatalf("GoroutineProfile failed")
+		}
+	}
+
+	// If the program didn't crash, we passed.
+	atomic.StoreUint32(&stop, 1)
+	wg.Wait()
+}
diff --git a/src/pkg/runtime/sema.goc b/src/pkg/runtime/sema.goc
index 57f32a0..c1e8e4e 100644
--- a/src/pkg/runtime/sema.goc
+++ b/src/pkg/runtime/sema.goc
@@ -137,7 +137,7 @@ runtime·semacquire(uint32 volatile *addr, bool profile)
 		// Any semrelease after the cansemacquire knows we're waiting
 		// (we set nwait above), so go to sleep.
 		semqueue(root, addr, &s);
-		runtime·park(runtime·unlock, root, "semacquire");
+		runtime·parkunlock(root, "semacquire");
 		if(cansemacquire(addr)) {
 			if(t0)
 				runtime·blockevent(s.releasetime - t0, 3);
@@ -254,7 +254,7 @@ func runtime_Syncsemacquire(s *SyncSema) {
 		else
 			s->tail->next = &w;
 		s->tail = &w;
-		runtime·park(runtime·unlock, s, "semacquire");
+		runtime·parkunlock(s, "semacquire");
 		if(t0)
 			runtime·blockevent(w.releasetime - t0, 2);
 	}
@@ -288,7 +288,7 @@ func runtime_Syncsemrelease(s *SyncSema, n uint32) {
 		else
 			s->tail->next = &w;
 		s->tail = &w;
-		runtime·park(runtime·unlock, s, "semarelease");
+		runtime·parkunlock(s, "semarelease");
 	} else
 		runtime·unlock(s);
 }
diff --git a/src/pkg/runtime/signal_386.c b/src/pkg/runtime/signal_386.c
index 5a913c6..70fcc6a 100644
--- a/src/pkg/runtime/signal_386.c
+++ b/src/pkg/runtime/signal_386.c
@@ -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
 
 #include "runtime.h"
 #include "defs_GOOS_GOARCH.h"
@@ -39,15 +39,12 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
 	bool crash;
 
 	if(sig == SIGPROF) {
-		runtime·sigprof((byte*)SIG_EIP(info, ctxt), (byte*)SIG_ESP(info, ctxt), nil, gp);
+		runtime·sigprof((byte*)SIG_EIP(info, ctxt), (byte*)SIG_ESP(info, ctxt), nil, gp, m);
 		return;
 	}
 
 	t = &runtime·sigtab[sig];
 	if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) {
-		if(gp == nil || gp == m->g0)
-			goto Throw;
-
 		// Make it look like a call to the signal func.
 		// Have to pass arguments out of band since
 		// augmenting the stack frame would break
@@ -94,7 +91,6 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
 	if(!(t->flags & SigThrow))
 		return;
 
-Throw:
 	m->throwing = 1;
 	m->caughtsig = gp;
 	runtime·startpanic();
@@ -112,6 +108,7 @@ Throw:
 	runtime·printf("\n");
 
 	if(runtime·gotraceback(&crash)){
+		runtime·goroutineheader(gp);
 		runtime·traceback(SIG_EIP(info, ctxt), SIG_ESP(info, ctxt), 0, gp);
 		runtime·tracebackothers(gp);
 		runtime·printf("\n");
diff --git a/src/pkg/runtime/signal_amd64.c b/src/pkg/runtime/signal_amd64.c
deleted file mode 100644
index f0cbb1f..0000000
--- a/src/pkg/runtime/signal_amd64.c
+++ /dev/null
@@ -1,135 +0,0 @@
-// 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 darwin dragonfly freebsd linux netbsd openbsd
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_GOOS_GOARCH.h"
-#include "signals_GOOS.h"
-
-void
-runtime·dumpregs(Siginfo *info, void *ctxt)
-{
-	USED(info);
-	USED(ctxt);
-	
-	runtime·printf("rax     %X\n", SIG_RAX(info, ctxt));
-	runtime·printf("rbx     %X\n", SIG_RBX(info, ctxt));
-	runtime·printf("rcx     %X\n", SIG_RCX(info, ctxt));
-	runtime·printf("rdx     %X\n", SIG_RDX(info, ctxt));
-	runtime·printf("rdi     %X\n", SIG_RDI(info, ctxt));
-	runtime·printf("rsi     %X\n", SIG_RSI(info, ctxt));
-	runtime·printf("rbp     %X\n", SIG_RBP(info, ctxt));
-	runtime·printf("rsp     %X\n", SIG_RSP(info, ctxt));
-	runtime·printf("r8      %X\n", SIG_R8(info, ctxt) );
-	runtime·printf("r9      %X\n", SIG_R9(info, ctxt) );
-	runtime·printf("r10     %X\n", SIG_R10(info, ctxt));
-	runtime·printf("r11     %X\n", SIG_R11(info, ctxt));
-	runtime·printf("r12     %X\n", SIG_R12(info, ctxt));
-	runtime·printf("r13     %X\n", SIG_R13(info, ctxt));
-	runtime·printf("r14     %X\n", SIG_R14(info, ctxt));
-	runtime·printf("r15     %X\n", SIG_R15(info, ctxt));
-	runtime·printf("rip     %X\n", SIG_RIP(info, ctxt));
-	runtime·printf("rflags  %X\n", SIG_RFLAGS(info, ctxt));
-	runtime·printf("cs      %X\n", SIG_CS(info, ctxt));
-	runtime·printf("fs      %X\n", SIG_FS(info, ctxt));
-	runtime·printf("gs      %X\n", SIG_GS(info, ctxt));
-}
-
-void
-runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
-{
-	uintptr *sp;
-	SigTab *t;
-	bool crash;
-
-	if(sig == SIGPROF) {
-		runtime·sigprof((byte*)SIG_RIP(info, ctxt), (byte*)SIG_RSP(info, ctxt), nil, gp);
-		return;
-	}
-
-	t = &runtime·sigtab[sig];
-	if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) {
-		if(gp == nil || gp == m->g0)
-			goto Throw;
-
-		// Make it look like a call to the signal func.
-		// Have to pass arguments out of band since
-		// augmenting the stack frame would break
-		// the unwinding code.
-		gp->sig = sig;
-		gp->sigcode0 = SIG_CODE0(info, ctxt);
-		gp->sigcode1 = SIG_CODE1(info, ctxt);
-		gp->sigpc = SIG_RIP(info, ctxt);
-
-#ifdef GOOS_darwin
-		// Work around Leopard bug that doesn't set FPE_INTDIV.
-		// Look at instruction to see if it is a divide.
-		// Not necessary in Snow Leopard (si_code will be != 0).
-		if(sig == SIGFPE && gp->sigcode0 == 0) {
-			byte *pc;
-			pc = (byte*)gp->sigpc;
-			if((pc[0]&0xF0) == 0x40)	// 64-bit REX prefix
-				pc++;
-			else if(pc[0] == 0x66)	// 16-bit instruction prefix
-				pc++;
-			if(pc[0] == 0xF6 || pc[0] == 0xF7)
-				gp->sigcode0 = FPE_INTDIV;
-		}
-#endif
-
-		// Only push runtime·sigpanic if rip != 0.
-		// If rip == 0, probably panicked because of a
-		// call to a nil func.  Not pushing that onto sp will
-		// make the trace look like a call to runtime·sigpanic instead.
-		// (Otherwise the trace will end at runtime·sigpanic and we
-		// won't get to see who faulted.)
-		if(SIG_RIP(info, ctxt) != 0) {
-			sp = (uintptr*)SIG_RSP(info, ctxt);
-			*--sp = SIG_RIP(info, ctxt);
-			SIG_RSP(info, ctxt) = (uintptr)sp;
-		}
-		SIG_RIP(info, ctxt) = (uintptr)runtime·sigpanic;
-		return;
-	}
-
-	if(SIG_CODE0(info, ctxt) == SI_USER || (t->flags & SigNotify))
-		if(runtime·sigsend(sig))
-			return;
-	if(t->flags & SigKill)
-		runtime·exit(2);
-	if(!(t->flags & SigThrow))
-		return;
-
-Throw:
-	m->throwing = 1;
-	m->caughtsig = gp;
-	runtime·startpanic();
-
-	if(sig < 0 || sig >= NSIG)
-		runtime·printf("Signal %d\n", sig);
-	else
-		runtime·printf("%s\n", runtime·sigtab[sig].name);
-
-	runtime·printf("PC=%X\n", SIG_RIP(info, ctxt));
-	if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
-		runtime·printf("signal arrived during cgo execution\n");
-		gp = m->lockedg;
-	}
-	runtime·printf("\n");
-
-	if(runtime·gotraceback(&crash)){
-		runtime·traceback(SIG_RIP(info, ctxt), SIG_RSP(info, ctxt), 0, gp);
-		runtime·tracebackothers(gp);
-		runtime·printf("\n");
-		runtime·dumpregs(info, ctxt);
-	}
-	
-	if(crash)
-		runtime·crash();
-
-	runtime·exit(2);
-}
diff --git a/src/pkg/runtime/signal_amd64x.c b/src/pkg/runtime/signal_amd64x.c
new file mode 100644
index 0000000..04026f3
--- /dev/null
+++ b/src/pkg/runtime/signal_amd64x.c
@@ -0,0 +1,156 @@
+// 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 amd64 amd64p32
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "signal_GOOS_GOARCH.h"
+#include "signals_GOOS.h"
+
+void
+runtime·dumpregs(Siginfo *info, void *ctxt)
+{
+	USED(info);
+	USED(ctxt);
+	
+	runtime·printf("rax     %X\n", SIG_RAX(info, ctxt));
+	runtime·printf("rbx     %X\n", SIG_RBX(info, ctxt));
+	runtime·printf("rcx     %X\n", SIG_RCX(info, ctxt));
+	runtime·printf("rdx     %X\n", SIG_RDX(info, ctxt));
+	runtime·printf("rdi     %X\n", SIG_RDI(info, ctxt));
+	runtime·printf("rsi     %X\n", SIG_RSI(info, ctxt));
+	runtime·printf("rbp     %X\n", SIG_RBP(info, ctxt));
+	runtime·printf("rsp     %X\n", SIG_RSP(info, ctxt));
+	runtime·printf("r8      %X\n", SIG_R8(info, ctxt) );
+	runtime·printf("r9      %X\n", SIG_R9(info, ctxt) );
+	runtime·printf("r10     %X\n", SIG_R10(info, ctxt));
+	runtime·printf("r11     %X\n", SIG_R11(info, ctxt));
+	runtime·printf("r12     %X\n", SIG_R12(info, ctxt));
+	runtime·printf("r13     %X\n", SIG_R13(info, ctxt));
+	runtime·printf("r14     %X\n", SIG_R14(info, ctxt));
+	runtime·printf("r15     %X\n", SIG_R15(info, ctxt));
+	runtime·printf("rip     %X\n", SIG_RIP(info, ctxt));
+	runtime·printf("rflags  %X\n", SIG_RFLAGS(info, ctxt));
+	runtime·printf("cs      %X\n", SIG_CS(info, ctxt));
+	runtime·printf("fs      %X\n", SIG_FS(info, ctxt));
+	runtime·printf("gs      %X\n", SIG_GS(info, ctxt));
+}
+
+void
+runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
+{
+	uintptr *sp;
+	SigTab *t;
+	bool crash;
+
+	if(sig == SIGPROF) {
+		runtime·sigprof((byte*)SIG_RIP(info, ctxt), (byte*)SIG_RSP(info, ctxt), nil, gp, m);
+		return;
+	}
+
+#ifdef GOOS_darwin
+	// x86-64 has 48-bit virtual addresses. The top 16 bits must echo bit 47.
+	// The hardware delivers a different kind of fault for a malformed address
+	// than it does for an attempt to access a valid but unmapped address.
+	// OS X 10.9.2 mishandles the malformed address case, making it look like
+	// a user-generated signal (like someone ran kill -SEGV ourpid).
+	// We pass user-generated signals to os/signal, or else ignore them.
+	// Doing that here - and returning to the faulting code - results in an
+	// infinite loop. It appears the best we can do is rewrite what the kernel
+	// delivers into something more like the truth. The address used below
+	// has very little chance of being the one that caused the fault, but it is
+	// malformed, it is clearly not a real pointer, and if it does get printed
+	// in real life, people will probably search for it and find this code.
+	// There are no Google hits for b01dfacedebac1e or 0xb01dfacedebac1e
+	// as I type this comment.
+	if(sig == SIGSEGV && SIG_CODE0(info, ctxt) == SI_USER) {
+		SIG_CODE0(info, ctxt) = SI_USER+1;
+		info->si_addr = (void*)(uintptr)0xb01dfacedebac1eULL;
+	}
+#endif
+
+	t = &runtime·sigtab[sig];
+	if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) {
+		// Make it look like a call to the signal func.
+		// Have to pass arguments out of band since
+		// augmenting the stack frame would break
+		// the unwinding code.
+		gp->sig = sig;
+		gp->sigcode0 = SIG_CODE0(info, ctxt);
+		gp->sigcode1 = SIG_CODE1(info, ctxt);
+		gp->sigpc = SIG_RIP(info, ctxt);
+
+#ifdef GOOS_darwin
+		// Work around Leopard bug that doesn't set FPE_INTDIV.
+		// Look at instruction to see if it is a divide.
+		// Not necessary in Snow Leopard (si_code will be != 0).
+		if(sig == SIGFPE && gp->sigcode0 == 0) {
+			byte *pc;
+			pc = (byte*)gp->sigpc;
+			if((pc[0]&0xF0) == 0x40)	// 64-bit REX prefix
+				pc++;
+			else if(pc[0] == 0x66)	// 16-bit instruction prefix
+				pc++;
+			if(pc[0] == 0xF6 || pc[0] == 0xF7)
+				gp->sigcode0 = FPE_INTDIV;
+		}
+#endif
+
+		// Only push runtime·sigpanic if rip != 0.
+		// If rip == 0, probably panicked because of a
+		// call to a nil func.  Not pushing that onto sp will
+		// make the trace look like a call to runtime·sigpanic instead.
+		// (Otherwise the trace will end at runtime·sigpanic and we
+		// won't get to see who faulted.)
+		if(SIG_RIP(info, ctxt) != 0) {
+			sp = (uintptr*)SIG_RSP(info, ctxt);
+			if(sizeof(uintreg) > sizeof(uintptr))
+				*--sp = 0;
+			*--sp = SIG_RIP(info, ctxt);
+			SIG_RSP(info, ctxt) = (uintptr)sp;
+		}
+		SIG_RIP(info, ctxt) = (uintptr)runtime·sigpanic;
+		return;
+	}
+
+	if(SIG_CODE0(info, ctxt) == SI_USER || (t->flags & SigNotify))
+		if(runtime·sigsend(sig))
+			return;
+	if(t->flags & SigKill)
+		runtime·exit(2);
+	if(!(t->flags & SigThrow))
+		return;
+
+	m->throwing = 1;
+	m->caughtsig = gp;
+	runtime·startpanic();
+
+	if(sig < 0 || sig >= NSIG)
+		runtime·printf("Signal %d\n", sig);
+	else
+		runtime·printf("%s\n", runtime·sigtab[sig].name);
+
+	runtime·printf("PC=%X\n", SIG_RIP(info, ctxt));
+	if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+		runtime·printf("signal arrived during cgo execution\n");
+		gp = m->lockedg;
+	}
+	runtime·printf("\n");
+
+	if(runtime·gotraceback(&crash)){
+		runtime·goroutineheader(gp);
+		runtime·traceback(SIG_RIP(info, ctxt), SIG_RSP(info, ctxt), 0, gp);
+		runtime·tracebackothers(gp);
+		runtime·printf("\n");
+		runtime·dumpregs(info, ctxt);
+	}
+	
+	if(crash)
+		runtime·crash();
+
+	runtime·exit(2);
+}
diff --git a/src/pkg/runtime/signal_arm.c b/src/pkg/runtime/signal_arm.c
index a6e2396..9b2a43d 100644
--- a/src/pkg/runtime/signal_arm.c
+++ b/src/pkg/runtime/signal_arm.c
@@ -46,15 +46,12 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
 	bool crash;
 
 	if(sig == SIGPROF) {
-		runtime·sigprof((uint8*)SIG_PC(info, ctxt), (uint8*)SIG_SP(info, ctxt), (uint8*)SIG_LR(info, ctxt), gp);
+		runtime·sigprof((uint8*)SIG_PC(info, ctxt), (uint8*)SIG_SP(info, ctxt), (uint8*)SIG_LR(info, ctxt), gp, m);
 		return;
 	}
 
 	t = &runtime·sigtab[sig];
 	if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) {
-		if(gp == nil || gp == m->g0)
-			goto Throw;
-
 		// Make it look like a call to the signal func.
 		// Have to pass arguments out of band since
 		// augmenting the stack frame would break
@@ -92,7 +89,6 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
 	if(!(t->flags & SigThrow))
 		return;
 
-Throw:
 	m->throwing = 1;
 	m->caughtsig = gp;
 	if(runtime·panicking)	// traceback already printed
@@ -112,6 +108,7 @@ Throw:
 	runtime·printf("\n");
 
 	if(runtime·gotraceback(&crash)){
+		runtime·goroutineheader(gp);
 		runtime·traceback(SIG_PC(info, ctxt), SIG_SP(info, ctxt), SIG_LR(info, ctxt), gp);
 		runtime·tracebackothers(gp);
 		runtime·printf("\n");
diff --git a/src/pkg/runtime/signal_nacl_386.h b/src/pkg/runtime/signal_nacl_386.h
new file mode 100644
index 0000000..c9481b5
--- /dev/null
+++ b/src/pkg/runtime/signal_nacl_386.h
@@ -0,0 +1,23 @@
+// 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.
+
+#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs)
+
+#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).eax)
+#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).ebx)
+#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).ecx)
+#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).edx)
+#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).edi)
+#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).esi)
+#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).ebp)
+#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).esp)
+#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).eip)
+#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).eflags)
+
+#define SIG_CS(info, ctxt) (~0)
+#define SIG_FS(info, ctxt) (~0)
+#define SIG_GS(info, ctxt) (~0)
+
+#define SIG_CODE0(info, ctxt) (~0)
+#define SIG_CODE1(info, ctxt) (0)
diff --git a/src/pkg/runtime/signal_nacl_amd64p32.h b/src/pkg/runtime/signal_nacl_amd64p32.h
new file mode 100644
index 0000000..c58593a
--- /dev/null
+++ b/src/pkg/runtime/signal_nacl_amd64p32.h
@@ -0,0 +1,31 @@
+// 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.
+
+#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs64)
+
+#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).rax)
+#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).rbx)
+#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).rcx)
+#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).rdx)
+#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).rdi)
+#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).rsi)
+#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).rbp)
+#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).rsp)
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8)
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9)
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10)
+#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).r11)
+#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).r12)
+#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).r13)
+#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).r14)
+#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).r15)
+#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).rip)
+#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).rflags)
+
+#define SIG_CS(info, ctxt) (~0)
+#define SIG_FS(info, ctxt) (~0)
+#define SIG_GS(info, ctxt) (~0)
+
+#define SIG_CODE0(info, ctxt) (~0)
+#define SIG_CODE1(info, ctxt) (0)
diff --git a/src/pkg/runtime/signal_solaris_amd64.h b/src/pkg/runtime/signal_solaris_amd64.h
new file mode 100644
index 0000000..c2e0a15
--- /dev/null
+++ b/src/pkg/runtime/signal_solaris_amd64.h
@@ -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.
+
+#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext)
+
+#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RAX])
+#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RBX])
+#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RCX])
+#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RDX])
+#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RDI])
+#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RSI])
+#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RBP])
+#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RSP])
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R8])
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R9])
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R10])
+#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R11])
+#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R12])
+#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R13])
+#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R14])
+#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R15])
+#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RIP])
+#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RFLAGS])
+
+#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).gregs[REG_CS])
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).gregs[REG_FS])
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).gregs[REG_GS])
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->__data[0])
diff --git a/src/pkg/runtime/signal_unix.c b/src/pkg/runtime/signal_unix.c
index 4d14b22..246a1eb 100644
--- a/src/pkg/runtime/signal_unix.c
+++ b/src/pkg/runtime/signal_unix.c
@@ -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 openbsd netbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 #include "runtime.h"
 #include "defs_GOOS_GOARCH.h"
@@ -113,6 +113,7 @@ runtime·crash(void)
 		return;
 #endif
 
+	runtime·unblocksignals();
 	runtime·setsig(SIGABRT, SIG_DFL, false);
 	runtime·raise(SIGABRT);
 }
diff --git a/src/pkg/runtime/signals_freebsd.h b/src/pkg/runtime/signals_freebsd.h
index 4d27e05..8d45c50 100644
--- a/src/pkg/runtime/signals_freebsd.h
+++ b/src/pkg/runtime/signals_freebsd.h
@@ -21,7 +21,7 @@ SigTab runtime·sigtab[] = {
 	/* 9 */	0, "SIGKILL: kill",
 	/* 10 */	P, "SIGBUS: bus error",
 	/* 11 */	P, "SIGSEGV: segmentation violation",
-	/* 12 */	T, "SIGSYS: bad system call",
+	/* 12 */	N, "SIGSYS: bad system call",
 	/* 13 */	N, "SIGPIPE: write to broken pipe",
 	/* 14 */	N, "SIGALRM: alarm clock",
 	/* 15 */	N+K, "SIGTERM: termination",
diff --git a/src/pkg/runtime/signals_linux.h b/src/pkg/runtime/signals_linux.h
index 9c35670..368afc1 100644
--- a/src/pkg/runtime/signals_linux.h
+++ b/src/pkg/runtime/signals_linux.h
@@ -41,7 +41,7 @@ SigTab runtime·sigtab[] = {
 	/* 29 */	N, "SIGIO: i/o now possible",
 	/* 30 */	N, "SIGPWR: power failure restart",
 	/* 31 */	N, "SIGSYS: bad system call",
-	/* 32 */	N, "signal 32",
+	/* 32 */	0, "signal 32", /* SIGCANCEL; see issue 6997 */
 	/* 33 */	0, "signal 33", /* SIGSETXID; see issue 3871 */
 	/* 34 */	N, "signal 34",
 	/* 35 */	N, "signal 35",
diff --git a/src/pkg/runtime/signals_darwin.h b/src/pkg/runtime/signals_nacl.h
similarity index 100%
copy from src/pkg/runtime/signals_darwin.h
copy to src/pkg/runtime/signals_nacl.h
diff --git a/src/pkg/runtime/signals_plan9.h b/src/pkg/runtime/signals_plan9.h
index f9bec65..818f508 100644
--- a/src/pkg/runtime/signals_plan9.h
+++ b/src/pkg/runtime/signals_plan9.h
@@ -3,26 +3,58 @@
 // license that can be found in the LICENSE file.
 
 #define N SigNotify
+#define K SigKill
 #define T SigThrow
 #define P SigPanic
+#define E SigGoExit
+
+// Incoming notes are compared against this table using strncmp, so the
+// order matters: longer patterns must appear before their prefixes.
+// There are #defined SIG constants in os_plan9.h for the table index of
+// some of these.
+//
+// If you add entries to this table, you must respect the prefix ordering
+// and also update the constant values is os_plan9.h.
 
 SigTab runtime·sigtab[] = {
-	P, "sys: fp:",
-
-	// Go libraries expect to be able
-	// to recover from memory
-	// read/write errors, so we flag
-	// those as panics. All other traps
-	// are generally more serious and
-	// should immediately throw an
-	// exception.
-	P, "sys: trap: fault read addr",
-	P, "sys: trap: fault write addr",
-	T, "sys: trap:",
-
-	N, "sys: bad sys call",
+	// Traps that we cannot be recovered.
+	T,	"sys: trap: debug exception",
+	T,	"sys: trap: invalid opcode",
+
+	// We can recover from some memory errors in runtime·sigpanic.
+	P,	"sys: trap: fault read addr",	// SIGRFAULT
+	P,	"sys: trap: fault write addr",	// SIGWFAULT
+
+	// We can also recover from math errors.
+	P,	"sys: trap: divide error",	// SIGINTDIV
+	P,	"sys: fp:",	// SIGFLOAT
+
+	// All other traps are normally handled as if they were marked SigThrow.
+	// We mark them SigPanic here so that debug.SetPanicOnFault will work.
+	P,	"sys: trap:",	// SIGTRAP
+
+	// Writes to a closed pipe can be handled if desired, otherwise they're ignored.
+	N,	"sys: write on closed pipe",
+
+	// Other system notes are more serious and cannot be recovered.
+	T,	"sys:",
+
+	// Issued to all other procs when calling runtime·exit.
+	E,	"go: exit ",
+
+	// Kill is sent by external programs to cause an exit.
+	K,	"kill",
+
+	// Interrupts can be handled if desired, otherwise they cause an exit.
+	N+K,	"interrupt",
+	N+K,	"hangup",
+
+	// Alarms can be handled if desired, otherwise they're ignored.
+	N,	"alarm",
 };
 
 #undef N
+#undef K
 #undef T
 #undef P
+#undef E
diff --git a/src/pkg/runtime/signals_solaris.h b/src/pkg/runtime/signals_solaris.h
new file mode 100644
index 0000000..c272cad
--- /dev/null
+++ b/src/pkg/runtime/signals_solaris.h
@@ -0,0 +1,94 @@
+// 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.
+
+#define N SigNotify
+#define K SigKill
+#define T SigThrow
+#define P SigPanic
+#define D SigDefault
+
+SigTab runtime·sigtab[] = {
+	/* 0 */		0, "SIGNONE: no trap",
+	/* 1 */		N+K, "SIGHUP: hangup",
+	/* 2 */		N+K, "SIGINT: interrupt (rubout)",
+	/* 3 */		N+T, "SIGQUIT: quit (ASCII FS)",
+	/* 4 */		T, "SIGILL: illegal instruction (not reset when caught)",
+	/* 5 */		T, "SIGTRAP: trace trap (not reset when caught)",
+	/* 6 */		N+T, "SIGABRT: used by abort, replace SIGIOT in the future",
+	/* 7 */		T, "SIGEMT: EMT instruction",
+	/* 8 */		P, "SIGFPE: floating point exception",
+	/* 9 */		0, "SIGKILL: kill (cannot be caught or ignored)",
+	/* 10 */	P, "SIGBUS: bus error",
+	/* 11 */	P, "SIGSEGV: segmentation violation",
+	/* 12 */	T, "SIGSYS: bad argument to system call",
+	/* 13 */	N, "SIGPIPE: write on a pipe with no one to read it",
+	/* 14 */	N, "SIGALRM: alarm clock",
+	/* 15 */	N+K, "SIGTERM: software termination signal from kill",
+	/* 16 */	N, "SIGUSR1: user defined signal 1",
+	/* 17 */	N, "SIGUSR2: user defined signal 2",
+	/* 18 */	N, "SIGCLD: child status change",
+	/* 18 */	N, "SIGCHLD: child status change alias (POSIX)",
+	/* 19 */	N, "SIGPWR: power-fail restart",
+	/* 20 */	N, "SIGWINCH: window size change",
+	/* 21 */	N, "SIGURG: urgent socket condition",
+	/* 22 */	N, "SIGPOLL: pollable event occured",
+	/* 23 */	N+D, "SIGSTOP: stop (cannot be caught or ignored)",
+	/* 24 */	0, "SIGTSTP: user stop requested from tty",
+	/* 25 */	0, "SIGCONT: stopped process has been continued",
+	/* 26 */	N+D, "SIGTTIN: background tty read attempted",
+	/* 27 */	N+D, "SIGTTOU: background tty write attempted",
+	/* 28 */	N, "SIGVTALRM: virtual timer expired",
+	/* 29 */	N, "SIGPROF: profiling timer expired",
+	/* 30 */	N, "SIGXCPU: exceeded cpu limit",
+	/* 31 */	N, "SIGXFSZ: exceeded file size limit",
+	/* 32 */	N, "SIGWAITING: reserved signal no longer used by",
+	/* 33 */	N, "SIGLWP: reserved signal no longer used by",
+	/* 34 */	N, "SIGFREEZE: special signal used by CPR",
+	/* 35 */	N, "SIGTHAW: special signal used by CPR",
+	/* 36 */	0, "SIGCANCEL: reserved signal for thread cancellation",
+	/* 37 */	N, "SIGLOST: resource lost (eg, record-lock lost)",
+	/* 38 */	N, "SIGXRES: resource control exceeded",
+	/* 39 */	N, "SIGJVM1: reserved signal for Java Virtual Machine",
+	/* 40 */	N, "SIGJVM2: reserved signal for Java Virtual Machine",
+
+	/* TODO(aram): what should be do about these signals? D or N? is this set static? */
+	/* 41 */	N, "real time signal",
+	/* 42 */	N, "real time signal",
+	/* 43 */	N, "real time signal",
+	/* 44 */	N, "real time signal",
+	/* 45 */	N, "real time signal",
+	/* 46 */	N, "real time signal",
+	/* 47 */	N, "real time signal",
+	/* 48 */	N, "real time signal",
+	/* 49 */	N, "real time signal",
+	/* 50 */	N, "real time signal",
+	/* 51 */	N, "real time signal",
+	/* 52 */	N, "real time signal",
+	/* 53 */	N, "real time signal",
+	/* 54 */	N, "real time signal",
+	/* 55 */	N, "real time signal",
+	/* 56 */	N, "real time signal",
+	/* 57 */	N, "real time signal",
+	/* 58 */	N, "real time signal",
+	/* 59 */	N, "real time signal",
+	/* 60 */	N, "real time signal",
+	/* 61 */	N, "real time signal",
+	/* 62 */	N, "real time signal",
+	/* 63 */	N, "real time signal",
+	/* 64 */	N, "real time signal",
+	/* 65 */	N, "real time signal",
+	/* 66 */	N, "real time signal",
+	/* 67 */	N, "real time signal",
+	/* 68 */	N, "real time signal",
+	/* 69 */	N, "real time signal",
+	/* 70 */	N, "real time signal",
+	/* 71 */	N, "real time signal",
+	/* 72 */	N, "real time signal",
+};
+
+#undef N
+#undef K
+#undef T
+#undef P
+#undef D
diff --git a/src/pkg/runtime/slice.c b/src/pkg/runtime/slice.c
deleted file mode 100644
index ef8ab7f..0000000
--- a/src/pkg/runtime/slice.c
+++ /dev/null
@@ -1,196 +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 "runtime.h"
-#include "arch_GOARCH.h"
-#include "type.h"
-#include "typekind.h"
-#include "malloc.h"
-#include "race.h"
-#include "../../cmd/ld/textflag.h"
-
-enum
-{
-	debug = 0
-};
-
-static	void	makeslice1(SliceType*, intgo, intgo, Slice*);
-static	void	growslice1(SliceType*, Slice, intgo, Slice *);
-	void	runtime·copy(Slice to, Slice fm, uintptr width, intgo ret);
-
-// see also unsafe·NewArray
-// makeslice(typ *Type, len, cap int64) (ary []any);
-void
-runtime·makeslice(SliceType *t, int64 len, int64 cap, Slice ret)
-{
-	// NOTE: The len > MaxMem/elemsize check here is not strictly necessary,
-	// but it produces a 'len out of range' error instead of a 'cap out of range' error
-	// when someone does make([]T, bignumber). 'cap out of range' is true too,
-	// but since the cap is only being supplied implicitly, saying len is clearer.
-	// See issue 4085.
-	if(len < 0 || (intgo)len != len || t->elem->size > 0 && len > MaxMem / t->elem->size)
-		runtime·panicstring("makeslice: len out of range");
-
-	if(cap < len || (intgo)cap != cap || t->elem->size > 0 && cap > MaxMem / t->elem->size)
-		runtime·panicstring("makeslice: cap out of range");
-
-	makeslice1(t, len, cap, &ret);
-
-	if(debug) {
-		runtime·printf("makeslice(%S, %D, %D); ret=",
-			*t->string, len, cap);
-		runtime·printslice(ret);
-	}
-}
-
-// Dummy word to use as base pointer for make([]T, 0).
-// Since you cannot take the address of such a slice,
-// you can't tell that they all have the same base pointer.
-uintptr runtime·zerobase;
-
-static void
-makeslice1(SliceType *t, intgo len, intgo cap, Slice *ret)
-{
-	ret->len = len;
-	ret->cap = cap;
-	ret->array = runtime·cnewarray(t->elem, cap);
-}
-
-// growslice(type *Type, x, []T, n int64) []T
-void
-runtime·growslice(SliceType *t, Slice old, int64 n, Slice ret)
-{
-	int64 cap;
-	void *pc;
-
-	if(n < 1)
-		runtime·panicstring("growslice: invalid n");
-
-	cap = old.cap + n;
-
-	if((intgo)cap != cap || cap < old.cap || (t->elem->size > 0 && cap > MaxMem/t->elem->size))
-		runtime·panicstring("growslice: cap out of range");
-
-	if(raceenabled) {
-		pc = runtime·getcallerpc(&t);
-		runtime·racereadrangepc(old.array, old.len*t->elem->size, pc, runtime·growslice);
-	}
-
-	growslice1(t, old, cap, &ret);
-
-	FLUSH(&ret);
-
-	if(debug) {
-		runtime·printf("growslice(%S,", *t->string);
-		runtime·printslice(old);
-		runtime·printf(", new cap=%D) =", cap);
-		runtime·printslice(ret);
-	}
-}
-
-static void
-growslice1(SliceType *t, Slice x, intgo newcap, Slice *ret)
-{
-	intgo m;
-
-	m = x.cap;
-	
-	// Using newcap directly for m+m < newcap handles
-	// both the case where m == 0 and also the case where
-	// m+m/4 wraps around, in which case the loop
-	// below might never terminate.
-	if(m+m < newcap)
-		m = newcap;
-	else {
-		do {
-			if(x.len < 1024)
-				m += m;
-			else
-				m += m/4;
-		} while(m < newcap);
-	}
-	makeslice1(t, x.len, m, ret);
-	runtime·memmove(ret->array, x.array, ret->len * t->elem->size);
-}
-
-// copy(to any, fr any, wid uintptr) int
-#pragma textflag NOSPLIT
-void
-runtime·copy(Slice to, Slice fm, uintptr width, intgo ret)
-{
-	void *pc;
-
-	if(fm.len == 0 || to.len == 0 || width == 0) {
-		ret = 0;
-		goto out;
-	}
-
-	ret = fm.len;
-	if(to.len < ret)
-		ret = to.len;
-
-	if(raceenabled) {
-		pc = runtime·getcallerpc(&to);
-		runtime·racewriterangepc(to.array, ret*width, pc, runtime·copy);
-		runtime·racereadrangepc(fm.array, ret*width, pc, runtime·copy);
-	}
-
-	if(ret == 1 && width == 1) {	// common case worth about 2x to do here
-		*to.array = *fm.array;	// known to be a byte pointer
-	} else {
-		runtime·memmove(to.array, fm.array, ret*width);
-	}
-
-out:
-	FLUSH(&ret);
-
-	if(debug) {
-		runtime·prints("main·copy: to=");
-		runtime·printslice(to);
-		runtime·prints("; fm=");
-		runtime·printslice(fm);
-		runtime·prints("; width=");
-		runtime·printint(width);
-		runtime·prints("; ret=");
-		runtime·printint(ret);
-		runtime·prints("\n");
-	}
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·slicestringcopy(Slice to, String fm, intgo ret)
-{
-	void *pc;
-
-	if(fm.len == 0 || to.len == 0) {
-		ret = 0;
-		goto out;
-	}
-
-	ret = fm.len;
-	if(to.len < ret)
-		ret = to.len;
-
-	if(raceenabled) {
-		pc = runtime·getcallerpc(&to);
-		runtime·racewriterangepc(to.array, ret, pc, runtime·slicestringcopy);
-	}
-
-	runtime·memmove(to.array, fm.str, ret);
-
-out:
-	FLUSH(&ret);
-}
-
-void
-runtime·printslice(Slice a)
-{
-	runtime·prints("[");
-	runtime·printint(a.len);
-	runtime·prints("/");
-	runtime·printint(a.cap);
-	runtime·prints("]");
-	runtime·printpointer(a.array);
-}
diff --git a/src/pkg/runtime/slice.goc b/src/pkg/runtime/slice.goc
new file mode 100644
index 0000000..2a14daf
--- /dev/null
+++ b/src/pkg/runtime/slice.goc
@@ -0,0 +1,204 @@
+// 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.
+
+package runtime
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "type.h"
+#include "typekind.h"
+#include "malloc.h"
+#include "race.h"
+#include "stack.h"
+#include "../../cmd/ld/textflag.h"
+
+enum
+{
+	debug = 0
+};
+
+static	void	makeslice1(SliceType*, intgo, intgo, Slice*);
+static	void	growslice1(SliceType*, Slice, intgo, Slice *);
+
+// see also unsafe·NewArray
+func makeslice(t *SliceType, len int64, cap int64) (ret Slice) {
+	// NOTE: The len > MaxMem/elemsize check here is not strictly necessary,
+	// but it produces a 'len out of range' error instead of a 'cap out of range' error
+	// when someone does make([]T, bignumber). 'cap out of range' is true too,
+	// but since the cap is only being supplied implicitly, saying len is clearer.
+	// See issue 4085.
+	if(len < 0 || (intgo)len != len || t->elem->size > 0 && len > MaxMem / t->elem->size)
+		runtime·panicstring("makeslice: len out of range");
+
+	if(cap < len || (intgo)cap != cap || t->elem->size > 0 && cap > MaxMem / t->elem->size)
+		runtime·panicstring("makeslice: cap out of range");
+
+	makeslice1(t, len, cap, &ret);
+
+	if(debug) {
+		runtime·printf("makeslice(%S, %D, %D); ret=",
+			*t->string, len, cap);
+		runtime·printslice(ret);
+	}
+}
+
+// Dummy word to use as base pointer for make([]T, 0).
+// Since you cannot take the address of such a slice,
+// you can't tell that they all have the same base pointer.
+uintptr runtime·zerobase;
+
+static void
+makeslice1(SliceType *t, intgo len, intgo cap, Slice *ret)
+{
+	ret->len = len;
+	ret->cap = cap;
+	ret->array = runtime·cnewarray(t->elem, cap);
+}
+
+// growslice(type *Type, x, []T, n int64) []T
+func growslice(t *SliceType, old Slice, n int64) (ret Slice) {
+	int64 cap;
+	void *pc;
+
+	if(n < 1)
+		runtime·panicstring("growslice: invalid n");
+
+	cap = old.cap + n;
+
+	if((intgo)cap != cap || cap < (int64)old.cap || (t->elem->size > 0 && cap > MaxMem/t->elem->size))
+		runtime·panicstring("growslice: cap out of range");
+
+	if(raceenabled) {
+		pc = runtime·getcallerpc(&t);
+		runtime·racereadrangepc(old.array, old.len*t->elem->size, pc, runtime·growslice);
+	}
+
+	growslice1(t, old, cap, &ret);
+
+	if(debug) {
+		runtime·printf("growslice(%S,", *t->string);
+		runtime·printslice(old);
+		runtime·printf(", new cap=%D) =", cap);
+		runtime·printslice(ret);
+	}
+}
+
+static void
+growslice1(SliceType *t, Slice x, intgo newcap, Slice *ret)
+{
+	intgo newcap1;
+	uintptr capmem, lenmem;
+	int32 flag;
+	Type *typ;
+
+	typ = t->elem;
+	if(typ->size == 0) {
+		*ret = x;
+		ret->cap = newcap;
+		return;
+	}
+
+	newcap1 = x.cap;
+	
+	// Using newcap directly for m+m < newcap handles
+	// both the case where m == 0 and also the case where
+	// m+m/4 wraps around, in which case the loop
+	// below might never terminate.
+	if(newcap1+newcap1 < newcap)
+		newcap1 = newcap;
+	else {
+		do {
+			if(x.len < 1024)
+				newcap1 += newcap1;
+			else
+				newcap1 += newcap1/4;
+		} while(newcap1 < newcap);
+	}
+
+	if(newcap1 > MaxMem/typ->size)
+		runtime·panicstring("growslice: cap out of range");
+	capmem = runtime·roundupsize(newcap1*typ->size);
+	flag = 0;
+	// Can't use FlagNoZero w/o FlagNoScan, because otherwise GC can scan unitialized memory.
+	if(typ->kind&KindNoPointers)
+		flag = FlagNoScan|FlagNoZero;
+	ret->array = runtime·mallocgc(capmem, (uintptr)typ|TypeInfo_Array, flag);
+	ret->len = x.len;
+	ret->cap = capmem/typ->size;
+	lenmem = x.len*typ->size;
+	runtime·memmove(ret->array, x.array, lenmem);
+	if(typ->kind&KindNoPointers)
+		runtime·memclr(ret->array+lenmem, capmem-lenmem);
+}
+
+#pragma textflag NOSPLIT
+func copy(to Slice, fm Slice, width uintptr) (ret int) {
+	void *pc;
+
+	if(fm.len == 0 || to.len == 0 || width == 0) {
+		ret = 0;
+		goto out;
+	}
+
+	ret = fm.len;
+	if(to.len < ret)
+		ret = to.len;
+
+	if(raceenabled) {
+		pc = runtime·getcallerpc(&to);
+		runtime·racewriterangepc(to.array, ret*width, pc, runtime·copy);
+		runtime·racereadrangepc(fm.array, ret*width, pc, runtime·copy);
+	}
+
+	if(ret == 1 && width == 1) {	// common case worth about 2x to do here
+		*to.array = *fm.array;	// known to be a byte pointer
+	} else {
+		runtime·memmove(to.array, fm.array, ret*width);
+	}
+
+out:
+
+	if(debug) {
+		runtime·prints("main·copy: to=");
+		runtime·printslice(to);
+		runtime·prints("; fm=");
+		runtime·printslice(fm);
+		runtime·prints("; width=");
+		runtime·printint(width);
+		runtime·prints("; ret=");
+		runtime·printint(ret);
+		runtime·prints("\n");
+	}
+}
+
+#pragma textflag NOSPLIT
+func slicestringcopy(to Slice, fm String) (ret int) {
+	void *pc;
+
+	if(fm.len == 0 || to.len == 0) {
+		ret = 0;
+		goto out;
+	}
+
+	ret = fm.len;
+	if(to.len < ret)
+		ret = to.len;
+
+	if(raceenabled) {
+		pc = runtime·getcallerpc(&to);
+		runtime·racewriterangepc(to.array, ret, pc, runtime·slicestringcopy);
+	}
+
+	runtime·memmove(to.array, fm.str, ret);
+
+out:;
+}
+
+func printslice(a Slice) {
+	runtime·prints("[");
+	runtime·printint(a.len);
+	runtime·prints("/");
+	runtime·printint(a.cap);
+	runtime·prints("]");
+	runtime·printpointer(a.array);
+}
diff --git a/src/pkg/runtime/softfloat_arm.c b/src/pkg/runtime/softfloat_arm.c
index f5801dd..29a52bd 100644
--- a/src/pkg/runtime/softfloat_arm.c
+++ b/src/pkg/runtime/softfloat_arm.c
@@ -16,7 +16,7 @@
 #define FLAGS_V (1U << 28)
 
 void	runtime·abort(void);
-void	math·sqrtC(uint64, uint64*);
+void	runtime·sqrtC(uint64, uint64*);
 
 static	uint32	trace = 0;
 
@@ -413,7 +413,7 @@ stage3:	// regd, regm are 4bit variables
 		break;
 
 	case 0xeeb10bc0:	// D[regd] = sqrt D[regm]
-		math·sqrtC(getd(regm), &uval);
+		runtime·sqrtC(getd(regm), &uval);
 		putd(regd, uval);
 
 		if(trace)
diff --git a/src/pkg/runtime/sqrt.go b/src/pkg/runtime/sqrt.go
new file mode 100644
index 0000000..34a8c38
--- /dev/null
+++ b/src/pkg/runtime/sqrt.go
@@ -0,0 +1,150 @@
+// 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.
+
+// Copy of math/sqrt.go, here for use by ARM softfloat.
+
+package runtime
+
+import "unsafe"
+
+// The original C code and the long comment below are
+// from FreeBSD's /usr/src/lib/msun/src/e_sqrt.c and
+// came with this notice.  The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunPro, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+// __ieee754_sqrt(x)
+// Return correctly rounded sqrt.
+//           -----------------------------------------
+//           | Use the hardware sqrt if you have one |
+//           -----------------------------------------
+// Method:
+//   Bit by bit method using integer arithmetic. (Slow, but portable)
+//   1. Normalization
+//      Scale x to y in [1,4) with even powers of 2:
+//      find an integer k such that  1 <= (y=x*2**(2k)) < 4, then
+//              sqrt(x) = 2**k * sqrt(y)
+//   2. Bit by bit computation
+//      Let q  = sqrt(y) truncated to i bit after binary point (q = 1),
+//           i                                                   0
+//                                     i+1         2
+//          s  = 2*q , and      y  =  2   * ( y - q  ).          (1)
+//           i      i            i                 i
+//
+//      To compute q    from q , one checks whether
+//                  i+1       i
+//
+//                            -(i+1) 2
+//                      (q + 2      )  <= y.                     (2)
+//                        i
+//                                                            -(i+1)
+//      If (2) is false, then q   = q ; otherwise q   = q  + 2      .
+//                             i+1   i             i+1   i
+//
+//      With some algebraic manipulation, it is not difficult to see
+//      that (2) is equivalent to
+//                             -(i+1)
+//                      s  +  2       <= y                       (3)
+//                       i                i
+//
+//      The advantage of (3) is that s  and y  can be computed by
+//                                    i      i
+//      the following recurrence formula:
+//          if (3) is false
+//
+//          s     =  s  ,       y    = y   ;                     (4)
+//           i+1      i          i+1    i
+//
+//      otherwise,
+//                         -i                      -(i+1)
+//          s     =  s  + 2  ,  y    = y  -  s  - 2              (5)
+//           i+1      i          i+1    i     i
+//
+//      One may easily use induction to prove (4) and (5).
+//      Note. Since the left hand side of (3) contain only i+2 bits,
+//            it does not necessary to do a full (53-bit) comparison
+//            in (3).
+//   3. Final rounding
+//      After generating the 53 bits result, we compute one more bit.
+//      Together with the remainder, we can decide whether the
+//      result is exact, bigger than 1/2ulp, or less than 1/2ulp
+//      (it will never equal to 1/2ulp).
+//      The rounding mode can be detected by checking whether
+//      huge + tiny is equal to huge, and whether huge - tiny is
+//      equal to huge for some floating point number "huge" and "tiny".
+//
+//
+// Notes:  Rounding mode detection omitted.
+
+const (
+	uvnan      = 0x7FF8000000000001
+	uvinf      = 0x7FF0000000000000
+	uvneginf   = 0xFFF0000000000000
+	mask       = 0x7FF
+	shift      = 64 - 11 - 1
+	bias       = 1023
+	maxFloat64 = 1.797693134862315708145274237317043567981e+308 // 2**1023 * (2**53 - 1) / 2**52
+)
+
+func float64bits(f float64) uint64     { return *(*uint64)(unsafe.Pointer(&f)) }
+func float64frombits(b uint64) float64 { return *(*float64)(unsafe.Pointer(&b)) }
+
+func sqrt(x float64) float64 {
+	// special cases
+	switch {
+	case x == 0 || x != x || x > maxFloat64:
+		return x
+	case x < 0:
+		return nan
+	}
+	ix := float64bits(x)
+	// normalize x
+	exp := int((ix >> shift) & mask)
+	if exp == 0 { // subnormal x
+		for ix&1<<shift == 0 {
+			ix <<= 1
+			exp--
+		}
+		exp++
+	}
+	exp -= bias // unbias exponent
+	ix &^= mask << shift
+	ix |= 1 << shift
+	if exp&1 == 1 { // odd exp, double x to make it even
+		ix <<= 1
+	}
+	exp >>= 1 // exp = exp/2, exponent of square root
+	// generate sqrt(x) bit by bit
+	ix <<= 1
+	var q, s uint64               // q = sqrt(x)
+	r := uint64(1 << (shift + 1)) // r = moving bit from MSB to LSB
+	for r != 0 {
+		t := s + r
+		if t <= ix {
+			s = t + r
+			ix -= t
+			q += r
+		}
+		ix <<= 1
+		r >>= 1
+	}
+	// final rounding
+	if ix != 0 { // remainder, result not exact
+		q += q & 1 // round according to extra bit
+	}
+	ix = q>>1 + uint64(exp-1+bias)<<shift // significand + biased exponent
+	return float64frombits(ix)
+}
+
+func sqrtC(f float64, r *float64) {
+	*r = sqrt(f)
+}
diff --git a/src/pkg/runtime/stack.c b/src/pkg/runtime/stack.c
index 6347060..1680f00 100644
--- a/src/pkg/runtime/stack.c
+++ b/src/pkg/runtime/stack.c
@@ -6,10 +6,21 @@
 #include "arch_GOARCH.h"
 #include "malloc.h"
 #include "stack.h"
+#include "funcdata.h"
+#include "typekind.h"
+#include "type.h"
+#include "../../cmd/ld/textflag.h"
 
 enum
 {
+	// StackDebug == 0: no logging
+	//            == 1: logging of per-stack operations
+	//            == 2: logging of per-frame operations
+	//            == 3: logging of per-word updates
+	//            == 4: logging of per-word reads
 	StackDebug = 0,
+	StackFromSystem = 0,	// allocate stacks from system memory instead of the heap
+	StackFaultOnFree = 0,	// old stacks are mapped noaccess to detect use after free
 };
 
 typedef struct StackCacheNode StackCacheNode;
@@ -74,22 +85,37 @@ stackcacherelease(void)
 }
 
 void*
-runtime·stackalloc(uint32 n)
+runtime·stackalloc(G *gp, uint32 n)
 {
 	uint32 pos;
 	void *v;
+	bool malloced;
+	Stktop *top;
 
 	// Stackalloc must be called on scheduler stack, so that we
 	// never try to grow the stack during the code that stackalloc runs.
 	// Doing so would cause a deadlock (issue 1547).
 	if(g != m->g0)
 		runtime·throw("stackalloc not on scheduler stack");
+	if((n & (n-1)) != 0)
+		runtime·throw("stack size not a power of 2");
+	if(StackDebug >= 1)
+		runtime·printf("stackalloc %d\n", n);
+
+	gp->stacksize += n;
+	if(runtime·debug.efence || StackFromSystem) {
+		v = runtime·SysAlloc(ROUND(n, PageSize), &mstats.stacks_sys);
+		if(v == nil)
+			runtime·throw("out of memory (stackalloc)");
+		return v;
+	}
 
-	// Stacks are usually allocated with a fixed-size free-list allocator,
-	// but if we need a stack of non-standard size, we fall back on malloc
-	// (assuming that inside malloc and GC all the stack frames are small,
+	// Minimum-sized stacks are allocated with a fixed-size free-list allocator,
+	// but if we need a stack of a bigger size, we fall back on malloc
+	// (assuming that inside malloc all the stack frames are small,
 	// so that we do not deadlock).
-	if(n == FixedStack || m->mallocing || m->gcing) {
+	malloced = true;
+	if(n == FixedStack || m->mallocing) {
 		if(n != FixedStack) {
 			runtime·printf("stackalloc: in malloc, size=%d want %d\n", FixedStack, n);
 			runtime·throw("stackalloc");
@@ -102,27 +128,46 @@ runtime·stackalloc(uint32 n)
 		m->stackcachepos = pos;
 		m->stackcachecnt--;
 		m->stackinuse++;
-		return v;
-	}
-	return runtime·mallocgc(n, 0, FlagNoProfiling|FlagNoGC|FlagNoZero|FlagNoInvokeGC);
+		malloced = false;
+	} else
+		v = runtime·mallocgc(n, 0, FlagNoProfiling|FlagNoGC|FlagNoZero|FlagNoInvokeGC);
+
+	top = (Stktop*)((byte*)v+n-sizeof(Stktop));
+	runtime·memclr((byte*)top, sizeof(*top));
+	top->malloced = malloced;
+	return v;
 }
 
 void
-runtime·stackfree(void *v, uintptr n)
+runtime·stackfree(G *gp, void *v, Stktop *top)
 {
 	uint32 pos;
-
-	if(n == FixedStack || m->mallocing || m->gcing) {
-		if(m->stackcachecnt == StackCacheSize)
-			stackcacherelease();
-		pos = m->stackcachepos;
-		m->stackcache[pos] = v;
-		m->stackcachepos = (pos + 1) % StackCacheSize;
-		m->stackcachecnt++;
-		m->stackinuse--;
+	uintptr n;
+
+	n = (uintptr)(top+1) - (uintptr)v;
+	if(StackDebug >= 1)
+		runtime·printf("stackfree %p %d\n", v, (int32)n);
+	gp->stacksize -= n;
+	if(runtime·debug.efence || StackFromSystem) {
+		if(runtime·debug.efence || StackFaultOnFree)
+			runtime·SysFault(v, n);
+		else
+			runtime·SysFree(v, n, &mstats.stacks_sys);
+		return;
+	}
+	if(top->malloced) {
+		runtime·free(v);
 		return;
 	}
-	runtime·free(v);
+	if(n != FixedStack)
+		runtime·throw("stackfree: bad fixed size");
+	if(m->stackcachecnt == StackCacheSize)
+		stackcacherelease();
+	pos = m->stackcachepos;
+	m->stackcache[pos] = v;
+	m->stackcachepos = (pos + 1) % StackCacheSize;
+	m->stackcachecnt++;
+	m->stackinuse--;
 }
 
 // Called from runtime·lessstack when returning from a function which
@@ -145,12 +190,12 @@ runtime·oldstack(void)
 	sp = (byte*)top;
 	argsize = top->argsize;
 
-	if(StackDebug) {
+	if(StackDebug >= 1) {
 		runtime·printf("runtime: oldstack gobuf={pc:%p sp:%p lr:%p} cret=%p argsize=%p\n",
-			top->gobuf.pc, top->gobuf.sp, top->gobuf.lr, m->cret, (uintptr)argsize);
+			top->gobuf.pc, top->gobuf.sp, top->gobuf.lr, (uintptr)m->cret, (uintptr)argsize);
 	}
 
-	// gp->status is usually Grunning, but it could be Gsyscall if a stack split
+	// gp->status is usually Grunning, but it could be Gsyscall if a stack overflow
 	// happens during a function call inside entersyscall.
 	oldstatus = gp->status;
 	
@@ -175,11 +220,7 @@ runtime·oldstack(void)
 	gp->stackguard = top->stackguard;
 	gp->stackguard0 = gp->stackguard;
 	gp->panicwrap = top->panicwrap;
-
-	if(top->free != 0) {
-		gp->stacksize -= top->free;
-		runtime·stackfree(old, top->free);
-	}
+	runtime·stackfree(gp, old, top);
 
 	gp->status = oldstatus;
 	runtime·gogo(&gp->sched);
@@ -187,6 +228,435 @@ runtime·oldstack(void)
 
 uintptr runtime·maxstacksize = 1<<20; // enough until runtime.main sets it for real
 
+static uint8*
+mapnames[] = {
+	(uint8*)"---",
+	(uint8*)"scalar",
+	(uint8*)"ptr",
+	(uint8*)"multi",
+};
+
+// Stack frame layout
+//
+// (x86)
+// +------------------+
+// | args from caller |
+// +------------------+ <- frame->argp
+// |  return address  |
+// +------------------+ <- frame->varp
+// |     locals       |
+// +------------------+
+// |  args to callee  |
+// +------------------+ <- frame->sp
+//
+// (arm: TODO)
+
+typedef struct CopyableInfo CopyableInfo;
+struct CopyableInfo {
+	byte *stk;	// bottom address of segment
+	byte *base;	// top address of segment (including Stktop)
+	int32 frames;	// count of copyable frames (-1 = not copyable)
+};
+
+void runtime·main(void);
+
+static bool
+checkframecopy(Stkframe *frame, void *arg)
+{
+	CopyableInfo *cinfo;
+	Func *f;
+	StackMap *stackmap;
+
+	cinfo = arg;
+	f = frame->fn;
+	if(StackDebug >= 2)
+		runtime·printf("    checking %s frame=[%p,%p] stk=[%p,%p]\n", runtime·funcname(f), frame->sp, frame->fp, cinfo->stk, cinfo->base);
+	// if we're not in the segment any more, return immediately.
+	if(frame->varp < cinfo->stk || frame->varp >= cinfo->base) {
+		if(StackDebug >= 2)
+			runtime·printf("    <next segment>\n");
+		return false; // stop traceback
+	}
+	if(f->entry == (uintptr)runtime·main) {
+		// A special routine at the TOS of the main routine.
+		// We will allow it to be copied even though we don't
+		// have full GC info for it (because it is written in C).
+		cinfo->frames++;
+		return false; // stop traceback
+	}
+	if(frame->varp != (byte*)frame->sp) { // not in prologue (and has at least one local or outarg)
+		stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
+		if(stackmap == nil) {
+			cinfo->frames = -1;
+			if(StackDebug >= 1)
+				runtime·printf("copystack: no locals info for %s\n", runtime·funcname(f));
+			return false;
+		}
+		if(stackmap->n <= 0) {
+			cinfo->frames = -1;
+			if(StackDebug >= 1)
+				runtime·printf("copystack: locals size info only for %s\n", runtime·funcname(f));
+			return false;
+		}
+	}
+	if(frame->arglen != 0) {
+		stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
+		if(stackmap == nil) {
+			cinfo->frames = -1;
+			if(StackDebug >= 1)
+				runtime·printf("copystack: no arg info for %s\n", runtime·funcname(f));
+			return false;
+		}
+	}
+	cinfo->frames++;
+	return true; // this frame is ok; keep going
+}
+
+// If the top segment of the stack contains an uncopyable
+// frame, return -1.  Otherwise return the number of frames
+// in the top segment, all of which are copyable.
+static int32
+copyabletopsegment(G *gp)
+{
+	CopyableInfo cinfo;
+	Defer *d;
+	Func *f;
+	FuncVal *fn;
+	StackMap *stackmap;
+
+	cinfo.stk = (byte*)gp->stackguard - StackGuard;
+	cinfo.base = (byte*)gp->stackbase + sizeof(Stktop);
+	cinfo.frames = 0;
+
+	// Check that each frame is copyable.  As a side effect,
+	// count the frames.
+	runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, checkframecopy, &cinfo, false);
+	if(StackDebug >= 1 && cinfo.frames != -1)
+		runtime·printf("copystack: %d copyable frames\n", cinfo.frames);
+
+	// Check to make sure all Defers are copyable
+	for(d = gp->defer; d != nil; d = d->link) {
+		if(cinfo.stk <= (byte*)d && (byte*)d < cinfo.base) {
+			// Defer is on the stack.  Its copyableness has
+			// been established during stack walking.
+			// For now, this only happens with the Defer in runtime.main.
+			continue;
+		}
+		if(d->argp < cinfo.stk || cinfo.base <= d->argp)
+			break; // a defer for the next segment
+		fn = d->fn;
+		if(fn == nil) // See issue 8047
+			continue;
+		f = runtime·findfunc((uintptr)fn->fn);
+		if(f == nil)
+			return -1;
+
+		// Check to make sure we have an args pointer map for the defer's args.
+		// We only need the args map, but we check
+		// for the locals map also, because when the locals map
+		// isn't provided it means the ptr map came from C and
+		// C (particularly, cgo) lies to us.  See issue 7695.
+		stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
+		if(stackmap == nil || stackmap->n <= 0)
+			return -1;
+		stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
+		if(stackmap == nil || stackmap->n <= 0)
+			return -1;
+
+		if(cinfo.stk <= (byte*)fn && (byte*)fn < cinfo.base) {
+			// FuncVal is on the stack.  Again, its copyableness
+			// was established during stack walking.
+			continue;
+		}
+		// The FuncVal may have pointers in it, but fortunately for us
+		// the compiler won't put pointers into the stack in a
+		// heap-allocated FuncVal.
+		// One day if we do need to check this, we'll need maps of the
+		// pointerness of the closure args.  The only place we have that map
+		// right now is in the gc program for the FuncVal.  Ugh.
+	}
+
+	return cinfo.frames;
+}
+
+typedef struct AdjustInfo AdjustInfo;
+struct AdjustInfo {
+	byte *oldstk;	// bottom address of segment
+	byte *oldbase;	// top address of segment (after Stktop)
+	uintptr delta;  // ptr distance from old to new stack (newbase - oldbase)
+};
+
+// bv describes the memory starting at address scanp.
+// Adjust any pointers contained therein.
+static void
+adjustpointers(byte **scanp, BitVector *bv, AdjustInfo *adjinfo, Func *f)
+{
+	uintptr delta;
+	int32 num, i;
+	byte *p, *minp, *maxp;
+	Type *t;
+	Itab *tab;
+	
+	minp = adjinfo->oldstk;
+	maxp = adjinfo->oldbase;
+	delta = adjinfo->delta;
+	num = bv->n / BitsPerPointer;
+	for(i = 0; i < num; i++) {
+		if(StackDebug >= 4)
+			runtime·printf("        %p:%s:%p\n", &scanp[i], mapnames[bv->data[i / (32 / BitsPerPointer)] >> (i * BitsPerPointer & 31) & 3], scanp[i]);
+		switch(bv->data[i / (32 / BitsPerPointer)] >> (i * BitsPerPointer & 31) & 3) {
+		case BitsDead:
+			if(runtime·debug.gcdead)
+				scanp[i] = (byte*)PoisonStack;
+			break;
+		case BitsScalar:
+			break;
+		case BitsPointer:
+			p = scanp[i];
+			if(f != nil && (byte*)0 < p && (p < (byte*)PageSize || (uintptr)p == PoisonGC || (uintptr)p == PoisonStack)) {
+				// Looks like a junk value in a pointer slot.
+				// Live analysis wrong?
+				m->traceback = 2;
+				runtime·printf("runtime: bad pointer in frame %s at %p: %p\n", runtime·funcname(f), &scanp[i], p);
+				runtime·throw("bad pointer!");
+			}
+			if(minp <= p && p < maxp) {
+				if(StackDebug >= 3)
+					runtime·printf("adjust ptr %p %s\n", p, runtime·funcname(f));
+				scanp[i] = p + delta;
+			}
+			break;
+		case BitsMultiWord:
+			switch(bv->data[(i+1) / (32 / BitsPerPointer)] >> ((i+1) * BitsPerPointer & 31) & 3) {
+			case BitsString:
+				// string referents are never on the stack, never need to be adjusted
+				i++; // skip len
+				break;
+			case BitsSlice:
+				p = scanp[i];
+				if(minp <= p && p < maxp) {
+					if(StackDebug >= 3)
+						runtime·printf("adjust slice %p\n", p);
+					scanp[i] = p + delta;
+				}
+				i += 2; // skip len, cap
+				break;
+			case BitsEface:
+				t = (Type*)scanp[i];
+				if(t != nil && (t->size > PtrSize || (t->kind & KindNoPointers) == 0)) {
+					p = scanp[i+1];
+					if(minp <= p && p < maxp) {
+						if(StackDebug >= 3)
+							runtime·printf("adjust eface %p\n", p);
+						if(t->size > PtrSize) // currently we always allocate such objects on the heap
+							runtime·throw("large interface value found on stack");
+						scanp[i+1] = p + delta;
+					}
+				}
+				i++;
+				break;
+			case BitsIface:
+				tab = (Itab*)scanp[i];
+				if(tab != nil) {
+					t = tab->type;
+					//runtime·printf("          type=%p\n", t);
+					if(t->size > PtrSize || (t->kind & KindNoPointers) == 0) {
+						p = scanp[i+1];
+						if(minp <= p && p < maxp) {
+							if(StackDebug >= 3)
+								runtime·printf("adjust iface %p\n", p);
+							if(t->size > PtrSize) // currently we always allocate such objects on the heap
+								runtime·throw("large interface value found on stack");
+							scanp[i+1] = p + delta;
+						}
+					}
+				}
+				i++;
+				break;
+			}
+			break;
+		}
+	}
+}
+
+// Note: the argument/return area is adjusted by the callee.
+static bool
+adjustframe(Stkframe *frame, void *arg)
+{
+	AdjustInfo *adjinfo;
+	Func *f;
+	StackMap *stackmap;
+	int32 pcdata;
+	BitVector bv;
+	uintptr targetpc;
+
+	adjinfo = arg;
+	f = frame->fn;
+	if(StackDebug >= 2)
+		runtime·printf("    adjusting %s frame=[%p,%p] pc=%p continpc=%p\n", runtime·funcname(f), frame->sp, frame->fp, frame->pc, frame->continpc);
+	if(f->entry == (uintptr)runtime·main)
+		return true;
+	targetpc = frame->continpc;
+	if(targetpc == 0) {
+		// Frame is dead.
+		return true;
+	}
+	if(targetpc != f->entry)
+		targetpc--;
+	pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc);
+	if(pcdata == -1)
+		pcdata = 0; // in prologue
+
+	// adjust local pointers
+	if(frame->varp != (byte*)frame->sp) {
+		stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
+		if(stackmap == nil)
+			runtime·throw("no locals info");
+		if(stackmap->n <= 0)
+			runtime·throw("locals size info only");
+		bv = runtime·stackmapdata(stackmap, pcdata);
+		if(StackDebug >= 3)
+			runtime·printf("      locals\n");
+		adjustpointers((byte**)frame->varp - bv.n / BitsPerPointer, &bv, adjinfo, f);
+	}
+	// adjust inargs and outargs
+	if(frame->arglen != 0) {
+		stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
+		if(stackmap == nil)
+			runtime·throw("no arg info");
+		bv = runtime·stackmapdata(stackmap, pcdata);
+		if(StackDebug >= 3)
+			runtime·printf("      args\n");
+		adjustpointers((byte**)frame->argp, &bv, adjinfo, nil);
+	}
+	return true;
+}
+
+static void
+adjustctxt(G *gp, AdjustInfo *adjinfo)
+{
+	if(adjinfo->oldstk <= (byte*)gp->sched.ctxt && (byte*)gp->sched.ctxt < adjinfo->oldbase)
+		gp->sched.ctxt = (byte*)gp->sched.ctxt + adjinfo->delta;
+}
+
+static void
+adjustdefers(G *gp, AdjustInfo *adjinfo)
+{
+	Defer *d, **dp;
+	Func *f;
+	FuncVal *fn;
+	StackMap *stackmap;
+	BitVector bv;
+
+	for(dp = &gp->defer, d = *dp; d != nil; dp = &d->link, d = *dp) {
+		if(adjinfo->oldstk <= (byte*)d && (byte*)d < adjinfo->oldbase) {
+			// The Defer record is on the stack.  Its fields will
+			// get adjusted appropriately.
+			// This only happens for runtime.main now, but a compiler
+			// optimization could do more of this.
+			*dp = (Defer*)((byte*)d + adjinfo->delta);
+			continue;
+		}
+		if(d->argp < adjinfo->oldstk || adjinfo->oldbase <= d->argp)
+			break; // a defer for the next segment
+		fn = d->fn;
+		if(fn == nil) {
+			// Defer of nil function.  It will panic when run, and there
+			// aren't any args to adjust.  See issue 8047.
+			d->argp += adjinfo->delta;
+			continue;
+		}
+		f = runtime·findfunc((uintptr)fn->fn);
+		if(f == nil)
+			runtime·throw("can't adjust unknown defer");
+		if(StackDebug >= 4)
+			runtime·printf("  checking defer %s\n", runtime·funcname(f));
+		// Defer's FuncVal might be on the stack
+		if(adjinfo->oldstk <= (byte*)fn && (byte*)fn < adjinfo->oldbase) {
+			if(StackDebug >= 3)
+				runtime·printf("    adjust defer fn %s\n", runtime·funcname(f));
+			d->fn = (FuncVal*)((byte*)fn + adjinfo->delta);
+		} else {
+			// deferred function's args might point into the stack.
+			if(StackDebug >= 3)
+				runtime·printf("    adjust deferred args for %s\n", runtime·funcname(f));
+			stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
+			if(stackmap == nil)
+				runtime·throw("runtime: deferred function has no arg ptr map");
+			bv = runtime·stackmapdata(stackmap, 0);
+			adjustpointers(d->args, &bv, adjinfo, f);
+		}
+		d->argp += adjinfo->delta;
+	}
+}
+
+// Copies the top stack segment of gp to a new stack segment of a
+// different size.  The top segment must contain nframes frames.
+static void
+copystack(G *gp, uintptr nframes, uintptr newsize)
+{
+	byte *oldstk, *oldbase, *newstk, *newbase;
+	uintptr oldsize, used;
+	AdjustInfo adjinfo;
+	Stktop *oldtop, *newtop;
+	bool malloced;
+
+	if(gp->syscallstack != 0)
+		runtime·throw("can't handle stack copy in syscall yet");
+	oldstk = (byte*)gp->stackguard - StackGuard;
+	oldbase = (byte*)gp->stackbase + sizeof(Stktop);
+	oldsize = oldbase - oldstk;
+	used = oldbase - (byte*)gp->sched.sp;
+	oldtop = (Stktop*)gp->stackbase;
+
+	// allocate new stack
+	newstk = runtime·stackalloc(gp, newsize);
+	newbase = newstk + newsize;
+	newtop = (Stktop*)(newbase - sizeof(Stktop));
+	malloced = newtop->malloced;
+
+	if(StackDebug >= 1)
+		runtime·printf("copystack [%p %p]/%d -> [%p %p]/%d\n", oldstk, oldbase, (int32)oldsize, newstk, newbase, (int32)newsize);
+	USED(oldsize);
+	
+	// adjust pointers in the to-be-copied frames
+	adjinfo.oldstk = oldstk;
+	adjinfo.oldbase = oldbase;
+	adjinfo.delta = newbase - oldbase;
+	runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, nframes, adjustframe, &adjinfo, false);
+	
+	// adjust other miscellaneous things that have pointers into stacks.
+	adjustctxt(gp, &adjinfo);
+	adjustdefers(gp, &adjinfo);
+	
+	// copy the stack (including Stktop) to the new location
+	runtime·memmove(newbase - used, oldbase - used, used);
+	newtop->malloced = malloced;
+	
+	// Swap out old stack for new one
+	gp->stackbase = (uintptr)newtop;
+	gp->stackguard = (uintptr)newstk + StackGuard;
+	gp->stackguard0 = (uintptr)newstk + StackGuard; // NOTE: might clobber a preempt request
+	if(gp->stack0 == (uintptr)oldstk)
+		gp->stack0 = (uintptr)newstk;
+	gp->sched.sp = (uintptr)(newbase - used);
+
+	// free old stack
+	runtime·stackfree(gp, oldstk, oldtop);
+}
+
+// round x up to a power of 2.
+int32
+runtime·round2(int32 x)
+{
+	int32 s;
+
+	s = 0;
+	while((1 << s) < x)
+		s++;
+	return 1 << s;
+}
+
 // Called from runtime·newstackcall or from runtime·morestack when a new
 // stack segment is needed.  Allocate a new stack big enough for
 // m->moreframesize bytes, copy m->moreargsize bytes to the new frame,
@@ -195,16 +665,18 @@ uintptr runtime·maxstacksize = 1<<20; // enough until runtime.main sets it for
 void
 runtime·newstack(void)
 {
-	int32 framesize, argsize, oldstatus;
+	int32 framesize, argsize, oldstatus, oldsize, newsize, nframes;
 	Stktop *top, *oldtop;
-	byte *stk;
+	byte *stk, *oldstk, *oldbase;
 	uintptr sp;
 	uintptr *src, *dst, *dstend;
 	G *gp;
-	Gobuf label;
+	Gobuf label, morebuf;
+	void *moreargp;
 	bool newstackcall;
-	uintptr free;
 
+	if(m->forkstackguard)
+		runtime·throw("split stack after fork");
 	if(m->morebuf.g != m->curg) {
 		runtime·printf("runtime: newstack called from g=%p\n"
 			"\tm=%p m->curg=%p m->g0=%p m->gsignal=%p\n",
@@ -212,15 +684,21 @@ runtime·newstack(void)
 		runtime·throw("runtime: wrong goroutine in newstack");
 	}
 
-	// gp->status is usually Grunning, but it could be Gsyscall if a stack split
+	// gp->status is usually Grunning, but it could be Gsyscall if a stack overflow
 	// happens during a function call inside entersyscall.
 	gp = m->curg;
 	oldstatus = gp->status;
 
 	framesize = m->moreframesize;
 	argsize = m->moreargsize;
+	moreargp = m->moreargp;
+	m->moreargp = nil;
+	morebuf = m->morebuf;
+	m->morebuf.pc = (uintptr)nil;
+	m->morebuf.lr = (uintptr)nil;
+	m->morebuf.sp = (uintptr)nil;
 	gp->status = Gwaiting;
-	gp->waitreason = "stack split";
+	gp->waitreason = "stack growth";
 	newstackcall = framesize==1;
 	if(newstackcall)
 		framesize = 0;
@@ -234,7 +712,7 @@ runtime·newstack(void)
 		// The call to morestack cost a word.
 		sp -= sizeof(uintptr);
 	}
-	if(StackDebug || sp < gp->stackguard - StackGuard) {
+	if(StackDebug >= 1 || sp < gp->stackguard - StackGuard) {
 		runtime·printf("runtime: newstack framesize=%p argsize=%p sp=%p stack=[%p, %p]\n"
 			"\tmorebuf={pc:%p sp:%p lr:%p}\n"
 			"\tsched={pc:%p sp:%p lr:%p ctxt:%p}\n",
@@ -248,8 +726,8 @@ runtime·newstack(void)
 	}
 
 	if(argsize % sizeof(uintptr) != 0) {
-		runtime·printf("runtime: stack split with misaligned argsize %d\n", argsize);
-		runtime·throw("runtime: stack split argsize");
+		runtime·printf("runtime: stack growth with misaligned argsize %d\n", argsize);
+		runtime·throw("runtime: stack growth argsize");
 	}
 
 	if(gp->stackguard0 == (uintptr)StackPreempt) {
@@ -258,7 +736,7 @@ runtime·newstack(void)
 		if(oldstatus == Grunning && m->p == nil && m->locks == 0)
 			runtime·throw("runtime: g is running but p is not");
 		if(oldstatus == Gsyscall && m->locks == 0)
-			runtime·throw("runtime: stack split during syscall");
+			runtime·throw("runtime: stack growth during syscall");
 		// Be conservative about where we preempt.
 		// We are interested in preempting user Go code, not runtime code.
 		if(oldstatus != Grunning || m->locks || m->mallocing || m->gcing || m->p->status != Prunning) {
@@ -273,46 +751,55 @@ runtime·newstack(void)
 		runtime·gosched0(gp);	// never return
 	}
 
-	if(newstackcall && m->morebuf.sp - sizeof(Stktop) - argsize - 32 > gp->stackguard) {
-		// special case: called from runtime.newstackcall (framesize==1)
-		// to call code with an arbitrary argument size,
-		// and we have enough space on the current stack.
-		// the new Stktop* is necessary to unwind, but
-		// we don't need to create a new segment.
-		top = (Stktop*)(m->morebuf.sp - sizeof(*top));
-		stk = (byte*)gp->stackguard - StackGuard;
-		free = 0;
-	} else {
-		// allocate new segment.
-		framesize += argsize;
-		framesize += StackExtra;	// room for more functions, Stktop.
-		if(framesize < StackMin)
-			framesize = StackMin;
-		framesize += StackSystem;
-		gp->stacksize += framesize;
-		if(gp->stacksize > runtime·maxstacksize) {
-			runtime·printf("runtime: goroutine stack exceeds %D-byte limit\n", (uint64)runtime·maxstacksize);
-			runtime·throw("stack overflow");
+	// If every frame on the top segment is copyable, allocate a bigger segment
+	// and move the segment instead of allocating a new segment.
+	if(runtime·copystack) {
+		if(!runtime·precisestack)
+			runtime·throw("can't copy stacks without precise stacks");
+		nframes = copyabletopsegment(gp);
+		if(nframes != -1) {
+			oldstk = (byte*)gp->stackguard - StackGuard;
+			oldbase = (byte*)gp->stackbase + sizeof(Stktop);
+			oldsize = oldbase - oldstk;
+			newsize = oldsize * 2;
+			copystack(gp, nframes, newsize);
+			if(StackDebug >= 1)
+				runtime·printf("stack grow done\n");
+			if(gp->stacksize > runtime·maxstacksize) {
+				runtime·printf("runtime: goroutine stack exceeds %D-byte limit\n", (uint64)runtime·maxstacksize);
+				runtime·throw("stack overflow");
+			}
+			gp->status = oldstatus;
+			runtime·gogo(&gp->sched);
 		}
-		stk = runtime·stackalloc(framesize);
-		top = (Stktop*)(stk+framesize-sizeof(*top));
-		free = framesize;
+		// TODO: if stack is uncopyable because we're in C code, patch return value at
+		// end of C code to trigger a copy as soon as C code exits.  That way, we'll
+		// have stack available if we get this deep again.
 	}
 
-	if(StackDebug) {
+	// allocate new segment.
+	framesize += argsize;
+	framesize += StackExtra;	// room for more functions, Stktop.
+	if(framesize < StackMin)
+		framesize = StackMin;
+	framesize += StackSystem;
+	framesize = runtime·round2(framesize);
+	stk = runtime·stackalloc(gp, framesize);
+	if(gp->stacksize > runtime·maxstacksize) {
+		runtime·printf("runtime: goroutine stack exceeds %D-byte limit\n", (uint64)runtime·maxstacksize);
+		runtime·throw("stack overflow");
+	}
+	top = (Stktop*)(stk+framesize-sizeof(*top));
+
+	if(StackDebug >= 1) {
 		runtime·printf("\t-> new stack [%p, %p]\n", stk, top);
 	}
 
 	top->stackbase = gp->stackbase;
 	top->stackguard = gp->stackguard;
-	top->gobuf = m->morebuf;
-	top->argp = m->moreargp;
+	top->gobuf = morebuf;
+	top->argp = moreargp;
 	top->argsize = argsize;
-	top->free = free;
-	m->moreargp = nil;
-	m->morebuf.pc = (uintptr)nil;
-	m->morebuf.lr = (uintptr)nil;
-	m->morebuf.sp = (uintptr)nil;
 
 	// copy flag from panic
 	top->panic = gp->ispanic;
@@ -365,18 +852,96 @@ runtime·newstack(void)
 	*(int32*)345 = 123;	// never return
 }
 
+#pragma textflag NOSPLIT
+void
+runtime·nilfunc(void)
+{
+	*(byte*)0 = 0;
+}
+
 // adjust Gobuf as if it executed a call to fn
 // and then did an immediate gosave.
 void
 runtime·gostartcallfn(Gobuf *gobuf, FuncVal *fv)
 {
-	runtime·gostartcall(gobuf, fv->fn, fv);
+	void *fn;
+
+	if(fv != nil)
+		fn = fv->fn;
+	else
+		fn = runtime·nilfunc;
+	runtime·gostartcall(gobuf, fn, fv);
 }
 
+// Maybe shrink the stack being used by gp.
+// Called at garbage collection time.
 void
-runtime∕debug·setMaxStack(intgo in, intgo out)
+runtime·shrinkstack(G *gp)
 {
-	out = runtime·maxstacksize;
-	runtime·maxstacksize = in;
-	FLUSH(&out);
+	int32 nframes;
+	byte *oldstk, *oldbase;
+	uintptr used, oldsize, newsize;
+	MSpan *span;
+
+	if(!runtime·copystack)
+		return;
+	oldstk = (byte*)gp->stackguard - StackGuard;
+	oldbase = (byte*)gp->stackbase + sizeof(Stktop);
+	oldsize = oldbase - oldstk;
+	newsize = oldsize / 2;
+	if(newsize < FixedStack)
+		return; // don't shrink below the minimum-sized stack
+	used = oldbase - (byte*)gp->sched.sp;
+	if(used >= oldsize / 4)
+		return; // still using at least 1/4 of the segment.
+
+	// To shrink to less than 1/2 a page, we need to copy.
+	if(newsize < PageSize/2) {
+		if(gp->syscallstack != (uintptr)nil) // TODO: can we handle this case?
+			return;
+#ifdef GOOS_windows
+		if(gp->m != nil && gp->m->libcallsp != 0)
+			return;
+#endif
+		nframes = copyabletopsegment(gp);
+		if(nframes == -1)
+			return;
+		copystack(gp, nframes, newsize);
+		return;
+	}
+
+	// To shrink a stack of one page size or more, we can shrink it
+	// without copying.  Just deallocate the lower half.
+	span = runtime·MHeap_LookupMaybe(&runtime·mheap, oldstk);
+	if(span == nil)
+		return; // stack allocated outside heap.  Can't shrink it.  Can happen if stack is allocated while inside malloc.  TODO: shrink by copying?
+	if(span->elemsize != oldsize)
+		runtime·throw("span element size doesn't match stack size");
+	if((uintptr)oldstk != span->start << PageShift)
+		runtime·throw("stack not at start of span");
+
+	if(StackDebug)
+		runtime·printf("shrinking stack in place %p %X->%X\n", oldstk, oldsize, newsize);
+
+	// new stack guard for smaller stack
+	gp->stackguard = (uintptr)oldstk + newsize + StackGuard;
+	gp->stackguard0 = (uintptr)oldstk + newsize + StackGuard;
+	if(gp->stack0 == (uintptr)oldstk)
+		gp->stack0 = (uintptr)oldstk + newsize;
+	gp->stacksize -= oldsize - newsize;
+
+	// Free bottom half of the stack.
+	if(runtime·debug.efence || StackFromSystem) {
+		if(runtime·debug.efence || StackFaultOnFree)
+			runtime·SysFault(oldstk, newsize);
+		else
+			runtime·SysFree(oldstk, newsize, &mstats.stacks_sys);
+		return;
+	}
+	// First, we trick malloc into thinking
+	// we allocated the stack as two separate half-size allocs.  Then the
+	// free() call does the rest of the work for us.
+	runtime·MSpan_EnsureSwept(span);
+	runtime·MHeap_SplitSpan(&runtime·mheap, span);
+	runtime·free(oldstk);
 }
diff --git a/src/pkg/runtime/stack.h b/src/pkg/runtime/stack.h
index 296eb68..18ab30b 100644
--- a/src/pkg/runtime/stack.h
+++ b/src/pkg/runtime/stack.h
@@ -77,7 +77,8 @@ enum {
 	// If the amount needed for the splitting frame + StackExtra
 	// is less than this number, the stack will have this size instead.
 	StackMin = 8192,
-	FixedStack = StackMin + StackSystem,
+	StackSystemRounded = StackSystem + (-StackSystem & (StackMin-1)),
+	FixedStack = StackMin + StackSystemRounded,
 
 	// Functions that need frames bigger than this use an extra
 	// instruction to do the stack split check, to avoid overflow
@@ -102,7 +103,7 @@ enum {
 	// The assumed size of the top-of-stack data block.
 	// The actual size can be smaller than this but cannot be larger.
 	// Checked in proc.c's runtime.malg.
-	StackTop = 96,
+	StackTop = 88,
 };
 
 // Goroutine preemption request.
diff --git a/src/pkg/runtime/stack_gen_test.go b/src/pkg/runtime/stack_gen_test.go
new file mode 100644
index 0000000..2810106
--- /dev/null
+++ b/src/pkg/runtime/stack_gen_test.go
@@ -0,0 +1,1473 @@
+// 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 runtime_test
+
+import (
+	. "runtime"
+)
+
+var splitTests = []func() (uintptr, uintptr){
+	// Edit .+1,/^}/-1|seq 4 4 5000 | sed 's/.*/	stack&,/' | fmt
+	stack4, stack8, stack12, stack16, stack20, stack24, stack28,
+	stack32, stack36, stack40, stack44, stack48, stack52, stack56,
+	stack60, stack64, stack68, stack72, stack76, stack80, stack84,
+	stack88, stack92, stack96, stack100, stack104, stack108, stack112,
+	stack116, stack120, stack124, stack128, stack132, stack136,
+	stack140, stack144, stack148, stack152, stack156, stack160,
+	stack164, stack168, stack172, stack176, stack180, stack184,
+	stack188, stack192, stack196, stack200, stack204, stack208,
+	stack212, stack216, stack220, stack224, stack228, stack232,
+	stack236, stack240, stack244, stack248, stack252, stack256,
+	stack260, stack264, stack268, stack272, stack276, stack280,
+	stack284, stack288, stack292, stack296, stack300, stack304,
+	stack308, stack312, stack316, stack320, stack324, stack328,
+	stack332, stack336, stack340, stack344, stack348, stack352,
+	stack356, stack360, stack364, stack368, stack372, stack376,
+	stack380, stack384, stack388, stack392, stack396, stack400,
+	stack404, stack408, stack412, stack416, stack420, stack424,
+	stack428, stack432, stack436, stack440, stack444, stack448,
+	stack452, stack456, stack460, stack464, stack468, stack472,
+	stack476, stack480, stack484, stack488, stack492, stack496,
+	stack500, stack504, stack508, stack512, stack516, stack520,
+	stack524, stack528, stack532, stack536, stack540, stack544,
+	stack548, stack552, stack556, stack560, stack564, stack568,
+	stack572, stack576, stack580, stack584, stack588, stack592,
+	stack596, stack600, stack604, stack608, stack612, stack616,
+	stack620, stack624, stack628, stack632, stack636, stack640,
+	stack644, stack648, stack652, stack656, stack660, stack664,
+	stack668, stack672, stack676, stack680, stack684, stack688,
+	stack692, stack696, stack700, stack704, stack708, stack712,
+	stack716, stack720, stack724, stack728, stack732, stack736,
+	stack740, stack744, stack748, stack752, stack756, stack760,
+	stack764, stack768, stack772, stack776, stack780, stack784,
+	stack788, stack792, stack796, stack800, stack804, stack808,
+	stack812, stack816, stack820, stack824, stack828, stack832,
+	stack836, stack840, stack844, stack848, stack852, stack856,
+	stack860, stack864, stack868, stack872, stack876, stack880,
+	stack884, stack888, stack892, stack896, stack900, stack904,
+	stack908, stack912, stack916, stack920, stack924, stack928,
+	stack932, stack936, stack940, stack944, stack948, stack952,
+	stack956, stack960, stack964, stack968, stack972, stack976,
+	stack980, stack984, stack988, stack992, stack996, stack1000,
+	stack1004, stack1008, stack1012, stack1016, stack1020, stack1024,
+	stack1028, stack1032, stack1036, stack1040, stack1044, stack1048,
+	stack1052, stack1056, stack1060, stack1064, stack1068, stack1072,
+	stack1076, stack1080, stack1084, stack1088, stack1092, stack1096,
+	stack1100, stack1104, stack1108, stack1112, stack1116, stack1120,
+	stack1124, stack1128, stack1132, stack1136, stack1140, stack1144,
+	stack1148, stack1152, stack1156, stack1160, stack1164, stack1168,
+	stack1172, stack1176, stack1180, stack1184, stack1188, stack1192,
+	stack1196, stack1200, stack1204, stack1208, stack1212, stack1216,
+	stack1220, stack1224, stack1228, stack1232, stack1236, stack1240,
+	stack1244, stack1248, stack1252, stack1256, stack1260, stack1264,
+	stack1268, stack1272, stack1276, stack1280, stack1284, stack1288,
+	stack1292, stack1296, stack1300, stack1304, stack1308, stack1312,
+	stack1316, stack1320, stack1324, stack1328, stack1332, stack1336,
+	stack1340, stack1344, stack1348, stack1352, stack1356, stack1360,
+	stack1364, stack1368, stack1372, stack1376, stack1380, stack1384,
+	stack1388, stack1392, stack1396, stack1400, stack1404, stack1408,
+	stack1412, stack1416, stack1420, stack1424, stack1428, stack1432,
+	stack1436, stack1440, stack1444, stack1448, stack1452, stack1456,
+	stack1460, stack1464, stack1468, stack1472, stack1476, stack1480,
+	stack1484, stack1488, stack1492, stack1496, stack1500, stack1504,
+	stack1508, stack1512, stack1516, stack1520, stack1524, stack1528,
+	stack1532, stack1536, stack1540, stack1544, stack1548, stack1552,
+	stack1556, stack1560, stack1564, stack1568, stack1572, stack1576,
+	stack1580, stack1584, stack1588, stack1592, stack1596, stack1600,
+	stack1604, stack1608, stack1612, stack1616, stack1620, stack1624,
+	stack1628, stack1632, stack1636, stack1640, stack1644, stack1648,
+	stack1652, stack1656, stack1660, stack1664, stack1668, stack1672,
+	stack1676, stack1680, stack1684, stack1688, stack1692, stack1696,
+	stack1700, stack1704, stack1708, stack1712, stack1716, stack1720,
+	stack1724, stack1728, stack1732, stack1736, stack1740, stack1744,
+	stack1748, stack1752, stack1756, stack1760, stack1764, stack1768,
+	stack1772, stack1776, stack1780, stack1784, stack1788, stack1792,
+	stack1796, stack1800, stack1804, stack1808, stack1812, stack1816,
+	stack1820, stack1824, stack1828, stack1832, stack1836, stack1840,
+	stack1844, stack1848, stack1852, stack1856, stack1860, stack1864,
+	stack1868, stack1872, stack1876, stack1880, stack1884, stack1888,
+	stack1892, stack1896, stack1900, stack1904, stack1908, stack1912,
+	stack1916, stack1920, stack1924, stack1928, stack1932, stack1936,
+	stack1940, stack1944, stack1948, stack1952, stack1956, stack1960,
+	stack1964, stack1968, stack1972, stack1976, stack1980, stack1984,
+	stack1988, stack1992, stack1996, stack2000, stack2004, stack2008,
+	stack2012, stack2016, stack2020, stack2024, stack2028, stack2032,
+	stack2036, stack2040, stack2044, stack2048, stack2052, stack2056,
+	stack2060, stack2064, stack2068, stack2072, stack2076, stack2080,
+	stack2084, stack2088, stack2092, stack2096, stack2100, stack2104,
+	stack2108, stack2112, stack2116, stack2120, stack2124, stack2128,
+	stack2132, stack2136, stack2140, stack2144, stack2148, stack2152,
+	stack2156, stack2160, stack2164, stack2168, stack2172, stack2176,
+	stack2180, stack2184, stack2188, stack2192, stack2196, stack2200,
+	stack2204, stack2208, stack2212, stack2216, stack2220, stack2224,
+	stack2228, stack2232, stack2236, stack2240, stack2244, stack2248,
+	stack2252, stack2256, stack2260, stack2264, stack2268, stack2272,
+	stack2276, stack2280, stack2284, stack2288, stack2292, stack2296,
+	stack2300, stack2304, stack2308, stack2312, stack2316, stack2320,
+	stack2324, stack2328, stack2332, stack2336, stack2340, stack2344,
+	stack2348, stack2352, stack2356, stack2360, stack2364, stack2368,
+	stack2372, stack2376, stack2380, stack2384, stack2388, stack2392,
+	stack2396, stack2400, stack2404, stack2408, stack2412, stack2416,
+	stack2420, stack2424, stack2428, stack2432, stack2436, stack2440,
+	stack2444, stack2448, stack2452, stack2456, stack2460, stack2464,
+	stack2468, stack2472, stack2476, stack2480, stack2484, stack2488,
+	stack2492, stack2496, stack2500, stack2504, stack2508, stack2512,
+	stack2516, stack2520, stack2524, stack2528, stack2532, stack2536,
+	stack2540, stack2544, stack2548, stack2552, stack2556, stack2560,
+	stack2564, stack2568, stack2572, stack2576, stack2580, stack2584,
+	stack2588, stack2592, stack2596, stack2600, stack2604, stack2608,
+	stack2612, stack2616, stack2620, stack2624, stack2628, stack2632,
+	stack2636, stack2640, stack2644, stack2648, stack2652, stack2656,
+	stack2660, stack2664, stack2668, stack2672, stack2676, stack2680,
+	stack2684, stack2688, stack2692, stack2696, stack2700, stack2704,
+	stack2708, stack2712, stack2716, stack2720, stack2724, stack2728,
+	stack2732, stack2736, stack2740, stack2744, stack2748, stack2752,
+	stack2756, stack2760, stack2764, stack2768, stack2772, stack2776,
+	stack2780, stack2784, stack2788, stack2792, stack2796, stack2800,
+	stack2804, stack2808, stack2812, stack2816, stack2820, stack2824,
+	stack2828, stack2832, stack2836, stack2840, stack2844, stack2848,
+	stack2852, stack2856, stack2860, stack2864, stack2868, stack2872,
+	stack2876, stack2880, stack2884, stack2888, stack2892, stack2896,
+	stack2900, stack2904, stack2908, stack2912, stack2916, stack2920,
+	stack2924, stack2928, stack2932, stack2936, stack2940, stack2944,
+	stack2948, stack2952, stack2956, stack2960, stack2964, stack2968,
+	stack2972, stack2976, stack2980, stack2984, stack2988, stack2992,
+	stack2996, stack3000, stack3004, stack3008, stack3012, stack3016,
+	stack3020, stack3024, stack3028, stack3032, stack3036, stack3040,
+	stack3044, stack3048, stack3052, stack3056, stack3060, stack3064,
+	stack3068, stack3072, stack3076, stack3080, stack3084, stack3088,
+	stack3092, stack3096, stack3100, stack3104, stack3108, stack3112,
+	stack3116, stack3120, stack3124, stack3128, stack3132, stack3136,
+	stack3140, stack3144, stack3148, stack3152, stack3156, stack3160,
+	stack3164, stack3168, stack3172, stack3176, stack3180, stack3184,
+	stack3188, stack3192, stack3196, stack3200, stack3204, stack3208,
+	stack3212, stack3216, stack3220, stack3224, stack3228, stack3232,
+	stack3236, stack3240, stack3244, stack3248, stack3252, stack3256,
+	stack3260, stack3264, stack3268, stack3272, stack3276, stack3280,
+	stack3284, stack3288, stack3292, stack3296, stack3300, stack3304,
+	stack3308, stack3312, stack3316, stack3320, stack3324, stack3328,
+	stack3332, stack3336, stack3340, stack3344, stack3348, stack3352,
+	stack3356, stack3360, stack3364, stack3368, stack3372, stack3376,
+	stack3380, stack3384, stack3388, stack3392, stack3396, stack3400,
+	stack3404, stack3408, stack3412, stack3416, stack3420, stack3424,
+	stack3428, stack3432, stack3436, stack3440, stack3444, stack3448,
+	stack3452, stack3456, stack3460, stack3464, stack3468, stack3472,
+	stack3476, stack3480, stack3484, stack3488, stack3492, stack3496,
+	stack3500, stack3504, stack3508, stack3512, stack3516, stack3520,
+	stack3524, stack3528, stack3532, stack3536, stack3540, stack3544,
+	stack3548, stack3552, stack3556, stack3560, stack3564, stack3568,
+	stack3572, stack3576, stack3580, stack3584, stack3588, stack3592,
+	stack3596, stack3600, stack3604, stack3608, stack3612, stack3616,
+	stack3620, stack3624, stack3628, stack3632, stack3636, stack3640,
+	stack3644, stack3648, stack3652, stack3656, stack3660, stack3664,
+	stack3668, stack3672, stack3676, stack3680, stack3684, stack3688,
+	stack3692, stack3696, stack3700, stack3704, stack3708, stack3712,
+	stack3716, stack3720, stack3724, stack3728, stack3732, stack3736,
+	stack3740, stack3744, stack3748, stack3752, stack3756, stack3760,
+	stack3764, stack3768, stack3772, stack3776, stack3780, stack3784,
+	stack3788, stack3792, stack3796, stack3800, stack3804, stack3808,
+	stack3812, stack3816, stack3820, stack3824, stack3828, stack3832,
+	stack3836, stack3840, stack3844, stack3848, stack3852, stack3856,
+	stack3860, stack3864, stack3868, stack3872, stack3876, stack3880,
+	stack3884, stack3888, stack3892, stack3896, stack3900, stack3904,
+	stack3908, stack3912, stack3916, stack3920, stack3924, stack3928,
+	stack3932, stack3936, stack3940, stack3944, stack3948, stack3952,
+	stack3956, stack3960, stack3964, stack3968, stack3972, stack3976,
+	stack3980, stack3984, stack3988, stack3992, stack3996, stack4000,
+	stack4004, stack4008, stack4012, stack4016, stack4020, stack4024,
+	stack4028, stack4032, stack4036, stack4040, stack4044, stack4048,
+	stack4052, stack4056, stack4060, stack4064, stack4068, stack4072,
+	stack4076, stack4080, stack4084, stack4088, stack4092, stack4096,
+	stack4100, stack4104, stack4108, stack4112, stack4116, stack4120,
+	stack4124, stack4128, stack4132, stack4136, stack4140, stack4144,
+	stack4148, stack4152, stack4156, stack4160, stack4164, stack4168,
+	stack4172, stack4176, stack4180, stack4184, stack4188, stack4192,
+	stack4196, stack4200, stack4204, stack4208, stack4212, stack4216,
+	stack4220, stack4224, stack4228, stack4232, stack4236, stack4240,
+	stack4244, stack4248, stack4252, stack4256, stack4260, stack4264,
+	stack4268, stack4272, stack4276, stack4280, stack4284, stack4288,
+	stack4292, stack4296, stack4300, stack4304, stack4308, stack4312,
+	stack4316, stack4320, stack4324, stack4328, stack4332, stack4336,
+	stack4340, stack4344, stack4348, stack4352, stack4356, stack4360,
+	stack4364, stack4368, stack4372, stack4376, stack4380, stack4384,
+	stack4388, stack4392, stack4396, stack4400, stack4404, stack4408,
+	stack4412, stack4416, stack4420, stack4424, stack4428, stack4432,
+	stack4436, stack4440, stack4444, stack4448, stack4452, stack4456,
+	stack4460, stack4464, stack4468, stack4472, stack4476, stack4480,
+	stack4484, stack4488, stack4492, stack4496, stack4500, stack4504,
+	stack4508, stack4512, stack4516, stack4520, stack4524, stack4528,
+	stack4532, stack4536, stack4540, stack4544, stack4548, stack4552,
+	stack4556, stack4560, stack4564, stack4568, stack4572, stack4576,
+	stack4580, stack4584, stack4588, stack4592, stack4596, stack4600,
+	stack4604, stack4608, stack4612, stack4616, stack4620, stack4624,
+	stack4628, stack4632, stack4636, stack4640, stack4644, stack4648,
+	stack4652, stack4656, stack4660, stack4664, stack4668, stack4672,
+	stack4676, stack4680, stack4684, stack4688, stack4692, stack4696,
+	stack4700, stack4704, stack4708, stack4712, stack4716, stack4720,
+	stack4724, stack4728, stack4732, stack4736, stack4740, stack4744,
+	stack4748, stack4752, stack4756, stack4760, stack4764, stack4768,
+	stack4772, stack4776, stack4780, stack4784, stack4788, stack4792,
+	stack4796, stack4800, stack4804, stack4808, stack4812, stack4816,
+	stack4820, stack4824, stack4828, stack4832, stack4836, stack4840,
+	stack4844, stack4848, stack4852, stack4856, stack4860, stack4864,
+	stack4868, stack4872, stack4876, stack4880, stack4884, stack4888,
+	stack4892, stack4896, stack4900, stack4904, stack4908, stack4912,
+	stack4916, stack4920, stack4924, stack4928, stack4932, stack4936,
+	stack4940, stack4944, stack4948, stack4952, stack4956, stack4960,
+	stack4964, stack4968, stack4972, stack4976, stack4980, stack4984,
+	stack4988, stack4992, stack4996, stack5000,
+}
+
+// Edit .+1,$ | seq 4 4 5000 | sed 's/.*/func stack&()(uintptr, uintptr) { var buf [&]byte; use(buf[:]); return Stackguard() }/'
+func stack4() (uintptr, uintptr)    { var buf [4]byte; use(buf[:]); return Stackguard() }
+func stack8() (uintptr, uintptr)    { var buf [8]byte; use(buf[:]); return Stackguard() }
+func stack12() (uintptr, uintptr)   { var buf [12]byte; use(buf[:]); return Stackguard() }
+func stack16() (uintptr, uintptr)   { var buf [16]byte; use(buf[:]); return Stackguard() }
+func stack20() (uintptr, uintptr)   { var buf [20]byte; use(buf[:]); return Stackguard() }
+func stack24() (uintptr, uintptr)   { var buf [24]byte; use(buf[:]); return Stackguard() }
+func stack28() (uintptr, uintptr)   { var buf [28]byte; use(buf[:]); return Stackguard() }
+func stack32() (uintptr, uintptr)   { var buf [32]byte; use(buf[:]); return Stackguard() }
+func stack36() (uintptr, uintptr)   { var buf [36]byte; use(buf[:]); return Stackguard() }
+func stack40() (uintptr, uintptr)   { var buf [40]byte; use(buf[:]); return Stackguard() }
+func stack44() (uintptr, uintptr)   { var buf [44]byte; use(buf[:]); return Stackguard() }
+func stack48() (uintptr, uintptr)   { var buf [48]byte; use(buf[:]); return Stackguard() }
+func stack52() (uintptr, uintptr)   { var buf [52]byte; use(buf[:]); return Stackguard() }
+func stack56() (uintptr, uintptr)   { var buf [56]byte; use(buf[:]); return Stackguard() }
+func stack60() (uintptr, uintptr)   { var buf [60]byte; use(buf[:]); return Stackguard() }
+func stack64() (uintptr, uintptr)   { var buf [64]byte; use(buf[:]); return Stackguard() }
+func stack68() (uintptr, uintptr)   { var buf [68]byte; use(buf[:]); return Stackguard() }
+func stack72() (uintptr, uintptr)   { var buf [72]byte; use(buf[:]); return Stackguard() }
+func stack76() (uintptr, uintptr)   { var buf [76]byte; use(buf[:]); return Stackguard() }
+func stack80() (uintptr, uintptr)   { var buf [80]byte; use(buf[:]); return Stackguard() }
+func stack84() (uintptr, uintptr)   { var buf [84]byte; use(buf[:]); return Stackguard() }
+func stack88() (uintptr, uintptr)   { var buf [88]byte; use(buf[:]); return Stackguard() }
+func stack92() (uintptr, uintptr)   { var buf [92]byte; use(buf[:]); return Stackguard() }
+func stack96() (uintptr, uintptr)   { var buf [96]byte; use(buf[:]); return Stackguard() }
+func stack100() (uintptr, uintptr)  { var buf [100]byte; use(buf[:]); return Stackguard() }
+func stack104() (uintptr, uintptr)  { var buf [104]byte; use(buf[:]); return Stackguard() }
+func stack108() (uintptr, uintptr)  { var buf [108]byte; use(buf[:]); return Stackguard() }
+func stack112() (uintptr, uintptr)  { var buf [112]byte; use(buf[:]); return Stackguard() }
+func stack116() (uintptr, uintptr)  { var buf [116]byte; use(buf[:]); return Stackguard() }
+func stack120() (uintptr, uintptr)  { var buf [120]byte; use(buf[:]); return Stackguard() }
+func stack124() (uintptr, uintptr)  { var buf [124]byte; use(buf[:]); return Stackguard() }
+func stack128() (uintptr, uintptr)  { var buf [128]byte; use(buf[:]); return Stackguard() }
+func stack132() (uintptr, uintptr)  { var buf [132]byte; use(buf[:]); return Stackguard() }
+func stack136() (uintptr, uintptr)  { var buf [136]byte; use(buf[:]); return Stackguard() }
+func stack140() (uintptr, uintptr)  { var buf [140]byte; use(buf[:]); return Stackguard() }
+func stack144() (uintptr, uintptr)  { var buf [144]byte; use(buf[:]); return Stackguard() }
+func stack148() (uintptr, uintptr)  { var buf [148]byte; use(buf[:]); return Stackguard() }
+func stack152() (uintptr, uintptr)  { var buf [152]byte; use(buf[:]); return Stackguard() }
+func stack156() (uintptr, uintptr)  { var buf [156]byte; use(buf[:]); return Stackguard() }
+func stack160() (uintptr, uintptr)  { var buf [160]byte; use(buf[:]); return Stackguard() }
+func stack164() (uintptr, uintptr)  { var buf [164]byte; use(buf[:]); return Stackguard() }
+func stack168() (uintptr, uintptr)  { var buf [168]byte; use(buf[:]); return Stackguard() }
+func stack172() (uintptr, uintptr)  { var buf [172]byte; use(buf[:]); return Stackguard() }
+func stack176() (uintptr, uintptr)  { var buf [176]byte; use(buf[:]); return Stackguard() }
+func stack180() (uintptr, uintptr)  { var buf [180]byte; use(buf[:]); return Stackguard() }
+func stack184() (uintptr, uintptr)  { var buf [184]byte; use(buf[:]); return Stackguard() }
+func stack188() (uintptr, uintptr)  { var buf [188]byte; use(buf[:]); return Stackguard() }
+func stack192() (uintptr, uintptr)  { var buf [192]byte; use(buf[:]); return Stackguard() }
+func stack196() (uintptr, uintptr)  { var buf [196]byte; use(buf[:]); return Stackguard() }
+func stack200() (uintptr, uintptr)  { var buf [200]byte; use(buf[:]); return Stackguard() }
+func stack204() (uintptr, uintptr)  { var buf [204]byte; use(buf[:]); return Stackguard() }
+func stack208() (uintptr, uintptr)  { var buf [208]byte; use(buf[:]); return Stackguard() }
+func stack212() (uintptr, uintptr)  { var buf [212]byte; use(buf[:]); return Stackguard() }
+func stack216() (uintptr, uintptr)  { var buf [216]byte; use(buf[:]); return Stackguard() }
+func stack220() (uintptr, uintptr)  { var buf [220]byte; use(buf[:]); return Stackguard() }
+func stack224() (uintptr, uintptr)  { var buf [224]byte; use(buf[:]); return Stackguard() }
+func stack228() (uintptr, uintptr)  { var buf [228]byte; use(buf[:]); return Stackguard() }
+func stack232() (uintptr, uintptr)  { var buf [232]byte; use(buf[:]); return Stackguard() }
+func stack236() (uintptr, uintptr)  { var buf [236]byte; use(buf[:]); return Stackguard() }
+func stack240() (uintptr, uintptr)  { var buf [240]byte; use(buf[:]); return Stackguard() }
+func stack244() (uintptr, uintptr)  { var buf [244]byte; use(buf[:]); return Stackguard() }
+func stack248() (uintptr, uintptr)  { var buf [248]byte; use(buf[:]); return Stackguard() }
+func stack252() (uintptr, uintptr)  { var buf [252]byte; use(buf[:]); return Stackguard() }
+func stack256() (uintptr, uintptr)  { var buf [256]byte; use(buf[:]); return Stackguard() }
+func stack260() (uintptr, uintptr)  { var buf [260]byte; use(buf[:]); return Stackguard() }
+func stack264() (uintptr, uintptr)  { var buf [264]byte; use(buf[:]); return Stackguard() }
+func stack268() (uintptr, uintptr)  { var buf [268]byte; use(buf[:]); return Stackguard() }
+func stack272() (uintptr, uintptr)  { var buf [272]byte; use(buf[:]); return Stackguard() }
+func stack276() (uintptr, uintptr)  { var buf [276]byte; use(buf[:]); return Stackguard() }
+func stack280() (uintptr, uintptr)  { var buf [280]byte; use(buf[:]); return Stackguard() }
+func stack284() (uintptr, uintptr)  { var buf [284]byte; use(buf[:]); return Stackguard() }
+func stack288() (uintptr, uintptr)  { var buf [288]byte; use(buf[:]); return Stackguard() }
+func stack292() (uintptr, uintptr)  { var buf [292]byte; use(buf[:]); return Stackguard() }
+func stack296() (uintptr, uintptr)  { var buf [296]byte; use(buf[:]); return Stackguard() }
+func stack300() (uintptr, uintptr)  { var buf [300]byte; use(buf[:]); return Stackguard() }
+func stack304() (uintptr, uintptr)  { var buf [304]byte; use(buf[:]); return Stackguard() }
+func stack308() (uintptr, uintptr)  { var buf [308]byte; use(buf[:]); return Stackguard() }
+func stack312() (uintptr, uintptr)  { var buf [312]byte; use(buf[:]); return Stackguard() }
+func stack316() (uintptr, uintptr)  { var buf [316]byte; use(buf[:]); return Stackguard() }
+func stack320() (uintptr, uintptr)  { var buf [320]byte; use(buf[:]); return Stackguard() }
+func stack324() (uintptr, uintptr)  { var buf [324]byte; use(buf[:]); return Stackguard() }
+func stack328() (uintptr, uintptr)  { var buf [328]byte; use(buf[:]); return Stackguard() }
+func stack332() (uintptr, uintptr)  { var buf [332]byte; use(buf[:]); return Stackguard() }
+func stack336() (uintptr, uintptr)  { var buf [336]byte; use(buf[:]); return Stackguard() }
+func stack340() (uintptr, uintptr)  { var buf [340]byte; use(buf[:]); return Stackguard() }
+func stack344() (uintptr, uintptr)  { var buf [344]byte; use(buf[:]); return Stackguard() }
+func stack348() (uintptr, uintptr)  { var buf [348]byte; use(buf[:]); return Stackguard() }
+func stack352() (uintptr, uintptr)  { var buf [352]byte; use(buf[:]); return Stackguard() }
+func stack356() (uintptr, uintptr)  { var buf [356]byte; use(buf[:]); return Stackguard() }
+func stack360() (uintptr, uintptr)  { var buf [360]byte; use(buf[:]); return Stackguard() }
+func stack364() (uintptr, uintptr)  { var buf [364]byte; use(buf[:]); return Stackguard() }
+func stack368() (uintptr, uintptr)  { var buf [368]byte; use(buf[:]); return Stackguard() }
+func stack372() (uintptr, uintptr)  { var buf [372]byte; use(buf[:]); return Stackguard() }
+func stack376() (uintptr, uintptr)  { var buf [376]byte; use(buf[:]); return Stackguard() }
+func stack380() (uintptr, uintptr)  { var buf [380]byte; use(buf[:]); return Stackguard() }
+func stack384() (uintptr, uintptr)  { var buf [384]byte; use(buf[:]); return Stackguard() }
+func stack388() (uintptr, uintptr)  { var buf [388]byte; use(buf[:]); return Stackguard() }
+func stack392() (uintptr, uintptr)  { var buf [392]byte; use(buf[:]); return Stackguard() }
+func stack396() (uintptr, uintptr)  { var buf [396]byte; use(buf[:]); return Stackguard() }
+func stack400() (uintptr, uintptr)  { var buf [400]byte; use(buf[:]); return Stackguard() }
+func stack404() (uintptr, uintptr)  { var buf [404]byte; use(buf[:]); return Stackguard() }
+func stack408() (uintptr, uintptr)  { var buf [408]byte; use(buf[:]); return Stackguard() }
+func stack412() (uintptr, uintptr)  { var buf [412]byte; use(buf[:]); return Stackguard() }
+func stack416() (uintptr, uintptr)  { var buf [416]byte; use(buf[:]); return Stackguard() }
+func stack420() (uintptr, uintptr)  { var buf [420]byte; use(buf[:]); return Stackguard() }
+func stack424() (uintptr, uintptr)  { var buf [424]byte; use(buf[:]); return Stackguard() }
+func stack428() (uintptr, uintptr)  { var buf [428]byte; use(buf[:]); return Stackguard() }
+func stack432() (uintptr, uintptr)  { var buf [432]byte; use(buf[:]); return Stackguard() }
+func stack436() (uintptr, uintptr)  { var buf [436]byte; use(buf[:]); return Stackguard() }
+func stack440() (uintptr, uintptr)  { var buf [440]byte; use(buf[:]); return Stackguard() }
+func stack444() (uintptr, uintptr)  { var buf [444]byte; use(buf[:]); return Stackguard() }
+func stack448() (uintptr, uintptr)  { var buf [448]byte; use(buf[:]); return Stackguard() }
+func stack452() (uintptr, uintptr)  { var buf [452]byte; use(buf[:]); return Stackguard() }
+func stack456() (uintptr, uintptr)  { var buf [456]byte; use(buf[:]); return Stackguard() }
+func stack460() (uintptr, uintptr)  { var buf [460]byte; use(buf[:]); return Stackguard() }
+func stack464() (uintptr, uintptr)  { var buf [464]byte; use(buf[:]); return Stackguard() }
+func stack468() (uintptr, uintptr)  { var buf [468]byte; use(buf[:]); return Stackguard() }
+func stack472() (uintptr, uintptr)  { var buf [472]byte; use(buf[:]); return Stackguard() }
+func stack476() (uintptr, uintptr)  { var buf [476]byte; use(buf[:]); return Stackguard() }
+func stack480() (uintptr, uintptr)  { var buf [480]byte; use(buf[:]); return Stackguard() }
+func stack484() (uintptr, uintptr)  { var buf [484]byte; use(buf[:]); return Stackguard() }
+func stack488() (uintptr, uintptr)  { var buf [488]byte; use(buf[:]); return Stackguard() }
+func stack492() (uintptr, uintptr)  { var buf [492]byte; use(buf[:]); return Stackguard() }
+func stack496() (uintptr, uintptr)  { var buf [496]byte; use(buf[:]); return Stackguard() }
+func stack500() (uintptr, uintptr)  { var buf [500]byte; use(buf[:]); return Stackguard() }
+func stack504() (uintptr, uintptr)  { var buf [504]byte; use(buf[:]); return Stackguard() }
+func stack508() (uintptr, uintptr)  { var buf [508]byte; use(buf[:]); return Stackguard() }
+func stack512() (uintptr, uintptr)  { var buf [512]byte; use(buf[:]); return Stackguard() }
+func stack516() (uintptr, uintptr)  { var buf [516]byte; use(buf[:]); return Stackguard() }
+func stack520() (uintptr, uintptr)  { var buf [520]byte; use(buf[:]); return Stackguard() }
+func stack524() (uintptr, uintptr)  { var buf [524]byte; use(buf[:]); return Stackguard() }
+func stack528() (uintptr, uintptr)  { var buf [528]byte; use(buf[:]); return Stackguard() }
+func stack532() (uintptr, uintptr)  { var buf [532]byte; use(buf[:]); return Stackguard() }
+func stack536() (uintptr, uintptr)  { var buf [536]byte; use(buf[:]); return Stackguard() }
+func stack540() (uintptr, uintptr)  { var buf [540]byte; use(buf[:]); return Stackguard() }
+func stack544() (uintptr, uintptr)  { var buf [544]byte; use(buf[:]); return Stackguard() }
+func stack548() (uintptr, uintptr)  { var buf [548]byte; use(buf[:]); return Stackguard() }
+func stack552() (uintptr, uintptr)  { var buf [552]byte; use(buf[:]); return Stackguard() }
+func stack556() (uintptr, uintptr)  { var buf [556]byte; use(buf[:]); return Stackguard() }
+func stack560() (uintptr, uintptr)  { var buf [560]byte; use(buf[:]); return Stackguard() }
+func stack564() (uintptr, uintptr)  { var buf [564]byte; use(buf[:]); return Stackguard() }
+func stack568() (uintptr, uintptr)  { var buf [568]byte; use(buf[:]); return Stackguard() }
+func stack572() (uintptr, uintptr)  { var buf [572]byte; use(buf[:]); return Stackguard() }
+func stack576() (uintptr, uintptr)  { var buf [576]byte; use(buf[:]); return Stackguard() }
+func stack580() (uintptr, uintptr)  { var buf [580]byte; use(buf[:]); return Stackguard() }
+func stack584() (uintptr, uintptr)  { var buf [584]byte; use(buf[:]); return Stackguard() }
+func stack588() (uintptr, uintptr)  { var buf [588]byte; use(buf[:]); return Stackguard() }
+func stack592() (uintptr, uintptr)  { var buf [592]byte; use(buf[:]); return Stackguard() }
+func stack596() (uintptr, uintptr)  { var buf [596]byte; use(buf[:]); return Stackguard() }
+func stack600() (uintptr, uintptr)  { var buf [600]byte; use(buf[:]); return Stackguard() }
+func stack604() (uintptr, uintptr)  { var buf [604]byte; use(buf[:]); return Stackguard() }
+func stack608() (uintptr, uintptr)  { var buf [608]byte; use(buf[:]); return Stackguard() }
+func stack612() (uintptr, uintptr)  { var buf [612]byte; use(buf[:]); return Stackguard() }
+func stack616() (uintptr, uintptr)  { var buf [616]byte; use(buf[:]); return Stackguard() }
+func stack620() (uintptr, uintptr)  { var buf [620]byte; use(buf[:]); return Stackguard() }
+func stack624() (uintptr, uintptr)  { var buf [624]byte; use(buf[:]); return Stackguard() }
+func stack628() (uintptr, uintptr)  { var buf [628]byte; use(buf[:]); return Stackguard() }
+func stack632() (uintptr, uintptr)  { var buf [632]byte; use(buf[:]); return Stackguard() }
+func stack636() (uintptr, uintptr)  { var buf [636]byte; use(buf[:]); return Stackguard() }
+func stack640() (uintptr, uintptr)  { var buf [640]byte; use(buf[:]); return Stackguard() }
+func stack644() (uintptr, uintptr)  { var buf [644]byte; use(buf[:]); return Stackguard() }
+func stack648() (uintptr, uintptr)  { var buf [648]byte; use(buf[:]); return Stackguard() }
+func stack652() (uintptr, uintptr)  { var buf [652]byte; use(buf[:]); return Stackguard() }
+func stack656() (uintptr, uintptr)  { var buf [656]byte; use(buf[:]); return Stackguard() }
+func stack660() (uintptr, uintptr)  { var buf [660]byte; use(buf[:]); return Stackguard() }
+func stack664() (uintptr, uintptr)  { var buf [664]byte; use(buf[:]); return Stackguard() }
+func stack668() (uintptr, uintptr)  { var buf [668]byte; use(buf[:]); return Stackguard() }
+func stack672() (uintptr, uintptr)  { var buf [672]byte; use(buf[:]); return Stackguard() }
+func stack676() (uintptr, uintptr)  { var buf [676]byte; use(buf[:]); return Stackguard() }
+func stack680() (uintptr, uintptr)  { var buf [680]byte; use(buf[:]); return Stackguard() }
+func stack684() (uintptr, uintptr)  { var buf [684]byte; use(buf[:]); return Stackguard() }
+func stack688() (uintptr, uintptr)  { var buf [688]byte; use(buf[:]); return Stackguard() }
+func stack692() (uintptr, uintptr)  { var buf [692]byte; use(buf[:]); return Stackguard() }
+func stack696() (uintptr, uintptr)  { var buf [696]byte; use(buf[:]); return Stackguard() }
+func stack700() (uintptr, uintptr)  { var buf [700]byte; use(buf[:]); return Stackguard() }
+func stack704() (uintptr, uintptr)  { var buf [704]byte; use(buf[:]); return Stackguard() }
+func stack708() (uintptr, uintptr)  { var buf [708]byte; use(buf[:]); return Stackguard() }
+func stack712() (uintptr, uintptr)  { var buf [712]byte; use(buf[:]); return Stackguard() }
+func stack716() (uintptr, uintptr)  { var buf [716]byte; use(buf[:]); return Stackguard() }
+func stack720() (uintptr, uintptr)  { var buf [720]byte; use(buf[:]); return Stackguard() }
+func stack724() (uintptr, uintptr)  { var buf [724]byte; use(buf[:]); return Stackguard() }
+func stack728() (uintptr, uintptr)  { var buf [728]byte; use(buf[:]); return Stackguard() }
+func stack732() (uintptr, uintptr)  { var buf [732]byte; use(buf[:]); return Stackguard() }
+func stack736() (uintptr, uintptr)  { var buf [736]byte; use(buf[:]); return Stackguard() }
+func stack740() (uintptr, uintptr)  { var buf [740]byte; use(buf[:]); return Stackguard() }
+func stack744() (uintptr, uintptr)  { var buf [744]byte; use(buf[:]); return Stackguard() }
+func stack748() (uintptr, uintptr)  { var buf [748]byte; use(buf[:]); return Stackguard() }
+func stack752() (uintptr, uintptr)  { var buf [752]byte; use(buf[:]); return Stackguard() }
+func stack756() (uintptr, uintptr)  { var buf [756]byte; use(buf[:]); return Stackguard() }
+func stack760() (uintptr, uintptr)  { var buf [760]byte; use(buf[:]); return Stackguard() }
+func stack764() (uintptr, uintptr)  { var buf [764]byte; use(buf[:]); return Stackguard() }
+func stack768() (uintptr, uintptr)  { var buf [768]byte; use(buf[:]); return Stackguard() }
+func stack772() (uintptr, uintptr)  { var buf [772]byte; use(buf[:]); return Stackguard() }
+func stack776() (uintptr, uintptr)  { var buf [776]byte; use(buf[:]); return Stackguard() }
+func stack780() (uintptr, uintptr)  { var buf [780]byte; use(buf[:]); return Stackguard() }
+func stack784() (uintptr, uintptr)  { var buf [784]byte; use(buf[:]); return Stackguard() }
+func stack788() (uintptr, uintptr)  { var buf [788]byte; use(buf[:]); return Stackguard() }
+func stack792() (uintptr, uintptr)  { var buf [792]byte; use(buf[:]); return Stackguard() }
+func stack796() (uintptr, uintptr)  { var buf [796]byte; use(buf[:]); return Stackguard() }
+func stack800() (uintptr, uintptr)  { var buf [800]byte; use(buf[:]); return Stackguard() }
+func stack804() (uintptr, uintptr)  { var buf [804]byte; use(buf[:]); return Stackguard() }
+func stack808() (uintptr, uintptr)  { var buf [808]byte; use(buf[:]); return Stackguard() }
+func stack812() (uintptr, uintptr)  { var buf [812]byte; use(buf[:]); return Stackguard() }
+func stack816() (uintptr, uintptr)  { var buf [816]byte; use(buf[:]); return Stackguard() }
+func stack820() (uintptr, uintptr)  { var buf [820]byte; use(buf[:]); return Stackguard() }
+func stack824() (uintptr, uintptr)  { var buf [824]byte; use(buf[:]); return Stackguard() }
+func stack828() (uintptr, uintptr)  { var buf [828]byte; use(buf[:]); return Stackguard() }
+func stack832() (uintptr, uintptr)  { var buf [832]byte; use(buf[:]); return Stackguard() }
+func stack836() (uintptr, uintptr)  { var buf [836]byte; use(buf[:]); return Stackguard() }
+func stack840() (uintptr, uintptr)  { var buf [840]byte; use(buf[:]); return Stackguard() }
+func stack844() (uintptr, uintptr)  { var buf [844]byte; use(buf[:]); return Stackguard() }
+func stack848() (uintptr, uintptr)  { var buf [848]byte; use(buf[:]); return Stackguard() }
+func stack852() (uintptr, uintptr)  { var buf [852]byte; use(buf[:]); return Stackguard() }
+func stack856() (uintptr, uintptr)  { var buf [856]byte; use(buf[:]); return Stackguard() }
+func stack860() (uintptr, uintptr)  { var buf [860]byte; use(buf[:]); return Stackguard() }
+func stack864() (uintptr, uintptr)  { var buf [864]byte; use(buf[:]); return Stackguard() }
+func stack868() (uintptr, uintptr)  { var buf [868]byte; use(buf[:]); return Stackguard() }
+func stack872() (uintptr, uintptr)  { var buf [872]byte; use(buf[:]); return Stackguard() }
+func stack876() (uintptr, uintptr)  { var buf [876]byte; use(buf[:]); return Stackguard() }
+func stack880() (uintptr, uintptr)  { var buf [880]byte; use(buf[:]); return Stackguard() }
+func stack884() (uintptr, uintptr)  { var buf [884]byte; use(buf[:]); return Stackguard() }
+func stack888() (uintptr, uintptr)  { var buf [888]byte; use(buf[:]); return Stackguard() }
+func stack892() (uintptr, uintptr)  { var buf [892]byte; use(buf[:]); return Stackguard() }
+func stack896() (uintptr, uintptr)  { var buf [896]byte; use(buf[:]); return Stackguard() }
+func stack900() (uintptr, uintptr)  { var buf [900]byte; use(buf[:]); return Stackguard() }
+func stack904() (uintptr, uintptr)  { var buf [904]byte; use(buf[:]); return Stackguard() }
+func stack908() (uintptr, uintptr)  { var buf [908]byte; use(buf[:]); return Stackguard() }
+func stack912() (uintptr, uintptr)  { var buf [912]byte; use(buf[:]); return Stackguard() }
+func stack916() (uintptr, uintptr)  { var buf [916]byte; use(buf[:]); return Stackguard() }
+func stack920() (uintptr, uintptr)  { var buf [920]byte; use(buf[:]); return Stackguard() }
+func stack924() (uintptr, uintptr)  { var buf [924]byte; use(buf[:]); return Stackguard() }
+func stack928() (uintptr, uintptr)  { var buf [928]byte; use(buf[:]); return Stackguard() }
+func stack932() (uintptr, uintptr)  { var buf [932]byte; use(buf[:]); return Stackguard() }
+func stack936() (uintptr, uintptr)  { var buf [936]byte; use(buf[:]); return Stackguard() }
+func stack940() (uintptr, uintptr)  { var buf [940]byte; use(buf[:]); return Stackguard() }
+func stack944() (uintptr, uintptr)  { var buf [944]byte; use(buf[:]); return Stackguard() }
+func stack948() (uintptr, uintptr)  { var buf [948]byte; use(buf[:]); return Stackguard() }
+func stack952() (uintptr, uintptr)  { var buf [952]byte; use(buf[:]); return Stackguard() }
+func stack956() (uintptr, uintptr)  { var buf [956]byte; use(buf[:]); return Stackguard() }
+func stack960() (uintptr, uintptr)  { var buf [960]byte; use(buf[:]); return Stackguard() }
+func stack964() (uintptr, uintptr)  { var buf [964]byte; use(buf[:]); return Stackguard() }
+func stack968() (uintptr, uintptr)  { var buf [968]byte; use(buf[:]); return Stackguard() }
+func stack972() (uintptr, uintptr)  { var buf [972]byte; use(buf[:]); return Stackguard() }
+func stack976() (uintptr, uintptr)  { var buf [976]byte; use(buf[:]); return Stackguard() }
+func stack980() (uintptr, uintptr)  { var buf [980]byte; use(buf[:]); return Stackguard() }
+func stack984() (uintptr, uintptr)  { var buf [984]byte; use(buf[:]); return Stackguard() }
+func stack988() (uintptr, uintptr)  { var buf [988]byte; use(buf[:]); return Stackguard() }
+func stack992() (uintptr, uintptr)  { var buf [992]byte; use(buf[:]); return Stackguard() }
+func stack996() (uintptr, uintptr)  { var buf [996]byte; use(buf[:]); return Stackguard() }
+func stack1000() (uintptr, uintptr) { var buf [1000]byte; use(buf[:]); return Stackguard() }
+func stack1004() (uintptr, uintptr) { var buf [1004]byte; use(buf[:]); return Stackguard() }
+func stack1008() (uintptr, uintptr) { var buf [1008]byte; use(buf[:]); return Stackguard() }
+func stack1012() (uintptr, uintptr) { var buf [1012]byte; use(buf[:]); return Stackguard() }
+func stack1016() (uintptr, uintptr) { var buf [1016]byte; use(buf[:]); return Stackguard() }
+func stack1020() (uintptr, uintptr) { var buf [1020]byte; use(buf[:]); return Stackguard() }
+func stack1024() (uintptr, uintptr) { var buf [1024]byte; use(buf[:]); return Stackguard() }
+func stack1028() (uintptr, uintptr) { var buf [1028]byte; use(buf[:]); return Stackguard() }
+func stack1032() (uintptr, uintptr) { var buf [1032]byte; use(buf[:]); return Stackguard() }
+func stack1036() (uintptr, uintptr) { var buf [1036]byte; use(buf[:]); return Stackguard() }
+func stack1040() (uintptr, uintptr) { var buf [1040]byte; use(buf[:]); return Stackguard() }
+func stack1044() (uintptr, uintptr) { var buf [1044]byte; use(buf[:]); return Stackguard() }
+func stack1048() (uintptr, uintptr) { var buf [1048]byte; use(buf[:]); return Stackguard() }
+func stack1052() (uintptr, uintptr) { var buf [1052]byte; use(buf[:]); return Stackguard() }
+func stack1056() (uintptr, uintptr) { var buf [1056]byte; use(buf[:]); return Stackguard() }
+func stack1060() (uintptr, uintptr) { var buf [1060]byte; use(buf[:]); return Stackguard() }
+func stack1064() (uintptr, uintptr) { var buf [1064]byte; use(buf[:]); return Stackguard() }
+func stack1068() (uintptr, uintptr) { var buf [1068]byte; use(buf[:]); return Stackguard() }
+func stack1072() (uintptr, uintptr) { var buf [1072]byte; use(buf[:]); return Stackguard() }
+func stack1076() (uintptr, uintptr) { var buf [1076]byte; use(buf[:]); return Stackguard() }
+func stack1080() (uintptr, uintptr) { var buf [1080]byte; use(buf[:]); return Stackguard() }
+func stack1084() (uintptr, uintptr) { var buf [1084]byte; use(buf[:]); return Stackguard() }
+func stack1088() (uintptr, uintptr) { var buf [1088]byte; use(buf[:]); return Stackguard() }
+func stack1092() (uintptr, uintptr) { var buf [1092]byte; use(buf[:]); return Stackguard() }
+func stack1096() (uintptr, uintptr) { var buf [1096]byte; use(buf[:]); return Stackguard() }
+func stack1100() (uintptr, uintptr) { var buf [1100]byte; use(buf[:]); return Stackguard() }
+func stack1104() (uintptr, uintptr) { var buf [1104]byte; use(buf[:]); return Stackguard() }
+func stack1108() (uintptr, uintptr) { var buf [1108]byte; use(buf[:]); return Stackguard() }
+func stack1112() (uintptr, uintptr) { var buf [1112]byte; use(buf[:]); return Stackguard() }
+func stack1116() (uintptr, uintptr) { var buf [1116]byte; use(buf[:]); return Stackguard() }
+func stack1120() (uintptr, uintptr) { var buf [1120]byte; use(buf[:]); return Stackguard() }
+func stack1124() (uintptr, uintptr) { var buf [1124]byte; use(buf[:]); return Stackguard() }
+func stack1128() (uintptr, uintptr) { var buf [1128]byte; use(buf[:]); return Stackguard() }
+func stack1132() (uintptr, uintptr) { var buf [1132]byte; use(buf[:]); return Stackguard() }
+func stack1136() (uintptr, uintptr) { var buf [1136]byte; use(buf[:]); return Stackguard() }
+func stack1140() (uintptr, uintptr) { var buf [1140]byte; use(buf[:]); return Stackguard() }
+func stack1144() (uintptr, uintptr) { var buf [1144]byte; use(buf[:]); return Stackguard() }
+func stack1148() (uintptr, uintptr) { var buf [1148]byte; use(buf[:]); return Stackguard() }
+func stack1152() (uintptr, uintptr) { var buf [1152]byte; use(buf[:]); return Stackguard() }
+func stack1156() (uintptr, uintptr) { var buf [1156]byte; use(buf[:]); return Stackguard() }
+func stack1160() (uintptr, uintptr) { var buf [1160]byte; use(buf[:]); return Stackguard() }
+func stack1164() (uintptr, uintptr) { var buf [1164]byte; use(buf[:]); return Stackguard() }
+func stack1168() (uintptr, uintptr) { var buf [1168]byte; use(buf[:]); return Stackguard() }
+func stack1172() (uintptr, uintptr) { var buf [1172]byte; use(buf[:]); return Stackguard() }
+func stack1176() (uintptr, uintptr) { var buf [1176]byte; use(buf[:]); return Stackguard() }
+func stack1180() (uintptr, uintptr) { var buf [1180]byte; use(buf[:]); return Stackguard() }
+func stack1184() (uintptr, uintptr) { var buf [1184]byte; use(buf[:]); return Stackguard() }
+func stack1188() (uintptr, uintptr) { var buf [1188]byte; use(buf[:]); return Stackguard() }
+func stack1192() (uintptr, uintptr) { var buf [1192]byte; use(buf[:]); return Stackguard() }
+func stack1196() (uintptr, uintptr) { var buf [1196]byte; use(buf[:]); return Stackguard() }
+func stack1200() (uintptr, uintptr) { var buf [1200]byte; use(buf[:]); return Stackguard() }
+func stack1204() (uintptr, uintptr) { var buf [1204]byte; use(buf[:]); return Stackguard() }
+func stack1208() (uintptr, uintptr) { var buf [1208]byte; use(buf[:]); return Stackguard() }
+func stack1212() (uintptr, uintptr) { var buf [1212]byte; use(buf[:]); return Stackguard() }
+func stack1216() (uintptr, uintptr) { var buf [1216]byte; use(buf[:]); return Stackguard() }
+func stack1220() (uintptr, uintptr) { var buf [1220]byte; use(buf[:]); return Stackguard() }
+func stack1224() (uintptr, uintptr) { var buf [1224]byte; use(buf[:]); return Stackguard() }
+func stack1228() (uintptr, uintptr) { var buf [1228]byte; use(buf[:]); return Stackguard() }
+func stack1232() (uintptr, uintptr) { var buf [1232]byte; use(buf[:]); return Stackguard() }
+func stack1236() (uintptr, uintptr) { var buf [1236]byte; use(buf[:]); return Stackguard() }
+func stack1240() (uintptr, uintptr) { var buf [1240]byte; use(buf[:]); return Stackguard() }
+func stack1244() (uintptr, uintptr) { var buf [1244]byte; use(buf[:]); return Stackguard() }
+func stack1248() (uintptr, uintptr) { var buf [1248]byte; use(buf[:]); return Stackguard() }
+func stack1252() (uintptr, uintptr) { var buf [1252]byte; use(buf[:]); return Stackguard() }
+func stack1256() (uintptr, uintptr) { var buf [1256]byte; use(buf[:]); return Stackguard() }
+func stack1260() (uintptr, uintptr) { var buf [1260]byte; use(buf[:]); return Stackguard() }
+func stack1264() (uintptr, uintptr) { var buf [1264]byte; use(buf[:]); return Stackguard() }
+func stack1268() (uintptr, uintptr) { var buf [1268]byte; use(buf[:]); return Stackguard() }
+func stack1272() (uintptr, uintptr) { var buf [1272]byte; use(buf[:]); return Stackguard() }
+func stack1276() (uintptr, uintptr) { var buf [1276]byte; use(buf[:]); return Stackguard() }
+func stack1280() (uintptr, uintptr) { var buf [1280]byte; use(buf[:]); return Stackguard() }
+func stack1284() (uintptr, uintptr) { var buf [1284]byte; use(buf[:]); return Stackguard() }
+func stack1288() (uintptr, uintptr) { var buf [1288]byte; use(buf[:]); return Stackguard() }
+func stack1292() (uintptr, uintptr) { var buf [1292]byte; use(buf[:]); return Stackguard() }
+func stack1296() (uintptr, uintptr) { var buf [1296]byte; use(buf[:]); return Stackguard() }
+func stack1300() (uintptr, uintptr) { var buf [1300]byte; use(buf[:]); return Stackguard() }
+func stack1304() (uintptr, uintptr) { var buf [1304]byte; use(buf[:]); return Stackguard() }
+func stack1308() (uintptr, uintptr) { var buf [1308]byte; use(buf[:]); return Stackguard() }
+func stack1312() (uintptr, uintptr) { var buf [1312]byte; use(buf[:]); return Stackguard() }
+func stack1316() (uintptr, uintptr) { var buf [1316]byte; use(buf[:]); return Stackguard() }
+func stack1320() (uintptr, uintptr) { var buf [1320]byte; use(buf[:]); return Stackguard() }
+func stack1324() (uintptr, uintptr) { var buf [1324]byte; use(buf[:]); return Stackguard() }
+func stack1328() (uintptr, uintptr) { var buf [1328]byte; use(buf[:]); return Stackguard() }
+func stack1332() (uintptr, uintptr) { var buf [1332]byte; use(buf[:]); return Stackguard() }
+func stack1336() (uintptr, uintptr) { var buf [1336]byte; use(buf[:]); return Stackguard() }
+func stack1340() (uintptr, uintptr) { var buf [1340]byte; use(buf[:]); return Stackguard() }
+func stack1344() (uintptr, uintptr) { var buf [1344]byte; use(buf[:]); return Stackguard() }
+func stack1348() (uintptr, uintptr) { var buf [1348]byte; use(buf[:]); return Stackguard() }
+func stack1352() (uintptr, uintptr) { var buf [1352]byte; use(buf[:]); return Stackguard() }
+func stack1356() (uintptr, uintptr) { var buf [1356]byte; use(buf[:]); return Stackguard() }
+func stack1360() (uintptr, uintptr) { var buf [1360]byte; use(buf[:]); return Stackguard() }
+func stack1364() (uintptr, uintptr) { var buf [1364]byte; use(buf[:]); return Stackguard() }
+func stack1368() (uintptr, uintptr) { var buf [1368]byte; use(buf[:]); return Stackguard() }
+func stack1372() (uintptr, uintptr) { var buf [1372]byte; use(buf[:]); return Stackguard() }
+func stack1376() (uintptr, uintptr) { var buf [1376]byte; use(buf[:]); return Stackguard() }
+func stack1380() (uintptr, uintptr) { var buf [1380]byte; use(buf[:]); return Stackguard() }
+func stack1384() (uintptr, uintptr) { var buf [1384]byte; use(buf[:]); return Stackguard() }
+func stack1388() (uintptr, uintptr) { var buf [1388]byte; use(buf[:]); return Stackguard() }
+func stack1392() (uintptr, uintptr) { var buf [1392]byte; use(buf[:]); return Stackguard() }
+func stack1396() (uintptr, uintptr) { var buf [1396]byte; use(buf[:]); return Stackguard() }
+func stack1400() (uintptr, uintptr) { var buf [1400]byte; use(buf[:]); return Stackguard() }
+func stack1404() (uintptr, uintptr) { var buf [1404]byte; use(buf[:]); return Stackguard() }
+func stack1408() (uintptr, uintptr) { var buf [1408]byte; use(buf[:]); return Stackguard() }
+func stack1412() (uintptr, uintptr) { var buf [1412]byte; use(buf[:]); return Stackguard() }
+func stack1416() (uintptr, uintptr) { var buf [1416]byte; use(buf[:]); return Stackguard() }
+func stack1420() (uintptr, uintptr) { var buf [1420]byte; use(buf[:]); return Stackguard() }
+func stack1424() (uintptr, uintptr) { var buf [1424]byte; use(buf[:]); return Stackguard() }
+func stack1428() (uintptr, uintptr) { var buf [1428]byte; use(buf[:]); return Stackguard() }
+func stack1432() (uintptr, uintptr) { var buf [1432]byte; use(buf[:]); return Stackguard() }
+func stack1436() (uintptr, uintptr) { var buf [1436]byte; use(buf[:]); return Stackguard() }
+func stack1440() (uintptr, uintptr) { var buf [1440]byte; use(buf[:]); return Stackguard() }
+func stack1444() (uintptr, uintptr) { var buf [1444]byte; use(buf[:]); return Stackguard() }
+func stack1448() (uintptr, uintptr) { var buf [1448]byte; use(buf[:]); return Stackguard() }
+func stack1452() (uintptr, uintptr) { var buf [1452]byte; use(buf[:]); return Stackguard() }
+func stack1456() (uintptr, uintptr) { var buf [1456]byte; use(buf[:]); return Stackguard() }
+func stack1460() (uintptr, uintptr) { var buf [1460]byte; use(buf[:]); return Stackguard() }
+func stack1464() (uintptr, uintptr) { var buf [1464]byte; use(buf[:]); return Stackguard() }
+func stack1468() (uintptr, uintptr) { var buf [1468]byte; use(buf[:]); return Stackguard() }
+func stack1472() (uintptr, uintptr) { var buf [1472]byte; use(buf[:]); return Stackguard() }
+func stack1476() (uintptr, uintptr) { var buf [1476]byte; use(buf[:]); return Stackguard() }
+func stack1480() (uintptr, uintptr) { var buf [1480]byte; use(buf[:]); return Stackguard() }
+func stack1484() (uintptr, uintptr) { var buf [1484]byte; use(buf[:]); return Stackguard() }
+func stack1488() (uintptr, uintptr) { var buf [1488]byte; use(buf[:]); return Stackguard() }
+func stack1492() (uintptr, uintptr) { var buf [1492]byte; use(buf[:]); return Stackguard() }
+func stack1496() (uintptr, uintptr) { var buf [1496]byte; use(buf[:]); return Stackguard() }
+func stack1500() (uintptr, uintptr) { var buf [1500]byte; use(buf[:]); return Stackguard() }
+func stack1504() (uintptr, uintptr) { var buf [1504]byte; use(buf[:]); return Stackguard() }
+func stack1508() (uintptr, uintptr) { var buf [1508]byte; use(buf[:]); return Stackguard() }
+func stack1512() (uintptr, uintptr) { var buf [1512]byte; use(buf[:]); return Stackguard() }
+func stack1516() (uintptr, uintptr) { var buf [1516]byte; use(buf[:]); return Stackguard() }
+func stack1520() (uintptr, uintptr) { var buf [1520]byte; use(buf[:]); return Stackguard() }
+func stack1524() (uintptr, uintptr) { var buf [1524]byte; use(buf[:]); return Stackguard() }
+func stack1528() (uintptr, uintptr) { var buf [1528]byte; use(buf[:]); return Stackguard() }
+func stack1532() (uintptr, uintptr) { var buf [1532]byte; use(buf[:]); return Stackguard() }
+func stack1536() (uintptr, uintptr) { var buf [1536]byte; use(buf[:]); return Stackguard() }
+func stack1540() (uintptr, uintptr) { var buf [1540]byte; use(buf[:]); return Stackguard() }
+func stack1544() (uintptr, uintptr) { var buf [1544]byte; use(buf[:]); return Stackguard() }
+func stack1548() (uintptr, uintptr) { var buf [1548]byte; use(buf[:]); return Stackguard() }
+func stack1552() (uintptr, uintptr) { var buf [1552]byte; use(buf[:]); return Stackguard() }
+func stack1556() (uintptr, uintptr) { var buf [1556]byte; use(buf[:]); return Stackguard() }
+func stack1560() (uintptr, uintptr) { var buf [1560]byte; use(buf[:]); return Stackguard() }
+func stack1564() (uintptr, uintptr) { var buf [1564]byte; use(buf[:]); return Stackguard() }
+func stack1568() (uintptr, uintptr) { var buf [1568]byte; use(buf[:]); return Stackguard() }
+func stack1572() (uintptr, uintptr) { var buf [1572]byte; use(buf[:]); return Stackguard() }
+func stack1576() (uintptr, uintptr) { var buf [1576]byte; use(buf[:]); return Stackguard() }
+func stack1580() (uintptr, uintptr) { var buf [1580]byte; use(buf[:]); return Stackguard() }
+func stack1584() (uintptr, uintptr) { var buf [1584]byte; use(buf[:]); return Stackguard() }
+func stack1588() (uintptr, uintptr) { var buf [1588]byte; use(buf[:]); return Stackguard() }
+func stack1592() (uintptr, uintptr) { var buf [1592]byte; use(buf[:]); return Stackguard() }
+func stack1596() (uintptr, uintptr) { var buf [1596]byte; use(buf[:]); return Stackguard() }
+func stack1600() (uintptr, uintptr) { var buf [1600]byte; use(buf[:]); return Stackguard() }
+func stack1604() (uintptr, uintptr) { var buf [1604]byte; use(buf[:]); return Stackguard() }
+func stack1608() (uintptr, uintptr) { var buf [1608]byte; use(buf[:]); return Stackguard() }
+func stack1612() (uintptr, uintptr) { var buf [1612]byte; use(buf[:]); return Stackguard() }
+func stack1616() (uintptr, uintptr) { var buf [1616]byte; use(buf[:]); return Stackguard() }
+func stack1620() (uintptr, uintptr) { var buf [1620]byte; use(buf[:]); return Stackguard() }
+func stack1624() (uintptr, uintptr) { var buf [1624]byte; use(buf[:]); return Stackguard() }
+func stack1628() (uintptr, uintptr) { var buf [1628]byte; use(buf[:]); return Stackguard() }
+func stack1632() (uintptr, uintptr) { var buf [1632]byte; use(buf[:]); return Stackguard() }
+func stack1636() (uintptr, uintptr) { var buf [1636]byte; use(buf[:]); return Stackguard() }
+func stack1640() (uintptr, uintptr) { var buf [1640]byte; use(buf[:]); return Stackguard() }
+func stack1644() (uintptr, uintptr) { var buf [1644]byte; use(buf[:]); return Stackguard() }
+func stack1648() (uintptr, uintptr) { var buf [1648]byte; use(buf[:]); return Stackguard() }
+func stack1652() (uintptr, uintptr) { var buf [1652]byte; use(buf[:]); return Stackguard() }
+func stack1656() (uintptr, uintptr) { var buf [1656]byte; use(buf[:]); return Stackguard() }
+func stack1660() (uintptr, uintptr) { var buf [1660]byte; use(buf[:]); return Stackguard() }
+func stack1664() (uintptr, uintptr) { var buf [1664]byte; use(buf[:]); return Stackguard() }
+func stack1668() (uintptr, uintptr) { var buf [1668]byte; use(buf[:]); return Stackguard() }
+func stack1672() (uintptr, uintptr) { var buf [1672]byte; use(buf[:]); return Stackguard() }
+func stack1676() (uintptr, uintptr) { var buf [1676]byte; use(buf[:]); return Stackguard() }
+func stack1680() (uintptr, uintptr) { var buf [1680]byte; use(buf[:]); return Stackguard() }
+func stack1684() (uintptr, uintptr) { var buf [1684]byte; use(buf[:]); return Stackguard() }
+func stack1688() (uintptr, uintptr) { var buf [1688]byte; use(buf[:]); return Stackguard() }
+func stack1692() (uintptr, uintptr) { var buf [1692]byte; use(buf[:]); return Stackguard() }
+func stack1696() (uintptr, uintptr) { var buf [1696]byte; use(buf[:]); return Stackguard() }
+func stack1700() (uintptr, uintptr) { var buf [1700]byte; use(buf[:]); return Stackguard() }
+func stack1704() (uintptr, uintptr) { var buf [1704]byte; use(buf[:]); return Stackguard() }
+func stack1708() (uintptr, uintptr) { var buf [1708]byte; use(buf[:]); return Stackguard() }
+func stack1712() (uintptr, uintptr) { var buf [1712]byte; use(buf[:]); return Stackguard() }
+func stack1716() (uintptr, uintptr) { var buf [1716]byte; use(buf[:]); return Stackguard() }
+func stack1720() (uintptr, uintptr) { var buf [1720]byte; use(buf[:]); return Stackguard() }
+func stack1724() (uintptr, uintptr) { var buf [1724]byte; use(buf[:]); return Stackguard() }
+func stack1728() (uintptr, uintptr) { var buf [1728]byte; use(buf[:]); return Stackguard() }
+func stack1732() (uintptr, uintptr) { var buf [1732]byte; use(buf[:]); return Stackguard() }
+func stack1736() (uintptr, uintptr) { var buf [1736]byte; use(buf[:]); return Stackguard() }
+func stack1740() (uintptr, uintptr) { var buf [1740]byte; use(buf[:]); return Stackguard() }
+func stack1744() (uintptr, uintptr) { var buf [1744]byte; use(buf[:]); return Stackguard() }
+func stack1748() (uintptr, uintptr) { var buf [1748]byte; use(buf[:]); return Stackguard() }
+func stack1752() (uintptr, uintptr) { var buf [1752]byte; use(buf[:]); return Stackguard() }
+func stack1756() (uintptr, uintptr) { var buf [1756]byte; use(buf[:]); return Stackguard() }
+func stack1760() (uintptr, uintptr) { var buf [1760]byte; use(buf[:]); return Stackguard() }
+func stack1764() (uintptr, uintptr) { var buf [1764]byte; use(buf[:]); return Stackguard() }
+func stack1768() (uintptr, uintptr) { var buf [1768]byte; use(buf[:]); return Stackguard() }
+func stack1772() (uintptr, uintptr) { var buf [1772]byte; use(buf[:]); return Stackguard() }
+func stack1776() (uintptr, uintptr) { var buf [1776]byte; use(buf[:]); return Stackguard() }
+func stack1780() (uintptr, uintptr) { var buf [1780]byte; use(buf[:]); return Stackguard() }
+func stack1784() (uintptr, uintptr) { var buf [1784]byte; use(buf[:]); return Stackguard() }
+func stack1788() (uintptr, uintptr) { var buf [1788]byte; use(buf[:]); return Stackguard() }
+func stack1792() (uintptr, uintptr) { var buf [1792]byte; use(buf[:]); return Stackguard() }
+func stack1796() (uintptr, uintptr) { var buf [1796]byte; use(buf[:]); return Stackguard() }
+func stack1800() (uintptr, uintptr) { var buf [1800]byte; use(buf[:]); return Stackguard() }
+func stack1804() (uintptr, uintptr) { var buf [1804]byte; use(buf[:]); return Stackguard() }
+func stack1808() (uintptr, uintptr) { var buf [1808]byte; use(buf[:]); return Stackguard() }
+func stack1812() (uintptr, uintptr) { var buf [1812]byte; use(buf[:]); return Stackguard() }
+func stack1816() (uintptr, uintptr) { var buf [1816]byte; use(buf[:]); return Stackguard() }
+func stack1820() (uintptr, uintptr) { var buf [1820]byte; use(buf[:]); return Stackguard() }
+func stack1824() (uintptr, uintptr) { var buf [1824]byte; use(buf[:]); return Stackguard() }
+func stack1828() (uintptr, uintptr) { var buf [1828]byte; use(buf[:]); return Stackguard() }
+func stack1832() (uintptr, uintptr) { var buf [1832]byte; use(buf[:]); return Stackguard() }
+func stack1836() (uintptr, uintptr) { var buf [1836]byte; use(buf[:]); return Stackguard() }
+func stack1840() (uintptr, uintptr) { var buf [1840]byte; use(buf[:]); return Stackguard() }
+func stack1844() (uintptr, uintptr) { var buf [1844]byte; use(buf[:]); return Stackguard() }
+func stack1848() (uintptr, uintptr) { var buf [1848]byte; use(buf[:]); return Stackguard() }
+func stack1852() (uintptr, uintptr) { var buf [1852]byte; use(buf[:]); return Stackguard() }
+func stack1856() (uintptr, uintptr) { var buf [1856]byte; use(buf[:]); return Stackguard() }
+func stack1860() (uintptr, uintptr) { var buf [1860]byte; use(buf[:]); return Stackguard() }
+func stack1864() (uintptr, uintptr) { var buf [1864]byte; use(buf[:]); return Stackguard() }
+func stack1868() (uintptr, uintptr) { var buf [1868]byte; use(buf[:]); return Stackguard() }
+func stack1872() (uintptr, uintptr) { var buf [1872]byte; use(buf[:]); return Stackguard() }
+func stack1876() (uintptr, uintptr) { var buf [1876]byte; use(buf[:]); return Stackguard() }
+func stack1880() (uintptr, uintptr) { var buf [1880]byte; use(buf[:]); return Stackguard() }
+func stack1884() (uintptr, uintptr) { var buf [1884]byte; use(buf[:]); return Stackguard() }
+func stack1888() (uintptr, uintptr) { var buf [1888]byte; use(buf[:]); return Stackguard() }
+func stack1892() (uintptr, uintptr) { var buf [1892]byte; use(buf[:]); return Stackguard() }
+func stack1896() (uintptr, uintptr) { var buf [1896]byte; use(buf[:]); return Stackguard() }
+func stack1900() (uintptr, uintptr) { var buf [1900]byte; use(buf[:]); return Stackguard() }
+func stack1904() (uintptr, uintptr) { var buf [1904]byte; use(buf[:]); return Stackguard() }
+func stack1908() (uintptr, uintptr) { var buf [1908]byte; use(buf[:]); return Stackguard() }
+func stack1912() (uintptr, uintptr) { var buf [1912]byte; use(buf[:]); return Stackguard() }
+func stack1916() (uintptr, uintptr) { var buf [1916]byte; use(buf[:]); return Stackguard() }
+func stack1920() (uintptr, uintptr) { var buf [1920]byte; use(buf[:]); return Stackguard() }
+func stack1924() (uintptr, uintptr) { var buf [1924]byte; use(buf[:]); return Stackguard() }
+func stack1928() (uintptr, uintptr) { var buf [1928]byte; use(buf[:]); return Stackguard() }
+func stack1932() (uintptr, uintptr) { var buf [1932]byte; use(buf[:]); return Stackguard() }
+func stack1936() (uintptr, uintptr) { var buf [1936]byte; use(buf[:]); return Stackguard() }
+func stack1940() (uintptr, uintptr) { var buf [1940]byte; use(buf[:]); return Stackguard() }
+func stack1944() (uintptr, uintptr) { var buf [1944]byte; use(buf[:]); return Stackguard() }
+func stack1948() (uintptr, uintptr) { var buf [1948]byte; use(buf[:]); return Stackguard() }
+func stack1952() (uintptr, uintptr) { var buf [1952]byte; use(buf[:]); return Stackguard() }
+func stack1956() (uintptr, uintptr) { var buf [1956]byte; use(buf[:]); return Stackguard() }
+func stack1960() (uintptr, uintptr) { var buf [1960]byte; use(buf[:]); return Stackguard() }
+func stack1964() (uintptr, uintptr) { var buf [1964]byte; use(buf[:]); return Stackguard() }
+func stack1968() (uintptr, uintptr) { var buf [1968]byte; use(buf[:]); return Stackguard() }
+func stack1972() (uintptr, uintptr) { var buf [1972]byte; use(buf[:]); return Stackguard() }
+func stack1976() (uintptr, uintptr) { var buf [1976]byte; use(buf[:]); return Stackguard() }
+func stack1980() (uintptr, uintptr) { var buf [1980]byte; use(buf[:]); return Stackguard() }
+func stack1984() (uintptr, uintptr) { var buf [1984]byte; use(buf[:]); return Stackguard() }
+func stack1988() (uintptr, uintptr) { var buf [1988]byte; use(buf[:]); return Stackguard() }
+func stack1992() (uintptr, uintptr) { var buf [1992]byte; use(buf[:]); return Stackguard() }
+func stack1996() (uintptr, uintptr) { var buf [1996]byte; use(buf[:]); return Stackguard() }
+func stack2000() (uintptr, uintptr) { var buf [2000]byte; use(buf[:]); return Stackguard() }
+func stack2004() (uintptr, uintptr) { var buf [2004]byte; use(buf[:]); return Stackguard() }
+func stack2008() (uintptr, uintptr) { var buf [2008]byte; use(buf[:]); return Stackguard() }
+func stack2012() (uintptr, uintptr) { var buf [2012]byte; use(buf[:]); return Stackguard() }
+func stack2016() (uintptr, uintptr) { var buf [2016]byte; use(buf[:]); return Stackguard() }
+func stack2020() (uintptr, uintptr) { var buf [2020]byte; use(buf[:]); return Stackguard() }
+func stack2024() (uintptr, uintptr) { var buf [2024]byte; use(buf[:]); return Stackguard() }
+func stack2028() (uintptr, uintptr) { var buf [2028]byte; use(buf[:]); return Stackguard() }
+func stack2032() (uintptr, uintptr) { var buf [2032]byte; use(buf[:]); return Stackguard() }
+func stack2036() (uintptr, uintptr) { var buf [2036]byte; use(buf[:]); return Stackguard() }
+func stack2040() (uintptr, uintptr) { var buf [2040]byte; use(buf[:]); return Stackguard() }
+func stack2044() (uintptr, uintptr) { var buf [2044]byte; use(buf[:]); return Stackguard() }
+func stack2048() (uintptr, uintptr) { var buf [2048]byte; use(buf[:]); return Stackguard() }
+func stack2052() (uintptr, uintptr) { var buf [2052]byte; use(buf[:]); return Stackguard() }
+func stack2056() (uintptr, uintptr) { var buf [2056]byte; use(buf[:]); return Stackguard() }
+func stack2060() (uintptr, uintptr) { var buf [2060]byte; use(buf[:]); return Stackguard() }
+func stack2064() (uintptr, uintptr) { var buf [2064]byte; use(buf[:]); return Stackguard() }
+func stack2068() (uintptr, uintptr) { var buf [2068]byte; use(buf[:]); return Stackguard() }
+func stack2072() (uintptr, uintptr) { var buf [2072]byte; use(buf[:]); return Stackguard() }
+func stack2076() (uintptr, uintptr) { var buf [2076]byte; use(buf[:]); return Stackguard() }
+func stack2080() (uintptr, uintptr) { var buf [2080]byte; use(buf[:]); return Stackguard() }
+func stack2084() (uintptr, uintptr) { var buf [2084]byte; use(buf[:]); return Stackguard() }
+func stack2088() (uintptr, uintptr) { var buf [2088]byte; use(buf[:]); return Stackguard() }
+func stack2092() (uintptr, uintptr) { var buf [2092]byte; use(buf[:]); return Stackguard() }
+func stack2096() (uintptr, uintptr) { var buf [2096]byte; use(buf[:]); return Stackguard() }
+func stack2100() (uintptr, uintptr) { var buf [2100]byte; use(buf[:]); return Stackguard() }
+func stack2104() (uintptr, uintptr) { var buf [2104]byte; use(buf[:]); return Stackguard() }
+func stack2108() (uintptr, uintptr) { var buf [2108]byte; use(buf[:]); return Stackguard() }
+func stack2112() (uintptr, uintptr) { var buf [2112]byte; use(buf[:]); return Stackguard() }
+func stack2116() (uintptr, uintptr) { var buf [2116]byte; use(buf[:]); return Stackguard() }
+func stack2120() (uintptr, uintptr) { var buf [2120]byte; use(buf[:]); return Stackguard() }
+func stack2124() (uintptr, uintptr) { var buf [2124]byte; use(buf[:]); return Stackguard() }
+func stack2128() (uintptr, uintptr) { var buf [2128]byte; use(buf[:]); return Stackguard() }
+func stack2132() (uintptr, uintptr) { var buf [2132]byte; use(buf[:]); return Stackguard() }
+func stack2136() (uintptr, uintptr) { var buf [2136]byte; use(buf[:]); return Stackguard() }
+func stack2140() (uintptr, uintptr) { var buf [2140]byte; use(buf[:]); return Stackguard() }
+func stack2144() (uintptr, uintptr) { var buf [2144]byte; use(buf[:]); return Stackguard() }
+func stack2148() (uintptr, uintptr) { var buf [2148]byte; use(buf[:]); return Stackguard() }
+func stack2152() (uintptr, uintptr) { var buf [2152]byte; use(buf[:]); return Stackguard() }
+func stack2156() (uintptr, uintptr) { var buf [2156]byte; use(buf[:]); return Stackguard() }
+func stack2160() (uintptr, uintptr) { var buf [2160]byte; use(buf[:]); return Stackguard() }
+func stack2164() (uintptr, uintptr) { var buf [2164]byte; use(buf[:]); return Stackguard() }
+func stack2168() (uintptr, uintptr) { var buf [2168]byte; use(buf[:]); return Stackguard() }
+func stack2172() (uintptr, uintptr) { var buf [2172]byte; use(buf[:]); return Stackguard() }
+func stack2176() (uintptr, uintptr) { var buf [2176]byte; use(buf[:]); return Stackguard() }
+func stack2180() (uintptr, uintptr) { var buf [2180]byte; use(buf[:]); return Stackguard() }
+func stack2184() (uintptr, uintptr) { var buf [2184]byte; use(buf[:]); return Stackguard() }
+func stack2188() (uintptr, uintptr) { var buf [2188]byte; use(buf[:]); return Stackguard() }
+func stack2192() (uintptr, uintptr) { var buf [2192]byte; use(buf[:]); return Stackguard() }
+func stack2196() (uintptr, uintptr) { var buf [2196]byte; use(buf[:]); return Stackguard() }
+func stack2200() (uintptr, uintptr) { var buf [2200]byte; use(buf[:]); return Stackguard() }
+func stack2204() (uintptr, uintptr) { var buf [2204]byte; use(buf[:]); return Stackguard() }
+func stack2208() (uintptr, uintptr) { var buf [2208]byte; use(buf[:]); return Stackguard() }
+func stack2212() (uintptr, uintptr) { var buf [2212]byte; use(buf[:]); return Stackguard() }
+func stack2216() (uintptr, uintptr) { var buf [2216]byte; use(buf[:]); return Stackguard() }
+func stack2220() (uintptr, uintptr) { var buf [2220]byte; use(buf[:]); return Stackguard() }
+func stack2224() (uintptr, uintptr) { var buf [2224]byte; use(buf[:]); return Stackguard() }
+func stack2228() (uintptr, uintptr) { var buf [2228]byte; use(buf[:]); return Stackguard() }
+func stack2232() (uintptr, uintptr) { var buf [2232]byte; use(buf[:]); return Stackguard() }
+func stack2236() (uintptr, uintptr) { var buf [2236]byte; use(buf[:]); return Stackguard() }
+func stack2240() (uintptr, uintptr) { var buf [2240]byte; use(buf[:]); return Stackguard() }
+func stack2244() (uintptr, uintptr) { var buf [2244]byte; use(buf[:]); return Stackguard() }
+func stack2248() (uintptr, uintptr) { var buf [2248]byte; use(buf[:]); return Stackguard() }
+func stack2252() (uintptr, uintptr) { var buf [2252]byte; use(buf[:]); return Stackguard() }
+func stack2256() (uintptr, uintptr) { var buf [2256]byte; use(buf[:]); return Stackguard() }
+func stack2260() (uintptr, uintptr) { var buf [2260]byte; use(buf[:]); return Stackguard() }
+func stack2264() (uintptr, uintptr) { var buf [2264]byte; use(buf[:]); return Stackguard() }
+func stack2268() (uintptr, uintptr) { var buf [2268]byte; use(buf[:]); return Stackguard() }
+func stack2272() (uintptr, uintptr) { var buf [2272]byte; use(buf[:]); return Stackguard() }
+func stack2276() (uintptr, uintptr) { var buf [2276]byte; use(buf[:]); return Stackguard() }
+func stack2280() (uintptr, uintptr) { var buf [2280]byte; use(buf[:]); return Stackguard() }
+func stack2284() (uintptr, uintptr) { var buf [2284]byte; use(buf[:]); return Stackguard() }
+func stack2288() (uintptr, uintptr) { var buf [2288]byte; use(buf[:]); return Stackguard() }
+func stack2292() (uintptr, uintptr) { var buf [2292]byte; use(buf[:]); return Stackguard() }
+func stack2296() (uintptr, uintptr) { var buf [2296]byte; use(buf[:]); return Stackguard() }
+func stack2300() (uintptr, uintptr) { var buf [2300]byte; use(buf[:]); return Stackguard() }
+func stack2304() (uintptr, uintptr) { var buf [2304]byte; use(buf[:]); return Stackguard() }
+func stack2308() (uintptr, uintptr) { var buf [2308]byte; use(buf[:]); return Stackguard() }
+func stack2312() (uintptr, uintptr) { var buf [2312]byte; use(buf[:]); return Stackguard() }
+func stack2316() (uintptr, uintptr) { var buf [2316]byte; use(buf[:]); return Stackguard() }
+func stack2320() (uintptr, uintptr) { var buf [2320]byte; use(buf[:]); return Stackguard() }
+func stack2324() (uintptr, uintptr) { var buf [2324]byte; use(buf[:]); return Stackguard() }
+func stack2328() (uintptr, uintptr) { var buf [2328]byte; use(buf[:]); return Stackguard() }
+func stack2332() (uintptr, uintptr) { var buf [2332]byte; use(buf[:]); return Stackguard() }
+func stack2336() (uintptr, uintptr) { var buf [2336]byte; use(buf[:]); return Stackguard() }
+func stack2340() (uintptr, uintptr) { var buf [2340]byte; use(buf[:]); return Stackguard() }
+func stack2344() (uintptr, uintptr) { var buf [2344]byte; use(buf[:]); return Stackguard() }
+func stack2348() (uintptr, uintptr) { var buf [2348]byte; use(buf[:]); return Stackguard() }
+func stack2352() (uintptr, uintptr) { var buf [2352]byte; use(buf[:]); return Stackguard() }
+func stack2356() (uintptr, uintptr) { var buf [2356]byte; use(buf[:]); return Stackguard() }
+func stack2360() (uintptr, uintptr) { var buf [2360]byte; use(buf[:]); return Stackguard() }
+func stack2364() (uintptr, uintptr) { var buf [2364]byte; use(buf[:]); return Stackguard() }
+func stack2368() (uintptr, uintptr) { var buf [2368]byte; use(buf[:]); return Stackguard() }
+func stack2372() (uintptr, uintptr) { var buf [2372]byte; use(buf[:]); return Stackguard() }
+func stack2376() (uintptr, uintptr) { var buf [2376]byte; use(buf[:]); return Stackguard() }
+func stack2380() (uintptr, uintptr) { var buf [2380]byte; use(buf[:]); return Stackguard() }
+func stack2384() (uintptr, uintptr) { var buf [2384]byte; use(buf[:]); return Stackguard() }
+func stack2388() (uintptr, uintptr) { var buf [2388]byte; use(buf[:]); return Stackguard() }
+func stack2392() (uintptr, uintptr) { var buf [2392]byte; use(buf[:]); return Stackguard() }
+func stack2396() (uintptr, uintptr) { var buf [2396]byte; use(buf[:]); return Stackguard() }
+func stack2400() (uintptr, uintptr) { var buf [2400]byte; use(buf[:]); return Stackguard() }
+func stack2404() (uintptr, uintptr) { var buf [2404]byte; use(buf[:]); return Stackguard() }
+func stack2408() (uintptr, uintptr) { var buf [2408]byte; use(buf[:]); return Stackguard() }
+func stack2412() (uintptr, uintptr) { var buf [2412]byte; use(buf[:]); return Stackguard() }
+func stack2416() (uintptr, uintptr) { var buf [2416]byte; use(buf[:]); return Stackguard() }
+func stack2420() (uintptr, uintptr) { var buf [2420]byte; use(buf[:]); return Stackguard() }
+func stack2424() (uintptr, uintptr) { var buf [2424]byte; use(buf[:]); return Stackguard() }
+func stack2428() (uintptr, uintptr) { var buf [2428]byte; use(buf[:]); return Stackguard() }
+func stack2432() (uintptr, uintptr) { var buf [2432]byte; use(buf[:]); return Stackguard() }
+func stack2436() (uintptr, uintptr) { var buf [2436]byte; use(buf[:]); return Stackguard() }
+func stack2440() (uintptr, uintptr) { var buf [2440]byte; use(buf[:]); return Stackguard() }
+func stack2444() (uintptr, uintptr) { var buf [2444]byte; use(buf[:]); return Stackguard() }
+func stack2448() (uintptr, uintptr) { var buf [2448]byte; use(buf[:]); return Stackguard() }
+func stack2452() (uintptr, uintptr) { var buf [2452]byte; use(buf[:]); return Stackguard() }
+func stack2456() (uintptr, uintptr) { var buf [2456]byte; use(buf[:]); return Stackguard() }
+func stack2460() (uintptr, uintptr) { var buf [2460]byte; use(buf[:]); return Stackguard() }
+func stack2464() (uintptr, uintptr) { var buf [2464]byte; use(buf[:]); return Stackguard() }
+func stack2468() (uintptr, uintptr) { var buf [2468]byte; use(buf[:]); return Stackguard() }
+func stack2472() (uintptr, uintptr) { var buf [2472]byte; use(buf[:]); return Stackguard() }
+func stack2476() (uintptr, uintptr) { var buf [2476]byte; use(buf[:]); return Stackguard() }
+func stack2480() (uintptr, uintptr) { var buf [2480]byte; use(buf[:]); return Stackguard() }
+func stack2484() (uintptr, uintptr) { var buf [2484]byte; use(buf[:]); return Stackguard() }
+func stack2488() (uintptr, uintptr) { var buf [2488]byte; use(buf[:]); return Stackguard() }
+func stack2492() (uintptr, uintptr) { var buf [2492]byte; use(buf[:]); return Stackguard() }
+func stack2496() (uintptr, uintptr) { var buf [2496]byte; use(buf[:]); return Stackguard() }
+func stack2500() (uintptr, uintptr) { var buf [2500]byte; use(buf[:]); return Stackguard() }
+func stack2504() (uintptr, uintptr) { var buf [2504]byte; use(buf[:]); return Stackguard() }
+func stack2508() (uintptr, uintptr) { var buf [2508]byte; use(buf[:]); return Stackguard() }
+func stack2512() (uintptr, uintptr) { var buf [2512]byte; use(buf[:]); return Stackguard() }
+func stack2516() (uintptr, uintptr) { var buf [2516]byte; use(buf[:]); return Stackguard() }
+func stack2520() (uintptr, uintptr) { var buf [2520]byte; use(buf[:]); return Stackguard() }
+func stack2524() (uintptr, uintptr) { var buf [2524]byte; use(buf[:]); return Stackguard() }
+func stack2528() (uintptr, uintptr) { var buf [2528]byte; use(buf[:]); return Stackguard() }
+func stack2532() (uintptr, uintptr) { var buf [2532]byte; use(buf[:]); return Stackguard() }
+func stack2536() (uintptr, uintptr) { var buf [2536]byte; use(buf[:]); return Stackguard() }
+func stack2540() (uintptr, uintptr) { var buf [2540]byte; use(buf[:]); return Stackguard() }
+func stack2544() (uintptr, uintptr) { var buf [2544]byte; use(buf[:]); return Stackguard() }
+func stack2548() (uintptr, uintptr) { var buf [2548]byte; use(buf[:]); return Stackguard() }
+func stack2552() (uintptr, uintptr) { var buf [2552]byte; use(buf[:]); return Stackguard() }
+func stack2556() (uintptr, uintptr) { var buf [2556]byte; use(buf[:]); return Stackguard() }
+func stack2560() (uintptr, uintptr) { var buf [2560]byte; use(buf[:]); return Stackguard() }
+func stack2564() (uintptr, uintptr) { var buf [2564]byte; use(buf[:]); return Stackguard() }
+func stack2568() (uintptr, uintptr) { var buf [2568]byte; use(buf[:]); return Stackguard() }
+func stack2572() (uintptr, uintptr) { var buf [2572]byte; use(buf[:]); return Stackguard() }
+func stack2576() (uintptr, uintptr) { var buf [2576]byte; use(buf[:]); return Stackguard() }
+func stack2580() (uintptr, uintptr) { var buf [2580]byte; use(buf[:]); return Stackguard() }
+func stack2584() (uintptr, uintptr) { var buf [2584]byte; use(buf[:]); return Stackguard() }
+func stack2588() (uintptr, uintptr) { var buf [2588]byte; use(buf[:]); return Stackguard() }
+func stack2592() (uintptr, uintptr) { var buf [2592]byte; use(buf[:]); return Stackguard() }
+func stack2596() (uintptr, uintptr) { var buf [2596]byte; use(buf[:]); return Stackguard() }
+func stack2600() (uintptr, uintptr) { var buf [2600]byte; use(buf[:]); return Stackguard() }
+func stack2604() (uintptr, uintptr) { var buf [2604]byte; use(buf[:]); return Stackguard() }
+func stack2608() (uintptr, uintptr) { var buf [2608]byte; use(buf[:]); return Stackguard() }
+func stack2612() (uintptr, uintptr) { var buf [2612]byte; use(buf[:]); return Stackguard() }
+func stack2616() (uintptr, uintptr) { var buf [2616]byte; use(buf[:]); return Stackguard() }
+func stack2620() (uintptr, uintptr) { var buf [2620]byte; use(buf[:]); return Stackguard() }
+func stack2624() (uintptr, uintptr) { var buf [2624]byte; use(buf[:]); return Stackguard() }
+func stack2628() (uintptr, uintptr) { var buf [2628]byte; use(buf[:]); return Stackguard() }
+func stack2632() (uintptr, uintptr) { var buf [2632]byte; use(buf[:]); return Stackguard() }
+func stack2636() (uintptr, uintptr) { var buf [2636]byte; use(buf[:]); return Stackguard() }
+func stack2640() (uintptr, uintptr) { var buf [2640]byte; use(buf[:]); return Stackguard() }
+func stack2644() (uintptr, uintptr) { var buf [2644]byte; use(buf[:]); return Stackguard() }
+func stack2648() (uintptr, uintptr) { var buf [2648]byte; use(buf[:]); return Stackguard() }
+func stack2652() (uintptr, uintptr) { var buf [2652]byte; use(buf[:]); return Stackguard() }
+func stack2656() (uintptr, uintptr) { var buf [2656]byte; use(buf[:]); return Stackguard() }
+func stack2660() (uintptr, uintptr) { var buf [2660]byte; use(buf[:]); return Stackguard() }
+func stack2664() (uintptr, uintptr) { var buf [2664]byte; use(buf[:]); return Stackguard() }
+func stack2668() (uintptr, uintptr) { var buf [2668]byte; use(buf[:]); return Stackguard() }
+func stack2672() (uintptr, uintptr) { var buf [2672]byte; use(buf[:]); return Stackguard() }
+func stack2676() (uintptr, uintptr) { var buf [2676]byte; use(buf[:]); return Stackguard() }
+func stack2680() (uintptr, uintptr) { var buf [2680]byte; use(buf[:]); return Stackguard() }
+func stack2684() (uintptr, uintptr) { var buf [2684]byte; use(buf[:]); return Stackguard() }
+func stack2688() (uintptr, uintptr) { var buf [2688]byte; use(buf[:]); return Stackguard() }
+func stack2692() (uintptr, uintptr) { var buf [2692]byte; use(buf[:]); return Stackguard() }
+func stack2696() (uintptr, uintptr) { var buf [2696]byte; use(buf[:]); return Stackguard() }
+func stack2700() (uintptr, uintptr) { var buf [2700]byte; use(buf[:]); return Stackguard() }
+func stack2704() (uintptr, uintptr) { var buf [2704]byte; use(buf[:]); return Stackguard() }
+func stack2708() (uintptr, uintptr) { var buf [2708]byte; use(buf[:]); return Stackguard() }
+func stack2712() (uintptr, uintptr) { var buf [2712]byte; use(buf[:]); return Stackguard() }
+func stack2716() (uintptr, uintptr) { var buf [2716]byte; use(buf[:]); return Stackguard() }
+func stack2720() (uintptr, uintptr) { var buf [2720]byte; use(buf[:]); return Stackguard() }
+func stack2724() (uintptr, uintptr) { var buf [2724]byte; use(buf[:]); return Stackguard() }
+func stack2728() (uintptr, uintptr) { var buf [2728]byte; use(buf[:]); return Stackguard() }
+func stack2732() (uintptr, uintptr) { var buf [2732]byte; use(buf[:]); return Stackguard() }
+func stack2736() (uintptr, uintptr) { var buf [2736]byte; use(buf[:]); return Stackguard() }
+func stack2740() (uintptr, uintptr) { var buf [2740]byte; use(buf[:]); return Stackguard() }
+func stack2744() (uintptr, uintptr) { var buf [2744]byte; use(buf[:]); return Stackguard() }
+func stack2748() (uintptr, uintptr) { var buf [2748]byte; use(buf[:]); return Stackguard() }
+func stack2752() (uintptr, uintptr) { var buf [2752]byte; use(buf[:]); return Stackguard() }
+func stack2756() (uintptr, uintptr) { var buf [2756]byte; use(buf[:]); return Stackguard() }
+func stack2760() (uintptr, uintptr) { var buf [2760]byte; use(buf[:]); return Stackguard() }
+func stack2764() (uintptr, uintptr) { var buf [2764]byte; use(buf[:]); return Stackguard() }
+func stack2768() (uintptr, uintptr) { var buf [2768]byte; use(buf[:]); return Stackguard() }
+func stack2772() (uintptr, uintptr) { var buf [2772]byte; use(buf[:]); return Stackguard() }
+func stack2776() (uintptr, uintptr) { var buf [2776]byte; use(buf[:]); return Stackguard() }
+func stack2780() (uintptr, uintptr) { var buf [2780]byte; use(buf[:]); return Stackguard() }
+func stack2784() (uintptr, uintptr) { var buf [2784]byte; use(buf[:]); return Stackguard() }
+func stack2788() (uintptr, uintptr) { var buf [2788]byte; use(buf[:]); return Stackguard() }
+func stack2792() (uintptr, uintptr) { var buf [2792]byte; use(buf[:]); return Stackguard() }
+func stack2796() (uintptr, uintptr) { var buf [2796]byte; use(buf[:]); return Stackguard() }
+func stack2800() (uintptr, uintptr) { var buf [2800]byte; use(buf[:]); return Stackguard() }
+func stack2804() (uintptr, uintptr) { var buf [2804]byte; use(buf[:]); return Stackguard() }
+func stack2808() (uintptr, uintptr) { var buf [2808]byte; use(buf[:]); return Stackguard() }
+func stack2812() (uintptr, uintptr) { var buf [2812]byte; use(buf[:]); return Stackguard() }
+func stack2816() (uintptr, uintptr) { var buf [2816]byte; use(buf[:]); return Stackguard() }
+func stack2820() (uintptr, uintptr) { var buf [2820]byte; use(buf[:]); return Stackguard() }
+func stack2824() (uintptr, uintptr) { var buf [2824]byte; use(buf[:]); return Stackguard() }
+func stack2828() (uintptr, uintptr) { var buf [2828]byte; use(buf[:]); return Stackguard() }
+func stack2832() (uintptr, uintptr) { var buf [2832]byte; use(buf[:]); return Stackguard() }
+func stack2836() (uintptr, uintptr) { var buf [2836]byte; use(buf[:]); return Stackguard() }
+func stack2840() (uintptr, uintptr) { var buf [2840]byte; use(buf[:]); return Stackguard() }
+func stack2844() (uintptr, uintptr) { var buf [2844]byte; use(buf[:]); return Stackguard() }
+func stack2848() (uintptr, uintptr) { var buf [2848]byte; use(buf[:]); return Stackguard() }
+func stack2852() (uintptr, uintptr) { var buf [2852]byte; use(buf[:]); return Stackguard() }
+func stack2856() (uintptr, uintptr) { var buf [2856]byte; use(buf[:]); return Stackguard() }
+func stack2860() (uintptr, uintptr) { var buf [2860]byte; use(buf[:]); return Stackguard() }
+func stack2864() (uintptr, uintptr) { var buf [2864]byte; use(buf[:]); return Stackguard() }
+func stack2868() (uintptr, uintptr) { var buf [2868]byte; use(buf[:]); return Stackguard() }
+func stack2872() (uintptr, uintptr) { var buf [2872]byte; use(buf[:]); return Stackguard() }
+func stack2876() (uintptr, uintptr) { var buf [2876]byte; use(buf[:]); return Stackguard() }
+func stack2880() (uintptr, uintptr) { var buf [2880]byte; use(buf[:]); return Stackguard() }
+func stack2884() (uintptr, uintptr) { var buf [2884]byte; use(buf[:]); return Stackguard() }
+func stack2888() (uintptr, uintptr) { var buf [2888]byte; use(buf[:]); return Stackguard() }
+func stack2892() (uintptr, uintptr) { var buf [2892]byte; use(buf[:]); return Stackguard() }
+func stack2896() (uintptr, uintptr) { var buf [2896]byte; use(buf[:]); return Stackguard() }
+func stack2900() (uintptr, uintptr) { var buf [2900]byte; use(buf[:]); return Stackguard() }
+func stack2904() (uintptr, uintptr) { var buf [2904]byte; use(buf[:]); return Stackguard() }
+func stack2908() (uintptr, uintptr) { var buf [2908]byte; use(buf[:]); return Stackguard() }
+func stack2912() (uintptr, uintptr) { var buf [2912]byte; use(buf[:]); return Stackguard() }
+func stack2916() (uintptr, uintptr) { var buf [2916]byte; use(buf[:]); return Stackguard() }
+func stack2920() (uintptr, uintptr) { var buf [2920]byte; use(buf[:]); return Stackguard() }
+func stack2924() (uintptr, uintptr) { var buf [2924]byte; use(buf[:]); return Stackguard() }
+func stack2928() (uintptr, uintptr) { var buf [2928]byte; use(buf[:]); return Stackguard() }
+func stack2932() (uintptr, uintptr) { var buf [2932]byte; use(buf[:]); return Stackguard() }
+func stack2936() (uintptr, uintptr) { var buf [2936]byte; use(buf[:]); return Stackguard() }
+func stack2940() (uintptr, uintptr) { var buf [2940]byte; use(buf[:]); return Stackguard() }
+func stack2944() (uintptr, uintptr) { var buf [2944]byte; use(buf[:]); return Stackguard() }
+func stack2948() (uintptr, uintptr) { var buf [2948]byte; use(buf[:]); return Stackguard() }
+func stack2952() (uintptr, uintptr) { var buf [2952]byte; use(buf[:]); return Stackguard() }
+func stack2956() (uintptr, uintptr) { var buf [2956]byte; use(buf[:]); return Stackguard() }
+func stack2960() (uintptr, uintptr) { var buf [2960]byte; use(buf[:]); return Stackguard() }
+func stack2964() (uintptr, uintptr) { var buf [2964]byte; use(buf[:]); return Stackguard() }
+func stack2968() (uintptr, uintptr) { var buf [2968]byte; use(buf[:]); return Stackguard() }
+func stack2972() (uintptr, uintptr) { var buf [2972]byte; use(buf[:]); return Stackguard() }
+func stack2976() (uintptr, uintptr) { var buf [2976]byte; use(buf[:]); return Stackguard() }
+func stack2980() (uintptr, uintptr) { var buf [2980]byte; use(buf[:]); return Stackguard() }
+func stack2984() (uintptr, uintptr) { var buf [2984]byte; use(buf[:]); return Stackguard() }
+func stack2988() (uintptr, uintptr) { var buf [2988]byte; use(buf[:]); return Stackguard() }
+func stack2992() (uintptr, uintptr) { var buf [2992]byte; use(buf[:]); return Stackguard() }
+func stack2996() (uintptr, uintptr) { var buf [2996]byte; use(buf[:]); return Stackguard() }
+func stack3000() (uintptr, uintptr) { var buf [3000]byte; use(buf[:]); return Stackguard() }
+func stack3004() (uintptr, uintptr) { var buf [3004]byte; use(buf[:]); return Stackguard() }
+func stack3008() (uintptr, uintptr) { var buf [3008]byte; use(buf[:]); return Stackguard() }
+func stack3012() (uintptr, uintptr) { var buf [3012]byte; use(buf[:]); return Stackguard() }
+func stack3016() (uintptr, uintptr) { var buf [3016]byte; use(buf[:]); return Stackguard() }
+func stack3020() (uintptr, uintptr) { var buf [3020]byte; use(buf[:]); return Stackguard() }
+func stack3024() (uintptr, uintptr) { var buf [3024]byte; use(buf[:]); return Stackguard() }
+func stack3028() (uintptr, uintptr) { var buf [3028]byte; use(buf[:]); return Stackguard() }
+func stack3032() (uintptr, uintptr) { var buf [3032]byte; use(buf[:]); return Stackguard() }
+func stack3036() (uintptr, uintptr) { var buf [3036]byte; use(buf[:]); return Stackguard() }
+func stack3040() (uintptr, uintptr) { var buf [3040]byte; use(buf[:]); return Stackguard() }
+func stack3044() (uintptr, uintptr) { var buf [3044]byte; use(buf[:]); return Stackguard() }
+func stack3048() (uintptr, uintptr) { var buf [3048]byte; use(buf[:]); return Stackguard() }
+func stack3052() (uintptr, uintptr) { var buf [3052]byte; use(buf[:]); return Stackguard() }
+func stack3056() (uintptr, uintptr) { var buf [3056]byte; use(buf[:]); return Stackguard() }
+func stack3060() (uintptr, uintptr) { var buf [3060]byte; use(buf[:]); return Stackguard() }
+func stack3064() (uintptr, uintptr) { var buf [3064]byte; use(buf[:]); return Stackguard() }
+func stack3068() (uintptr, uintptr) { var buf [3068]byte; use(buf[:]); return Stackguard() }
+func stack3072() (uintptr, uintptr) { var buf [3072]byte; use(buf[:]); return Stackguard() }
+func stack3076() (uintptr, uintptr) { var buf [3076]byte; use(buf[:]); return Stackguard() }
+func stack3080() (uintptr, uintptr) { var buf [3080]byte; use(buf[:]); return Stackguard() }
+func stack3084() (uintptr, uintptr) { var buf [3084]byte; use(buf[:]); return Stackguard() }
+func stack3088() (uintptr, uintptr) { var buf [3088]byte; use(buf[:]); return Stackguard() }
+func stack3092() (uintptr, uintptr) { var buf [3092]byte; use(buf[:]); return Stackguard() }
+func stack3096() (uintptr, uintptr) { var buf [3096]byte; use(buf[:]); return Stackguard() }
+func stack3100() (uintptr, uintptr) { var buf [3100]byte; use(buf[:]); return Stackguard() }
+func stack3104() (uintptr, uintptr) { var buf [3104]byte; use(buf[:]); return Stackguard() }
+func stack3108() (uintptr, uintptr) { var buf [3108]byte; use(buf[:]); return Stackguard() }
+func stack3112() (uintptr, uintptr) { var buf [3112]byte; use(buf[:]); return Stackguard() }
+func stack3116() (uintptr, uintptr) { var buf [3116]byte; use(buf[:]); return Stackguard() }
+func stack3120() (uintptr, uintptr) { var buf [3120]byte; use(buf[:]); return Stackguard() }
+func stack3124() (uintptr, uintptr) { var buf [3124]byte; use(buf[:]); return Stackguard() }
+func stack3128() (uintptr, uintptr) { var buf [3128]byte; use(buf[:]); return Stackguard() }
+func stack3132() (uintptr, uintptr) { var buf [3132]byte; use(buf[:]); return Stackguard() }
+func stack3136() (uintptr, uintptr) { var buf [3136]byte; use(buf[:]); return Stackguard() }
+func stack3140() (uintptr, uintptr) { var buf [3140]byte; use(buf[:]); return Stackguard() }
+func stack3144() (uintptr, uintptr) { var buf [3144]byte; use(buf[:]); return Stackguard() }
+func stack3148() (uintptr, uintptr) { var buf [3148]byte; use(buf[:]); return Stackguard() }
+func stack3152() (uintptr, uintptr) { var buf [3152]byte; use(buf[:]); return Stackguard() }
+func stack3156() (uintptr, uintptr) { var buf [3156]byte; use(buf[:]); return Stackguard() }
+func stack3160() (uintptr, uintptr) { var buf [3160]byte; use(buf[:]); return Stackguard() }
+func stack3164() (uintptr, uintptr) { var buf [3164]byte; use(buf[:]); return Stackguard() }
+func stack3168() (uintptr, uintptr) { var buf [3168]byte; use(buf[:]); return Stackguard() }
+func stack3172() (uintptr, uintptr) { var buf [3172]byte; use(buf[:]); return Stackguard() }
+func stack3176() (uintptr, uintptr) { var buf [3176]byte; use(buf[:]); return Stackguard() }
+func stack3180() (uintptr, uintptr) { var buf [3180]byte; use(buf[:]); return Stackguard() }
+func stack3184() (uintptr, uintptr) { var buf [3184]byte; use(buf[:]); return Stackguard() }
+func stack3188() (uintptr, uintptr) { var buf [3188]byte; use(buf[:]); return Stackguard() }
+func stack3192() (uintptr, uintptr) { var buf [3192]byte; use(buf[:]); return Stackguard() }
+func stack3196() (uintptr, uintptr) { var buf [3196]byte; use(buf[:]); return Stackguard() }
+func stack3200() (uintptr, uintptr) { var buf [3200]byte; use(buf[:]); return Stackguard() }
+func stack3204() (uintptr, uintptr) { var buf [3204]byte; use(buf[:]); return Stackguard() }
+func stack3208() (uintptr, uintptr) { var buf [3208]byte; use(buf[:]); return Stackguard() }
+func stack3212() (uintptr, uintptr) { var buf [3212]byte; use(buf[:]); return Stackguard() }
+func stack3216() (uintptr, uintptr) { var buf [3216]byte; use(buf[:]); return Stackguard() }
+func stack3220() (uintptr, uintptr) { var buf [3220]byte; use(buf[:]); return Stackguard() }
+func stack3224() (uintptr, uintptr) { var buf [3224]byte; use(buf[:]); return Stackguard() }
+func stack3228() (uintptr, uintptr) { var buf [3228]byte; use(buf[:]); return Stackguard() }
+func stack3232() (uintptr, uintptr) { var buf [3232]byte; use(buf[:]); return Stackguard() }
+func stack3236() (uintptr, uintptr) { var buf [3236]byte; use(buf[:]); return Stackguard() }
+func stack3240() (uintptr, uintptr) { var buf [3240]byte; use(buf[:]); return Stackguard() }
+func stack3244() (uintptr, uintptr) { var buf [3244]byte; use(buf[:]); return Stackguard() }
+func stack3248() (uintptr, uintptr) { var buf [3248]byte; use(buf[:]); return Stackguard() }
+func stack3252() (uintptr, uintptr) { var buf [3252]byte; use(buf[:]); return Stackguard() }
+func stack3256() (uintptr, uintptr) { var buf [3256]byte; use(buf[:]); return Stackguard() }
+func stack3260() (uintptr, uintptr) { var buf [3260]byte; use(buf[:]); return Stackguard() }
+func stack3264() (uintptr, uintptr) { var buf [3264]byte; use(buf[:]); return Stackguard() }
+func stack3268() (uintptr, uintptr) { var buf [3268]byte; use(buf[:]); return Stackguard() }
+func stack3272() (uintptr, uintptr) { var buf [3272]byte; use(buf[:]); return Stackguard() }
+func stack3276() (uintptr, uintptr) { var buf [3276]byte; use(buf[:]); return Stackguard() }
+func stack3280() (uintptr, uintptr) { var buf [3280]byte; use(buf[:]); return Stackguard() }
+func stack3284() (uintptr, uintptr) { var buf [3284]byte; use(buf[:]); return Stackguard() }
+func stack3288() (uintptr, uintptr) { var buf [3288]byte; use(buf[:]); return Stackguard() }
+func stack3292() (uintptr, uintptr) { var buf [3292]byte; use(buf[:]); return Stackguard() }
+func stack3296() (uintptr, uintptr) { var buf [3296]byte; use(buf[:]); return Stackguard() }
+func stack3300() (uintptr, uintptr) { var buf [3300]byte; use(buf[:]); return Stackguard() }
+func stack3304() (uintptr, uintptr) { var buf [3304]byte; use(buf[:]); return Stackguard() }
+func stack3308() (uintptr, uintptr) { var buf [3308]byte; use(buf[:]); return Stackguard() }
+func stack3312() (uintptr, uintptr) { var buf [3312]byte; use(buf[:]); return Stackguard() }
+func stack3316() (uintptr, uintptr) { var buf [3316]byte; use(buf[:]); return Stackguard() }
+func stack3320() (uintptr, uintptr) { var buf [3320]byte; use(buf[:]); return Stackguard() }
+func stack3324() (uintptr, uintptr) { var buf [3324]byte; use(buf[:]); return Stackguard() }
+func stack3328() (uintptr, uintptr) { var buf [3328]byte; use(buf[:]); return Stackguard() }
+func stack3332() (uintptr, uintptr) { var buf [3332]byte; use(buf[:]); return Stackguard() }
+func stack3336() (uintptr, uintptr) { var buf [3336]byte; use(buf[:]); return Stackguard() }
+func stack3340() (uintptr, uintptr) { var buf [3340]byte; use(buf[:]); return Stackguard() }
+func stack3344() (uintptr, uintptr) { var buf [3344]byte; use(buf[:]); return Stackguard() }
+func stack3348() (uintptr, uintptr) { var buf [3348]byte; use(buf[:]); return Stackguard() }
+func stack3352() (uintptr, uintptr) { var buf [3352]byte; use(buf[:]); return Stackguard() }
+func stack3356() (uintptr, uintptr) { var buf [3356]byte; use(buf[:]); return Stackguard() }
+func stack3360() (uintptr, uintptr) { var buf [3360]byte; use(buf[:]); return Stackguard() }
+func stack3364() (uintptr, uintptr) { var buf [3364]byte; use(buf[:]); return Stackguard() }
+func stack3368() (uintptr, uintptr) { var buf [3368]byte; use(buf[:]); return Stackguard() }
+func stack3372() (uintptr, uintptr) { var buf [3372]byte; use(buf[:]); return Stackguard() }
+func stack3376() (uintptr, uintptr) { var buf [3376]byte; use(buf[:]); return Stackguard() }
+func stack3380() (uintptr, uintptr) { var buf [3380]byte; use(buf[:]); return Stackguard() }
+func stack3384() (uintptr, uintptr) { var buf [3384]byte; use(buf[:]); return Stackguard() }
+func stack3388() (uintptr, uintptr) { var buf [3388]byte; use(buf[:]); return Stackguard() }
+func stack3392() (uintptr, uintptr) { var buf [3392]byte; use(buf[:]); return Stackguard() }
+func stack3396() (uintptr, uintptr) { var buf [3396]byte; use(buf[:]); return Stackguard() }
+func stack3400() (uintptr, uintptr) { var buf [3400]byte; use(buf[:]); return Stackguard() }
+func stack3404() (uintptr, uintptr) { var buf [3404]byte; use(buf[:]); return Stackguard() }
+func stack3408() (uintptr, uintptr) { var buf [3408]byte; use(buf[:]); return Stackguard() }
+func stack3412() (uintptr, uintptr) { var buf [3412]byte; use(buf[:]); return Stackguard() }
+func stack3416() (uintptr, uintptr) { var buf [3416]byte; use(buf[:]); return Stackguard() }
+func stack3420() (uintptr, uintptr) { var buf [3420]byte; use(buf[:]); return Stackguard() }
+func stack3424() (uintptr, uintptr) { var buf [3424]byte; use(buf[:]); return Stackguard() }
+func stack3428() (uintptr, uintptr) { var buf [3428]byte; use(buf[:]); return Stackguard() }
+func stack3432() (uintptr, uintptr) { var buf [3432]byte; use(buf[:]); return Stackguard() }
+func stack3436() (uintptr, uintptr) { var buf [3436]byte; use(buf[:]); return Stackguard() }
+func stack3440() (uintptr, uintptr) { var buf [3440]byte; use(buf[:]); return Stackguard() }
+func stack3444() (uintptr, uintptr) { var buf [3444]byte; use(buf[:]); return Stackguard() }
+func stack3448() (uintptr, uintptr) { var buf [3448]byte; use(buf[:]); return Stackguard() }
+func stack3452() (uintptr, uintptr) { var buf [3452]byte; use(buf[:]); return Stackguard() }
+func stack3456() (uintptr, uintptr) { var buf [3456]byte; use(buf[:]); return Stackguard() }
+func stack3460() (uintptr, uintptr) { var buf [3460]byte; use(buf[:]); return Stackguard() }
+func stack3464() (uintptr, uintptr) { var buf [3464]byte; use(buf[:]); return Stackguard() }
+func stack3468() (uintptr, uintptr) { var buf [3468]byte; use(buf[:]); return Stackguard() }
+func stack3472() (uintptr, uintptr) { var buf [3472]byte; use(buf[:]); return Stackguard() }
+func stack3476() (uintptr, uintptr) { var buf [3476]byte; use(buf[:]); return Stackguard() }
+func stack3480() (uintptr, uintptr) { var buf [3480]byte; use(buf[:]); return Stackguard() }
+func stack3484() (uintptr, uintptr) { var buf [3484]byte; use(buf[:]); return Stackguard() }
+func stack3488() (uintptr, uintptr) { var buf [3488]byte; use(buf[:]); return Stackguard() }
+func stack3492() (uintptr, uintptr) { var buf [3492]byte; use(buf[:]); return Stackguard() }
+func stack3496() (uintptr, uintptr) { var buf [3496]byte; use(buf[:]); return Stackguard() }
+func stack3500() (uintptr, uintptr) { var buf [3500]byte; use(buf[:]); return Stackguard() }
+func stack3504() (uintptr, uintptr) { var buf [3504]byte; use(buf[:]); return Stackguard() }
+func stack3508() (uintptr, uintptr) { var buf [3508]byte; use(buf[:]); return Stackguard() }
+func stack3512() (uintptr, uintptr) { var buf [3512]byte; use(buf[:]); return Stackguard() }
+func stack3516() (uintptr, uintptr) { var buf [3516]byte; use(buf[:]); return Stackguard() }
+func stack3520() (uintptr, uintptr) { var buf [3520]byte; use(buf[:]); return Stackguard() }
+func stack3524() (uintptr, uintptr) { var buf [3524]byte; use(buf[:]); return Stackguard() }
+func stack3528() (uintptr, uintptr) { var buf [3528]byte; use(buf[:]); return Stackguard() }
+func stack3532() (uintptr, uintptr) { var buf [3532]byte; use(buf[:]); return Stackguard() }
+func stack3536() (uintptr, uintptr) { var buf [3536]byte; use(buf[:]); return Stackguard() }
+func stack3540() (uintptr, uintptr) { var buf [3540]byte; use(buf[:]); return Stackguard() }
+func stack3544() (uintptr, uintptr) { var buf [3544]byte; use(buf[:]); return Stackguard() }
+func stack3548() (uintptr, uintptr) { var buf [3548]byte; use(buf[:]); return Stackguard() }
+func stack3552() (uintptr, uintptr) { var buf [3552]byte; use(buf[:]); return Stackguard() }
+func stack3556() (uintptr, uintptr) { var buf [3556]byte; use(buf[:]); return Stackguard() }
+func stack3560() (uintptr, uintptr) { var buf [3560]byte; use(buf[:]); return Stackguard() }
+func stack3564() (uintptr, uintptr) { var buf [3564]byte; use(buf[:]); return Stackguard() }
+func stack3568() (uintptr, uintptr) { var buf [3568]byte; use(buf[:]); return Stackguard() }
+func stack3572() (uintptr, uintptr) { var buf [3572]byte; use(buf[:]); return Stackguard() }
+func stack3576() (uintptr, uintptr) { var buf [3576]byte; use(buf[:]); return Stackguard() }
+func stack3580() (uintptr, uintptr) { var buf [3580]byte; use(buf[:]); return Stackguard() }
+func stack3584() (uintptr, uintptr) { var buf [3584]byte; use(buf[:]); return Stackguard() }
+func stack3588() (uintptr, uintptr) { var buf [3588]byte; use(buf[:]); return Stackguard() }
+func stack3592() (uintptr, uintptr) { var buf [3592]byte; use(buf[:]); return Stackguard() }
+func stack3596() (uintptr, uintptr) { var buf [3596]byte; use(buf[:]); return Stackguard() }
+func stack3600() (uintptr, uintptr) { var buf [3600]byte; use(buf[:]); return Stackguard() }
+func stack3604() (uintptr, uintptr) { var buf [3604]byte; use(buf[:]); return Stackguard() }
+func stack3608() (uintptr, uintptr) { var buf [3608]byte; use(buf[:]); return Stackguard() }
+func stack3612() (uintptr, uintptr) { var buf [3612]byte; use(buf[:]); return Stackguard() }
+func stack3616() (uintptr, uintptr) { var buf [3616]byte; use(buf[:]); return Stackguard() }
+func stack3620() (uintptr, uintptr) { var buf [3620]byte; use(buf[:]); return Stackguard() }
+func stack3624() (uintptr, uintptr) { var buf [3624]byte; use(buf[:]); return Stackguard() }
+func stack3628() (uintptr, uintptr) { var buf [3628]byte; use(buf[:]); return Stackguard() }
+func stack3632() (uintptr, uintptr) { var buf [3632]byte; use(buf[:]); return Stackguard() }
+func stack3636() (uintptr, uintptr) { var buf [3636]byte; use(buf[:]); return Stackguard() }
+func stack3640() (uintptr, uintptr) { var buf [3640]byte; use(buf[:]); return Stackguard() }
+func stack3644() (uintptr, uintptr) { var buf [3644]byte; use(buf[:]); return Stackguard() }
+func stack3648() (uintptr, uintptr) { var buf [3648]byte; use(buf[:]); return Stackguard() }
+func stack3652() (uintptr, uintptr) { var buf [3652]byte; use(buf[:]); return Stackguard() }
+func stack3656() (uintptr, uintptr) { var buf [3656]byte; use(buf[:]); return Stackguard() }
+func stack3660() (uintptr, uintptr) { var buf [3660]byte; use(buf[:]); return Stackguard() }
+func stack3664() (uintptr, uintptr) { var buf [3664]byte; use(buf[:]); return Stackguard() }
+func stack3668() (uintptr, uintptr) { var buf [3668]byte; use(buf[:]); return Stackguard() }
+func stack3672() (uintptr, uintptr) { var buf [3672]byte; use(buf[:]); return Stackguard() }
+func stack3676() (uintptr, uintptr) { var buf [3676]byte; use(buf[:]); return Stackguard() }
+func stack3680() (uintptr, uintptr) { var buf [3680]byte; use(buf[:]); return Stackguard() }
+func stack3684() (uintptr, uintptr) { var buf [3684]byte; use(buf[:]); return Stackguard() }
+func stack3688() (uintptr, uintptr) { var buf [3688]byte; use(buf[:]); return Stackguard() }
+func stack3692() (uintptr, uintptr) { var buf [3692]byte; use(buf[:]); return Stackguard() }
+func stack3696() (uintptr, uintptr) { var buf [3696]byte; use(buf[:]); return Stackguard() }
+func stack3700() (uintptr, uintptr) { var buf [3700]byte; use(buf[:]); return Stackguard() }
+func stack3704() (uintptr, uintptr) { var buf [3704]byte; use(buf[:]); return Stackguard() }
+func stack3708() (uintptr, uintptr) { var buf [3708]byte; use(buf[:]); return Stackguard() }
+func stack3712() (uintptr, uintptr) { var buf [3712]byte; use(buf[:]); return Stackguard() }
+func stack3716() (uintptr, uintptr) { var buf [3716]byte; use(buf[:]); return Stackguard() }
+func stack3720() (uintptr, uintptr) { var buf [3720]byte; use(buf[:]); return Stackguard() }
+func stack3724() (uintptr, uintptr) { var buf [3724]byte; use(buf[:]); return Stackguard() }
+func stack3728() (uintptr, uintptr) { var buf [3728]byte; use(buf[:]); return Stackguard() }
+func stack3732() (uintptr, uintptr) { var buf [3732]byte; use(buf[:]); return Stackguard() }
+func stack3736() (uintptr, uintptr) { var buf [3736]byte; use(buf[:]); return Stackguard() }
+func stack3740() (uintptr, uintptr) { var buf [3740]byte; use(buf[:]); return Stackguard() }
+func stack3744() (uintptr, uintptr) { var buf [3744]byte; use(buf[:]); return Stackguard() }
+func stack3748() (uintptr, uintptr) { var buf [3748]byte; use(buf[:]); return Stackguard() }
+func stack3752() (uintptr, uintptr) { var buf [3752]byte; use(buf[:]); return Stackguard() }
+func stack3756() (uintptr, uintptr) { var buf [3756]byte; use(buf[:]); return Stackguard() }
+func stack3760() (uintptr, uintptr) { var buf [3760]byte; use(buf[:]); return Stackguard() }
+func stack3764() (uintptr, uintptr) { var buf [3764]byte; use(buf[:]); return Stackguard() }
+func stack3768() (uintptr, uintptr) { var buf [3768]byte; use(buf[:]); return Stackguard() }
+func stack3772() (uintptr, uintptr) { var buf [3772]byte; use(buf[:]); return Stackguard() }
+func stack3776() (uintptr, uintptr) { var buf [3776]byte; use(buf[:]); return Stackguard() }
+func stack3780() (uintptr, uintptr) { var buf [3780]byte; use(buf[:]); return Stackguard() }
+func stack3784() (uintptr, uintptr) { var buf [3784]byte; use(buf[:]); return Stackguard() }
+func stack3788() (uintptr, uintptr) { var buf [3788]byte; use(buf[:]); return Stackguard() }
+func stack3792() (uintptr, uintptr) { var buf [3792]byte; use(buf[:]); return Stackguard() }
+func stack3796() (uintptr, uintptr) { var buf [3796]byte; use(buf[:]); return Stackguard() }
+func stack3800() (uintptr, uintptr) { var buf [3800]byte; use(buf[:]); return Stackguard() }
+func stack3804() (uintptr, uintptr) { var buf [3804]byte; use(buf[:]); return Stackguard() }
+func stack3808() (uintptr, uintptr) { var buf [3808]byte; use(buf[:]); return Stackguard() }
+func stack3812() (uintptr, uintptr) { var buf [3812]byte; use(buf[:]); return Stackguard() }
+func stack3816() (uintptr, uintptr) { var buf [3816]byte; use(buf[:]); return Stackguard() }
+func stack3820() (uintptr, uintptr) { var buf [3820]byte; use(buf[:]); return Stackguard() }
+func stack3824() (uintptr, uintptr) { var buf [3824]byte; use(buf[:]); return Stackguard() }
+func stack3828() (uintptr, uintptr) { var buf [3828]byte; use(buf[:]); return Stackguard() }
+func stack3832() (uintptr, uintptr) { var buf [3832]byte; use(buf[:]); return Stackguard() }
+func stack3836() (uintptr, uintptr) { var buf [3836]byte; use(buf[:]); return Stackguard() }
+func stack3840() (uintptr, uintptr) { var buf [3840]byte; use(buf[:]); return Stackguard() }
+func stack3844() (uintptr, uintptr) { var buf [3844]byte; use(buf[:]); return Stackguard() }
+func stack3848() (uintptr, uintptr) { var buf [3848]byte; use(buf[:]); return Stackguard() }
+func stack3852() (uintptr, uintptr) { var buf [3852]byte; use(buf[:]); return Stackguard() }
+func stack3856() (uintptr, uintptr) { var buf [3856]byte; use(buf[:]); return Stackguard() }
+func stack3860() (uintptr, uintptr) { var buf [3860]byte; use(buf[:]); return Stackguard() }
+func stack3864() (uintptr, uintptr) { var buf [3864]byte; use(buf[:]); return Stackguard() }
+func stack3868() (uintptr, uintptr) { var buf [3868]byte; use(buf[:]); return Stackguard() }
+func stack3872() (uintptr, uintptr) { var buf [3872]byte; use(buf[:]); return Stackguard() }
+func stack3876() (uintptr, uintptr) { var buf [3876]byte; use(buf[:]); return Stackguard() }
+func stack3880() (uintptr, uintptr) { var buf [3880]byte; use(buf[:]); return Stackguard() }
+func stack3884() (uintptr, uintptr) { var buf [3884]byte; use(buf[:]); return Stackguard() }
+func stack3888() (uintptr, uintptr) { var buf [3888]byte; use(buf[:]); return Stackguard() }
+func stack3892() (uintptr, uintptr) { var buf [3892]byte; use(buf[:]); return Stackguard() }
+func stack3896() (uintptr, uintptr) { var buf [3896]byte; use(buf[:]); return Stackguard() }
+func stack3900() (uintptr, uintptr) { var buf [3900]byte; use(buf[:]); return Stackguard() }
+func stack3904() (uintptr, uintptr) { var buf [3904]byte; use(buf[:]); return Stackguard() }
+func stack3908() (uintptr, uintptr) { var buf [3908]byte; use(buf[:]); return Stackguard() }
+func stack3912() (uintptr, uintptr) { var buf [3912]byte; use(buf[:]); return Stackguard() }
+func stack3916() (uintptr, uintptr) { var buf [3916]byte; use(buf[:]); return Stackguard() }
+func stack3920() (uintptr, uintptr) { var buf [3920]byte; use(buf[:]); return Stackguard() }
+func stack3924() (uintptr, uintptr) { var buf [3924]byte; use(buf[:]); return Stackguard() }
+func stack3928() (uintptr, uintptr) { var buf [3928]byte; use(buf[:]); return Stackguard() }
+func stack3932() (uintptr, uintptr) { var buf [3932]byte; use(buf[:]); return Stackguard() }
+func stack3936() (uintptr, uintptr) { var buf [3936]byte; use(buf[:]); return Stackguard() }
+func stack3940() (uintptr, uintptr) { var buf [3940]byte; use(buf[:]); return Stackguard() }
+func stack3944() (uintptr, uintptr) { var buf [3944]byte; use(buf[:]); return Stackguard() }
+func stack3948() (uintptr, uintptr) { var buf [3948]byte; use(buf[:]); return Stackguard() }
+func stack3952() (uintptr, uintptr) { var buf [3952]byte; use(buf[:]); return Stackguard() }
+func stack3956() (uintptr, uintptr) { var buf [3956]byte; use(buf[:]); return Stackguard() }
+func stack3960() (uintptr, uintptr) { var buf [3960]byte; use(buf[:]); return Stackguard() }
+func stack3964() (uintptr, uintptr) { var buf [3964]byte; use(buf[:]); return Stackguard() }
+func stack3968() (uintptr, uintptr) { var buf [3968]byte; use(buf[:]); return Stackguard() }
+func stack3972() (uintptr, uintptr) { var buf [3972]byte; use(buf[:]); return Stackguard() }
+func stack3976() (uintptr, uintptr) { var buf [3976]byte; use(buf[:]); return Stackguard() }
+func stack3980() (uintptr, uintptr) { var buf [3980]byte; use(buf[:]); return Stackguard() }
+func stack3984() (uintptr, uintptr) { var buf [3984]byte; use(buf[:]); return Stackguard() }
+func stack3988() (uintptr, uintptr) { var buf [3988]byte; use(buf[:]); return Stackguard() }
+func stack3992() (uintptr, uintptr) { var buf [3992]byte; use(buf[:]); return Stackguard() }
+func stack3996() (uintptr, uintptr) { var buf [3996]byte; use(buf[:]); return Stackguard() }
+func stack4000() (uintptr, uintptr) { var buf [4000]byte; use(buf[:]); return Stackguard() }
+func stack4004() (uintptr, uintptr) { var buf [4004]byte; use(buf[:]); return Stackguard() }
+func stack4008() (uintptr, uintptr) { var buf [4008]byte; use(buf[:]); return Stackguard() }
+func stack4012() (uintptr, uintptr) { var buf [4012]byte; use(buf[:]); return Stackguard() }
+func stack4016() (uintptr, uintptr) { var buf [4016]byte; use(buf[:]); return Stackguard() }
+func stack4020() (uintptr, uintptr) { var buf [4020]byte; use(buf[:]); return Stackguard() }
+func stack4024() (uintptr, uintptr) { var buf [4024]byte; use(buf[:]); return Stackguard() }
+func stack4028() (uintptr, uintptr) { var buf [4028]byte; use(buf[:]); return Stackguard() }
+func stack4032() (uintptr, uintptr) { var buf [4032]byte; use(buf[:]); return Stackguard() }
+func stack4036() (uintptr, uintptr) { var buf [4036]byte; use(buf[:]); return Stackguard() }
+func stack4040() (uintptr, uintptr) { var buf [4040]byte; use(buf[:]); return Stackguard() }
+func stack4044() (uintptr, uintptr) { var buf [4044]byte; use(buf[:]); return Stackguard() }
+func stack4048() (uintptr, uintptr) { var buf [4048]byte; use(buf[:]); return Stackguard() }
+func stack4052() (uintptr, uintptr) { var buf [4052]byte; use(buf[:]); return Stackguard() }
+func stack4056() (uintptr, uintptr) { var buf [4056]byte; use(buf[:]); return Stackguard() }
+func stack4060() (uintptr, uintptr) { var buf [4060]byte; use(buf[:]); return Stackguard() }
+func stack4064() (uintptr, uintptr) { var buf [4064]byte; use(buf[:]); return Stackguard() }
+func stack4068() (uintptr, uintptr) { var buf [4068]byte; use(buf[:]); return Stackguard() }
+func stack4072() (uintptr, uintptr) { var buf [4072]byte; use(buf[:]); return Stackguard() }
+func stack4076() (uintptr, uintptr) { var buf [4076]byte; use(buf[:]); return Stackguard() }
+func stack4080() (uintptr, uintptr) { var buf [4080]byte; use(buf[:]); return Stackguard() }
+func stack4084() (uintptr, uintptr) { var buf [4084]byte; use(buf[:]); return Stackguard() }
+func stack4088() (uintptr, uintptr) { var buf [4088]byte; use(buf[:]); return Stackguard() }
+func stack4092() (uintptr, uintptr) { var buf [4092]byte; use(buf[:]); return Stackguard() }
+func stack4096() (uintptr, uintptr) { var buf [4096]byte; use(buf[:]); return Stackguard() }
+func stack4100() (uintptr, uintptr) { var buf [4100]byte; use(buf[:]); return Stackguard() }
+func stack4104() (uintptr, uintptr) { var buf [4104]byte; use(buf[:]); return Stackguard() }
+func stack4108() (uintptr, uintptr) { var buf [4108]byte; use(buf[:]); return Stackguard() }
+func stack4112() (uintptr, uintptr) { var buf [4112]byte; use(buf[:]); return Stackguard() }
+func stack4116() (uintptr, uintptr) { var buf [4116]byte; use(buf[:]); return Stackguard() }
+func stack4120() (uintptr, uintptr) { var buf [4120]byte; use(buf[:]); return Stackguard() }
+func stack4124() (uintptr, uintptr) { var buf [4124]byte; use(buf[:]); return Stackguard() }
+func stack4128() (uintptr, uintptr) { var buf [4128]byte; use(buf[:]); return Stackguard() }
+func stack4132() (uintptr, uintptr) { var buf [4132]byte; use(buf[:]); return Stackguard() }
+func stack4136() (uintptr, uintptr) { var buf [4136]byte; use(buf[:]); return Stackguard() }
+func stack4140() (uintptr, uintptr) { var buf [4140]byte; use(buf[:]); return Stackguard() }
+func stack4144() (uintptr, uintptr) { var buf [4144]byte; use(buf[:]); return Stackguard() }
+func stack4148() (uintptr, uintptr) { var buf [4148]byte; use(buf[:]); return Stackguard() }
+func stack4152() (uintptr, uintptr) { var buf [4152]byte; use(buf[:]); return Stackguard() }
+func stack4156() (uintptr, uintptr) { var buf [4156]byte; use(buf[:]); return Stackguard() }
+func stack4160() (uintptr, uintptr) { var buf [4160]byte; use(buf[:]); return Stackguard() }
+func stack4164() (uintptr, uintptr) { var buf [4164]byte; use(buf[:]); return Stackguard() }
+func stack4168() (uintptr, uintptr) { var buf [4168]byte; use(buf[:]); return Stackguard() }
+func stack4172() (uintptr, uintptr) { var buf [4172]byte; use(buf[:]); return Stackguard() }
+func stack4176() (uintptr, uintptr) { var buf [4176]byte; use(buf[:]); return Stackguard() }
+func stack4180() (uintptr, uintptr) { var buf [4180]byte; use(buf[:]); return Stackguard() }
+func stack4184() (uintptr, uintptr) { var buf [4184]byte; use(buf[:]); return Stackguard() }
+func stack4188() (uintptr, uintptr) { var buf [4188]byte; use(buf[:]); return Stackguard() }
+func stack4192() (uintptr, uintptr) { var buf [4192]byte; use(buf[:]); return Stackguard() }
+func stack4196() (uintptr, uintptr) { var buf [4196]byte; use(buf[:]); return Stackguard() }
+func stack4200() (uintptr, uintptr) { var buf [4200]byte; use(buf[:]); return Stackguard() }
+func stack4204() (uintptr, uintptr) { var buf [4204]byte; use(buf[:]); return Stackguard() }
+func stack4208() (uintptr, uintptr) { var buf [4208]byte; use(buf[:]); return Stackguard() }
+func stack4212() (uintptr, uintptr) { var buf [4212]byte; use(buf[:]); return Stackguard() }
+func stack4216() (uintptr, uintptr) { var buf [4216]byte; use(buf[:]); return Stackguard() }
+func stack4220() (uintptr, uintptr) { var buf [4220]byte; use(buf[:]); return Stackguard() }
+func stack4224() (uintptr, uintptr) { var buf [4224]byte; use(buf[:]); return Stackguard() }
+func stack4228() (uintptr, uintptr) { var buf [4228]byte; use(buf[:]); return Stackguard() }
+func stack4232() (uintptr, uintptr) { var buf [4232]byte; use(buf[:]); return Stackguard() }
+func stack4236() (uintptr, uintptr) { var buf [4236]byte; use(buf[:]); return Stackguard() }
+func stack4240() (uintptr, uintptr) { var buf [4240]byte; use(buf[:]); return Stackguard() }
+func stack4244() (uintptr, uintptr) { var buf [4244]byte; use(buf[:]); return Stackguard() }
+func stack4248() (uintptr, uintptr) { var buf [4248]byte; use(buf[:]); return Stackguard() }
+func stack4252() (uintptr, uintptr) { var buf [4252]byte; use(buf[:]); return Stackguard() }
+func stack4256() (uintptr, uintptr) { var buf [4256]byte; use(buf[:]); return Stackguard() }
+func stack4260() (uintptr, uintptr) { var buf [4260]byte; use(buf[:]); return Stackguard() }
+func stack4264() (uintptr, uintptr) { var buf [4264]byte; use(buf[:]); return Stackguard() }
+func stack4268() (uintptr, uintptr) { var buf [4268]byte; use(buf[:]); return Stackguard() }
+func stack4272() (uintptr, uintptr) { var buf [4272]byte; use(buf[:]); return Stackguard() }
+func stack4276() (uintptr, uintptr) { var buf [4276]byte; use(buf[:]); return Stackguard() }
+func stack4280() (uintptr, uintptr) { var buf [4280]byte; use(buf[:]); return Stackguard() }
+func stack4284() (uintptr, uintptr) { var buf [4284]byte; use(buf[:]); return Stackguard() }
+func stack4288() (uintptr, uintptr) { var buf [4288]byte; use(buf[:]); return Stackguard() }
+func stack4292() (uintptr, uintptr) { var buf [4292]byte; use(buf[:]); return Stackguard() }
+func stack4296() (uintptr, uintptr) { var buf [4296]byte; use(buf[:]); return Stackguard() }
+func stack4300() (uintptr, uintptr) { var buf [4300]byte; use(buf[:]); return Stackguard() }
+func stack4304() (uintptr, uintptr) { var buf [4304]byte; use(buf[:]); return Stackguard() }
+func stack4308() (uintptr, uintptr) { var buf [4308]byte; use(buf[:]); return Stackguard() }
+func stack4312() (uintptr, uintptr) { var buf [4312]byte; use(buf[:]); return Stackguard() }
+func stack4316() (uintptr, uintptr) { var buf [4316]byte; use(buf[:]); return Stackguard() }
+func stack4320() (uintptr, uintptr) { var buf [4320]byte; use(buf[:]); return Stackguard() }
+func stack4324() (uintptr, uintptr) { var buf [4324]byte; use(buf[:]); return Stackguard() }
+func stack4328() (uintptr, uintptr) { var buf [4328]byte; use(buf[:]); return Stackguard() }
+func stack4332() (uintptr, uintptr) { var buf [4332]byte; use(buf[:]); return Stackguard() }
+func stack4336() (uintptr, uintptr) { var buf [4336]byte; use(buf[:]); return Stackguard() }
+func stack4340() (uintptr, uintptr) { var buf [4340]byte; use(buf[:]); return Stackguard() }
+func stack4344() (uintptr, uintptr) { var buf [4344]byte; use(buf[:]); return Stackguard() }
+func stack4348() (uintptr, uintptr) { var buf [4348]byte; use(buf[:]); return Stackguard() }
+func stack4352() (uintptr, uintptr) { var buf [4352]byte; use(buf[:]); return Stackguard() }
+func stack4356() (uintptr, uintptr) { var buf [4356]byte; use(buf[:]); return Stackguard() }
+func stack4360() (uintptr, uintptr) { var buf [4360]byte; use(buf[:]); return Stackguard() }
+func stack4364() (uintptr, uintptr) { var buf [4364]byte; use(buf[:]); return Stackguard() }
+func stack4368() (uintptr, uintptr) { var buf [4368]byte; use(buf[:]); return Stackguard() }
+func stack4372() (uintptr, uintptr) { var buf [4372]byte; use(buf[:]); return Stackguard() }
+func stack4376() (uintptr, uintptr) { var buf [4376]byte; use(buf[:]); return Stackguard() }
+func stack4380() (uintptr, uintptr) { var buf [4380]byte; use(buf[:]); return Stackguard() }
+func stack4384() (uintptr, uintptr) { var buf [4384]byte; use(buf[:]); return Stackguard() }
+func stack4388() (uintptr, uintptr) { var buf [4388]byte; use(buf[:]); return Stackguard() }
+func stack4392() (uintptr, uintptr) { var buf [4392]byte; use(buf[:]); return Stackguard() }
+func stack4396() (uintptr, uintptr) { var buf [4396]byte; use(buf[:]); return Stackguard() }
+func stack4400() (uintptr, uintptr) { var buf [4400]byte; use(buf[:]); return Stackguard() }
+func stack4404() (uintptr, uintptr) { var buf [4404]byte; use(buf[:]); return Stackguard() }
+func stack4408() (uintptr, uintptr) { var buf [4408]byte; use(buf[:]); return Stackguard() }
+func stack4412() (uintptr, uintptr) { var buf [4412]byte; use(buf[:]); return Stackguard() }
+func stack4416() (uintptr, uintptr) { var buf [4416]byte; use(buf[:]); return Stackguard() }
+func stack4420() (uintptr, uintptr) { var buf [4420]byte; use(buf[:]); return Stackguard() }
+func stack4424() (uintptr, uintptr) { var buf [4424]byte; use(buf[:]); return Stackguard() }
+func stack4428() (uintptr, uintptr) { var buf [4428]byte; use(buf[:]); return Stackguard() }
+func stack4432() (uintptr, uintptr) { var buf [4432]byte; use(buf[:]); return Stackguard() }
+func stack4436() (uintptr, uintptr) { var buf [4436]byte; use(buf[:]); return Stackguard() }
+func stack4440() (uintptr, uintptr) { var buf [4440]byte; use(buf[:]); return Stackguard() }
+func stack4444() (uintptr, uintptr) { var buf [4444]byte; use(buf[:]); return Stackguard() }
+func stack4448() (uintptr, uintptr) { var buf [4448]byte; use(buf[:]); return Stackguard() }
+func stack4452() (uintptr, uintptr) { var buf [4452]byte; use(buf[:]); return Stackguard() }
+func stack4456() (uintptr, uintptr) { var buf [4456]byte; use(buf[:]); return Stackguard() }
+func stack4460() (uintptr, uintptr) { var buf [4460]byte; use(buf[:]); return Stackguard() }
+func stack4464() (uintptr, uintptr) { var buf [4464]byte; use(buf[:]); return Stackguard() }
+func stack4468() (uintptr, uintptr) { var buf [4468]byte; use(buf[:]); return Stackguard() }
+func stack4472() (uintptr, uintptr) { var buf [4472]byte; use(buf[:]); return Stackguard() }
+func stack4476() (uintptr, uintptr) { var buf [4476]byte; use(buf[:]); return Stackguard() }
+func stack4480() (uintptr, uintptr) { var buf [4480]byte; use(buf[:]); return Stackguard() }
+func stack4484() (uintptr, uintptr) { var buf [4484]byte; use(buf[:]); return Stackguard() }
+func stack4488() (uintptr, uintptr) { var buf [4488]byte; use(buf[:]); return Stackguard() }
+func stack4492() (uintptr, uintptr) { var buf [4492]byte; use(buf[:]); return Stackguard() }
+func stack4496() (uintptr, uintptr) { var buf [4496]byte; use(buf[:]); return Stackguard() }
+func stack4500() (uintptr, uintptr) { var buf [4500]byte; use(buf[:]); return Stackguard() }
+func stack4504() (uintptr, uintptr) { var buf [4504]byte; use(buf[:]); return Stackguard() }
+func stack4508() (uintptr, uintptr) { var buf [4508]byte; use(buf[:]); return Stackguard() }
+func stack4512() (uintptr, uintptr) { var buf [4512]byte; use(buf[:]); return Stackguard() }
+func stack4516() (uintptr, uintptr) { var buf [4516]byte; use(buf[:]); return Stackguard() }
+func stack4520() (uintptr, uintptr) { var buf [4520]byte; use(buf[:]); return Stackguard() }
+func stack4524() (uintptr, uintptr) { var buf [4524]byte; use(buf[:]); return Stackguard() }
+func stack4528() (uintptr, uintptr) { var buf [4528]byte; use(buf[:]); return Stackguard() }
+func stack4532() (uintptr, uintptr) { var buf [4532]byte; use(buf[:]); return Stackguard() }
+func stack4536() (uintptr, uintptr) { var buf [4536]byte; use(buf[:]); return Stackguard() }
+func stack4540() (uintptr, uintptr) { var buf [4540]byte; use(buf[:]); return Stackguard() }
+func stack4544() (uintptr, uintptr) { var buf [4544]byte; use(buf[:]); return Stackguard() }
+func stack4548() (uintptr, uintptr) { var buf [4548]byte; use(buf[:]); return Stackguard() }
+func stack4552() (uintptr, uintptr) { var buf [4552]byte; use(buf[:]); return Stackguard() }
+func stack4556() (uintptr, uintptr) { var buf [4556]byte; use(buf[:]); return Stackguard() }
+func stack4560() (uintptr, uintptr) { var buf [4560]byte; use(buf[:]); return Stackguard() }
+func stack4564() (uintptr, uintptr) { var buf [4564]byte; use(buf[:]); return Stackguard() }
+func stack4568() (uintptr, uintptr) { var buf [4568]byte; use(buf[:]); return Stackguard() }
+func stack4572() (uintptr, uintptr) { var buf [4572]byte; use(buf[:]); return Stackguard() }
+func stack4576() (uintptr, uintptr) { var buf [4576]byte; use(buf[:]); return Stackguard() }
+func stack4580() (uintptr, uintptr) { var buf [4580]byte; use(buf[:]); return Stackguard() }
+func stack4584() (uintptr, uintptr) { var buf [4584]byte; use(buf[:]); return Stackguard() }
+func stack4588() (uintptr, uintptr) { var buf [4588]byte; use(buf[:]); return Stackguard() }
+func stack4592() (uintptr, uintptr) { var buf [4592]byte; use(buf[:]); return Stackguard() }
+func stack4596() (uintptr, uintptr) { var buf [4596]byte; use(buf[:]); return Stackguard() }
+func stack4600() (uintptr, uintptr) { var buf [4600]byte; use(buf[:]); return Stackguard() }
+func stack4604() (uintptr, uintptr) { var buf [4604]byte; use(buf[:]); return Stackguard() }
+func stack4608() (uintptr, uintptr) { var buf [4608]byte; use(buf[:]); return Stackguard() }
+func stack4612() (uintptr, uintptr) { var buf [4612]byte; use(buf[:]); return Stackguard() }
+func stack4616() (uintptr, uintptr) { var buf [4616]byte; use(buf[:]); return Stackguard() }
+func stack4620() (uintptr, uintptr) { var buf [4620]byte; use(buf[:]); return Stackguard() }
+func stack4624() (uintptr, uintptr) { var buf [4624]byte; use(buf[:]); return Stackguard() }
+func stack4628() (uintptr, uintptr) { var buf [4628]byte; use(buf[:]); return Stackguard() }
+func stack4632() (uintptr, uintptr) { var buf [4632]byte; use(buf[:]); return Stackguard() }
+func stack4636() (uintptr, uintptr) { var buf [4636]byte; use(buf[:]); return Stackguard() }
+func stack4640() (uintptr, uintptr) { var buf [4640]byte; use(buf[:]); return Stackguard() }
+func stack4644() (uintptr, uintptr) { var buf [4644]byte; use(buf[:]); return Stackguard() }
+func stack4648() (uintptr, uintptr) { var buf [4648]byte; use(buf[:]); return Stackguard() }
+func stack4652() (uintptr, uintptr) { var buf [4652]byte; use(buf[:]); return Stackguard() }
+func stack4656() (uintptr, uintptr) { var buf [4656]byte; use(buf[:]); return Stackguard() }
+func stack4660() (uintptr, uintptr) { var buf [4660]byte; use(buf[:]); return Stackguard() }
+func stack4664() (uintptr, uintptr) { var buf [4664]byte; use(buf[:]); return Stackguard() }
+func stack4668() (uintptr, uintptr) { var buf [4668]byte; use(buf[:]); return Stackguard() }
+func stack4672() (uintptr, uintptr) { var buf [4672]byte; use(buf[:]); return Stackguard() }
+func stack4676() (uintptr, uintptr) { var buf [4676]byte; use(buf[:]); return Stackguard() }
+func stack4680() (uintptr, uintptr) { var buf [4680]byte; use(buf[:]); return Stackguard() }
+func stack4684() (uintptr, uintptr) { var buf [4684]byte; use(buf[:]); return Stackguard() }
+func stack4688() (uintptr, uintptr) { var buf [4688]byte; use(buf[:]); return Stackguard() }
+func stack4692() (uintptr, uintptr) { var buf [4692]byte; use(buf[:]); return Stackguard() }
+func stack4696() (uintptr, uintptr) { var buf [4696]byte; use(buf[:]); return Stackguard() }
+func stack4700() (uintptr, uintptr) { var buf [4700]byte; use(buf[:]); return Stackguard() }
+func stack4704() (uintptr, uintptr) { var buf [4704]byte; use(buf[:]); return Stackguard() }
+func stack4708() (uintptr, uintptr) { var buf [4708]byte; use(buf[:]); return Stackguard() }
+func stack4712() (uintptr, uintptr) { var buf [4712]byte; use(buf[:]); return Stackguard() }
+func stack4716() (uintptr, uintptr) { var buf [4716]byte; use(buf[:]); return Stackguard() }
+func stack4720() (uintptr, uintptr) { var buf [4720]byte; use(buf[:]); return Stackguard() }
+func stack4724() (uintptr, uintptr) { var buf [4724]byte; use(buf[:]); return Stackguard() }
+func stack4728() (uintptr, uintptr) { var buf [4728]byte; use(buf[:]); return Stackguard() }
+func stack4732() (uintptr, uintptr) { var buf [4732]byte; use(buf[:]); return Stackguard() }
+func stack4736() (uintptr, uintptr) { var buf [4736]byte; use(buf[:]); return Stackguard() }
+func stack4740() (uintptr, uintptr) { var buf [4740]byte; use(buf[:]); return Stackguard() }
+func stack4744() (uintptr, uintptr) { var buf [4744]byte; use(buf[:]); return Stackguard() }
+func stack4748() (uintptr, uintptr) { var buf [4748]byte; use(buf[:]); return Stackguard() }
+func stack4752() (uintptr, uintptr) { var buf [4752]byte; use(buf[:]); return Stackguard() }
+func stack4756() (uintptr, uintptr) { var buf [4756]byte; use(buf[:]); return Stackguard() }
+func stack4760() (uintptr, uintptr) { var buf [4760]byte; use(buf[:]); return Stackguard() }
+func stack4764() (uintptr, uintptr) { var buf [4764]byte; use(buf[:]); return Stackguard() }
+func stack4768() (uintptr, uintptr) { var buf [4768]byte; use(buf[:]); return Stackguard() }
+func stack4772() (uintptr, uintptr) { var buf [4772]byte; use(buf[:]); return Stackguard() }
+func stack4776() (uintptr, uintptr) { var buf [4776]byte; use(buf[:]); return Stackguard() }
+func stack4780() (uintptr, uintptr) { var buf [4780]byte; use(buf[:]); return Stackguard() }
+func stack4784() (uintptr, uintptr) { var buf [4784]byte; use(buf[:]); return Stackguard() }
+func stack4788() (uintptr, uintptr) { var buf [4788]byte; use(buf[:]); return Stackguard() }
+func stack4792() (uintptr, uintptr) { var buf [4792]byte; use(buf[:]); return Stackguard() }
+func stack4796() (uintptr, uintptr) { var buf [4796]byte; use(buf[:]); return Stackguard() }
+func stack4800() (uintptr, uintptr) { var buf [4800]byte; use(buf[:]); return Stackguard() }
+func stack4804() (uintptr, uintptr) { var buf [4804]byte; use(buf[:]); return Stackguard() }
+func stack4808() (uintptr, uintptr) { var buf [4808]byte; use(buf[:]); return Stackguard() }
+func stack4812() (uintptr, uintptr) { var buf [4812]byte; use(buf[:]); return Stackguard() }
+func stack4816() (uintptr, uintptr) { var buf [4816]byte; use(buf[:]); return Stackguard() }
+func stack4820() (uintptr, uintptr) { var buf [4820]byte; use(buf[:]); return Stackguard() }
+func stack4824() (uintptr, uintptr) { var buf [4824]byte; use(buf[:]); return Stackguard() }
+func stack4828() (uintptr, uintptr) { var buf [4828]byte; use(buf[:]); return Stackguard() }
+func stack4832() (uintptr, uintptr) { var buf [4832]byte; use(buf[:]); return Stackguard() }
+func stack4836() (uintptr, uintptr) { var buf [4836]byte; use(buf[:]); return Stackguard() }
+func stack4840() (uintptr, uintptr) { var buf [4840]byte; use(buf[:]); return Stackguard() }
+func stack4844() (uintptr, uintptr) { var buf [4844]byte; use(buf[:]); return Stackguard() }
+func stack4848() (uintptr, uintptr) { var buf [4848]byte; use(buf[:]); return Stackguard() }
+func stack4852() (uintptr, uintptr) { var buf [4852]byte; use(buf[:]); return Stackguard() }
+func stack4856() (uintptr, uintptr) { var buf [4856]byte; use(buf[:]); return Stackguard() }
+func stack4860() (uintptr, uintptr) { var buf [4860]byte; use(buf[:]); return Stackguard() }
+func stack4864() (uintptr, uintptr) { var buf [4864]byte; use(buf[:]); return Stackguard() }
+func stack4868() (uintptr, uintptr) { var buf [4868]byte; use(buf[:]); return Stackguard() }
+func stack4872() (uintptr, uintptr) { var buf [4872]byte; use(buf[:]); return Stackguard() }
+func stack4876() (uintptr, uintptr) { var buf [4876]byte; use(buf[:]); return Stackguard() }
+func stack4880() (uintptr, uintptr) { var buf [4880]byte; use(buf[:]); return Stackguard() }
+func stack4884() (uintptr, uintptr) { var buf [4884]byte; use(buf[:]); return Stackguard() }
+func stack4888() (uintptr, uintptr) { var buf [4888]byte; use(buf[:]); return Stackguard() }
+func stack4892() (uintptr, uintptr) { var buf [4892]byte; use(buf[:]); return Stackguard() }
+func stack4896() (uintptr, uintptr) { var buf [4896]byte; use(buf[:]); return Stackguard() }
+func stack4900() (uintptr, uintptr) { var buf [4900]byte; use(buf[:]); return Stackguard() }
+func stack4904() (uintptr, uintptr) { var buf [4904]byte; use(buf[:]); return Stackguard() }
+func stack4908() (uintptr, uintptr) { var buf [4908]byte; use(buf[:]); return Stackguard() }
+func stack4912() (uintptr, uintptr) { var buf [4912]byte; use(buf[:]); return Stackguard() }
+func stack4916() (uintptr, uintptr) { var buf [4916]byte; use(buf[:]); return Stackguard() }
+func stack4920() (uintptr, uintptr) { var buf [4920]byte; use(buf[:]); return Stackguard() }
+func stack4924() (uintptr, uintptr) { var buf [4924]byte; use(buf[:]); return Stackguard() }
+func stack4928() (uintptr, uintptr) { var buf [4928]byte; use(buf[:]); return Stackguard() }
+func stack4932() (uintptr, uintptr) { var buf [4932]byte; use(buf[:]); return Stackguard() }
+func stack4936() (uintptr, uintptr) { var buf [4936]byte; use(buf[:]); return Stackguard() }
+func stack4940() (uintptr, uintptr) { var buf [4940]byte; use(buf[:]); return Stackguard() }
+func stack4944() (uintptr, uintptr) { var buf [4944]byte; use(buf[:]); return Stackguard() }
+func stack4948() (uintptr, uintptr) { var buf [4948]byte; use(buf[:]); return Stackguard() }
+func stack4952() (uintptr, uintptr) { var buf [4952]byte; use(buf[:]); return Stackguard() }
+func stack4956() (uintptr, uintptr) { var buf [4956]byte; use(buf[:]); return Stackguard() }
+func stack4960() (uintptr, uintptr) { var buf [4960]byte; use(buf[:]); return Stackguard() }
+func stack4964() (uintptr, uintptr) { var buf [4964]byte; use(buf[:]); return Stackguard() }
+func stack4968() (uintptr, uintptr) { var buf [4968]byte; use(buf[:]); return Stackguard() }
+func stack4972() (uintptr, uintptr) { var buf [4972]byte; use(buf[:]); return Stackguard() }
+func stack4976() (uintptr, uintptr) { var buf [4976]byte; use(buf[:]); return Stackguard() }
+func stack4980() (uintptr, uintptr) { var buf [4980]byte; use(buf[:]); return Stackguard() }
+func stack4984() (uintptr, uintptr) { var buf [4984]byte; use(buf[:]); return Stackguard() }
+func stack4988() (uintptr, uintptr) { var buf [4988]byte; use(buf[:]); return Stackguard() }
+func stack4992() (uintptr, uintptr) { var buf [4992]byte; use(buf[:]); return Stackguard() }
+func stack4996() (uintptr, uintptr) { var buf [4996]byte; use(buf[:]); return Stackguard() }
+func stack5000() (uintptr, uintptr) { var buf [5000]byte; use(buf[:]); return Stackguard() }
diff --git a/src/pkg/runtime/stack_test.go b/src/pkg/runtime/stack_test.go
index 00c2d0e..f0c599a 100644
--- a/src/pkg/runtime/stack_test.go
+++ b/src/pkg/runtime/stack_test.go
@@ -2,6 +2,22 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+package runtime_test
+
+import (
+	. "runtime"
+	"sync"
+	"testing"
+	"time"
+	"unsafe"
+)
+
+// See stack.h.
+const (
+	StackGuard = 256
+	StackLimit = 128
+)
+
 // Test stack split logic by calling functions of every frame size
 // from near 0 up to and beyond the default segment size (4k).
 // Each of those functions reports its SP + stack limit, and then
@@ -28,22 +44,6 @@
 // 	stack_test.go:22: after runtime_test.stack3860: sp=0x7f7818d5d048 < limit=0x7f7818d5d080
 // 	stack_test.go:22: after runtime_test.stack3864: sp=0x7f7818d5d048 < limit=0x7f7818d5d080
 // FAIL
-
-package runtime_test
-
-import (
-	. "runtime"
-	"testing"
-	"time"
-	"unsafe"
-)
-
-// See stack.h.
-const (
-	StackGuard = 256
-	StackLimit = 128
-)
-
 func TestStackSplit(t *testing.T) {
 	for _, f := range splitTests {
 		sp, guard := f()
@@ -56,218 +56,6 @@ func TestStackSplit(t *testing.T) {
 	}
 }
 
-var splitTests = []func() (uintptr, uintptr){
-	// Edit .+1,/^}/-1|seq 4 4 5000 | sed 's/.*/	stack&,/' | fmt
-	stack4, stack8, stack12, stack16, stack20, stack24, stack28,
-	stack32, stack36, stack40, stack44, stack48, stack52, stack56,
-	stack60, stack64, stack68, stack72, stack76, stack80, stack84,
-	stack88, stack92, stack96, stack100, stack104, stack108, stack112,
-	stack116, stack120, stack124, stack128, stack132, stack136,
-	stack140, stack144, stack148, stack152, stack156, stack160,
-	stack164, stack168, stack172, stack176, stack180, stack184,
-	stack188, stack192, stack196, stack200, stack204, stack208,
-	stack212, stack216, stack220, stack224, stack228, stack232,
-	stack236, stack240, stack244, stack248, stack252, stack256,
-	stack260, stack264, stack268, stack272, stack276, stack280,
-	stack284, stack288, stack292, stack296, stack300, stack304,
-	stack308, stack312, stack316, stack320, stack324, stack328,
-	stack332, stack336, stack340, stack344, stack348, stack352,
-	stack356, stack360, stack364, stack368, stack372, stack376,
-	stack380, stack384, stack388, stack392, stack396, stack400,
-	stack404, stack408, stack412, stack416, stack420, stack424,
-	stack428, stack432, stack436, stack440, stack444, stack448,
-	stack452, stack456, stack460, stack464, stack468, stack472,
-	stack476, stack480, stack484, stack488, stack492, stack496,
-	stack500, stack504, stack508, stack512, stack516, stack520,
-	stack524, stack528, stack532, stack536, stack540, stack544,
-	stack548, stack552, stack556, stack560, stack564, stack568,
-	stack572, stack576, stack580, stack584, stack588, stack592,
-	stack596, stack600, stack604, stack608, stack612, stack616,
-	stack620, stack624, stack628, stack632, stack636, stack640,
-	stack644, stack648, stack652, stack656, stack660, stack664,
-	stack668, stack672, stack676, stack680, stack684, stack688,
-	stack692, stack696, stack700, stack704, stack708, stack712,
-	stack716, stack720, stack724, stack728, stack732, stack736,
-	stack740, stack744, stack748, stack752, stack756, stack760,
-	stack764, stack768, stack772, stack776, stack780, stack784,
-	stack788, stack792, stack796, stack800, stack804, stack808,
-	stack812, stack816, stack820, stack824, stack828, stack832,
-	stack836, stack840, stack844, stack848, stack852, stack856,
-	stack860, stack864, stack868, stack872, stack876, stack880,
-	stack884, stack888, stack892, stack896, stack900, stack904,
-	stack908, stack912, stack916, stack920, stack924, stack928,
-	stack932, stack936, stack940, stack944, stack948, stack952,
-	stack956, stack960, stack964, stack968, stack972, stack976,
-	stack980, stack984, stack988, stack992, stack996, stack1000,
-	stack1004, stack1008, stack1012, stack1016, stack1020, stack1024,
-	stack1028, stack1032, stack1036, stack1040, stack1044, stack1048,
-	stack1052, stack1056, stack1060, stack1064, stack1068, stack1072,
-	stack1076, stack1080, stack1084, stack1088, stack1092, stack1096,
-	stack1100, stack1104, stack1108, stack1112, stack1116, stack1120,
-	stack1124, stack1128, stack1132, stack1136, stack1140, stack1144,
-	stack1148, stack1152, stack1156, stack1160, stack1164, stack1168,
-	stack1172, stack1176, stack1180, stack1184, stack1188, stack1192,
-	stack1196, stack1200, stack1204, stack1208, stack1212, stack1216,
-	stack1220, stack1224, stack1228, stack1232, stack1236, stack1240,
-	stack1244, stack1248, stack1252, stack1256, stack1260, stack1264,
-	stack1268, stack1272, stack1276, stack1280, stack1284, stack1288,
-	stack1292, stack1296, stack1300, stack1304, stack1308, stack1312,
-	stack1316, stack1320, stack1324, stack1328, stack1332, stack1336,
-	stack1340, stack1344, stack1348, stack1352, stack1356, stack1360,
-	stack1364, stack1368, stack1372, stack1376, stack1380, stack1384,
-	stack1388, stack1392, stack1396, stack1400, stack1404, stack1408,
-	stack1412, stack1416, stack1420, stack1424, stack1428, stack1432,
-	stack1436, stack1440, stack1444, stack1448, stack1452, stack1456,
-	stack1460, stack1464, stack1468, stack1472, stack1476, stack1480,
-	stack1484, stack1488, stack1492, stack1496, stack1500, stack1504,
-	stack1508, stack1512, stack1516, stack1520, stack1524, stack1528,
-	stack1532, stack1536, stack1540, stack1544, stack1548, stack1552,
-	stack1556, stack1560, stack1564, stack1568, stack1572, stack1576,
-	stack1580, stack1584, stack1588, stack1592, stack1596, stack1600,
-	stack1604, stack1608, stack1612, stack1616, stack1620, stack1624,
-	stack1628, stack1632, stack1636, stack1640, stack1644, stack1648,
-	stack1652, stack1656, stack1660, stack1664, stack1668, stack1672,
-	stack1676, stack1680, stack1684, stack1688, stack1692, stack1696,
-	stack1700, stack1704, stack1708, stack1712, stack1716, stack1720,
-	stack1724, stack1728, stack1732, stack1736, stack1740, stack1744,
-	stack1748, stack1752, stack1756, stack1760, stack1764, stack1768,
-	stack1772, stack1776, stack1780, stack1784, stack1788, stack1792,
-	stack1796, stack1800, stack1804, stack1808, stack1812, stack1816,
-	stack1820, stack1824, stack1828, stack1832, stack1836, stack1840,
-	stack1844, stack1848, stack1852, stack1856, stack1860, stack1864,
-	stack1868, stack1872, stack1876, stack1880, stack1884, stack1888,
-	stack1892, stack1896, stack1900, stack1904, stack1908, stack1912,
-	stack1916, stack1920, stack1924, stack1928, stack1932, stack1936,
-	stack1940, stack1944, stack1948, stack1952, stack1956, stack1960,
-	stack1964, stack1968, stack1972, stack1976, stack1980, stack1984,
-	stack1988, stack1992, stack1996, stack2000, stack2004, stack2008,
-	stack2012, stack2016, stack2020, stack2024, stack2028, stack2032,
-	stack2036, stack2040, stack2044, stack2048, stack2052, stack2056,
-	stack2060, stack2064, stack2068, stack2072, stack2076, stack2080,
-	stack2084, stack2088, stack2092, stack2096, stack2100, stack2104,
-	stack2108, stack2112, stack2116, stack2120, stack2124, stack2128,
-	stack2132, stack2136, stack2140, stack2144, stack2148, stack2152,
-	stack2156, stack2160, stack2164, stack2168, stack2172, stack2176,
-	stack2180, stack2184, stack2188, stack2192, stack2196, stack2200,
-	stack2204, stack2208, stack2212, stack2216, stack2220, stack2224,
-	stack2228, stack2232, stack2236, stack2240, stack2244, stack2248,
-	stack2252, stack2256, stack2260, stack2264, stack2268, stack2272,
-	stack2276, stack2280, stack2284, stack2288, stack2292, stack2296,
-	stack2300, stack2304, stack2308, stack2312, stack2316, stack2320,
-	stack2324, stack2328, stack2332, stack2336, stack2340, stack2344,
-	stack2348, stack2352, stack2356, stack2360, stack2364, stack2368,
-	stack2372, stack2376, stack2380, stack2384, stack2388, stack2392,
-	stack2396, stack2400, stack2404, stack2408, stack2412, stack2416,
-	stack2420, stack2424, stack2428, stack2432, stack2436, stack2440,
-	stack2444, stack2448, stack2452, stack2456, stack2460, stack2464,
-	stack2468, stack2472, stack2476, stack2480, stack2484, stack2488,
-	stack2492, stack2496, stack2500, stack2504, stack2508, stack2512,
-	stack2516, stack2520, stack2524, stack2528, stack2532, stack2536,
-	stack2540, stack2544, stack2548, stack2552, stack2556, stack2560,
-	stack2564, stack2568, stack2572, stack2576, stack2580, stack2584,
-	stack2588, stack2592, stack2596, stack2600, stack2604, stack2608,
-	stack2612, stack2616, stack2620, stack2624, stack2628, stack2632,
-	stack2636, stack2640, stack2644, stack2648, stack2652, stack2656,
-	stack2660, stack2664, stack2668, stack2672, stack2676, stack2680,
-	stack2684, stack2688, stack2692, stack2696, stack2700, stack2704,
-	stack2708, stack2712, stack2716, stack2720, stack2724, stack2728,
-	stack2732, stack2736, stack2740, stack2744, stack2748, stack2752,
-	stack2756, stack2760, stack2764, stack2768, stack2772, stack2776,
-	stack2780, stack2784, stack2788, stack2792, stack2796, stack2800,
-	stack2804, stack2808, stack2812, stack2816, stack2820, stack2824,
-	stack2828, stack2832, stack2836, stack2840, stack2844, stack2848,
-	stack2852, stack2856, stack2860, stack2864, stack2868, stack2872,
-	stack2876, stack2880, stack2884, stack2888, stack2892, stack2896,
-	stack2900, stack2904, stack2908, stack2912, stack2916, stack2920,
-	stack2924, stack2928, stack2932, stack2936, stack2940, stack2944,
-	stack2948, stack2952, stack2956, stack2960, stack2964, stack2968,
-	stack2972, stack2976, stack2980, stack2984, stack2988, stack2992,
-	stack2996, stack3000, stack3004, stack3008, stack3012, stack3016,
-	stack3020, stack3024, stack3028, stack3032, stack3036, stack3040,
-	stack3044, stack3048, stack3052, stack3056, stack3060, stack3064,
-	stack3068, stack3072, stack3076, stack3080, stack3084, stack3088,
-	stack3092, stack3096, stack3100, stack3104, stack3108, stack3112,
-	stack3116, stack3120, stack3124, stack3128, stack3132, stack3136,
-	stack3140, stack3144, stack3148, stack3152, stack3156, stack3160,
-	stack3164, stack3168, stack3172, stack3176, stack3180, stack3184,
-	stack3188, stack3192, stack3196, stack3200, stack3204, stack3208,
-	stack3212, stack3216, stack3220, stack3224, stack3228, stack3232,
-	stack3236, stack3240, stack3244, stack3248, stack3252, stack3256,
-	stack3260, stack3264, stack3268, stack3272, stack3276, stack3280,
-	stack3284, stack3288, stack3292, stack3296, stack3300, stack3304,
-	stack3308, stack3312, stack3316, stack3320, stack3324, stack3328,
-	stack3332, stack3336, stack3340, stack3344, stack3348, stack3352,
-	stack3356, stack3360, stack3364, stack3368, stack3372, stack3376,
-	stack3380, stack3384, stack3388, stack3392, stack3396, stack3400,
-	stack3404, stack3408, stack3412, stack3416, stack3420, stack3424,
-	stack3428, stack3432, stack3436, stack3440, stack3444, stack3448,
-	stack3452, stack3456, stack3460, stack3464, stack3468, stack3472,
-	stack3476, stack3480, stack3484, stack3488, stack3492, stack3496,
-	stack3500, stack3504, stack3508, stack3512, stack3516, stack3520,
-	stack3524, stack3528, stack3532, stack3536, stack3540, stack3544,
-	stack3548, stack3552, stack3556, stack3560, stack3564, stack3568,
-	stack3572, stack3576, stack3580, stack3584, stack3588, stack3592,
-	stack3596, stack3600, stack3604, stack3608, stack3612, stack3616,
-	stack3620, stack3624, stack3628, stack3632, stack3636, stack3640,
-	stack3644, stack3648, stack3652, stack3656, stack3660, stack3664,
-	stack3668, stack3672, stack3676, stack3680, stack3684, stack3688,
-	stack3692, stack3696, stack3700, stack3704, stack3708, stack3712,
-	stack3716, stack3720, stack3724, stack3728, stack3732, stack3736,
-	stack3740, stack3744, stack3748, stack3752, stack3756, stack3760,
-	stack3764, stack3768, stack3772, stack3776, stack3780, stack3784,
-	stack3788, stack3792, stack3796, stack3800, stack3804, stack3808,
-	stack3812, stack3816, stack3820, stack3824, stack3828, stack3832,
-	stack3836, stack3840, stack3844, stack3848, stack3852, stack3856,
-	stack3860, stack3864, stack3868, stack3872, stack3876, stack3880,
-	stack3884, stack3888, stack3892, stack3896, stack3900, stack3904,
-	stack3908, stack3912, stack3916, stack3920, stack3924, stack3928,
-	stack3932, stack3936, stack3940, stack3944, stack3948, stack3952,
-	stack3956, stack3960, stack3964, stack3968, stack3972, stack3976,
-	stack3980, stack3984, stack3988, stack3992, stack3996, stack4000,
-	stack4004, stack4008, stack4012, stack4016, stack4020, stack4024,
-	stack4028, stack4032, stack4036, stack4040, stack4044, stack4048,
-	stack4052, stack4056, stack4060, stack4064, stack4068, stack4072,
-	stack4076, stack4080, stack4084, stack4088, stack4092, stack4096,
-	stack4100, stack4104, stack4108, stack4112, stack4116, stack4120,
-	stack4124, stack4128, stack4132, stack4136, stack4140, stack4144,
-	stack4148, stack4152, stack4156, stack4160, stack4164, stack4168,
-	stack4172, stack4176, stack4180, stack4184, stack4188, stack4192,
-	stack4196, stack4200, stack4204, stack4208, stack4212, stack4216,
-	stack4220, stack4224, stack4228, stack4232, stack4236, stack4240,
-	stack4244, stack4248, stack4252, stack4256, stack4260, stack4264,
-	stack4268, stack4272, stack4276, stack4280, stack4284, stack4288,
-	stack4292, stack4296, stack4300, stack4304, stack4308, stack4312,
-	stack4316, stack4320, stack4324, stack4328, stack4332, stack4336,
-	stack4340, stack4344, stack4348, stack4352, stack4356, stack4360,
-	stack4364, stack4368, stack4372, stack4376, stack4380, stack4384,
-	stack4388, stack4392, stack4396, stack4400, stack4404, stack4408,
-	stack4412, stack4416, stack4420, stack4424, stack4428, stack4432,
-	stack4436, stack4440, stack4444, stack4448, stack4452, stack4456,
-	stack4460, stack4464, stack4468, stack4472, stack4476, stack4480,
-	stack4484, stack4488, stack4492, stack4496, stack4500, stack4504,
-	stack4508, stack4512, stack4516, stack4520, stack4524, stack4528,
-	stack4532, stack4536, stack4540, stack4544, stack4548, stack4552,
-	stack4556, stack4560, stack4564, stack4568, stack4572, stack4576,
-	stack4580, stack4584, stack4588, stack4592, stack4596, stack4600,
-	stack4604, stack4608, stack4612, stack4616, stack4620, stack4624,
-	stack4628, stack4632, stack4636, stack4640, stack4644, stack4648,
-	stack4652, stack4656, stack4660, stack4664, stack4668, stack4672,
-	stack4676, stack4680, stack4684, stack4688, stack4692, stack4696,
-	stack4700, stack4704, stack4708, stack4712, stack4716, stack4720,
-	stack4724, stack4728, stack4732, stack4736, stack4740, stack4744,
-	stack4748, stack4752, stack4756, stack4760, stack4764, stack4768,
-	stack4772, stack4776, stack4780, stack4784, stack4788, stack4792,
-	stack4796, stack4800, stack4804, stack4808, stack4812, stack4816,
-	stack4820, stack4824, stack4828, stack4832, stack4836, stack4840,
-	stack4844, stack4848, stack4852, stack4856, stack4860, stack4864,
-	stack4868, stack4872, stack4876, stack4880, stack4884, stack4888,
-	stack4892, stack4896, stack4900, stack4904, stack4908, stack4912,
-	stack4916, stack4920, stack4924, stack4928, stack4932, stack4936,
-	stack4940, stack4944, stack4948, stack4952, stack4956, stack4960,
-	stack4964, stack4968, stack4972, stack4976, stack4980, stack4984,
-	stack4988, stack4992, stack4996, stack5000,
-}
-
 var Used byte
 
 func use(buf []byte) {
@@ -276,1258 +64,6 @@ func use(buf []byte) {
 	}
 }
 
-// Edit .+1,$ | seq 4 4 5000 | sed 's/.*/func stack&()(uintptr, uintptr) { var buf [&]byte; use(buf[:]); return Stackguard() }/'
-func stack4() (uintptr, uintptr)    { var buf [4]byte; use(buf[:]); return Stackguard() }
-func stack8() (uintptr, uintptr)    { var buf [8]byte; use(buf[:]); return Stackguard() }
-func stack12() (uintptr, uintptr)   { var buf [12]byte; use(buf[:]); return Stackguard() }
-func stack16() (uintptr, uintptr)   { var buf [16]byte; use(buf[:]); return Stackguard() }
-func stack20() (uintptr, uintptr)   { var buf [20]byte; use(buf[:]); return Stackguard() }
-func stack24() (uintptr, uintptr)   { var buf [24]byte; use(buf[:]); return Stackguard() }
-func stack28() (uintptr, uintptr)   { var buf [28]byte; use(buf[:]); return Stackguard() }
-func stack32() (uintptr, uintptr)   { var buf [32]byte; use(buf[:]); return Stackguard() }
-func stack36() (uintptr, uintptr)   { var buf [36]byte; use(buf[:]); return Stackguard() }
-func stack40() (uintptr, uintptr)   { var buf [40]byte; use(buf[:]); return Stackguard() }
-func stack44() (uintptr, uintptr)   { var buf [44]byte; use(buf[:]); return Stackguard() }
-func stack48() (uintptr, uintptr)   { var buf [48]byte; use(buf[:]); return Stackguard() }
-func stack52() (uintptr, uintptr)   { var buf [52]byte; use(buf[:]); return Stackguard() }
-func stack56() (uintptr, uintptr)   { var buf [56]byte; use(buf[:]); return Stackguard() }
-func stack60() (uintptr, uintptr)   { var buf [60]byte; use(buf[:]); return Stackguard() }
-func stack64() (uintptr, uintptr)   { var buf [64]byte; use(buf[:]); return Stackguard() }
-func stack68() (uintptr, uintptr)   { var buf [68]byte; use(buf[:]); return Stackguard() }
-func stack72() (uintptr, uintptr)   { var buf [72]byte; use(buf[:]); return Stackguard() }
-func stack76() (uintptr, uintptr)   { var buf [76]byte; use(buf[:]); return Stackguard() }
-func stack80() (uintptr, uintptr)   { var buf [80]byte; use(buf[:]); return Stackguard() }
-func stack84() (uintptr, uintptr)   { var buf [84]byte; use(buf[:]); return Stackguard() }
-func stack88() (uintptr, uintptr)   { var buf [88]byte; use(buf[:]); return Stackguard() }
-func stack92() (uintptr, uintptr)   { var buf [92]byte; use(buf[:]); return Stackguard() }
-func stack96() (uintptr, uintptr)   { var buf [96]byte; use(buf[:]); return Stackguard() }
-func stack100() (uintptr, uintptr)  { var buf [100]byte; use(buf[:]); return Stackguard() }
-func stack104() (uintptr, uintptr)  { var buf [104]byte; use(buf[:]); return Stackguard() }
-func stack108() (uintptr, uintptr)  { var buf [108]byte; use(buf[:]); return Stackguard() }
-func stack112() (uintptr, uintptr)  { var buf [112]byte; use(buf[:]); return Stackguard() }
-func stack116() (uintptr, uintptr)  { var buf [116]byte; use(buf[:]); return Stackguard() }
-func stack120() (uintptr, uintptr)  { var buf [120]byte; use(buf[:]); return Stackguard() }
-func stack124() (uintptr, uintptr)  { var buf [124]byte; use(buf[:]); return Stackguard() }
-func stack128() (uintptr, uintptr)  { var buf [128]byte; use(buf[:]); return Stackguard() }
-func stack132() (uintptr, uintptr)  { var buf [132]byte; use(buf[:]); return Stackguard() }
-func stack136() (uintptr, uintptr)  { var buf [136]byte; use(buf[:]); return Stackguard() }
-func stack140() (uintptr, uintptr)  { var buf [140]byte; use(buf[:]); return Stackguard() }
-func stack144() (uintptr, uintptr)  { var buf [144]byte; use(buf[:]); return Stackguard() }
-func stack148() (uintptr, uintptr)  { var buf [148]byte; use(buf[:]); return Stackguard() }
-func stack152() (uintptr, uintptr)  { var buf [152]byte; use(buf[:]); return Stackguard() }
-func stack156() (uintptr, uintptr)  { var buf [156]byte; use(buf[:]); return Stackguard() }
-func stack160() (uintptr, uintptr)  { var buf [160]byte; use(buf[:]); return Stackguard() }
-func stack164() (uintptr, uintptr)  { var buf [164]byte; use(buf[:]); return Stackguard() }
-func stack168() (uintptr, uintptr)  { var buf [168]byte; use(buf[:]); return Stackguard() }
-func stack172() (uintptr, uintptr)  { var buf [172]byte; use(buf[:]); return Stackguard() }
-func stack176() (uintptr, uintptr)  { var buf [176]byte; use(buf[:]); return Stackguard() }
-func stack180() (uintptr, uintptr)  { var buf [180]byte; use(buf[:]); return Stackguard() }
-func stack184() (uintptr, uintptr)  { var buf [184]byte; use(buf[:]); return Stackguard() }
-func stack188() (uintptr, uintptr)  { var buf [188]byte; use(buf[:]); return Stackguard() }
-func stack192() (uintptr, uintptr)  { var buf [192]byte; use(buf[:]); return Stackguard() }
-func stack196() (uintptr, uintptr)  { var buf [196]byte; use(buf[:]); return Stackguard() }
-func stack200() (uintptr, uintptr)  { var buf [200]byte; use(buf[:]); return Stackguard() }
-func stack204() (uintptr, uintptr)  { var buf [204]byte; use(buf[:]); return Stackguard() }
-func stack208() (uintptr, uintptr)  { var buf [208]byte; use(buf[:]); return Stackguard() }
-func stack212() (uintptr, uintptr)  { var buf [212]byte; use(buf[:]); return Stackguard() }
-func stack216() (uintptr, uintptr)  { var buf [216]byte; use(buf[:]); return Stackguard() }
-func stack220() (uintptr, uintptr)  { var buf [220]byte; use(buf[:]); return Stackguard() }
-func stack224() (uintptr, uintptr)  { var buf [224]byte; use(buf[:]); return Stackguard() }
-func stack228() (uintptr, uintptr)  { var buf [228]byte; use(buf[:]); return Stackguard() }
-func stack232() (uintptr, uintptr)  { var buf [232]byte; use(buf[:]); return Stackguard() }
-func stack236() (uintptr, uintptr)  { var buf [236]byte; use(buf[:]); return Stackguard() }
-func stack240() (uintptr, uintptr)  { var buf [240]byte; use(buf[:]); return Stackguard() }
-func stack244() (uintptr, uintptr)  { var buf [244]byte; use(buf[:]); return Stackguard() }
-func stack248() (uintptr, uintptr)  { var buf [248]byte; use(buf[:]); return Stackguard() }
-func stack252() (uintptr, uintptr)  { var buf [252]byte; use(buf[:]); return Stackguard() }
-func stack256() (uintptr, uintptr)  { var buf [256]byte; use(buf[:]); return Stackguard() }
-func stack260() (uintptr, uintptr)  { var buf [260]byte; use(buf[:]); return Stackguard() }
-func stack264() (uintptr, uintptr)  { var buf [264]byte; use(buf[:]); return Stackguard() }
-func stack268() (uintptr, uintptr)  { var buf [268]byte; use(buf[:]); return Stackguard() }
-func stack272() (uintptr, uintptr)  { var buf [272]byte; use(buf[:]); return Stackguard() }
-func stack276() (uintptr, uintptr)  { var buf [276]byte; use(buf[:]); return Stackguard() }
-func stack280() (uintptr, uintptr)  { var buf [280]byte; use(buf[:]); return Stackguard() }
-func stack284() (uintptr, uintptr)  { var buf [284]byte; use(buf[:]); return Stackguard() }
-func stack288() (uintptr, uintptr)  { var buf [288]byte; use(buf[:]); return Stackguard() }
-func stack292() (uintptr, uintptr)  { var buf [292]byte; use(buf[:]); return Stackguard() }
-func stack296() (uintptr, uintptr)  { var buf [296]byte; use(buf[:]); return Stackguard() }
-func stack300() (uintptr, uintptr)  { var buf [300]byte; use(buf[:]); return Stackguard() }
-func stack304() (uintptr, uintptr)  { var buf [304]byte; use(buf[:]); return Stackguard() }
-func stack308() (uintptr, uintptr)  { var buf [308]byte; use(buf[:]); return Stackguard() }
-func stack312() (uintptr, uintptr)  { var buf [312]byte; use(buf[:]); return Stackguard() }
-func stack316() (uintptr, uintptr)  { var buf [316]byte; use(buf[:]); return Stackguard() }
-func stack320() (uintptr, uintptr)  { var buf [320]byte; use(buf[:]); return Stackguard() }
-func stack324() (uintptr, uintptr)  { var buf [324]byte; use(buf[:]); return Stackguard() }
-func stack328() (uintptr, uintptr)  { var buf [328]byte; use(buf[:]); return Stackguard() }
-func stack332() (uintptr, uintptr)  { var buf [332]byte; use(buf[:]); return Stackguard() }
-func stack336() (uintptr, uintptr)  { var buf [336]byte; use(buf[:]); return Stackguard() }
-func stack340() (uintptr, uintptr)  { var buf [340]byte; use(buf[:]); return Stackguard() }
-func stack344() (uintptr, uintptr)  { var buf [344]byte; use(buf[:]); return Stackguard() }
-func stack348() (uintptr, uintptr)  { var buf [348]byte; use(buf[:]); return Stackguard() }
-func stack352() (uintptr, uintptr)  { var buf [352]byte; use(buf[:]); return Stackguard() }
-func stack356() (uintptr, uintptr)  { var buf [356]byte; use(buf[:]); return Stackguard() }
-func stack360() (uintptr, uintptr)  { var buf [360]byte; use(buf[:]); return Stackguard() }
-func stack364() (uintptr, uintptr)  { var buf [364]byte; use(buf[:]); return Stackguard() }
-func stack368() (uintptr, uintptr)  { var buf [368]byte; use(buf[:]); return Stackguard() }
-func stack372() (uintptr, uintptr)  { var buf [372]byte; use(buf[:]); return Stackguard() }
-func stack376() (uintptr, uintptr)  { var buf [376]byte; use(buf[:]); return Stackguard() }
-func stack380() (uintptr, uintptr)  { var buf [380]byte; use(buf[:]); return Stackguard() }
-func stack384() (uintptr, uintptr)  { var buf [384]byte; use(buf[:]); return Stackguard() }
-func stack388() (uintptr, uintptr)  { var buf [388]byte; use(buf[:]); return Stackguard() }
-func stack392() (uintptr, uintptr)  { var buf [392]byte; use(buf[:]); return Stackguard() }
-func stack396() (uintptr, uintptr)  { var buf [396]byte; use(buf[:]); return Stackguard() }
-func stack400() (uintptr, uintptr)  { var buf [400]byte; use(buf[:]); return Stackguard() }
-func stack404() (uintptr, uintptr)  { var buf [404]byte; use(buf[:]); return Stackguard() }
-func stack408() (uintptr, uintptr)  { var buf [408]byte; use(buf[:]); return Stackguard() }
-func stack412() (uintptr, uintptr)  { var buf [412]byte; use(buf[:]); return Stackguard() }
-func stack416() (uintptr, uintptr)  { var buf [416]byte; use(buf[:]); return Stackguard() }
-func stack420() (uintptr, uintptr)  { var buf [420]byte; use(buf[:]); return Stackguard() }
-func stack424() (uintptr, uintptr)  { var buf [424]byte; use(buf[:]); return Stackguard() }
-func stack428() (uintptr, uintptr)  { var buf [428]byte; use(buf[:]); return Stackguard() }
-func stack432() (uintptr, uintptr)  { var buf [432]byte; use(buf[:]); return Stackguard() }
-func stack436() (uintptr, uintptr)  { var buf [436]byte; use(buf[:]); return Stackguard() }
-func stack440() (uintptr, uintptr)  { var buf [440]byte; use(buf[:]); return Stackguard() }
-func stack444() (uintptr, uintptr)  { var buf [444]byte; use(buf[:]); return Stackguard() }
-func stack448() (uintptr, uintptr)  { var buf [448]byte; use(buf[:]); return Stackguard() }
-func stack452() (uintptr, uintptr)  { var buf [452]byte; use(buf[:]); return Stackguard() }
-func stack456() (uintptr, uintptr)  { var buf [456]byte; use(buf[:]); return Stackguard() }
-func stack460() (uintptr, uintptr)  { var buf [460]byte; use(buf[:]); return Stackguard() }
-func stack464() (uintptr, uintptr)  { var buf [464]byte; use(buf[:]); return Stackguard() }
-func stack468() (uintptr, uintptr)  { var buf [468]byte; use(buf[:]); return Stackguard() }
-func stack472() (uintptr, uintptr)  { var buf [472]byte; use(buf[:]); return Stackguard() }
-func stack476() (uintptr, uintptr)  { var buf [476]byte; use(buf[:]); return Stackguard() }
-func stack480() (uintptr, uintptr)  { var buf [480]byte; use(buf[:]); return Stackguard() }
-func stack484() (uintptr, uintptr)  { var buf [484]byte; use(buf[:]); return Stackguard() }
-func stack488() (uintptr, uintptr)  { var buf [488]byte; use(buf[:]); return Stackguard() }
-func stack492() (uintptr, uintptr)  { var buf [492]byte; use(buf[:]); return Stackguard() }
-func stack496() (uintptr, uintptr)  { var buf [496]byte; use(buf[:]); return Stackguard() }
-func stack500() (uintptr, uintptr)  { var buf [500]byte; use(buf[:]); return Stackguard() }
-func stack504() (uintptr, uintptr)  { var buf [504]byte; use(buf[:]); return Stackguard() }
-func stack508() (uintptr, uintptr)  { var buf [508]byte; use(buf[:]); return Stackguard() }
-func stack512() (uintptr, uintptr)  { var buf [512]byte; use(buf[:]); return Stackguard() }
-func stack516() (uintptr, uintptr)  { var buf [516]byte; use(buf[:]); return Stackguard() }
-func stack520() (uintptr, uintptr)  { var buf [520]byte; use(buf[:]); return Stackguard() }
-func stack524() (uintptr, uintptr)  { var buf [524]byte; use(buf[:]); return Stackguard() }
-func stack528() (uintptr, uintptr)  { var buf [528]byte; use(buf[:]); return Stackguard() }
-func stack532() (uintptr, uintptr)  { var buf [532]byte; use(buf[:]); return Stackguard() }
-func stack536() (uintptr, uintptr)  { var buf [536]byte; use(buf[:]); return Stackguard() }
-func stack540() (uintptr, uintptr)  { var buf [540]byte; use(buf[:]); return Stackguard() }
-func stack544() (uintptr, uintptr)  { var buf [544]byte; use(buf[:]); return Stackguard() }
-func stack548() (uintptr, uintptr)  { var buf [548]byte; use(buf[:]); return Stackguard() }
-func stack552() (uintptr, uintptr)  { var buf [552]byte; use(buf[:]); return Stackguard() }
-func stack556() (uintptr, uintptr)  { var buf [556]byte; use(buf[:]); return Stackguard() }
-func stack560() (uintptr, uintptr)  { var buf [560]byte; use(buf[:]); return Stackguard() }
-func stack564() (uintptr, uintptr)  { var buf [564]byte; use(buf[:]); return Stackguard() }
-func stack568() (uintptr, uintptr)  { var buf [568]byte; use(buf[:]); return Stackguard() }
-func stack572() (uintptr, uintptr)  { var buf [572]byte; use(buf[:]); return Stackguard() }
-func stack576() (uintptr, uintptr)  { var buf [576]byte; use(buf[:]); return Stackguard() }
-func stack580() (uintptr, uintptr)  { var buf [580]byte; use(buf[:]); return Stackguard() }
-func stack584() (uintptr, uintptr)  { var buf [584]byte; use(buf[:]); return Stackguard() }
-func stack588() (uintptr, uintptr)  { var buf [588]byte; use(buf[:]); return Stackguard() }
-func stack592() (uintptr, uintptr)  { var buf [592]byte; use(buf[:]); return Stackguard() }
-func stack596() (uintptr, uintptr)  { var buf [596]byte; use(buf[:]); return Stackguard() }
-func stack600() (uintptr, uintptr)  { var buf [600]byte; use(buf[:]); return Stackguard() }
-func stack604() (uintptr, uintptr)  { var buf [604]byte; use(buf[:]); return Stackguard() }
-func stack608() (uintptr, uintptr)  { var buf [608]byte; use(buf[:]); return Stackguard() }
-func stack612() (uintptr, uintptr)  { var buf [612]byte; use(buf[:]); return Stackguard() }
-func stack616() (uintptr, uintptr)  { var buf [616]byte; use(buf[:]); return Stackguard() }
-func stack620() (uintptr, uintptr)  { var buf [620]byte; use(buf[:]); return Stackguard() }
-func stack624() (uintptr, uintptr)  { var buf [624]byte; use(buf[:]); return Stackguard() }
-func stack628() (uintptr, uintptr)  { var buf [628]byte; use(buf[:]); return Stackguard() }
-func stack632() (uintptr, uintptr)  { var buf [632]byte; use(buf[:]); return Stackguard() }
-func stack636() (uintptr, uintptr)  { var buf [636]byte; use(buf[:]); return Stackguard() }
-func stack640() (uintptr, uintptr)  { var buf [640]byte; use(buf[:]); return Stackguard() }
-func stack644() (uintptr, uintptr)  { var buf [644]byte; use(buf[:]); return Stackguard() }
-func stack648() (uintptr, uintptr)  { var buf [648]byte; use(buf[:]); return Stackguard() }
-func stack652() (uintptr, uintptr)  { var buf [652]byte; use(buf[:]); return Stackguard() }
-func stack656() (uintptr, uintptr)  { var buf [656]byte; use(buf[:]); return Stackguard() }
-func stack660() (uintptr, uintptr)  { var buf [660]byte; use(buf[:]); return Stackguard() }
-func stack664() (uintptr, uintptr)  { var buf [664]byte; use(buf[:]); return Stackguard() }
-func stack668() (uintptr, uintptr)  { var buf [668]byte; use(buf[:]); return Stackguard() }
-func stack672() (uintptr, uintptr)  { var buf [672]byte; use(buf[:]); return Stackguard() }
-func stack676() (uintptr, uintptr)  { var buf [676]byte; use(buf[:]); return Stackguard() }
-func stack680() (uintptr, uintptr)  { var buf [680]byte; use(buf[:]); return Stackguard() }
-func stack684() (uintptr, uintptr)  { var buf [684]byte; use(buf[:]); return Stackguard() }
-func stack688() (uintptr, uintptr)  { var buf [688]byte; use(buf[:]); return Stackguard() }
-func stack692() (uintptr, uintptr)  { var buf [692]byte; use(buf[:]); return Stackguard() }
-func stack696() (uintptr, uintptr)  { var buf [696]byte; use(buf[:]); return Stackguard() }
-func stack700() (uintptr, uintptr)  { var buf [700]byte; use(buf[:]); return Stackguard() }
-func stack704() (uintptr, uintptr)  { var buf [704]byte; use(buf[:]); return Stackguard() }
-func stack708() (uintptr, uintptr)  { var buf [708]byte; use(buf[:]); return Stackguard() }
-func stack712() (uintptr, uintptr)  { var buf [712]byte; use(buf[:]); return Stackguard() }
-func stack716() (uintptr, uintptr)  { var buf [716]byte; use(buf[:]); return Stackguard() }
-func stack720() (uintptr, uintptr)  { var buf [720]byte; use(buf[:]); return Stackguard() }
-func stack724() (uintptr, uintptr)  { var buf [724]byte; use(buf[:]); return Stackguard() }
-func stack728() (uintptr, uintptr)  { var buf [728]byte; use(buf[:]); return Stackguard() }
-func stack732() (uintptr, uintptr)  { var buf [732]byte; use(buf[:]); return Stackguard() }
-func stack736() (uintptr, uintptr)  { var buf [736]byte; use(buf[:]); return Stackguard() }
-func stack740() (uintptr, uintptr)  { var buf [740]byte; use(buf[:]); return Stackguard() }
-func stack744() (uintptr, uintptr)  { var buf [744]byte; use(buf[:]); return Stackguard() }
-func stack748() (uintptr, uintptr)  { var buf [748]byte; use(buf[:]); return Stackguard() }
-func stack752() (uintptr, uintptr)  { var buf [752]byte; use(buf[:]); return Stackguard() }
-func stack756() (uintptr, uintptr)  { var buf [756]byte; use(buf[:]); return Stackguard() }
-func stack760() (uintptr, uintptr)  { var buf [760]byte; use(buf[:]); return Stackguard() }
-func stack764() (uintptr, uintptr)  { var buf [764]byte; use(buf[:]); return Stackguard() }
-func stack768() (uintptr, uintptr)  { var buf [768]byte; use(buf[:]); return Stackguard() }
-func stack772() (uintptr, uintptr)  { var buf [772]byte; use(buf[:]); return Stackguard() }
-func stack776() (uintptr, uintptr)  { var buf [776]byte; use(buf[:]); return Stackguard() }
-func stack780() (uintptr, uintptr)  { var buf [780]byte; use(buf[:]); return Stackguard() }
-func stack784() (uintptr, uintptr)  { var buf [784]byte; use(buf[:]); return Stackguard() }
-func stack788() (uintptr, uintptr)  { var buf [788]byte; use(buf[:]); return Stackguard() }
-func stack792() (uintptr, uintptr)  { var buf [792]byte; use(buf[:]); return Stackguard() }
-func stack796() (uintptr, uintptr)  { var buf [796]byte; use(buf[:]); return Stackguard() }
-func stack800() (uintptr, uintptr)  { var buf [800]byte; use(buf[:]); return Stackguard() }
-func stack804() (uintptr, uintptr)  { var buf [804]byte; use(buf[:]); return Stackguard() }
-func stack808() (uintptr, uintptr)  { var buf [808]byte; use(buf[:]); return Stackguard() }
-func stack812() (uintptr, uintptr)  { var buf [812]byte; use(buf[:]); return Stackguard() }
-func stack816() (uintptr, uintptr)  { var buf [816]byte; use(buf[:]); return Stackguard() }
-func stack820() (uintptr, uintptr)  { var buf [820]byte; use(buf[:]); return Stackguard() }
-func stack824() (uintptr, uintptr)  { var buf [824]byte; use(buf[:]); return Stackguard() }
-func stack828() (uintptr, uintptr)  { var buf [828]byte; use(buf[:]); return Stackguard() }
-func stack832() (uintptr, uintptr)  { var buf [832]byte; use(buf[:]); return Stackguard() }
-func stack836() (uintptr, uintptr)  { var buf [836]byte; use(buf[:]); return Stackguard() }
-func stack840() (uintptr, uintptr)  { var buf [840]byte; use(buf[:]); return Stackguard() }
-func stack844() (uintptr, uintptr)  { var buf [844]byte; use(buf[:]); return Stackguard() }
-func stack848() (uintptr, uintptr)  { var buf [848]byte; use(buf[:]); return Stackguard() }
-func stack852() (uintptr, uintptr)  { var buf [852]byte; use(buf[:]); return Stackguard() }
-func stack856() (uintptr, uintptr)  { var buf [856]byte; use(buf[:]); return Stackguard() }
-func stack860() (uintptr, uintptr)  { var buf [860]byte; use(buf[:]); return Stackguard() }
-func stack864() (uintptr, uintptr)  { var buf [864]byte; use(buf[:]); return Stackguard() }
-func stack868() (uintptr, uintptr)  { var buf [868]byte; use(buf[:]); return Stackguard() }
-func stack872() (uintptr, uintptr)  { var buf [872]byte; use(buf[:]); return Stackguard() }
-func stack876() (uintptr, uintptr)  { var buf [876]byte; use(buf[:]); return Stackguard() }
-func stack880() (uintptr, uintptr)  { var buf [880]byte; use(buf[:]); return Stackguard() }
-func stack884() (uintptr, uintptr)  { var buf [884]byte; use(buf[:]); return Stackguard() }
-func stack888() (uintptr, uintptr)  { var buf [888]byte; use(buf[:]); return Stackguard() }
-func stack892() (uintptr, uintptr)  { var buf [892]byte; use(buf[:]); return Stackguard() }
-func stack896() (uintptr, uintptr)  { var buf [896]byte; use(buf[:]); return Stackguard() }
-func stack900() (uintptr, uintptr)  { var buf [900]byte; use(buf[:]); return Stackguard() }
-func stack904() (uintptr, uintptr)  { var buf [904]byte; use(buf[:]); return Stackguard() }
-func stack908() (uintptr, uintptr)  { var buf [908]byte; use(buf[:]); return Stackguard() }
-func stack912() (uintptr, uintptr)  { var buf [912]byte; use(buf[:]); return Stackguard() }
-func stack916() (uintptr, uintptr)  { var buf [916]byte; use(buf[:]); return Stackguard() }
-func stack920() (uintptr, uintptr)  { var buf [920]byte; use(buf[:]); return Stackguard() }
-func stack924() (uintptr, uintptr)  { var buf [924]byte; use(buf[:]); return Stackguard() }
-func stack928() (uintptr, uintptr)  { var buf [928]byte; use(buf[:]); return Stackguard() }
-func stack932() (uintptr, uintptr)  { var buf [932]byte; use(buf[:]); return Stackguard() }
-func stack936() (uintptr, uintptr)  { var buf [936]byte; use(buf[:]); return Stackguard() }
-func stack940() (uintptr, uintptr)  { var buf [940]byte; use(buf[:]); return Stackguard() }
-func stack944() (uintptr, uintptr)  { var buf [944]byte; use(buf[:]); return Stackguard() }
-func stack948() (uintptr, uintptr)  { var buf [948]byte; use(buf[:]); return Stackguard() }
-func stack952() (uintptr, uintptr)  { var buf [952]byte; use(buf[:]); return Stackguard() }
-func stack956() (uintptr, uintptr)  { var buf [956]byte; use(buf[:]); return Stackguard() }
-func stack960() (uintptr, uintptr)  { var buf [960]byte; use(buf[:]); return Stackguard() }
-func stack964() (uintptr, uintptr)  { var buf [964]byte; use(buf[:]); return Stackguard() }
-func stack968() (uintptr, uintptr)  { var buf [968]byte; use(buf[:]); return Stackguard() }
-func stack972() (uintptr, uintptr)  { var buf [972]byte; use(buf[:]); return Stackguard() }
-func stack976() (uintptr, uintptr)  { var buf [976]byte; use(buf[:]); return Stackguard() }
-func stack980() (uintptr, uintptr)  { var buf [980]byte; use(buf[:]); return Stackguard() }
-func stack984() (uintptr, uintptr)  { var buf [984]byte; use(buf[:]); return Stackguard() }
-func stack988() (uintptr, uintptr)  { var buf [988]byte; use(buf[:]); return Stackguard() }
-func stack992() (uintptr, uintptr)  { var buf [992]byte; use(buf[:]); return Stackguard() }
-func stack996() (uintptr, uintptr)  { var buf [996]byte; use(buf[:]); return Stackguard() }
-func stack1000() (uintptr, uintptr) { var buf [1000]byte; use(buf[:]); return Stackguard() }
-func stack1004() (uintptr, uintptr) { var buf [1004]byte; use(buf[:]); return Stackguard() }
-func stack1008() (uintptr, uintptr) { var buf [1008]byte; use(buf[:]); return Stackguard() }
-func stack1012() (uintptr, uintptr) { var buf [1012]byte; use(buf[:]); return Stackguard() }
-func stack1016() (uintptr, uintptr) { var buf [1016]byte; use(buf[:]); return Stackguard() }
-func stack1020() (uintptr, uintptr) { var buf [1020]byte; use(buf[:]); return Stackguard() }
-func stack1024() (uintptr, uintptr) { var buf [1024]byte; use(buf[:]); return Stackguard() }
-func stack1028() (uintptr, uintptr) { var buf [1028]byte; use(buf[:]); return Stackguard() }
-func stack1032() (uintptr, uintptr) { var buf [1032]byte; use(buf[:]); return Stackguard() }
-func stack1036() (uintptr, uintptr) { var buf [1036]byte; use(buf[:]); return Stackguard() }
-func stack1040() (uintptr, uintptr) { var buf [1040]byte; use(buf[:]); return Stackguard() }
-func stack1044() (uintptr, uintptr) { var buf [1044]byte; use(buf[:]); return Stackguard() }
-func stack1048() (uintptr, uintptr) { var buf [1048]byte; use(buf[:]); return Stackguard() }
-func stack1052() (uintptr, uintptr) { var buf [1052]byte; use(buf[:]); return Stackguard() }
-func stack1056() (uintptr, uintptr) { var buf [1056]byte; use(buf[:]); return Stackguard() }
-func stack1060() (uintptr, uintptr) { var buf [1060]byte; use(buf[:]); return Stackguard() }
-func stack1064() (uintptr, uintptr) { var buf [1064]byte; use(buf[:]); return Stackguard() }
-func stack1068() (uintptr, uintptr) { var buf [1068]byte; use(buf[:]); return Stackguard() }
-func stack1072() (uintptr, uintptr) { var buf [1072]byte; use(buf[:]); return Stackguard() }
-func stack1076() (uintptr, uintptr) { var buf [1076]byte; use(buf[:]); return Stackguard() }
-func stack1080() (uintptr, uintptr) { var buf [1080]byte; use(buf[:]); return Stackguard() }
-func stack1084() (uintptr, uintptr) { var buf [1084]byte; use(buf[:]); return Stackguard() }
-func stack1088() (uintptr, uintptr) { var buf [1088]byte; use(buf[:]); return Stackguard() }
-func stack1092() (uintptr, uintptr) { var buf [1092]byte; use(buf[:]); return Stackguard() }
-func stack1096() (uintptr, uintptr) { var buf [1096]byte; use(buf[:]); return Stackguard() }
-func stack1100() (uintptr, uintptr) { var buf [1100]byte; use(buf[:]); return Stackguard() }
-func stack1104() (uintptr, uintptr) { var buf [1104]byte; use(buf[:]); return Stackguard() }
-func stack1108() (uintptr, uintptr) { var buf [1108]byte; use(buf[:]); return Stackguard() }
-func stack1112() (uintptr, uintptr) { var buf [1112]byte; use(buf[:]); return Stackguard() }
-func stack1116() (uintptr, uintptr) { var buf [1116]byte; use(buf[:]); return Stackguard() }
-func stack1120() (uintptr, uintptr) { var buf [1120]byte; use(buf[:]); return Stackguard() }
-func stack1124() (uintptr, uintptr) { var buf [1124]byte; use(buf[:]); return Stackguard() }
-func stack1128() (uintptr, uintptr) { var buf [1128]byte; use(buf[:]); return Stackguard() }
-func stack1132() (uintptr, uintptr) { var buf [1132]byte; use(buf[:]); return Stackguard() }
-func stack1136() (uintptr, uintptr) { var buf [1136]byte; use(buf[:]); return Stackguard() }
-func stack1140() (uintptr, uintptr) { var buf [1140]byte; use(buf[:]); return Stackguard() }
-func stack1144() (uintptr, uintptr) { var buf [1144]byte; use(buf[:]); return Stackguard() }
-func stack1148() (uintptr, uintptr) { var buf [1148]byte; use(buf[:]); return Stackguard() }
-func stack1152() (uintptr, uintptr) { var buf [1152]byte; use(buf[:]); return Stackguard() }
-func stack1156() (uintptr, uintptr) { var buf [1156]byte; use(buf[:]); return Stackguard() }
-func stack1160() (uintptr, uintptr) { var buf [1160]byte; use(buf[:]); return Stackguard() }
-func stack1164() (uintptr, uintptr) { var buf [1164]byte; use(buf[:]); return Stackguard() }
-func stack1168() (uintptr, uintptr) { var buf [1168]byte; use(buf[:]); return Stackguard() }
-func stack1172() (uintptr, uintptr) { var buf [1172]byte; use(buf[:]); return Stackguard() }
-func stack1176() (uintptr, uintptr) { var buf [1176]byte; use(buf[:]); return Stackguard() }
-func stack1180() (uintptr, uintptr) { var buf [1180]byte; use(buf[:]); return Stackguard() }
-func stack1184() (uintptr, uintptr) { var buf [1184]byte; use(buf[:]); return Stackguard() }
-func stack1188() (uintptr, uintptr) { var buf [1188]byte; use(buf[:]); return Stackguard() }
-func stack1192() (uintptr, uintptr) { var buf [1192]byte; use(buf[:]); return Stackguard() }
-func stack1196() (uintptr, uintptr) { var buf [1196]byte; use(buf[:]); return Stackguard() }
-func stack1200() (uintptr, uintptr) { var buf [1200]byte; use(buf[:]); return Stackguard() }
-func stack1204() (uintptr, uintptr) { var buf [1204]byte; use(buf[:]); return Stackguard() }
-func stack1208() (uintptr, uintptr) { var buf [1208]byte; use(buf[:]); return Stackguard() }
-func stack1212() (uintptr, uintptr) { var buf [1212]byte; use(buf[:]); return Stackguard() }
-func stack1216() (uintptr, uintptr) { var buf [1216]byte; use(buf[:]); return Stackguard() }
-func stack1220() (uintptr, uintptr) { var buf [1220]byte; use(buf[:]); return Stackguard() }
-func stack1224() (uintptr, uintptr) { var buf [1224]byte; use(buf[:]); return Stackguard() }
-func stack1228() (uintptr, uintptr) { var buf [1228]byte; use(buf[:]); return Stackguard() }
-func stack1232() (uintptr, uintptr) { var buf [1232]byte; use(buf[:]); return Stackguard() }
-func stack1236() (uintptr, uintptr) { var buf [1236]byte; use(buf[:]); return Stackguard() }
-func stack1240() (uintptr, uintptr) { var buf [1240]byte; use(buf[:]); return Stackguard() }
-func stack1244() (uintptr, uintptr) { var buf [1244]byte; use(buf[:]); return Stackguard() }
-func stack1248() (uintptr, uintptr) { var buf [1248]byte; use(buf[:]); return Stackguard() }
-func stack1252() (uintptr, uintptr) { var buf [1252]byte; use(buf[:]); return Stackguard() }
-func stack1256() (uintptr, uintptr) { var buf [1256]byte; use(buf[:]); return Stackguard() }
-func stack1260() (uintptr, uintptr) { var buf [1260]byte; use(buf[:]); return Stackguard() }
-func stack1264() (uintptr, uintptr) { var buf [1264]byte; use(buf[:]); return Stackguard() }
-func stack1268() (uintptr, uintptr) { var buf [1268]byte; use(buf[:]); return Stackguard() }
-func stack1272() (uintptr, uintptr) { var buf [1272]byte; use(buf[:]); return Stackguard() }
-func stack1276() (uintptr, uintptr) { var buf [1276]byte; use(buf[:]); return Stackguard() }
-func stack1280() (uintptr, uintptr) { var buf [1280]byte; use(buf[:]); return Stackguard() }
-func stack1284() (uintptr, uintptr) { var buf [1284]byte; use(buf[:]); return Stackguard() }
-func stack1288() (uintptr, uintptr) { var buf [1288]byte; use(buf[:]); return Stackguard() }
-func stack1292() (uintptr, uintptr) { var buf [1292]byte; use(buf[:]); return Stackguard() }
-func stack1296() (uintptr, uintptr) { var buf [1296]byte; use(buf[:]); return Stackguard() }
-func stack1300() (uintptr, uintptr) { var buf [1300]byte; use(buf[:]); return Stackguard() }
-func stack1304() (uintptr, uintptr) { var buf [1304]byte; use(buf[:]); return Stackguard() }
-func stack1308() (uintptr, uintptr) { var buf [1308]byte; use(buf[:]); return Stackguard() }
-func stack1312() (uintptr, uintptr) { var buf [1312]byte; use(buf[:]); return Stackguard() }
-func stack1316() (uintptr, uintptr) { var buf [1316]byte; use(buf[:]); return Stackguard() }
-func stack1320() (uintptr, uintptr) { var buf [1320]byte; use(buf[:]); return Stackguard() }
-func stack1324() (uintptr, uintptr) { var buf [1324]byte; use(buf[:]); return Stackguard() }
-func stack1328() (uintptr, uintptr) { var buf [1328]byte; use(buf[:]); return Stackguard() }
-func stack1332() (uintptr, uintptr) { var buf [1332]byte; use(buf[:]); return Stackguard() }
-func stack1336() (uintptr, uintptr) { var buf [1336]byte; use(buf[:]); return Stackguard() }
-func stack1340() (uintptr, uintptr) { var buf [1340]byte; use(buf[:]); return Stackguard() }
-func stack1344() (uintptr, uintptr) { var buf [1344]byte; use(buf[:]); return Stackguard() }
-func stack1348() (uintptr, uintptr) { var buf [1348]byte; use(buf[:]); return Stackguard() }
-func stack1352() (uintptr, uintptr) { var buf [1352]byte; use(buf[:]); return Stackguard() }
-func stack1356() (uintptr, uintptr) { var buf [1356]byte; use(buf[:]); return Stackguard() }
-func stack1360() (uintptr, uintptr) { var buf [1360]byte; use(buf[:]); return Stackguard() }
-func stack1364() (uintptr, uintptr) { var buf [1364]byte; use(buf[:]); return Stackguard() }
-func stack1368() (uintptr, uintptr) { var buf [1368]byte; use(buf[:]); return Stackguard() }
-func stack1372() (uintptr, uintptr) { var buf [1372]byte; use(buf[:]); return Stackguard() }
-func stack1376() (uintptr, uintptr) { var buf [1376]byte; use(buf[:]); return Stackguard() }
-func stack1380() (uintptr, uintptr) { var buf [1380]byte; use(buf[:]); return Stackguard() }
-func stack1384() (uintptr, uintptr) { var buf [1384]byte; use(buf[:]); return Stackguard() }
-func stack1388() (uintptr, uintptr) { var buf [1388]byte; use(buf[:]); return Stackguard() }
-func stack1392() (uintptr, uintptr) { var buf [1392]byte; use(buf[:]); return Stackguard() }
-func stack1396() (uintptr, uintptr) { var buf [1396]byte; use(buf[:]); return Stackguard() }
-func stack1400() (uintptr, uintptr) { var buf [1400]byte; use(buf[:]); return Stackguard() }
-func stack1404() (uintptr, uintptr) { var buf [1404]byte; use(buf[:]); return Stackguard() }
-func stack1408() (uintptr, uintptr) { var buf [1408]byte; use(buf[:]); return Stackguard() }
-func stack1412() (uintptr, uintptr) { var buf [1412]byte; use(buf[:]); return Stackguard() }
-func stack1416() (uintptr, uintptr) { var buf [1416]byte; use(buf[:]); return Stackguard() }
-func stack1420() (uintptr, uintptr) { var buf [1420]byte; use(buf[:]); return Stackguard() }
-func stack1424() (uintptr, uintptr) { var buf [1424]byte; use(buf[:]); return Stackguard() }
-func stack1428() (uintptr, uintptr) { var buf [1428]byte; use(buf[:]); return Stackguard() }
-func stack1432() (uintptr, uintptr) { var buf [1432]byte; use(buf[:]); return Stackguard() }
-func stack1436() (uintptr, uintptr) { var buf [1436]byte; use(buf[:]); return Stackguard() }
-func stack1440() (uintptr, uintptr) { var buf [1440]byte; use(buf[:]); return Stackguard() }
-func stack1444() (uintptr, uintptr) { var buf [1444]byte; use(buf[:]); return Stackguard() }
-func stack1448() (uintptr, uintptr) { var buf [1448]byte; use(buf[:]); return Stackguard() }
-func stack1452() (uintptr, uintptr) { var buf [1452]byte; use(buf[:]); return Stackguard() }
-func stack1456() (uintptr, uintptr) { var buf [1456]byte; use(buf[:]); return Stackguard() }
-func stack1460() (uintptr, uintptr) { var buf [1460]byte; use(buf[:]); return Stackguard() }
-func stack1464() (uintptr, uintptr) { var buf [1464]byte; use(buf[:]); return Stackguard() }
-func stack1468() (uintptr, uintptr) { var buf [1468]byte; use(buf[:]); return Stackguard() }
-func stack1472() (uintptr, uintptr) { var buf [1472]byte; use(buf[:]); return Stackguard() }
-func stack1476() (uintptr, uintptr) { var buf [1476]byte; use(buf[:]); return Stackguard() }
-func stack1480() (uintptr, uintptr) { var buf [1480]byte; use(buf[:]); return Stackguard() }
-func stack1484() (uintptr, uintptr) { var buf [1484]byte; use(buf[:]); return Stackguard() }
-func stack1488() (uintptr, uintptr) { var buf [1488]byte; use(buf[:]); return Stackguard() }
-func stack1492() (uintptr, uintptr) { var buf [1492]byte; use(buf[:]); return Stackguard() }
-func stack1496() (uintptr, uintptr) { var buf [1496]byte; use(buf[:]); return Stackguard() }
-func stack1500() (uintptr, uintptr) { var buf [1500]byte; use(buf[:]); return Stackguard() }
-func stack1504() (uintptr, uintptr) { var buf [1504]byte; use(buf[:]); return Stackguard() }
-func stack1508() (uintptr, uintptr) { var buf [1508]byte; use(buf[:]); return Stackguard() }
-func stack1512() (uintptr, uintptr) { var buf [1512]byte; use(buf[:]); return Stackguard() }
-func stack1516() (uintptr, uintptr) { var buf [1516]byte; use(buf[:]); return Stackguard() }
-func stack1520() (uintptr, uintptr) { var buf [1520]byte; use(buf[:]); return Stackguard() }
-func stack1524() (uintptr, uintptr) { var buf [1524]byte; use(buf[:]); return Stackguard() }
-func stack1528() (uintptr, uintptr) { var buf [1528]byte; use(buf[:]); return Stackguard() }
-func stack1532() (uintptr, uintptr) { var buf [1532]byte; use(buf[:]); return Stackguard() }
-func stack1536() (uintptr, uintptr) { var buf [1536]byte; use(buf[:]); return Stackguard() }
-func stack1540() (uintptr, uintptr) { var buf [1540]byte; use(buf[:]); return Stackguard() }
-func stack1544() (uintptr, uintptr) { var buf [1544]byte; use(buf[:]); return Stackguard() }
-func stack1548() (uintptr, uintptr) { var buf [1548]byte; use(buf[:]); return Stackguard() }
-func stack1552() (uintptr, uintptr) { var buf [1552]byte; use(buf[:]); return Stackguard() }
-func stack1556() (uintptr, uintptr) { var buf [1556]byte; use(buf[:]); return Stackguard() }
-func stack1560() (uintptr, uintptr) { var buf [1560]byte; use(buf[:]); return Stackguard() }
-func stack1564() (uintptr, uintptr) { var buf [1564]byte; use(buf[:]); return Stackguard() }
-func stack1568() (uintptr, uintptr) { var buf [1568]byte; use(buf[:]); return Stackguard() }
-func stack1572() (uintptr, uintptr) { var buf [1572]byte; use(buf[:]); return Stackguard() }
-func stack1576() (uintptr, uintptr) { var buf [1576]byte; use(buf[:]); return Stackguard() }
-func stack1580() (uintptr, uintptr) { var buf [1580]byte; use(buf[:]); return Stackguard() }
-func stack1584() (uintptr, uintptr) { var buf [1584]byte; use(buf[:]); return Stackguard() }
-func stack1588() (uintptr, uintptr) { var buf [1588]byte; use(buf[:]); return Stackguard() }
-func stack1592() (uintptr, uintptr) { var buf [1592]byte; use(buf[:]); return Stackguard() }
-func stack1596() (uintptr, uintptr) { var buf [1596]byte; use(buf[:]); return Stackguard() }
-func stack1600() (uintptr, uintptr) { var buf [1600]byte; use(buf[:]); return Stackguard() }
-func stack1604() (uintptr, uintptr) { var buf [1604]byte; use(buf[:]); return Stackguard() }
-func stack1608() (uintptr, uintptr) { var buf [1608]byte; use(buf[:]); return Stackguard() }
-func stack1612() (uintptr, uintptr) { var buf [1612]byte; use(buf[:]); return Stackguard() }
-func stack1616() (uintptr, uintptr) { var buf [1616]byte; use(buf[:]); return Stackguard() }
-func stack1620() (uintptr, uintptr) { var buf [1620]byte; use(buf[:]); return Stackguard() }
-func stack1624() (uintptr, uintptr) { var buf [1624]byte; use(buf[:]); return Stackguard() }
-func stack1628() (uintptr, uintptr) { var buf [1628]byte; use(buf[:]); return Stackguard() }
-func stack1632() (uintptr, uintptr) { var buf [1632]byte; use(buf[:]); return Stackguard() }
-func stack1636() (uintptr, uintptr) { var buf [1636]byte; use(buf[:]); return Stackguard() }
-func stack1640() (uintptr, uintptr) { var buf [1640]byte; use(buf[:]); return Stackguard() }
-func stack1644() (uintptr, uintptr) { var buf [1644]byte; use(buf[:]); return Stackguard() }
-func stack1648() (uintptr, uintptr) { var buf [1648]byte; use(buf[:]); return Stackguard() }
-func stack1652() (uintptr, uintptr) { var buf [1652]byte; use(buf[:]); return Stackguard() }
-func stack1656() (uintptr, uintptr) { var buf [1656]byte; use(buf[:]); return Stackguard() }
-func stack1660() (uintptr, uintptr) { var buf [1660]byte; use(buf[:]); return Stackguard() }
-func stack1664() (uintptr, uintptr) { var buf [1664]byte; use(buf[:]); return Stackguard() }
-func stack1668() (uintptr, uintptr) { var buf [1668]byte; use(buf[:]); return Stackguard() }
-func stack1672() (uintptr, uintptr) { var buf [1672]byte; use(buf[:]); return Stackguard() }
-func stack1676() (uintptr, uintptr) { var buf [1676]byte; use(buf[:]); return Stackguard() }
-func stack1680() (uintptr, uintptr) { var buf [1680]byte; use(buf[:]); return Stackguard() }
-func stack1684() (uintptr, uintptr) { var buf [1684]byte; use(buf[:]); return Stackguard() }
-func stack1688() (uintptr, uintptr) { var buf [1688]byte; use(buf[:]); return Stackguard() }
-func stack1692() (uintptr, uintptr) { var buf [1692]byte; use(buf[:]); return Stackguard() }
-func stack1696() (uintptr, uintptr) { var buf [1696]byte; use(buf[:]); return Stackguard() }
-func stack1700() (uintptr, uintptr) { var buf [1700]byte; use(buf[:]); return Stackguard() }
-func stack1704() (uintptr, uintptr) { var buf [1704]byte; use(buf[:]); return Stackguard() }
-func stack1708() (uintptr, uintptr) { var buf [1708]byte; use(buf[:]); return Stackguard() }
-func stack1712() (uintptr, uintptr) { var buf [1712]byte; use(buf[:]); return Stackguard() }
-func stack1716() (uintptr, uintptr) { var buf [1716]byte; use(buf[:]); return Stackguard() }
-func stack1720() (uintptr, uintptr) { var buf [1720]byte; use(buf[:]); return Stackguard() }
-func stack1724() (uintptr, uintptr) { var buf [1724]byte; use(buf[:]); return Stackguard() }
-func stack1728() (uintptr, uintptr) { var buf [1728]byte; use(buf[:]); return Stackguard() }
-func stack1732() (uintptr, uintptr) { var buf [1732]byte; use(buf[:]); return Stackguard() }
-func stack1736() (uintptr, uintptr) { var buf [1736]byte; use(buf[:]); return Stackguard() }
-func stack1740() (uintptr, uintptr) { var buf [1740]byte; use(buf[:]); return Stackguard() }
-func stack1744() (uintptr, uintptr) { var buf [1744]byte; use(buf[:]); return Stackguard() }
-func stack1748() (uintptr, uintptr) { var buf [1748]byte; use(buf[:]); return Stackguard() }
-func stack1752() (uintptr, uintptr) { var buf [1752]byte; use(buf[:]); return Stackguard() }
-func stack1756() (uintptr, uintptr) { var buf [1756]byte; use(buf[:]); return Stackguard() }
-func stack1760() (uintptr, uintptr) { var buf [1760]byte; use(buf[:]); return Stackguard() }
-func stack1764() (uintptr, uintptr) { var buf [1764]byte; use(buf[:]); return Stackguard() }
-func stack1768() (uintptr, uintptr) { var buf [1768]byte; use(buf[:]); return Stackguard() }
-func stack1772() (uintptr, uintptr) { var buf [1772]byte; use(buf[:]); return Stackguard() }
-func stack1776() (uintptr, uintptr) { var buf [1776]byte; use(buf[:]); return Stackguard() }
-func stack1780() (uintptr, uintptr) { var buf [1780]byte; use(buf[:]); return Stackguard() }
-func stack1784() (uintptr, uintptr) { var buf [1784]byte; use(buf[:]); return Stackguard() }
-func stack1788() (uintptr, uintptr) { var buf [1788]byte; use(buf[:]); return Stackguard() }
-func stack1792() (uintptr, uintptr) { var buf [1792]byte; use(buf[:]); return Stackguard() }
-func stack1796() (uintptr, uintptr) { var buf [1796]byte; use(buf[:]); return Stackguard() }
-func stack1800() (uintptr, uintptr) { var buf [1800]byte; use(buf[:]); return Stackguard() }
-func stack1804() (uintptr, uintptr) { var buf [1804]byte; use(buf[:]); return Stackguard() }
-func stack1808() (uintptr, uintptr) { var buf [1808]byte; use(buf[:]); return Stackguard() }
-func stack1812() (uintptr, uintptr) { var buf [1812]byte; use(buf[:]); return Stackguard() }
-func stack1816() (uintptr, uintptr) { var buf [1816]byte; use(buf[:]); return Stackguard() }
-func stack1820() (uintptr, uintptr) { var buf [1820]byte; use(buf[:]); return Stackguard() }
-func stack1824() (uintptr, uintptr) { var buf [1824]byte; use(buf[:]); return Stackguard() }
-func stack1828() (uintptr, uintptr) { var buf [1828]byte; use(buf[:]); return Stackguard() }
-func stack1832() (uintptr, uintptr) { var buf [1832]byte; use(buf[:]); return Stackguard() }
-func stack1836() (uintptr, uintptr) { var buf [1836]byte; use(buf[:]); return Stackguard() }
-func stack1840() (uintptr, uintptr) { var buf [1840]byte; use(buf[:]); return Stackguard() }
-func stack1844() (uintptr, uintptr) { var buf [1844]byte; use(buf[:]); return Stackguard() }
-func stack1848() (uintptr, uintptr) { var buf [1848]byte; use(buf[:]); return Stackguard() }
-func stack1852() (uintptr, uintptr) { var buf [1852]byte; use(buf[:]); return Stackguard() }
-func stack1856() (uintptr, uintptr) { var buf [1856]byte; use(buf[:]); return Stackguard() }
-func stack1860() (uintptr, uintptr) { var buf [1860]byte; use(buf[:]); return Stackguard() }
-func stack1864() (uintptr, uintptr) { var buf [1864]byte; use(buf[:]); return Stackguard() }
-func stack1868() (uintptr, uintptr) { var buf [1868]byte; use(buf[:]); return Stackguard() }
-func stack1872() (uintptr, uintptr) { var buf [1872]byte; use(buf[:]); return Stackguard() }
-func stack1876() (uintptr, uintptr) { var buf [1876]byte; use(buf[:]); return Stackguard() }
-func stack1880() (uintptr, uintptr) { var buf [1880]byte; use(buf[:]); return Stackguard() }
-func stack1884() (uintptr, uintptr) { var buf [1884]byte; use(buf[:]); return Stackguard() }
-func stack1888() (uintptr, uintptr) { var buf [1888]byte; use(buf[:]); return Stackguard() }
-func stack1892() (uintptr, uintptr) { var buf [1892]byte; use(buf[:]); return Stackguard() }
-func stack1896() (uintptr, uintptr) { var buf [1896]byte; use(buf[:]); return Stackguard() }
-func stack1900() (uintptr, uintptr) { var buf [1900]byte; use(buf[:]); return Stackguard() }
-func stack1904() (uintptr, uintptr) { var buf [1904]byte; use(buf[:]); return Stackguard() }
-func stack1908() (uintptr, uintptr) { var buf [1908]byte; use(buf[:]); return Stackguard() }
-func stack1912() (uintptr, uintptr) { var buf [1912]byte; use(buf[:]); return Stackguard() }
-func stack1916() (uintptr, uintptr) { var buf [1916]byte; use(buf[:]); return Stackguard() }
-func stack1920() (uintptr, uintptr) { var buf [1920]byte; use(buf[:]); return Stackguard() }
-func stack1924() (uintptr, uintptr) { var buf [1924]byte; use(buf[:]); return Stackguard() }
-func stack1928() (uintptr, uintptr) { var buf [1928]byte; use(buf[:]); return Stackguard() }
-func stack1932() (uintptr, uintptr) { var buf [1932]byte; use(buf[:]); return Stackguard() }
-func stack1936() (uintptr, uintptr) { var buf [1936]byte; use(buf[:]); return Stackguard() }
-func stack1940() (uintptr, uintptr) { var buf [1940]byte; use(buf[:]); return Stackguard() }
-func stack1944() (uintptr, uintptr) { var buf [1944]byte; use(buf[:]); return Stackguard() }
-func stack1948() (uintptr, uintptr) { var buf [1948]byte; use(buf[:]); return Stackguard() }
-func stack1952() (uintptr, uintptr) { var buf [1952]byte; use(buf[:]); return Stackguard() }
-func stack1956() (uintptr, uintptr) { var buf [1956]byte; use(buf[:]); return Stackguard() }
-func stack1960() (uintptr, uintptr) { var buf [1960]byte; use(buf[:]); return Stackguard() }
-func stack1964() (uintptr, uintptr) { var buf [1964]byte; use(buf[:]); return Stackguard() }
-func stack1968() (uintptr, uintptr) { var buf [1968]byte; use(buf[:]); return Stackguard() }
-func stack1972() (uintptr, uintptr) { var buf [1972]byte; use(buf[:]); return Stackguard() }
-func stack1976() (uintptr, uintptr) { var buf [1976]byte; use(buf[:]); return Stackguard() }
-func stack1980() (uintptr, uintptr) { var buf [1980]byte; use(buf[:]); return Stackguard() }
-func stack1984() (uintptr, uintptr) { var buf [1984]byte; use(buf[:]); return Stackguard() }
-func stack1988() (uintptr, uintptr) { var buf [1988]byte; use(buf[:]); return Stackguard() }
-func stack1992() (uintptr, uintptr) { var buf [1992]byte; use(buf[:]); return Stackguard() }
-func stack1996() (uintptr, uintptr) { var buf [1996]byte; use(buf[:]); return Stackguard() }
-func stack2000() (uintptr, uintptr) { var buf [2000]byte; use(buf[:]); return Stackguard() }
-func stack2004() (uintptr, uintptr) { var buf [2004]byte; use(buf[:]); return Stackguard() }
-func stack2008() (uintptr, uintptr) { var buf [2008]byte; use(buf[:]); return Stackguard() }
-func stack2012() (uintptr, uintptr) { var buf [2012]byte; use(buf[:]); return Stackguard() }
-func stack2016() (uintptr, uintptr) { var buf [2016]byte; use(buf[:]); return Stackguard() }
-func stack2020() (uintptr, uintptr) { var buf [2020]byte; use(buf[:]); return Stackguard() }
-func stack2024() (uintptr, uintptr) { var buf [2024]byte; use(buf[:]); return Stackguard() }
-func stack2028() (uintptr, uintptr) { var buf [2028]byte; use(buf[:]); return Stackguard() }
-func stack2032() (uintptr, uintptr) { var buf [2032]byte; use(buf[:]); return Stackguard() }
-func stack2036() (uintptr, uintptr) { var buf [2036]byte; use(buf[:]); return Stackguard() }
-func stack2040() (uintptr, uintptr) { var buf [2040]byte; use(buf[:]); return Stackguard() }
-func stack2044() (uintptr, uintptr) { var buf [2044]byte; use(buf[:]); return Stackguard() }
-func stack2048() (uintptr, uintptr) { var buf [2048]byte; use(buf[:]); return Stackguard() }
-func stack2052() (uintptr, uintptr) { var buf [2052]byte; use(buf[:]); return Stackguard() }
-func stack2056() (uintptr, uintptr) { var buf [2056]byte; use(buf[:]); return Stackguard() }
-func stack2060() (uintptr, uintptr) { var buf [2060]byte; use(buf[:]); return Stackguard() }
-func stack2064() (uintptr, uintptr) { var buf [2064]byte; use(buf[:]); return Stackguard() }
-func stack2068() (uintptr, uintptr) { var buf [2068]byte; use(buf[:]); return Stackguard() }
-func stack2072() (uintptr, uintptr) { var buf [2072]byte; use(buf[:]); return Stackguard() }
-func stack2076() (uintptr, uintptr) { var buf [2076]byte; use(buf[:]); return Stackguard() }
-func stack2080() (uintptr, uintptr) { var buf [2080]byte; use(buf[:]); return Stackguard() }
-func stack2084() (uintptr, uintptr) { var buf [2084]byte; use(buf[:]); return Stackguard() }
-func stack2088() (uintptr, uintptr) { var buf [2088]byte; use(buf[:]); return Stackguard() }
-func stack2092() (uintptr, uintptr) { var buf [2092]byte; use(buf[:]); return Stackguard() }
-func stack2096() (uintptr, uintptr) { var buf [2096]byte; use(buf[:]); return Stackguard() }
-func stack2100() (uintptr, uintptr) { var buf [2100]byte; use(buf[:]); return Stackguard() }
-func stack2104() (uintptr, uintptr) { var buf [2104]byte; use(buf[:]); return Stackguard() }
-func stack2108() (uintptr, uintptr) { var buf [2108]byte; use(buf[:]); return Stackguard() }
-func stack2112() (uintptr, uintptr) { var buf [2112]byte; use(buf[:]); return Stackguard() }
-func stack2116() (uintptr, uintptr) { var buf [2116]byte; use(buf[:]); return Stackguard() }
-func stack2120() (uintptr, uintptr) { var buf [2120]byte; use(buf[:]); return Stackguard() }
-func stack2124() (uintptr, uintptr) { var buf [2124]byte; use(buf[:]); return Stackguard() }
-func stack2128() (uintptr, uintptr) { var buf [2128]byte; use(buf[:]); return Stackguard() }
-func stack2132() (uintptr, uintptr) { var buf [2132]byte; use(buf[:]); return Stackguard() }
-func stack2136() (uintptr, uintptr) { var buf [2136]byte; use(buf[:]); return Stackguard() }
-func stack2140() (uintptr, uintptr) { var buf [2140]byte; use(buf[:]); return Stackguard() }
-func stack2144() (uintptr, uintptr) { var buf [2144]byte; use(buf[:]); return Stackguard() }
-func stack2148() (uintptr, uintptr) { var buf [2148]byte; use(buf[:]); return Stackguard() }
-func stack2152() (uintptr, uintptr) { var buf [2152]byte; use(buf[:]); return Stackguard() }
-func stack2156() (uintptr, uintptr) { var buf [2156]byte; use(buf[:]); return Stackguard() }
-func stack2160() (uintptr, uintptr) { var buf [2160]byte; use(buf[:]); return Stackguard() }
-func stack2164() (uintptr, uintptr) { var buf [2164]byte; use(buf[:]); return Stackguard() }
-func stack2168() (uintptr, uintptr) { var buf [2168]byte; use(buf[:]); return Stackguard() }
-func stack2172() (uintptr, uintptr) { var buf [2172]byte; use(buf[:]); return Stackguard() }
-func stack2176() (uintptr, uintptr) { var buf [2176]byte; use(buf[:]); return Stackguard() }
-func stack2180() (uintptr, uintptr) { var buf [2180]byte; use(buf[:]); return Stackguard() }
-func stack2184() (uintptr, uintptr) { var buf [2184]byte; use(buf[:]); return Stackguard() }
-func stack2188() (uintptr, uintptr) { var buf [2188]byte; use(buf[:]); return Stackguard() }
-func stack2192() (uintptr, uintptr) { var buf [2192]byte; use(buf[:]); return Stackguard() }
-func stack2196() (uintptr, uintptr) { var buf [2196]byte; use(buf[:]); return Stackguard() }
-func stack2200() (uintptr, uintptr) { var buf [2200]byte; use(buf[:]); return Stackguard() }
-func stack2204() (uintptr, uintptr) { var buf [2204]byte; use(buf[:]); return Stackguard() }
-func stack2208() (uintptr, uintptr) { var buf [2208]byte; use(buf[:]); return Stackguard() }
-func stack2212() (uintptr, uintptr) { var buf [2212]byte; use(buf[:]); return Stackguard() }
-func stack2216() (uintptr, uintptr) { var buf [2216]byte; use(buf[:]); return Stackguard() }
-func stack2220() (uintptr, uintptr) { var buf [2220]byte; use(buf[:]); return Stackguard() }
-func stack2224() (uintptr, uintptr) { var buf [2224]byte; use(buf[:]); return Stackguard() }
-func stack2228() (uintptr, uintptr) { var buf [2228]byte; use(buf[:]); return Stackguard() }
-func stack2232() (uintptr, uintptr) { var buf [2232]byte; use(buf[:]); return Stackguard() }
-func stack2236() (uintptr, uintptr) { var buf [2236]byte; use(buf[:]); return Stackguard() }
-func stack2240() (uintptr, uintptr) { var buf [2240]byte; use(buf[:]); return Stackguard() }
-func stack2244() (uintptr, uintptr) { var buf [2244]byte; use(buf[:]); return Stackguard() }
-func stack2248() (uintptr, uintptr) { var buf [2248]byte; use(buf[:]); return Stackguard() }
-func stack2252() (uintptr, uintptr) { var buf [2252]byte; use(buf[:]); return Stackguard() }
-func stack2256() (uintptr, uintptr) { var buf [2256]byte; use(buf[:]); return Stackguard() }
-func stack2260() (uintptr, uintptr) { var buf [2260]byte; use(buf[:]); return Stackguard() }
-func stack2264() (uintptr, uintptr) { var buf [2264]byte; use(buf[:]); return Stackguard() }
-func stack2268() (uintptr, uintptr) { var buf [2268]byte; use(buf[:]); return Stackguard() }
-func stack2272() (uintptr, uintptr) { var buf [2272]byte; use(buf[:]); return Stackguard() }
-func stack2276() (uintptr, uintptr) { var buf [2276]byte; use(buf[:]); return Stackguard() }
-func stack2280() (uintptr, uintptr) { var buf [2280]byte; use(buf[:]); return Stackguard() }
-func stack2284() (uintptr, uintptr) { var buf [2284]byte; use(buf[:]); return Stackguard() }
-func stack2288() (uintptr, uintptr) { var buf [2288]byte; use(buf[:]); return Stackguard() }
-func stack2292() (uintptr, uintptr) { var buf [2292]byte; use(buf[:]); return Stackguard() }
-func stack2296() (uintptr, uintptr) { var buf [2296]byte; use(buf[:]); return Stackguard() }
-func stack2300() (uintptr, uintptr) { var buf [2300]byte; use(buf[:]); return Stackguard() }
-func stack2304() (uintptr, uintptr) { var buf [2304]byte; use(buf[:]); return Stackguard() }
-func stack2308() (uintptr, uintptr) { var buf [2308]byte; use(buf[:]); return Stackguard() }
-func stack2312() (uintptr, uintptr) { var buf [2312]byte; use(buf[:]); return Stackguard() }
-func stack2316() (uintptr, uintptr) { var buf [2316]byte; use(buf[:]); return Stackguard() }
-func stack2320() (uintptr, uintptr) { var buf [2320]byte; use(buf[:]); return Stackguard() }
-func stack2324() (uintptr, uintptr) { var buf [2324]byte; use(buf[:]); return Stackguard() }
-func stack2328() (uintptr, uintptr) { var buf [2328]byte; use(buf[:]); return Stackguard() }
-func stack2332() (uintptr, uintptr) { var buf [2332]byte; use(buf[:]); return Stackguard() }
-func stack2336() (uintptr, uintptr) { var buf [2336]byte; use(buf[:]); return Stackguard() }
-func stack2340() (uintptr, uintptr) { var buf [2340]byte; use(buf[:]); return Stackguard() }
-func stack2344() (uintptr, uintptr) { var buf [2344]byte; use(buf[:]); return Stackguard() }
-func stack2348() (uintptr, uintptr) { var buf [2348]byte; use(buf[:]); return Stackguard() }
-func stack2352() (uintptr, uintptr) { var buf [2352]byte; use(buf[:]); return Stackguard() }
-func stack2356() (uintptr, uintptr) { var buf [2356]byte; use(buf[:]); return Stackguard() }
-func stack2360() (uintptr, uintptr) { var buf [2360]byte; use(buf[:]); return Stackguard() }
-func stack2364() (uintptr, uintptr) { var buf [2364]byte; use(buf[:]); return Stackguard() }
-func stack2368() (uintptr, uintptr) { var buf [2368]byte; use(buf[:]); return Stackguard() }
-func stack2372() (uintptr, uintptr) { var buf [2372]byte; use(buf[:]); return Stackguard() }
-func stack2376() (uintptr, uintptr) { var buf [2376]byte; use(buf[:]); return Stackguard() }
-func stack2380() (uintptr, uintptr) { var buf [2380]byte; use(buf[:]); return Stackguard() }
-func stack2384() (uintptr, uintptr) { var buf [2384]byte; use(buf[:]); return Stackguard() }
-func stack2388() (uintptr, uintptr) { var buf [2388]byte; use(buf[:]); return Stackguard() }
-func stack2392() (uintptr, uintptr) { var buf [2392]byte; use(buf[:]); return Stackguard() }
-func stack2396() (uintptr, uintptr) { var buf [2396]byte; use(buf[:]); return Stackguard() }
-func stack2400() (uintptr, uintptr) { var buf [2400]byte; use(buf[:]); return Stackguard() }
-func stack2404() (uintptr, uintptr) { var buf [2404]byte; use(buf[:]); return Stackguard() }
-func stack2408() (uintptr, uintptr) { var buf [2408]byte; use(buf[:]); return Stackguard() }
-func stack2412() (uintptr, uintptr) { var buf [2412]byte; use(buf[:]); return Stackguard() }
-func stack2416() (uintptr, uintptr) { var buf [2416]byte; use(buf[:]); return Stackguard() }
-func stack2420() (uintptr, uintptr) { var buf [2420]byte; use(buf[:]); return Stackguard() }
-func stack2424() (uintptr, uintptr) { var buf [2424]byte; use(buf[:]); return Stackguard() }
-func stack2428() (uintptr, uintptr) { var buf [2428]byte; use(buf[:]); return Stackguard() }
-func stack2432() (uintptr, uintptr) { var buf [2432]byte; use(buf[:]); return Stackguard() }
-func stack2436() (uintptr, uintptr) { var buf [2436]byte; use(buf[:]); return Stackguard() }
-func stack2440() (uintptr, uintptr) { var buf [2440]byte; use(buf[:]); return Stackguard() }
-func stack2444() (uintptr, uintptr) { var buf [2444]byte; use(buf[:]); return Stackguard() }
-func stack2448() (uintptr, uintptr) { var buf [2448]byte; use(buf[:]); return Stackguard() }
-func stack2452() (uintptr, uintptr) { var buf [2452]byte; use(buf[:]); return Stackguard() }
-func stack2456() (uintptr, uintptr) { var buf [2456]byte; use(buf[:]); return Stackguard() }
-func stack2460() (uintptr, uintptr) { var buf [2460]byte; use(buf[:]); return Stackguard() }
-func stack2464() (uintptr, uintptr) { var buf [2464]byte; use(buf[:]); return Stackguard() }
-func stack2468() (uintptr, uintptr) { var buf [2468]byte; use(buf[:]); return Stackguard() }
-func stack2472() (uintptr, uintptr) { var buf [2472]byte; use(buf[:]); return Stackguard() }
-func stack2476() (uintptr, uintptr) { var buf [2476]byte; use(buf[:]); return Stackguard() }
-func stack2480() (uintptr, uintptr) { var buf [2480]byte; use(buf[:]); return Stackguard() }
-func stack2484() (uintptr, uintptr) { var buf [2484]byte; use(buf[:]); return Stackguard() }
-func stack2488() (uintptr, uintptr) { var buf [2488]byte; use(buf[:]); return Stackguard() }
-func stack2492() (uintptr, uintptr) { var buf [2492]byte; use(buf[:]); return Stackguard() }
-func stack2496() (uintptr, uintptr) { var buf [2496]byte; use(buf[:]); return Stackguard() }
-func stack2500() (uintptr, uintptr) { var buf [2500]byte; use(buf[:]); return Stackguard() }
-func stack2504() (uintptr, uintptr) { var buf [2504]byte; use(buf[:]); return Stackguard() }
-func stack2508() (uintptr, uintptr) { var buf [2508]byte; use(buf[:]); return Stackguard() }
-func stack2512() (uintptr, uintptr) { var buf [2512]byte; use(buf[:]); return Stackguard() }
-func stack2516() (uintptr, uintptr) { var buf [2516]byte; use(buf[:]); return Stackguard() }
-func stack2520() (uintptr, uintptr) { var buf [2520]byte; use(buf[:]); return Stackguard() }
-func stack2524() (uintptr, uintptr) { var buf [2524]byte; use(buf[:]); return Stackguard() }
-func stack2528() (uintptr, uintptr) { var buf [2528]byte; use(buf[:]); return Stackguard() }
-func stack2532() (uintptr, uintptr) { var buf [2532]byte; use(buf[:]); return Stackguard() }
-func stack2536() (uintptr, uintptr) { var buf [2536]byte; use(buf[:]); return Stackguard() }
-func stack2540() (uintptr, uintptr) { var buf [2540]byte; use(buf[:]); return Stackguard() }
-func stack2544() (uintptr, uintptr) { var buf [2544]byte; use(buf[:]); return Stackguard() }
-func stack2548() (uintptr, uintptr) { var buf [2548]byte; use(buf[:]); return Stackguard() }
-func stack2552() (uintptr, uintptr) { var buf [2552]byte; use(buf[:]); return Stackguard() }
-func stack2556() (uintptr, uintptr) { var buf [2556]byte; use(buf[:]); return Stackguard() }
-func stack2560() (uintptr, uintptr) { var buf [2560]byte; use(buf[:]); return Stackguard() }
-func stack2564() (uintptr, uintptr) { var buf [2564]byte; use(buf[:]); return Stackguard() }
-func stack2568() (uintptr, uintptr) { var buf [2568]byte; use(buf[:]); return Stackguard() }
-func stack2572() (uintptr, uintptr) { var buf [2572]byte; use(buf[:]); return Stackguard() }
-func stack2576() (uintptr, uintptr) { var buf [2576]byte; use(buf[:]); return Stackguard() }
-func stack2580() (uintptr, uintptr) { var buf [2580]byte; use(buf[:]); return Stackguard() }
-func stack2584() (uintptr, uintptr) { var buf [2584]byte; use(buf[:]); return Stackguard() }
-func stack2588() (uintptr, uintptr) { var buf [2588]byte; use(buf[:]); return Stackguard() }
-func stack2592() (uintptr, uintptr) { var buf [2592]byte; use(buf[:]); return Stackguard() }
-func stack2596() (uintptr, uintptr) { var buf [2596]byte; use(buf[:]); return Stackguard() }
-func stack2600() (uintptr, uintptr) { var buf [2600]byte; use(buf[:]); return Stackguard() }
-func stack2604() (uintptr, uintptr) { var buf [2604]byte; use(buf[:]); return Stackguard() }
-func stack2608() (uintptr, uintptr) { var buf [2608]byte; use(buf[:]); return Stackguard() }
-func stack2612() (uintptr, uintptr) { var buf [2612]byte; use(buf[:]); return Stackguard() }
-func stack2616() (uintptr, uintptr) { var buf [2616]byte; use(buf[:]); return Stackguard() }
-func stack2620() (uintptr, uintptr) { var buf [2620]byte; use(buf[:]); return Stackguard() }
-func stack2624() (uintptr, uintptr) { var buf [2624]byte; use(buf[:]); return Stackguard() }
-func stack2628() (uintptr, uintptr) { var buf [2628]byte; use(buf[:]); return Stackguard() }
-func stack2632() (uintptr, uintptr) { var buf [2632]byte; use(buf[:]); return Stackguard() }
-func stack2636() (uintptr, uintptr) { var buf [2636]byte; use(buf[:]); return Stackguard() }
-func stack2640() (uintptr, uintptr) { var buf [2640]byte; use(buf[:]); return Stackguard() }
-func stack2644() (uintptr, uintptr) { var buf [2644]byte; use(buf[:]); return Stackguard() }
-func stack2648() (uintptr, uintptr) { var buf [2648]byte; use(buf[:]); return Stackguard() }
-func stack2652() (uintptr, uintptr) { var buf [2652]byte; use(buf[:]); return Stackguard() }
-func stack2656() (uintptr, uintptr) { var buf [2656]byte; use(buf[:]); return Stackguard() }
-func stack2660() (uintptr, uintptr) { var buf [2660]byte; use(buf[:]); return Stackguard() }
-func stack2664() (uintptr, uintptr) { var buf [2664]byte; use(buf[:]); return Stackguard() }
-func stack2668() (uintptr, uintptr) { var buf [2668]byte; use(buf[:]); return Stackguard() }
-func stack2672() (uintptr, uintptr) { var buf [2672]byte; use(buf[:]); return Stackguard() }
-func stack2676() (uintptr, uintptr) { var buf [2676]byte; use(buf[:]); return Stackguard() }
-func stack2680() (uintptr, uintptr) { var buf [2680]byte; use(buf[:]); return Stackguard() }
-func stack2684() (uintptr, uintptr) { var buf [2684]byte; use(buf[:]); return Stackguard() }
-func stack2688() (uintptr, uintptr) { var buf [2688]byte; use(buf[:]); return Stackguard() }
-func stack2692() (uintptr, uintptr) { var buf [2692]byte; use(buf[:]); return Stackguard() }
-func stack2696() (uintptr, uintptr) { var buf [2696]byte; use(buf[:]); return Stackguard() }
-func stack2700() (uintptr, uintptr) { var buf [2700]byte; use(buf[:]); return Stackguard() }
-func stack2704() (uintptr, uintptr) { var buf [2704]byte; use(buf[:]); return Stackguard() }
-func stack2708() (uintptr, uintptr) { var buf [2708]byte; use(buf[:]); return Stackguard() }
-func stack2712() (uintptr, uintptr) { var buf [2712]byte; use(buf[:]); return Stackguard() }
-func stack2716() (uintptr, uintptr) { var buf [2716]byte; use(buf[:]); return Stackguard() }
-func stack2720() (uintptr, uintptr) { var buf [2720]byte; use(buf[:]); return Stackguard() }
-func stack2724() (uintptr, uintptr) { var buf [2724]byte; use(buf[:]); return Stackguard() }
-func stack2728() (uintptr, uintptr) { var buf [2728]byte; use(buf[:]); return Stackguard() }
-func stack2732() (uintptr, uintptr) { var buf [2732]byte; use(buf[:]); return Stackguard() }
-func stack2736() (uintptr, uintptr) { var buf [2736]byte; use(buf[:]); return Stackguard() }
-func stack2740() (uintptr, uintptr) { var buf [2740]byte; use(buf[:]); return Stackguard() }
-func stack2744() (uintptr, uintptr) { var buf [2744]byte; use(buf[:]); return Stackguard() }
-func stack2748() (uintptr, uintptr) { var buf [2748]byte; use(buf[:]); return Stackguard() }
-func stack2752() (uintptr, uintptr) { var buf [2752]byte; use(buf[:]); return Stackguard() }
-func stack2756() (uintptr, uintptr) { var buf [2756]byte; use(buf[:]); return Stackguard() }
-func stack2760() (uintptr, uintptr) { var buf [2760]byte; use(buf[:]); return Stackguard() }
-func stack2764() (uintptr, uintptr) { var buf [2764]byte; use(buf[:]); return Stackguard() }
-func stack2768() (uintptr, uintptr) { var buf [2768]byte; use(buf[:]); return Stackguard() }
-func stack2772() (uintptr, uintptr) { var buf [2772]byte; use(buf[:]); return Stackguard() }
-func stack2776() (uintptr, uintptr) { var buf [2776]byte; use(buf[:]); return Stackguard() }
-func stack2780() (uintptr, uintptr) { var buf [2780]byte; use(buf[:]); return Stackguard() }
-func stack2784() (uintptr, uintptr) { var buf [2784]byte; use(buf[:]); return Stackguard() }
-func stack2788() (uintptr, uintptr) { var buf [2788]byte; use(buf[:]); return Stackguard() }
-func stack2792() (uintptr, uintptr) { var buf [2792]byte; use(buf[:]); return Stackguard() }
-func stack2796() (uintptr, uintptr) { var buf [2796]byte; use(buf[:]); return Stackguard() }
-func stack2800() (uintptr, uintptr) { var buf [2800]byte; use(buf[:]); return Stackguard() }
-func stack2804() (uintptr, uintptr) { var buf [2804]byte; use(buf[:]); return Stackguard() }
-func stack2808() (uintptr, uintptr) { var buf [2808]byte; use(buf[:]); return Stackguard() }
-func stack2812() (uintptr, uintptr) { var buf [2812]byte; use(buf[:]); return Stackguard() }
-func stack2816() (uintptr, uintptr) { var buf [2816]byte; use(buf[:]); return Stackguard() }
-func stack2820() (uintptr, uintptr) { var buf [2820]byte; use(buf[:]); return Stackguard() }
-func stack2824() (uintptr, uintptr) { var buf [2824]byte; use(buf[:]); return Stackguard() }
-func stack2828() (uintptr, uintptr) { var buf [2828]byte; use(buf[:]); return Stackguard() }
-func stack2832() (uintptr, uintptr) { var buf [2832]byte; use(buf[:]); return Stackguard() }
-func stack2836() (uintptr, uintptr) { var buf [2836]byte; use(buf[:]); return Stackguard() }
-func stack2840() (uintptr, uintptr) { var buf [2840]byte; use(buf[:]); return Stackguard() }
-func stack2844() (uintptr, uintptr) { var buf [2844]byte; use(buf[:]); return Stackguard() }
-func stack2848() (uintptr, uintptr) { var buf [2848]byte; use(buf[:]); return Stackguard() }
-func stack2852() (uintptr, uintptr) { var buf [2852]byte; use(buf[:]); return Stackguard() }
-func stack2856() (uintptr, uintptr) { var buf [2856]byte; use(buf[:]); return Stackguard() }
-func stack2860() (uintptr, uintptr) { var buf [2860]byte; use(buf[:]); return Stackguard() }
-func stack2864() (uintptr, uintptr) { var buf [2864]byte; use(buf[:]); return Stackguard() }
-func stack2868() (uintptr, uintptr) { var buf [2868]byte; use(buf[:]); return Stackguard() }
-func stack2872() (uintptr, uintptr) { var buf [2872]byte; use(buf[:]); return Stackguard() }
-func stack2876() (uintptr, uintptr) { var buf [2876]byte; use(buf[:]); return Stackguard() }
-func stack2880() (uintptr, uintptr) { var buf [2880]byte; use(buf[:]); return Stackguard() }
-func stack2884() (uintptr, uintptr) { var buf [2884]byte; use(buf[:]); return Stackguard() }
-func stack2888() (uintptr, uintptr) { var buf [2888]byte; use(buf[:]); return Stackguard() }
-func stack2892() (uintptr, uintptr) { var buf [2892]byte; use(buf[:]); return Stackguard() }
-func stack2896() (uintptr, uintptr) { var buf [2896]byte; use(buf[:]); return Stackguard() }
-func stack2900() (uintptr, uintptr) { var buf [2900]byte; use(buf[:]); return Stackguard() }
-func stack2904() (uintptr, uintptr) { var buf [2904]byte; use(buf[:]); return Stackguard() }
-func stack2908() (uintptr, uintptr) { var buf [2908]byte; use(buf[:]); return Stackguard() }
-func stack2912() (uintptr, uintptr) { var buf [2912]byte; use(buf[:]); return Stackguard() }
-func stack2916() (uintptr, uintptr) { var buf [2916]byte; use(buf[:]); return Stackguard() }
-func stack2920() (uintptr, uintptr) { var buf [2920]byte; use(buf[:]); return Stackguard() }
-func stack2924() (uintptr, uintptr) { var buf [2924]byte; use(buf[:]); return Stackguard() }
-func stack2928() (uintptr, uintptr) { var buf [2928]byte; use(buf[:]); return Stackguard() }
-func stack2932() (uintptr, uintptr) { var buf [2932]byte; use(buf[:]); return Stackguard() }
-func stack2936() (uintptr, uintptr) { var buf [2936]byte; use(buf[:]); return Stackguard() }
-func stack2940() (uintptr, uintptr) { var buf [2940]byte; use(buf[:]); return Stackguard() }
-func stack2944() (uintptr, uintptr) { var buf [2944]byte; use(buf[:]); return Stackguard() }
-func stack2948() (uintptr, uintptr) { var buf [2948]byte; use(buf[:]); return Stackguard() }
-func stack2952() (uintptr, uintptr) { var buf [2952]byte; use(buf[:]); return Stackguard() }
-func stack2956() (uintptr, uintptr) { var buf [2956]byte; use(buf[:]); return Stackguard() }
-func stack2960() (uintptr, uintptr) { var buf [2960]byte; use(buf[:]); return Stackguard() }
-func stack2964() (uintptr, uintptr) { var buf [2964]byte; use(buf[:]); return Stackguard() }
-func stack2968() (uintptr, uintptr) { var buf [2968]byte; use(buf[:]); return Stackguard() }
-func stack2972() (uintptr, uintptr) { var buf [2972]byte; use(buf[:]); return Stackguard() }
-func stack2976() (uintptr, uintptr) { var buf [2976]byte; use(buf[:]); return Stackguard() }
-func stack2980() (uintptr, uintptr) { var buf [2980]byte; use(buf[:]); return Stackguard() }
-func stack2984() (uintptr, uintptr) { var buf [2984]byte; use(buf[:]); return Stackguard() }
-func stack2988() (uintptr, uintptr) { var buf [2988]byte; use(buf[:]); return Stackguard() }
-func stack2992() (uintptr, uintptr) { var buf [2992]byte; use(buf[:]); return Stackguard() }
-func stack2996() (uintptr, uintptr) { var buf [2996]byte; use(buf[:]); return Stackguard() }
-func stack3000() (uintptr, uintptr) { var buf [3000]byte; use(buf[:]); return Stackguard() }
-func stack3004() (uintptr, uintptr) { var buf [3004]byte; use(buf[:]); return Stackguard() }
-func stack3008() (uintptr, uintptr) { var buf [3008]byte; use(buf[:]); return Stackguard() }
-func stack3012() (uintptr, uintptr) { var buf [3012]byte; use(buf[:]); return Stackguard() }
-func stack3016() (uintptr, uintptr) { var buf [3016]byte; use(buf[:]); return Stackguard() }
-func stack3020() (uintptr, uintptr) { var buf [3020]byte; use(buf[:]); return Stackguard() }
-func stack3024() (uintptr, uintptr) { var buf [3024]byte; use(buf[:]); return Stackguard() }
-func stack3028() (uintptr, uintptr) { var buf [3028]byte; use(buf[:]); return Stackguard() }
-func stack3032() (uintptr, uintptr) { var buf [3032]byte; use(buf[:]); return Stackguard() }
-func stack3036() (uintptr, uintptr) { var buf [3036]byte; use(buf[:]); return Stackguard() }
-func stack3040() (uintptr, uintptr) { var buf [3040]byte; use(buf[:]); return Stackguard() }
-func stack3044() (uintptr, uintptr) { var buf [3044]byte; use(buf[:]); return Stackguard() }
-func stack3048() (uintptr, uintptr) { var buf [3048]byte; use(buf[:]); return Stackguard() }
-func stack3052() (uintptr, uintptr) { var buf [3052]byte; use(buf[:]); return Stackguard() }
-func stack3056() (uintptr, uintptr) { var buf [3056]byte; use(buf[:]); return Stackguard() }
-func stack3060() (uintptr, uintptr) { var buf [3060]byte; use(buf[:]); return Stackguard() }
-func stack3064() (uintptr, uintptr) { var buf [3064]byte; use(buf[:]); return Stackguard() }
-func stack3068() (uintptr, uintptr) { var buf [3068]byte; use(buf[:]); return Stackguard() }
-func stack3072() (uintptr, uintptr) { var buf [3072]byte; use(buf[:]); return Stackguard() }
-func stack3076() (uintptr, uintptr) { var buf [3076]byte; use(buf[:]); return Stackguard() }
-func stack3080() (uintptr, uintptr) { var buf [3080]byte; use(buf[:]); return Stackguard() }
-func stack3084() (uintptr, uintptr) { var buf [3084]byte; use(buf[:]); return Stackguard() }
-func stack3088() (uintptr, uintptr) { var buf [3088]byte; use(buf[:]); return Stackguard() }
-func stack3092() (uintptr, uintptr) { var buf [3092]byte; use(buf[:]); return Stackguard() }
-func stack3096() (uintptr, uintptr) { var buf [3096]byte; use(buf[:]); return Stackguard() }
-func stack3100() (uintptr, uintptr) { var buf [3100]byte; use(buf[:]); return Stackguard() }
-func stack3104() (uintptr, uintptr) { var buf [3104]byte; use(buf[:]); return Stackguard() }
-func stack3108() (uintptr, uintptr) { var buf [3108]byte; use(buf[:]); return Stackguard() }
-func stack3112() (uintptr, uintptr) { var buf [3112]byte; use(buf[:]); return Stackguard() }
-func stack3116() (uintptr, uintptr) { var buf [3116]byte; use(buf[:]); return Stackguard() }
-func stack3120() (uintptr, uintptr) { var buf [3120]byte; use(buf[:]); return Stackguard() }
-func stack3124() (uintptr, uintptr) { var buf [3124]byte; use(buf[:]); return Stackguard() }
-func stack3128() (uintptr, uintptr) { var buf [3128]byte; use(buf[:]); return Stackguard() }
-func stack3132() (uintptr, uintptr) { var buf [3132]byte; use(buf[:]); return Stackguard() }
-func stack3136() (uintptr, uintptr) { var buf [3136]byte; use(buf[:]); return Stackguard() }
-func stack3140() (uintptr, uintptr) { var buf [3140]byte; use(buf[:]); return Stackguard() }
-func stack3144() (uintptr, uintptr) { var buf [3144]byte; use(buf[:]); return Stackguard() }
-func stack3148() (uintptr, uintptr) { var buf [3148]byte; use(buf[:]); return Stackguard() }
-func stack3152() (uintptr, uintptr) { var buf [3152]byte; use(buf[:]); return Stackguard() }
-func stack3156() (uintptr, uintptr) { var buf [3156]byte; use(buf[:]); return Stackguard() }
-func stack3160() (uintptr, uintptr) { var buf [3160]byte; use(buf[:]); return Stackguard() }
-func stack3164() (uintptr, uintptr) { var buf [3164]byte; use(buf[:]); return Stackguard() }
-func stack3168() (uintptr, uintptr) { var buf [3168]byte; use(buf[:]); return Stackguard() }
-func stack3172() (uintptr, uintptr) { var buf [3172]byte; use(buf[:]); return Stackguard() }
-func stack3176() (uintptr, uintptr) { var buf [3176]byte; use(buf[:]); return Stackguard() }
-func stack3180() (uintptr, uintptr) { var buf [3180]byte; use(buf[:]); return Stackguard() }
-func stack3184() (uintptr, uintptr) { var buf [3184]byte; use(buf[:]); return Stackguard() }
-func stack3188() (uintptr, uintptr) { var buf [3188]byte; use(buf[:]); return Stackguard() }
-func stack3192() (uintptr, uintptr) { var buf [3192]byte; use(buf[:]); return Stackguard() }
-func stack3196() (uintptr, uintptr) { var buf [3196]byte; use(buf[:]); return Stackguard() }
-func stack3200() (uintptr, uintptr) { var buf [3200]byte; use(buf[:]); return Stackguard() }
-func stack3204() (uintptr, uintptr) { var buf [3204]byte; use(buf[:]); return Stackguard() }
-func stack3208() (uintptr, uintptr) { var buf [3208]byte; use(buf[:]); return Stackguard() }
-func stack3212() (uintptr, uintptr) { var buf [3212]byte; use(buf[:]); return Stackguard() }
-func stack3216() (uintptr, uintptr) { var buf [3216]byte; use(buf[:]); return Stackguard() }
-func stack3220() (uintptr, uintptr) { var buf [3220]byte; use(buf[:]); return Stackguard() }
-func stack3224() (uintptr, uintptr) { var buf [3224]byte; use(buf[:]); return Stackguard() }
-func stack3228() (uintptr, uintptr) { var buf [3228]byte; use(buf[:]); return Stackguard() }
-func stack3232() (uintptr, uintptr) { var buf [3232]byte; use(buf[:]); return Stackguard() }
-func stack3236() (uintptr, uintptr) { var buf [3236]byte; use(buf[:]); return Stackguard() }
-func stack3240() (uintptr, uintptr) { var buf [3240]byte; use(buf[:]); return Stackguard() }
-func stack3244() (uintptr, uintptr) { var buf [3244]byte; use(buf[:]); return Stackguard() }
-func stack3248() (uintptr, uintptr) { var buf [3248]byte; use(buf[:]); return Stackguard() }
-func stack3252() (uintptr, uintptr) { var buf [3252]byte; use(buf[:]); return Stackguard() }
-func stack3256() (uintptr, uintptr) { var buf [3256]byte; use(buf[:]); return Stackguard() }
-func stack3260() (uintptr, uintptr) { var buf [3260]byte; use(buf[:]); return Stackguard() }
-func stack3264() (uintptr, uintptr) { var buf [3264]byte; use(buf[:]); return Stackguard() }
-func stack3268() (uintptr, uintptr) { var buf [3268]byte; use(buf[:]); return Stackguard() }
-func stack3272() (uintptr, uintptr) { var buf [3272]byte; use(buf[:]); return Stackguard() }
-func stack3276() (uintptr, uintptr) { var buf [3276]byte; use(buf[:]); return Stackguard() }
-func stack3280() (uintptr, uintptr) { var buf [3280]byte; use(buf[:]); return Stackguard() }
-func stack3284() (uintptr, uintptr) { var buf [3284]byte; use(buf[:]); return Stackguard() }
-func stack3288() (uintptr, uintptr) { var buf [3288]byte; use(buf[:]); return Stackguard() }
-func stack3292() (uintptr, uintptr) { var buf [3292]byte; use(buf[:]); return Stackguard() }
-func stack3296() (uintptr, uintptr) { var buf [3296]byte; use(buf[:]); return Stackguard() }
-func stack3300() (uintptr, uintptr) { var buf [3300]byte; use(buf[:]); return Stackguard() }
-func stack3304() (uintptr, uintptr) { var buf [3304]byte; use(buf[:]); return Stackguard() }
-func stack3308() (uintptr, uintptr) { var buf [3308]byte; use(buf[:]); return Stackguard() }
-func stack3312() (uintptr, uintptr) { var buf [3312]byte; use(buf[:]); return Stackguard() }
-func stack3316() (uintptr, uintptr) { var buf [3316]byte; use(buf[:]); return Stackguard() }
-func stack3320() (uintptr, uintptr) { var buf [3320]byte; use(buf[:]); return Stackguard() }
-func stack3324() (uintptr, uintptr) { var buf [3324]byte; use(buf[:]); return Stackguard() }
-func stack3328() (uintptr, uintptr) { var buf [3328]byte; use(buf[:]); return Stackguard() }
-func stack3332() (uintptr, uintptr) { var buf [3332]byte; use(buf[:]); return Stackguard() }
-func stack3336() (uintptr, uintptr) { var buf [3336]byte; use(buf[:]); return Stackguard() }
-func stack3340() (uintptr, uintptr) { var buf [3340]byte; use(buf[:]); return Stackguard() }
-func stack3344() (uintptr, uintptr) { var buf [3344]byte; use(buf[:]); return Stackguard() }
-func stack3348() (uintptr, uintptr) { var buf [3348]byte; use(buf[:]); return Stackguard() }
-func stack3352() (uintptr, uintptr) { var buf [3352]byte; use(buf[:]); return Stackguard() }
-func stack3356() (uintptr, uintptr) { var buf [3356]byte; use(buf[:]); return Stackguard() }
-func stack3360() (uintptr, uintptr) { var buf [3360]byte; use(buf[:]); return Stackguard() }
-func stack3364() (uintptr, uintptr) { var buf [3364]byte; use(buf[:]); return Stackguard() }
-func stack3368() (uintptr, uintptr) { var buf [3368]byte; use(buf[:]); return Stackguard() }
-func stack3372() (uintptr, uintptr) { var buf [3372]byte; use(buf[:]); return Stackguard() }
-func stack3376() (uintptr, uintptr) { var buf [3376]byte; use(buf[:]); return Stackguard() }
-func stack3380() (uintptr, uintptr) { var buf [3380]byte; use(buf[:]); return Stackguard() }
-func stack3384() (uintptr, uintptr) { var buf [3384]byte; use(buf[:]); return Stackguard() }
-func stack3388() (uintptr, uintptr) { var buf [3388]byte; use(buf[:]); return Stackguard() }
-func stack3392() (uintptr, uintptr) { var buf [3392]byte; use(buf[:]); return Stackguard() }
-func stack3396() (uintptr, uintptr) { var buf [3396]byte; use(buf[:]); return Stackguard() }
-func stack3400() (uintptr, uintptr) { var buf [3400]byte; use(buf[:]); return Stackguard() }
-func stack3404() (uintptr, uintptr) { var buf [3404]byte; use(buf[:]); return Stackguard() }
-func stack3408() (uintptr, uintptr) { var buf [3408]byte; use(buf[:]); return Stackguard() }
-func stack3412() (uintptr, uintptr) { var buf [3412]byte; use(buf[:]); return Stackguard() }
-func stack3416() (uintptr, uintptr) { var buf [3416]byte; use(buf[:]); return Stackguard() }
-func stack3420() (uintptr, uintptr) { var buf [3420]byte; use(buf[:]); return Stackguard() }
-func stack3424() (uintptr, uintptr) { var buf [3424]byte; use(buf[:]); return Stackguard() }
-func stack3428() (uintptr, uintptr) { var buf [3428]byte; use(buf[:]); return Stackguard() }
-func stack3432() (uintptr, uintptr) { var buf [3432]byte; use(buf[:]); return Stackguard() }
-func stack3436() (uintptr, uintptr) { var buf [3436]byte; use(buf[:]); return Stackguard() }
-func stack3440() (uintptr, uintptr) { var buf [3440]byte; use(buf[:]); return Stackguard() }
-func stack3444() (uintptr, uintptr) { var buf [3444]byte; use(buf[:]); return Stackguard() }
-func stack3448() (uintptr, uintptr) { var buf [3448]byte; use(buf[:]); return Stackguard() }
-func stack3452() (uintptr, uintptr) { var buf [3452]byte; use(buf[:]); return Stackguard() }
-func stack3456() (uintptr, uintptr) { var buf [3456]byte; use(buf[:]); return Stackguard() }
-func stack3460() (uintptr, uintptr) { var buf [3460]byte; use(buf[:]); return Stackguard() }
-func stack3464() (uintptr, uintptr) { var buf [3464]byte; use(buf[:]); return Stackguard() }
-func stack3468() (uintptr, uintptr) { var buf [3468]byte; use(buf[:]); return Stackguard() }
-func stack3472() (uintptr, uintptr) { var buf [3472]byte; use(buf[:]); return Stackguard() }
-func stack3476() (uintptr, uintptr) { var buf [3476]byte; use(buf[:]); return Stackguard() }
-func stack3480() (uintptr, uintptr) { var buf [3480]byte; use(buf[:]); return Stackguard() }
-func stack3484() (uintptr, uintptr) { var buf [3484]byte; use(buf[:]); return Stackguard() }
-func stack3488() (uintptr, uintptr) { var buf [3488]byte; use(buf[:]); return Stackguard() }
-func stack3492() (uintptr, uintptr) { var buf [3492]byte; use(buf[:]); return Stackguard() }
-func stack3496() (uintptr, uintptr) { var buf [3496]byte; use(buf[:]); return Stackguard() }
-func stack3500() (uintptr, uintptr) { var buf [3500]byte; use(buf[:]); return Stackguard() }
-func stack3504() (uintptr, uintptr) { var buf [3504]byte; use(buf[:]); return Stackguard() }
-func stack3508() (uintptr, uintptr) { var buf [3508]byte; use(buf[:]); return Stackguard() }
-func stack3512() (uintptr, uintptr) { var buf [3512]byte; use(buf[:]); return Stackguard() }
-func stack3516() (uintptr, uintptr) { var buf [3516]byte; use(buf[:]); return Stackguard() }
-func stack3520() (uintptr, uintptr) { var buf [3520]byte; use(buf[:]); return Stackguard() }
-func stack3524() (uintptr, uintptr) { var buf [3524]byte; use(buf[:]); return Stackguard() }
-func stack3528() (uintptr, uintptr) { var buf [3528]byte; use(buf[:]); return Stackguard() }
-func stack3532() (uintptr, uintptr) { var buf [3532]byte; use(buf[:]); return Stackguard() }
-func stack3536() (uintptr, uintptr) { var buf [3536]byte; use(buf[:]); return Stackguard() }
-func stack3540() (uintptr, uintptr) { var buf [3540]byte; use(buf[:]); return Stackguard() }
-func stack3544() (uintptr, uintptr) { var buf [3544]byte; use(buf[:]); return Stackguard() }
-func stack3548() (uintptr, uintptr) { var buf [3548]byte; use(buf[:]); return Stackguard() }
-func stack3552() (uintptr, uintptr) { var buf [3552]byte; use(buf[:]); return Stackguard() }
-func stack3556() (uintptr, uintptr) { var buf [3556]byte; use(buf[:]); return Stackguard() }
-func stack3560() (uintptr, uintptr) { var buf [3560]byte; use(buf[:]); return Stackguard() }
-func stack3564() (uintptr, uintptr) { var buf [3564]byte; use(buf[:]); return Stackguard() }
-func stack3568() (uintptr, uintptr) { var buf [3568]byte; use(buf[:]); return Stackguard() }
-func stack3572() (uintptr, uintptr) { var buf [3572]byte; use(buf[:]); return Stackguard() }
-func stack3576() (uintptr, uintptr) { var buf [3576]byte; use(buf[:]); return Stackguard() }
-func stack3580() (uintptr, uintptr) { var buf [3580]byte; use(buf[:]); return Stackguard() }
-func stack3584() (uintptr, uintptr) { var buf [3584]byte; use(buf[:]); return Stackguard() }
-func stack3588() (uintptr, uintptr) { var buf [3588]byte; use(buf[:]); return Stackguard() }
-func stack3592() (uintptr, uintptr) { var buf [3592]byte; use(buf[:]); return Stackguard() }
-func stack3596() (uintptr, uintptr) { var buf [3596]byte; use(buf[:]); return Stackguard() }
-func stack3600() (uintptr, uintptr) { var buf [3600]byte; use(buf[:]); return Stackguard() }
-func stack3604() (uintptr, uintptr) { var buf [3604]byte; use(buf[:]); return Stackguard() }
-func stack3608() (uintptr, uintptr) { var buf [3608]byte; use(buf[:]); return Stackguard() }
-func stack3612() (uintptr, uintptr) { var buf [3612]byte; use(buf[:]); return Stackguard() }
-func stack3616() (uintptr, uintptr) { var buf [3616]byte; use(buf[:]); return Stackguard() }
-func stack3620() (uintptr, uintptr) { var buf [3620]byte; use(buf[:]); return Stackguard() }
-func stack3624() (uintptr, uintptr) { var buf [3624]byte; use(buf[:]); return Stackguard() }
-func stack3628() (uintptr, uintptr) { var buf [3628]byte; use(buf[:]); return Stackguard() }
-func stack3632() (uintptr, uintptr) { var buf [3632]byte; use(buf[:]); return Stackguard() }
-func stack3636() (uintptr, uintptr) { var buf [3636]byte; use(buf[:]); return Stackguard() }
-func stack3640() (uintptr, uintptr) { var buf [3640]byte; use(buf[:]); return Stackguard() }
-func stack3644() (uintptr, uintptr) { var buf [3644]byte; use(buf[:]); return Stackguard() }
-func stack3648() (uintptr, uintptr) { var buf [3648]byte; use(buf[:]); return Stackguard() }
-func stack3652() (uintptr, uintptr) { var buf [3652]byte; use(buf[:]); return Stackguard() }
-func stack3656() (uintptr, uintptr) { var buf [3656]byte; use(buf[:]); return Stackguard() }
-func stack3660() (uintptr, uintptr) { var buf [3660]byte; use(buf[:]); return Stackguard() }
-func stack3664() (uintptr, uintptr) { var buf [3664]byte; use(buf[:]); return Stackguard() }
-func stack3668() (uintptr, uintptr) { var buf [3668]byte; use(buf[:]); return Stackguard() }
-func stack3672() (uintptr, uintptr) { var buf [3672]byte; use(buf[:]); return Stackguard() }
-func stack3676() (uintptr, uintptr) { var buf [3676]byte; use(buf[:]); return Stackguard() }
-func stack3680() (uintptr, uintptr) { var buf [3680]byte; use(buf[:]); return Stackguard() }
-func stack3684() (uintptr, uintptr) { var buf [3684]byte; use(buf[:]); return Stackguard() }
-func stack3688() (uintptr, uintptr) { var buf [3688]byte; use(buf[:]); return Stackguard() }
-func stack3692() (uintptr, uintptr) { var buf [3692]byte; use(buf[:]); return Stackguard() }
-func stack3696() (uintptr, uintptr) { var buf [3696]byte; use(buf[:]); return Stackguard() }
-func stack3700() (uintptr, uintptr) { var buf [3700]byte; use(buf[:]); return Stackguard() }
-func stack3704() (uintptr, uintptr) { var buf [3704]byte; use(buf[:]); return Stackguard() }
-func stack3708() (uintptr, uintptr) { var buf [3708]byte; use(buf[:]); return Stackguard() }
-func stack3712() (uintptr, uintptr) { var buf [3712]byte; use(buf[:]); return Stackguard() }
-func stack3716() (uintptr, uintptr) { var buf [3716]byte; use(buf[:]); return Stackguard() }
-func stack3720() (uintptr, uintptr) { var buf [3720]byte; use(buf[:]); return Stackguard() }
-func stack3724() (uintptr, uintptr) { var buf [3724]byte; use(buf[:]); return Stackguard() }
-func stack3728() (uintptr, uintptr) { var buf [3728]byte; use(buf[:]); return Stackguard() }
-func stack3732() (uintptr, uintptr) { var buf [3732]byte; use(buf[:]); return Stackguard() }
-func stack3736() (uintptr, uintptr) { var buf [3736]byte; use(buf[:]); return Stackguard() }
-func stack3740() (uintptr, uintptr) { var buf [3740]byte; use(buf[:]); return Stackguard() }
-func stack3744() (uintptr, uintptr) { var buf [3744]byte; use(buf[:]); return Stackguard() }
-func stack3748() (uintptr, uintptr) { var buf [3748]byte; use(buf[:]); return Stackguard() }
-func stack3752() (uintptr, uintptr) { var buf [3752]byte; use(buf[:]); return Stackguard() }
-func stack3756() (uintptr, uintptr) { var buf [3756]byte; use(buf[:]); return Stackguard() }
-func stack3760() (uintptr, uintptr) { var buf [3760]byte; use(buf[:]); return Stackguard() }
-func stack3764() (uintptr, uintptr) { var buf [3764]byte; use(buf[:]); return Stackguard() }
-func stack3768() (uintptr, uintptr) { var buf [3768]byte; use(buf[:]); return Stackguard() }
-func stack3772() (uintptr, uintptr) { var buf [3772]byte; use(buf[:]); return Stackguard() }
-func stack3776() (uintptr, uintptr) { var buf [3776]byte; use(buf[:]); return Stackguard() }
-func stack3780() (uintptr, uintptr) { var buf [3780]byte; use(buf[:]); return Stackguard() }
-func stack3784() (uintptr, uintptr) { var buf [3784]byte; use(buf[:]); return Stackguard() }
-func stack3788() (uintptr, uintptr) { var buf [3788]byte; use(buf[:]); return Stackguard() }
-func stack3792() (uintptr, uintptr) { var buf [3792]byte; use(buf[:]); return Stackguard() }
-func stack3796() (uintptr, uintptr) { var buf [3796]byte; use(buf[:]); return Stackguard() }
-func stack3800() (uintptr, uintptr) { var buf [3800]byte; use(buf[:]); return Stackguard() }
-func stack3804() (uintptr, uintptr) { var buf [3804]byte; use(buf[:]); return Stackguard() }
-func stack3808() (uintptr, uintptr) { var buf [3808]byte; use(buf[:]); return Stackguard() }
-func stack3812() (uintptr, uintptr) { var buf [3812]byte; use(buf[:]); return Stackguard() }
-func stack3816() (uintptr, uintptr) { var buf [3816]byte; use(buf[:]); return Stackguard() }
-func stack3820() (uintptr, uintptr) { var buf [3820]byte; use(buf[:]); return Stackguard() }
-func stack3824() (uintptr, uintptr) { var buf [3824]byte; use(buf[:]); return Stackguard() }
-func stack3828() (uintptr, uintptr) { var buf [3828]byte; use(buf[:]); return Stackguard() }
-func stack3832() (uintptr, uintptr) { var buf [3832]byte; use(buf[:]); return Stackguard() }
-func stack3836() (uintptr, uintptr) { var buf [3836]byte; use(buf[:]); return Stackguard() }
-func stack3840() (uintptr, uintptr) { var buf [3840]byte; use(buf[:]); return Stackguard() }
-func stack3844() (uintptr, uintptr) { var buf [3844]byte; use(buf[:]); return Stackguard() }
-func stack3848() (uintptr, uintptr) { var buf [3848]byte; use(buf[:]); return Stackguard() }
-func stack3852() (uintptr, uintptr) { var buf [3852]byte; use(buf[:]); return Stackguard() }
-func stack3856() (uintptr, uintptr) { var buf [3856]byte; use(buf[:]); return Stackguard() }
-func stack3860() (uintptr, uintptr) { var buf [3860]byte; use(buf[:]); return Stackguard() }
-func stack3864() (uintptr, uintptr) { var buf [3864]byte; use(buf[:]); return Stackguard() }
-func stack3868() (uintptr, uintptr) { var buf [3868]byte; use(buf[:]); return Stackguard() }
-func stack3872() (uintptr, uintptr) { var buf [3872]byte; use(buf[:]); return Stackguard() }
-func stack3876() (uintptr, uintptr) { var buf [3876]byte; use(buf[:]); return Stackguard() }
-func stack3880() (uintptr, uintptr) { var buf [3880]byte; use(buf[:]); return Stackguard() }
-func stack3884() (uintptr, uintptr) { var buf [3884]byte; use(buf[:]); return Stackguard() }
-func stack3888() (uintptr, uintptr) { var buf [3888]byte; use(buf[:]); return Stackguard() }
-func stack3892() (uintptr, uintptr) { var buf [3892]byte; use(buf[:]); return Stackguard() }
-func stack3896() (uintptr, uintptr) { var buf [3896]byte; use(buf[:]); return Stackguard() }
-func stack3900() (uintptr, uintptr) { var buf [3900]byte; use(buf[:]); return Stackguard() }
-func stack3904() (uintptr, uintptr) { var buf [3904]byte; use(buf[:]); return Stackguard() }
-func stack3908() (uintptr, uintptr) { var buf [3908]byte; use(buf[:]); return Stackguard() }
-func stack3912() (uintptr, uintptr) { var buf [3912]byte; use(buf[:]); return Stackguard() }
-func stack3916() (uintptr, uintptr) { var buf [3916]byte; use(buf[:]); return Stackguard() }
-func stack3920() (uintptr, uintptr) { var buf [3920]byte; use(buf[:]); return Stackguard() }
-func stack3924() (uintptr, uintptr) { var buf [3924]byte; use(buf[:]); return Stackguard() }
-func stack3928() (uintptr, uintptr) { var buf [3928]byte; use(buf[:]); return Stackguard() }
-func stack3932() (uintptr, uintptr) { var buf [3932]byte; use(buf[:]); return Stackguard() }
-func stack3936() (uintptr, uintptr) { var buf [3936]byte; use(buf[:]); return Stackguard() }
-func stack3940() (uintptr, uintptr) { var buf [3940]byte; use(buf[:]); return Stackguard() }
-func stack3944() (uintptr, uintptr) { var buf [3944]byte; use(buf[:]); return Stackguard() }
-func stack3948() (uintptr, uintptr) { var buf [3948]byte; use(buf[:]); return Stackguard() }
-func stack3952() (uintptr, uintptr) { var buf [3952]byte; use(buf[:]); return Stackguard() }
-func stack3956() (uintptr, uintptr) { var buf [3956]byte; use(buf[:]); return Stackguard() }
-func stack3960() (uintptr, uintptr) { var buf [3960]byte; use(buf[:]); return Stackguard() }
-func stack3964() (uintptr, uintptr) { var buf [3964]byte; use(buf[:]); return Stackguard() }
-func stack3968() (uintptr, uintptr) { var buf [3968]byte; use(buf[:]); return Stackguard() }
-func stack3972() (uintptr, uintptr) { var buf [3972]byte; use(buf[:]); return Stackguard() }
-func stack3976() (uintptr, uintptr) { var buf [3976]byte; use(buf[:]); return Stackguard() }
-func stack3980() (uintptr, uintptr) { var buf [3980]byte; use(buf[:]); return Stackguard() }
-func stack3984() (uintptr, uintptr) { var buf [3984]byte; use(buf[:]); return Stackguard() }
-func stack3988() (uintptr, uintptr) { var buf [3988]byte; use(buf[:]); return Stackguard() }
-func stack3992() (uintptr, uintptr) { var buf [3992]byte; use(buf[:]); return Stackguard() }
-func stack3996() (uintptr, uintptr) { var buf [3996]byte; use(buf[:]); return Stackguard() }
-func stack4000() (uintptr, uintptr) { var buf [4000]byte; use(buf[:]); return Stackguard() }
-func stack4004() (uintptr, uintptr) { var buf [4004]byte; use(buf[:]); return Stackguard() }
-func stack4008() (uintptr, uintptr) { var buf [4008]byte; use(buf[:]); return Stackguard() }
-func stack4012() (uintptr, uintptr) { var buf [4012]byte; use(buf[:]); return Stackguard() }
-func stack4016() (uintptr, uintptr) { var buf [4016]byte; use(buf[:]); return Stackguard() }
-func stack4020() (uintptr, uintptr) { var buf [4020]byte; use(buf[:]); return Stackguard() }
-func stack4024() (uintptr, uintptr) { var buf [4024]byte; use(buf[:]); return Stackguard() }
-func stack4028() (uintptr, uintptr) { var buf [4028]byte; use(buf[:]); return Stackguard() }
-func stack4032() (uintptr, uintptr) { var buf [4032]byte; use(buf[:]); return Stackguard() }
-func stack4036() (uintptr, uintptr) { var buf [4036]byte; use(buf[:]); return Stackguard() }
-func stack4040() (uintptr, uintptr) { var buf [4040]byte; use(buf[:]); return Stackguard() }
-func stack4044() (uintptr, uintptr) { var buf [4044]byte; use(buf[:]); return Stackguard() }
-func stack4048() (uintptr, uintptr) { var buf [4048]byte; use(buf[:]); return Stackguard() }
-func stack4052() (uintptr, uintptr) { var buf [4052]byte; use(buf[:]); return Stackguard() }
-func stack4056() (uintptr, uintptr) { var buf [4056]byte; use(buf[:]); return Stackguard() }
-func stack4060() (uintptr, uintptr) { var buf [4060]byte; use(buf[:]); return Stackguard() }
-func stack4064() (uintptr, uintptr) { var buf [4064]byte; use(buf[:]); return Stackguard() }
-func stack4068() (uintptr, uintptr) { var buf [4068]byte; use(buf[:]); return Stackguard() }
-func stack4072() (uintptr, uintptr) { var buf [4072]byte; use(buf[:]); return Stackguard() }
-func stack4076() (uintptr, uintptr) { var buf [4076]byte; use(buf[:]); return Stackguard() }
-func stack4080() (uintptr, uintptr) { var buf [4080]byte; use(buf[:]); return Stackguard() }
-func stack4084() (uintptr, uintptr) { var buf [4084]byte; use(buf[:]); return Stackguard() }
-func stack4088() (uintptr, uintptr) { var buf [4088]byte; use(buf[:]); return Stackguard() }
-func stack4092() (uintptr, uintptr) { var buf [4092]byte; use(buf[:]); return Stackguard() }
-func stack4096() (uintptr, uintptr) { var buf [4096]byte; use(buf[:]); return Stackguard() }
-func stack4100() (uintptr, uintptr) { var buf [4100]byte; use(buf[:]); return Stackguard() }
-func stack4104() (uintptr, uintptr) { var buf [4104]byte; use(buf[:]); return Stackguard() }
-func stack4108() (uintptr, uintptr) { var buf [4108]byte; use(buf[:]); return Stackguard() }
-func stack4112() (uintptr, uintptr) { var buf [4112]byte; use(buf[:]); return Stackguard() }
-func stack4116() (uintptr, uintptr) { var buf [4116]byte; use(buf[:]); return Stackguard() }
-func stack4120() (uintptr, uintptr) { var buf [4120]byte; use(buf[:]); return Stackguard() }
-func stack4124() (uintptr, uintptr) { var buf [4124]byte; use(buf[:]); return Stackguard() }
-func stack4128() (uintptr, uintptr) { var buf [4128]byte; use(buf[:]); return Stackguard() }
-func stack4132() (uintptr, uintptr) { var buf [4132]byte; use(buf[:]); return Stackguard() }
-func stack4136() (uintptr, uintptr) { var buf [4136]byte; use(buf[:]); return Stackguard() }
-func stack4140() (uintptr, uintptr) { var buf [4140]byte; use(buf[:]); return Stackguard() }
-func stack4144() (uintptr, uintptr) { var buf [4144]byte; use(buf[:]); return Stackguard() }
-func stack4148() (uintptr, uintptr) { var buf [4148]byte; use(buf[:]); return Stackguard() }
-func stack4152() (uintptr, uintptr) { var buf [4152]byte; use(buf[:]); return Stackguard() }
-func stack4156() (uintptr, uintptr) { var buf [4156]byte; use(buf[:]); return Stackguard() }
-func stack4160() (uintptr, uintptr) { var buf [4160]byte; use(buf[:]); return Stackguard() }
-func stack4164() (uintptr, uintptr) { var buf [4164]byte; use(buf[:]); return Stackguard() }
-func stack4168() (uintptr, uintptr) { var buf [4168]byte; use(buf[:]); return Stackguard() }
-func stack4172() (uintptr, uintptr) { var buf [4172]byte; use(buf[:]); return Stackguard() }
-func stack4176() (uintptr, uintptr) { var buf [4176]byte; use(buf[:]); return Stackguard() }
-func stack4180() (uintptr, uintptr) { var buf [4180]byte; use(buf[:]); return Stackguard() }
-func stack4184() (uintptr, uintptr) { var buf [4184]byte; use(buf[:]); return Stackguard() }
-func stack4188() (uintptr, uintptr) { var buf [4188]byte; use(buf[:]); return Stackguard() }
-func stack4192() (uintptr, uintptr) { var buf [4192]byte; use(buf[:]); return Stackguard() }
-func stack4196() (uintptr, uintptr) { var buf [4196]byte; use(buf[:]); return Stackguard() }
-func stack4200() (uintptr, uintptr) { var buf [4200]byte; use(buf[:]); return Stackguard() }
-func stack4204() (uintptr, uintptr) { var buf [4204]byte; use(buf[:]); return Stackguard() }
-func stack4208() (uintptr, uintptr) { var buf [4208]byte; use(buf[:]); return Stackguard() }
-func stack4212() (uintptr, uintptr) { var buf [4212]byte; use(buf[:]); return Stackguard() }
-func stack4216() (uintptr, uintptr) { var buf [4216]byte; use(buf[:]); return Stackguard() }
-func stack4220() (uintptr, uintptr) { var buf [4220]byte; use(buf[:]); return Stackguard() }
-func stack4224() (uintptr, uintptr) { var buf [4224]byte; use(buf[:]); return Stackguard() }
-func stack4228() (uintptr, uintptr) { var buf [4228]byte; use(buf[:]); return Stackguard() }
-func stack4232() (uintptr, uintptr) { var buf [4232]byte; use(buf[:]); return Stackguard() }
-func stack4236() (uintptr, uintptr) { var buf [4236]byte; use(buf[:]); return Stackguard() }
-func stack4240() (uintptr, uintptr) { var buf [4240]byte; use(buf[:]); return Stackguard() }
-func stack4244() (uintptr, uintptr) { var buf [4244]byte; use(buf[:]); return Stackguard() }
-func stack4248() (uintptr, uintptr) { var buf [4248]byte; use(buf[:]); return Stackguard() }
-func stack4252() (uintptr, uintptr) { var buf [4252]byte; use(buf[:]); return Stackguard() }
-func stack4256() (uintptr, uintptr) { var buf [4256]byte; use(buf[:]); return Stackguard() }
-func stack4260() (uintptr, uintptr) { var buf [4260]byte; use(buf[:]); return Stackguard() }
-func stack4264() (uintptr, uintptr) { var buf [4264]byte; use(buf[:]); return Stackguard() }
-func stack4268() (uintptr, uintptr) { var buf [4268]byte; use(buf[:]); return Stackguard() }
-func stack4272() (uintptr, uintptr) { var buf [4272]byte; use(buf[:]); return Stackguard() }
-func stack4276() (uintptr, uintptr) { var buf [4276]byte; use(buf[:]); return Stackguard() }
-func stack4280() (uintptr, uintptr) { var buf [4280]byte; use(buf[:]); return Stackguard() }
-func stack4284() (uintptr, uintptr) { var buf [4284]byte; use(buf[:]); return Stackguard() }
-func stack4288() (uintptr, uintptr) { var buf [4288]byte; use(buf[:]); return Stackguard() }
-func stack4292() (uintptr, uintptr) { var buf [4292]byte; use(buf[:]); return Stackguard() }
-func stack4296() (uintptr, uintptr) { var buf [4296]byte; use(buf[:]); return Stackguard() }
-func stack4300() (uintptr, uintptr) { var buf [4300]byte; use(buf[:]); return Stackguard() }
-func stack4304() (uintptr, uintptr) { var buf [4304]byte; use(buf[:]); return Stackguard() }
-func stack4308() (uintptr, uintptr) { var buf [4308]byte; use(buf[:]); return Stackguard() }
-func stack4312() (uintptr, uintptr) { var buf [4312]byte; use(buf[:]); return Stackguard() }
-func stack4316() (uintptr, uintptr) { var buf [4316]byte; use(buf[:]); return Stackguard() }
-func stack4320() (uintptr, uintptr) { var buf [4320]byte; use(buf[:]); return Stackguard() }
-func stack4324() (uintptr, uintptr) { var buf [4324]byte; use(buf[:]); return Stackguard() }
-func stack4328() (uintptr, uintptr) { var buf [4328]byte; use(buf[:]); return Stackguard() }
-func stack4332() (uintptr, uintptr) { var buf [4332]byte; use(buf[:]); return Stackguard() }
-func stack4336() (uintptr, uintptr) { var buf [4336]byte; use(buf[:]); return Stackguard() }
-func stack4340() (uintptr, uintptr) { var buf [4340]byte; use(buf[:]); return Stackguard() }
-func stack4344() (uintptr, uintptr) { var buf [4344]byte; use(buf[:]); return Stackguard() }
-func stack4348() (uintptr, uintptr) { var buf [4348]byte; use(buf[:]); return Stackguard() }
-func stack4352() (uintptr, uintptr) { var buf [4352]byte; use(buf[:]); return Stackguard() }
-func stack4356() (uintptr, uintptr) { var buf [4356]byte; use(buf[:]); return Stackguard() }
-func stack4360() (uintptr, uintptr) { var buf [4360]byte; use(buf[:]); return Stackguard() }
-func stack4364() (uintptr, uintptr) { var buf [4364]byte; use(buf[:]); return Stackguard() }
-func stack4368() (uintptr, uintptr) { var buf [4368]byte; use(buf[:]); return Stackguard() }
-func stack4372() (uintptr, uintptr) { var buf [4372]byte; use(buf[:]); return Stackguard() }
-func stack4376() (uintptr, uintptr) { var buf [4376]byte; use(buf[:]); return Stackguard() }
-func stack4380() (uintptr, uintptr) { var buf [4380]byte; use(buf[:]); return Stackguard() }
-func stack4384() (uintptr, uintptr) { var buf [4384]byte; use(buf[:]); return Stackguard() }
-func stack4388() (uintptr, uintptr) { var buf [4388]byte; use(buf[:]); return Stackguard() }
-func stack4392() (uintptr, uintptr) { var buf [4392]byte; use(buf[:]); return Stackguard() }
-func stack4396() (uintptr, uintptr) { var buf [4396]byte; use(buf[:]); return Stackguard() }
-func stack4400() (uintptr, uintptr) { var buf [4400]byte; use(buf[:]); return Stackguard() }
-func stack4404() (uintptr, uintptr) { var buf [4404]byte; use(buf[:]); return Stackguard() }
-func stack4408() (uintptr, uintptr) { var buf [4408]byte; use(buf[:]); return Stackguard() }
-func stack4412() (uintptr, uintptr) { var buf [4412]byte; use(buf[:]); return Stackguard() }
-func stack4416() (uintptr, uintptr) { var buf [4416]byte; use(buf[:]); return Stackguard() }
-func stack4420() (uintptr, uintptr) { var buf [4420]byte; use(buf[:]); return Stackguard() }
-func stack4424() (uintptr, uintptr) { var buf [4424]byte; use(buf[:]); return Stackguard() }
-func stack4428() (uintptr, uintptr) { var buf [4428]byte; use(buf[:]); return Stackguard() }
-func stack4432() (uintptr, uintptr) { var buf [4432]byte; use(buf[:]); return Stackguard() }
-func stack4436() (uintptr, uintptr) { var buf [4436]byte; use(buf[:]); return Stackguard() }
-func stack4440() (uintptr, uintptr) { var buf [4440]byte; use(buf[:]); return Stackguard() }
-func stack4444() (uintptr, uintptr) { var buf [4444]byte; use(buf[:]); return Stackguard() }
-func stack4448() (uintptr, uintptr) { var buf [4448]byte; use(buf[:]); return Stackguard() }
-func stack4452() (uintptr, uintptr) { var buf [4452]byte; use(buf[:]); return Stackguard() }
-func stack4456() (uintptr, uintptr) { var buf [4456]byte; use(buf[:]); return Stackguard() }
-func stack4460() (uintptr, uintptr) { var buf [4460]byte; use(buf[:]); return Stackguard() }
-func stack4464() (uintptr, uintptr) { var buf [4464]byte; use(buf[:]); return Stackguard() }
-func stack4468() (uintptr, uintptr) { var buf [4468]byte; use(buf[:]); return Stackguard() }
-func stack4472() (uintptr, uintptr) { var buf [4472]byte; use(buf[:]); return Stackguard() }
-func stack4476() (uintptr, uintptr) { var buf [4476]byte; use(buf[:]); return Stackguard() }
-func stack4480() (uintptr, uintptr) { var buf [4480]byte; use(buf[:]); return Stackguard() }
-func stack4484() (uintptr, uintptr) { var buf [4484]byte; use(buf[:]); return Stackguard() }
-func stack4488() (uintptr, uintptr) { var buf [4488]byte; use(buf[:]); return Stackguard() }
-func stack4492() (uintptr, uintptr) { var buf [4492]byte; use(buf[:]); return Stackguard() }
-func stack4496() (uintptr, uintptr) { var buf [4496]byte; use(buf[:]); return Stackguard() }
-func stack4500() (uintptr, uintptr) { var buf [4500]byte; use(buf[:]); return Stackguard() }
-func stack4504() (uintptr, uintptr) { var buf [4504]byte; use(buf[:]); return Stackguard() }
-func stack4508() (uintptr, uintptr) { var buf [4508]byte; use(buf[:]); return Stackguard() }
-func stack4512() (uintptr, uintptr) { var buf [4512]byte; use(buf[:]); return Stackguard() }
-func stack4516() (uintptr, uintptr) { var buf [4516]byte; use(buf[:]); return Stackguard() }
-func stack4520() (uintptr, uintptr) { var buf [4520]byte; use(buf[:]); return Stackguard() }
-func stack4524() (uintptr, uintptr) { var buf [4524]byte; use(buf[:]); return Stackguard() }
-func stack4528() (uintptr, uintptr) { var buf [4528]byte; use(buf[:]); return Stackguard() }
-func stack4532() (uintptr, uintptr) { var buf [4532]byte; use(buf[:]); return Stackguard() }
-func stack4536() (uintptr, uintptr) { var buf [4536]byte; use(buf[:]); return Stackguard() }
-func stack4540() (uintptr, uintptr) { var buf [4540]byte; use(buf[:]); return Stackguard() }
-func stack4544() (uintptr, uintptr) { var buf [4544]byte; use(buf[:]); return Stackguard() }
-func stack4548() (uintptr, uintptr) { var buf [4548]byte; use(buf[:]); return Stackguard() }
-func stack4552() (uintptr, uintptr) { var buf [4552]byte; use(buf[:]); return Stackguard() }
-func stack4556() (uintptr, uintptr) { var buf [4556]byte; use(buf[:]); return Stackguard() }
-func stack4560() (uintptr, uintptr) { var buf [4560]byte; use(buf[:]); return Stackguard() }
-func stack4564() (uintptr, uintptr) { var buf [4564]byte; use(buf[:]); return Stackguard() }
-func stack4568() (uintptr, uintptr) { var buf [4568]byte; use(buf[:]); return Stackguard() }
-func stack4572() (uintptr, uintptr) { var buf [4572]byte; use(buf[:]); return Stackguard() }
-func stack4576() (uintptr, uintptr) { var buf [4576]byte; use(buf[:]); return Stackguard() }
-func stack4580() (uintptr, uintptr) { var buf [4580]byte; use(buf[:]); return Stackguard() }
-func stack4584() (uintptr, uintptr) { var buf [4584]byte; use(buf[:]); return Stackguard() }
-func stack4588() (uintptr, uintptr) { var buf [4588]byte; use(buf[:]); return Stackguard() }
-func stack4592() (uintptr, uintptr) { var buf [4592]byte; use(buf[:]); return Stackguard() }
-func stack4596() (uintptr, uintptr) { var buf [4596]byte; use(buf[:]); return Stackguard() }
-func stack4600() (uintptr, uintptr) { var buf [4600]byte; use(buf[:]); return Stackguard() }
-func stack4604() (uintptr, uintptr) { var buf [4604]byte; use(buf[:]); return Stackguard() }
-func stack4608() (uintptr, uintptr) { var buf [4608]byte; use(buf[:]); return Stackguard() }
-func stack4612() (uintptr, uintptr) { var buf [4612]byte; use(buf[:]); return Stackguard() }
-func stack4616() (uintptr, uintptr) { var buf [4616]byte; use(buf[:]); return Stackguard() }
-func stack4620() (uintptr, uintptr) { var buf [4620]byte; use(buf[:]); return Stackguard() }
-func stack4624() (uintptr, uintptr) { var buf [4624]byte; use(buf[:]); return Stackguard() }
-func stack4628() (uintptr, uintptr) { var buf [4628]byte; use(buf[:]); return Stackguard() }
-func stack4632() (uintptr, uintptr) { var buf [4632]byte; use(buf[:]); return Stackguard() }
-func stack4636() (uintptr, uintptr) { var buf [4636]byte; use(buf[:]); return Stackguard() }
-func stack4640() (uintptr, uintptr) { var buf [4640]byte; use(buf[:]); return Stackguard() }
-func stack4644() (uintptr, uintptr) { var buf [4644]byte; use(buf[:]); return Stackguard() }
-func stack4648() (uintptr, uintptr) { var buf [4648]byte; use(buf[:]); return Stackguard() }
-func stack4652() (uintptr, uintptr) { var buf [4652]byte; use(buf[:]); return Stackguard() }
-func stack4656() (uintptr, uintptr) { var buf [4656]byte; use(buf[:]); return Stackguard() }
-func stack4660() (uintptr, uintptr) { var buf [4660]byte; use(buf[:]); return Stackguard() }
-func stack4664() (uintptr, uintptr) { var buf [4664]byte; use(buf[:]); return Stackguard() }
-func stack4668() (uintptr, uintptr) { var buf [4668]byte; use(buf[:]); return Stackguard() }
-func stack4672() (uintptr, uintptr) { var buf [4672]byte; use(buf[:]); return Stackguard() }
-func stack4676() (uintptr, uintptr) { var buf [4676]byte; use(buf[:]); return Stackguard() }
-func stack4680() (uintptr, uintptr) { var buf [4680]byte; use(buf[:]); return Stackguard() }
-func stack4684() (uintptr, uintptr) { var buf [4684]byte; use(buf[:]); return Stackguard() }
-func stack4688() (uintptr, uintptr) { var buf [4688]byte; use(buf[:]); return Stackguard() }
-func stack4692() (uintptr, uintptr) { var buf [4692]byte; use(buf[:]); return Stackguard() }
-func stack4696() (uintptr, uintptr) { var buf [4696]byte; use(buf[:]); return Stackguard() }
-func stack4700() (uintptr, uintptr) { var buf [4700]byte; use(buf[:]); return Stackguard() }
-func stack4704() (uintptr, uintptr) { var buf [4704]byte; use(buf[:]); return Stackguard() }
-func stack4708() (uintptr, uintptr) { var buf [4708]byte; use(buf[:]); return Stackguard() }
-func stack4712() (uintptr, uintptr) { var buf [4712]byte; use(buf[:]); return Stackguard() }
-func stack4716() (uintptr, uintptr) { var buf [4716]byte; use(buf[:]); return Stackguard() }
-func stack4720() (uintptr, uintptr) { var buf [4720]byte; use(buf[:]); return Stackguard() }
-func stack4724() (uintptr, uintptr) { var buf [4724]byte; use(buf[:]); return Stackguard() }
-func stack4728() (uintptr, uintptr) { var buf [4728]byte; use(buf[:]); return Stackguard() }
-func stack4732() (uintptr, uintptr) { var buf [4732]byte; use(buf[:]); return Stackguard() }
-func stack4736() (uintptr, uintptr) { var buf [4736]byte; use(buf[:]); return Stackguard() }
-func stack4740() (uintptr, uintptr) { var buf [4740]byte; use(buf[:]); return Stackguard() }
-func stack4744() (uintptr, uintptr) { var buf [4744]byte; use(buf[:]); return Stackguard() }
-func stack4748() (uintptr, uintptr) { var buf [4748]byte; use(buf[:]); return Stackguard() }
-func stack4752() (uintptr, uintptr) { var buf [4752]byte; use(buf[:]); return Stackguard() }
-func stack4756() (uintptr, uintptr) { var buf [4756]byte; use(buf[:]); return Stackguard() }
-func stack4760() (uintptr, uintptr) { var buf [4760]byte; use(buf[:]); return Stackguard() }
-func stack4764() (uintptr, uintptr) { var buf [4764]byte; use(buf[:]); return Stackguard() }
-func stack4768() (uintptr, uintptr) { var buf [4768]byte; use(buf[:]); return Stackguard() }
-func stack4772() (uintptr, uintptr) { var buf [4772]byte; use(buf[:]); return Stackguard() }
-func stack4776() (uintptr, uintptr) { var buf [4776]byte; use(buf[:]); return Stackguard() }
-func stack4780() (uintptr, uintptr) { var buf [4780]byte; use(buf[:]); return Stackguard() }
-func stack4784() (uintptr, uintptr) { var buf [4784]byte; use(buf[:]); return Stackguard() }
-func stack4788() (uintptr, uintptr) { var buf [4788]byte; use(buf[:]); return Stackguard() }
-func stack4792() (uintptr, uintptr) { var buf [4792]byte; use(buf[:]); return Stackguard() }
-func stack4796() (uintptr, uintptr) { var buf [4796]byte; use(buf[:]); return Stackguard() }
-func stack4800() (uintptr, uintptr) { var buf [4800]byte; use(buf[:]); return Stackguard() }
-func stack4804() (uintptr, uintptr) { var buf [4804]byte; use(buf[:]); return Stackguard() }
-func stack4808() (uintptr, uintptr) { var buf [4808]byte; use(buf[:]); return Stackguard() }
-func stack4812() (uintptr, uintptr) { var buf [4812]byte; use(buf[:]); return Stackguard() }
-func stack4816() (uintptr, uintptr) { var buf [4816]byte; use(buf[:]); return Stackguard() }
-func stack4820() (uintptr, uintptr) { var buf [4820]byte; use(buf[:]); return Stackguard() }
-func stack4824() (uintptr, uintptr) { var buf [4824]byte; use(buf[:]); return Stackguard() }
-func stack4828() (uintptr, uintptr) { var buf [4828]byte; use(buf[:]); return Stackguard() }
-func stack4832() (uintptr, uintptr) { var buf [4832]byte; use(buf[:]); return Stackguard() }
-func stack4836() (uintptr, uintptr) { var buf [4836]byte; use(buf[:]); return Stackguard() }
-func stack4840() (uintptr, uintptr) { var buf [4840]byte; use(buf[:]); return Stackguard() }
-func stack4844() (uintptr, uintptr) { var buf [4844]byte; use(buf[:]); return Stackguard() }
-func stack4848() (uintptr, uintptr) { var buf [4848]byte; use(buf[:]); return Stackguard() }
-func stack4852() (uintptr, uintptr) { var buf [4852]byte; use(buf[:]); return Stackguard() }
-func stack4856() (uintptr, uintptr) { var buf [4856]byte; use(buf[:]); return Stackguard() }
-func stack4860() (uintptr, uintptr) { var buf [4860]byte; use(buf[:]); return Stackguard() }
-func stack4864() (uintptr, uintptr) { var buf [4864]byte; use(buf[:]); return Stackguard() }
-func stack4868() (uintptr, uintptr) { var buf [4868]byte; use(buf[:]); return Stackguard() }
-func stack4872() (uintptr, uintptr) { var buf [4872]byte; use(buf[:]); return Stackguard() }
-func stack4876() (uintptr, uintptr) { var buf [4876]byte; use(buf[:]); return Stackguard() }
-func stack4880() (uintptr, uintptr) { var buf [4880]byte; use(buf[:]); return Stackguard() }
-func stack4884() (uintptr, uintptr) { var buf [4884]byte; use(buf[:]); return Stackguard() }
-func stack4888() (uintptr, uintptr) { var buf [4888]byte; use(buf[:]); return Stackguard() }
-func stack4892() (uintptr, uintptr) { var buf [4892]byte; use(buf[:]); return Stackguard() }
-func stack4896() (uintptr, uintptr) { var buf [4896]byte; use(buf[:]); return Stackguard() }
-func stack4900() (uintptr, uintptr) { var buf [4900]byte; use(buf[:]); return Stackguard() }
-func stack4904() (uintptr, uintptr) { var buf [4904]byte; use(buf[:]); return Stackguard() }
-func stack4908() (uintptr, uintptr) { var buf [4908]byte; use(buf[:]); return Stackguard() }
-func stack4912() (uintptr, uintptr) { var buf [4912]byte; use(buf[:]); return Stackguard() }
-func stack4916() (uintptr, uintptr) { var buf [4916]byte; use(buf[:]); return Stackguard() }
-func stack4920() (uintptr, uintptr) { var buf [4920]byte; use(buf[:]); return Stackguard() }
-func stack4924() (uintptr, uintptr) { var buf [4924]byte; use(buf[:]); return Stackguard() }
-func stack4928() (uintptr, uintptr) { var buf [4928]byte; use(buf[:]); return Stackguard() }
-func stack4932() (uintptr, uintptr) { var buf [4932]byte; use(buf[:]); return Stackguard() }
-func stack4936() (uintptr, uintptr) { var buf [4936]byte; use(buf[:]); return Stackguard() }
-func stack4940() (uintptr, uintptr) { var buf [4940]byte; use(buf[:]); return Stackguard() }
-func stack4944() (uintptr, uintptr) { var buf [4944]byte; use(buf[:]); return Stackguard() }
-func stack4948() (uintptr, uintptr) { var buf [4948]byte; use(buf[:]); return Stackguard() }
-func stack4952() (uintptr, uintptr) { var buf [4952]byte; use(buf[:]); return Stackguard() }
-func stack4956() (uintptr, uintptr) { var buf [4956]byte; use(buf[:]); return Stackguard() }
-func stack4960() (uintptr, uintptr) { var buf [4960]byte; use(buf[:]); return Stackguard() }
-func stack4964() (uintptr, uintptr) { var buf [4964]byte; use(buf[:]); return Stackguard() }
-func stack4968() (uintptr, uintptr) { var buf [4968]byte; use(buf[:]); return Stackguard() }
-func stack4972() (uintptr, uintptr) { var buf [4972]byte; use(buf[:]); return Stackguard() }
-func stack4976() (uintptr, uintptr) { var buf [4976]byte; use(buf[:]); return Stackguard() }
-func stack4980() (uintptr, uintptr) { var buf [4980]byte; use(buf[:]); return Stackguard() }
-func stack4984() (uintptr, uintptr) { var buf [4984]byte; use(buf[:]); return Stackguard() }
-func stack4988() (uintptr, uintptr) { var buf [4988]byte; use(buf[:]); return Stackguard() }
-func stack4992() (uintptr, uintptr) { var buf [4992]byte; use(buf[:]); return Stackguard() }
-func stack4996() (uintptr, uintptr) { var buf [4996]byte; use(buf[:]); return Stackguard() }
-func stack5000() (uintptr, uintptr) { var buf [5000]byte; use(buf[:]); return Stackguard() }
-
 // TestStackMem measures per-thread stack segment cache behavior.
 // The test consumed up to 500MB in the past.
 func TestStackMem(t *testing.T) {
@@ -1576,9 +112,172 @@ func TestStackMem(t *testing.T) {
 	if consumed > estimate {
 		t.Fatalf("Stack mem: want %v, got %v", estimate, consumed)
 	}
-	inuse := s1.StackInuse - s0.StackInuse
+	// Due to broken stack memory accounting (http://golang.org/issue/7468),
+	// StackInuse can decrease during function execution, so we cast the values to int64.
+	inuse := int64(s1.StackInuse) - int64(s0.StackInuse)
 	t.Logf("Inuse %vMB for stack mem", inuse>>20)
 	if inuse > 4<<20 {
 		t.Fatalf("Stack inuse: want %v, got %v", 4<<20, inuse)
 	}
 }
+
+// Test stack growing in different contexts.
+func TestStackGrowth(t *testing.T) {
+	switch GOARCH {
+	case "386", "arm":
+		t.Skipf("skipping test on %q; see issue 8083", GOARCH)
+	}
+	t.Parallel()
+	var wg sync.WaitGroup
+
+	// in a normal goroutine
+	wg.Add(1)
+	go func() {
+		defer wg.Done()
+		growStack()
+	}()
+	wg.Wait()
+
+	// in locked goroutine
+	wg.Add(1)
+	go func() {
+		defer wg.Done()
+		LockOSThread()
+		growStack()
+		UnlockOSThread()
+	}()
+	wg.Wait()
+
+	// in finalizer
+	wg.Add(1)
+	go func() {
+		defer wg.Done()
+		done := make(chan bool)
+		go func() {
+			s := new(string)
+			SetFinalizer(s, func(ss *string) {
+				growStack()
+				done <- true
+			})
+			s = nil
+			done <- true
+		}()
+		<-done
+		GC()
+		select {
+		case <-done:
+		case <-time.After(20 * time.Second):
+			t.Fatal("finalizer did not run")
+		}
+	}()
+	wg.Wait()
+}
+
+// ... and in init
+//func init() {
+//	growStack()
+//}
+
+func growStack() {
+	n := 1 << 10
+	if testing.Short() {
+		n = 1 << 8
+	}
+	for i := 0; i < n; i++ {
+		x := 0
+		growStackIter(&x, i)
+		if x != i+1 {
+			panic("stack is corrupted")
+		}
+	}
+	GC()
+}
+
+// This function is not an anonimous func, so that the compiler can do escape
+// analysis and place x on stack (and subsequently stack growth update the pointer).
+func growStackIter(p *int, n int) {
+	if n == 0 {
+		*p = n + 1
+		GC()
+		return
+	}
+	*p = n + 1
+	x := 0
+	growStackIter(&x, n-1)
+	if x != n {
+		panic("stack is corrupted")
+	}
+}
+
+func TestStackGrowthCallback(t *testing.T) {
+	t.Parallel()
+	var wg sync.WaitGroup
+
+	// test stack growth at chan op
+	wg.Add(1)
+	go func() {
+		defer wg.Done()
+		c := make(chan int, 1)
+		growStackWithCallback(func() {
+			c <- 1
+			<-c
+		})
+	}()
+
+	// test stack growth at map op
+	wg.Add(1)
+	go func() {
+		defer wg.Done()
+		m := make(map[int]int)
+		growStackWithCallback(func() {
+			_, _ = m[1]
+			m[1] = 1
+		})
+	}()
+
+	// test stack growth at goroutine creation
+	wg.Add(1)
+	go func() {
+		defer wg.Done()
+		growStackWithCallback(func() {
+			done := make(chan bool)
+			go func() {
+				done <- true
+			}()
+			<-done
+		})
+	}()
+
+	wg.Wait()
+}
+
+func growStackWithCallback(cb func()) {
+	var f func(n int)
+	f = func(n int) {
+		if n == 0 {
+			cb()
+			return
+		}
+		f(n - 1)
+	}
+	for i := 0; i < 1<<10; i++ {
+		f(i)
+	}
+}
+
+// TestDeferPtrs tests the adjustment of Defer's argument pointers (p aka &y)
+// during a stack copy.
+func set(p *int, x int) {
+	*p = x
+}
+func TestDeferPtrs(t *testing.T) {
+	var y int
+
+	defer func() {
+		if y != 42 {
+			t.Errorf("defer's stack references were not adjusted appropriately")
+		}
+	}()
+	defer set(&y, 42)
+	growStack()
+}
diff --git a/src/pkg/runtime/string.goc b/src/pkg/runtime/string.goc
index b79acbe..97a69d0 100644
--- a/src/pkg/runtime/string.goc
+++ b/src/pkg/runtime/string.goc
@@ -46,10 +46,8 @@ gostringsize(intgo l)
 
 	if(l == 0)
 		return runtime·emptystring;
-	// leave room for NUL for C runtime (e.g., callers of getenv)
-	s.str = runtime·mallocgc(l+1, 0, FlagNoScan|FlagNoZero);
+	s.str = runtime·mallocgc(l, 0, FlagNoScan|FlagNoZero);
 	s.len = l;
-	s.str[l] = 0;
 	for(;;) {
 		ms = runtime·maxstring;
 		if((uintptr)l <= ms || runtime·casp((void**)&runtime·maxstring, (void*)ms, (void*)l))
@@ -80,6 +78,7 @@ runtime·gostringn(byte *str, intgo l)
 	return s;
 }
 
+// used by cmd/cgo
 Slice
 runtime·gobytes(byte *p, intgo n)
 {
@@ -102,11 +101,8 @@ runtime·gostringnocopy(byte *str)
 	return s;
 }
 
-void
-runtime·cstringToGo(byte *str, String s)
-{
+func cstringToGo(str *byte) (s String) {
 	s = runtime·gostringnocopy(str);
-	FLUSH(&s);
 }
 
 String
@@ -179,14 +175,35 @@ concatstring(intgo n, String *s)
 	return out;
 }
 
-// NOTE: Cannot use func syntax, because we need the ...,
-// to signal to the garbage collector that this function does
-// not have a fixed size argument count.
 #pragma textflag NOSPLIT
-void
-runtime·concatstring(intgo n, String s1, ...)
-{
-	(&s1)[n] = concatstring(n, &s1);
+func concatstring2(s1 String, s2 String) (res String) {
+	USED(&s2);
+	res = concatstring(2, &s1);
+}
+#pragma textflag NOSPLIT
+func concatstring3(s1 String, s2 String, s3 String) (res String) {
+	USED(&s2);
+	USED(&s3);
+	res = concatstring(3, &s1);
+}
+#pragma textflag NOSPLIT
+func concatstring4(s1 String, s2 String, s3 String, s4 String) (res String) {
+	USED(&s2);
+	USED(&s3);
+	USED(&s4);
+	res = concatstring(4, &s1);
+}
+#pragma textflag NOSPLIT
+func concatstring5(s1 String, s2 String, s3 String, s4 String, s5 String) (res String) {
+	USED(&s2);
+	USED(&s3);
+	USED(&s4);
+	USED(&s5);
+	res = concatstring(5, &s1);
+}
+#pragma textflag NOSPLIT
+func concatstrings(s Slice) (res String) {
+	res = concatstring(s.len, (String*)s.array);
 }
 
 func eqstring(s1 String, s2 String) (v bool) {
@@ -219,6 +236,25 @@ runtime·strcmp(byte *s1, byte *s2)
 	}
 }
 
+int32
+runtime·strncmp(byte *s1, byte *s2, uintptr n)
+{
+	uintptr i;
+	byte c1, c2;
+
+	for(i=0; i<n; i++) {
+		c1 = s1[i];
+		c2 = s2[i];
+		if(c1 < c2)
+			return -1;
+		if(c1 > c2)
+			return +1;
+		if(c1 == 0)
+			break;
+	}
+	return 0;
+}
+
 byte*
 runtime·strstr(byte *s1, byte *s2)
 {
@@ -258,11 +294,35 @@ func slicebytetostring(b Slice) (s String) {
 	runtime·memmove(s.str, b.array, s.len);
 }
 
+func slicebytetostringtmp(b Slice) (s String) {
+	void *pc;
+
+	if(raceenabled) {
+		pc = runtime·getcallerpc(&b);
+		runtime·racereadrangepc(b.array, b.len, pc, runtime·slicebytetostringtmp);
+	}
+	
+	// Return a "string" referring to the actual []byte bytes.
+	// This is only for use by internal compiler optimizations
+	// that know that the string form will be discarded before
+	// the calling goroutine could possibly modify the original
+	// slice or synchronize with another goroutine.
+	// Today, the only such case is a m[string(k)] lookup where
+	// m is a string-keyed map and k is a []byte.
+	s.str = b.array;
+	s.len = b.len;
+}
+
 func stringtoslicebyte(s String) (b Slice) {
-	b.array = runtime·mallocgc(s.len, 0, FlagNoScan|FlagNoZero);
+	uintptr cap;
+
+	cap = runtime·roundupsize(s.len);
+	b.array = runtime·mallocgc(cap, 0, FlagNoScan|FlagNoZero);
 	b.len = s.len;
-	b.cap = s.len;
+	b.cap = cap;
 	runtime·memmove(b.array, s.str, s.len);
+	if(cap != b.len)
+		runtime·memclr(b.array+b.len, cap-b.len);
 }
 
 func slicerunetostring(b Slice) (s String) {
@@ -297,6 +357,7 @@ func stringtoslicerune(s String) (b Slice) {
 	intgo n;
 	int32 dum, *r;
 	uint8 *p, *ep;
+	uintptr mem;
 
 	// two passes.
 	// unlike slicerunetostring, no race because strings are immutable.
@@ -308,13 +369,18 @@ func stringtoslicerune(s String) (b Slice) {
 		n++;
 	}
 
-	b.array = runtime·mallocgc(n*sizeof(r[0]), 0, FlagNoScan|FlagNoZero);
+	if(n > MaxMem/sizeof(r[0]))
+		runtime·throw("out of memory");
+	mem = runtime·roundupsize(n*sizeof(r[0]));
+	b.array = runtime·mallocgc(mem, 0, FlagNoScan|FlagNoZero);
 	b.len = n;
-	b.cap = n;
+	b.cap = mem/sizeof(r[0]);
 	p = s.str;
 	r = (int32*)b.array;
 	while(p < ep)
 		p += runtime·charntorune(r++, p, ep-p);
+	if(b.cap > b.len)
+		runtime·memclr(b.array+b.len*sizeof(r[0]), (b.cap-b.len)*sizeof(r[0]));
 }
 
 enum
diff --git a/src/pkg/runtime/symtab.c b/src/pkg/runtime/symtab.c
deleted file mode 100644
index dd0015a..0000000
--- a/src/pkg/runtime/symtab.c
+++ /dev/null
@@ -1,333 +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.
-
-// Runtime symbol table parsing.
-// See http://golang.org/s/go12symtab for an overview.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "funcdata.h"
-
-typedef struct Ftab Ftab;
-struct Ftab
-{
-	uintptr	entry;
-	uintptr	funcoff;
-};
-
-extern byte pclntab[];
-
-static Ftab *ftab;
-static uintptr nftab;
-static uint32 *filetab;
-static uint32 nfiletab;
-
-static String end = { (uint8*)"end", 3 };
-
-void
-runtime·symtabinit(void)
-{
-	int32 i, j;
-	Func *f1, *f2;
-	
-	// See golang.org/s/go12symtab for header: 0xfffffffb,
-	// two zero bytes, a byte giving the PC quantum,
-	// and a byte giving the pointer width in bytes.
-	if(*(uint32*)pclntab != 0xfffffffb || pclntab[4] != 0 || pclntab[5] != 0 || pclntab[6] != PCQuantum || pclntab[7] != sizeof(void*)) {
-		runtime·printf("runtime: function symbol table header: 0x%x 0x%x\n", *(uint32*)pclntab, *(uint32*)(pclntab+4));
-		runtime·throw("invalid function symbol table\n");
-	}
-
-	nftab = *(uintptr*)(pclntab+8);
-	ftab = (Ftab*)(pclntab+8+sizeof(void*));
-	for(i=0; i<nftab; i++) {
-		// NOTE: ftab[nftab].entry is legal; it is the address beyond the final function.
-		if(ftab[i].entry > ftab[i+1].entry) {
-			f1 = (Func*)(pclntab + ftab[i].funcoff);
-			f2 = (Func*)(pclntab + ftab[i+1].funcoff);
-			runtime·printf("function symbol table not sorted by program counter: %p %s > %p %s", ftab[i].entry, runtime·funcname(f1), ftab[i+1].entry, i+1 == nftab ? "end" : runtime·funcname(f2));
-			for(j=0; j<=i; j++)
-				runtime·printf("\t%p %s\n", ftab[j].entry, runtime·funcname((Func*)(pclntab + ftab[j].funcoff)));
-			runtime·throw("invalid runtime symbol table");
-		}
-	}
-	
-	filetab = (uint32*)(pclntab + *(uint32*)&ftab[nftab].funcoff);
-	nfiletab = filetab[0];
-}
-
-static uint32
-readvarint(byte **pp)
-{
-	byte *p;
-	uint32 v;
-	int32 shift;
-	
-	v = 0;
-	p = *pp;
-	for(shift = 0;; shift += 7) {
-		v |= (*p & 0x7F) << shift;
-		if(!(*p++ & 0x80))
-			break;
-	}
-	*pp = p;
-	return v;
-}
-
-void*
-runtime·funcdata(Func *f, int32 i)
-{
-	byte *p;
-
-	if(i < 0 || i >= f->nfuncdata)
-		return nil;
-	p = (byte*)&f->nfuncdata + 4 + f->npcdata*4;
-	if(sizeof(void*) == 8 && ((uintptr)p & 4))
-		p += 4;
-	return ((void**)p)[i];
-}
-
-static bool
-step(byte **pp, uintptr *pc, int32 *value, bool first)
-{
-	uint32 uvdelta, pcdelta;
-	int32 vdelta;
-
-	uvdelta = readvarint(pp);
-	if(uvdelta == 0 && !first)
-		return 0;
-	if(uvdelta&1)
-		uvdelta = ~(uvdelta>>1);
-	else
-		uvdelta >>= 1;
-	vdelta = (int32)uvdelta;
-	pcdelta = readvarint(pp) * PCQuantum;
-	*value += vdelta;
-	*pc += pcdelta;
-	return 1;
-}
-
-// Return associated data value for targetpc in func f.
-// (Source file is f->src.)
-static int32
-pcvalue(Func *f, int32 off, uintptr targetpc, bool strict)
-{
-	byte *p;
-	uintptr pc;
-	int32 value;
-
-	enum {
-		debug = 0
-	};
-
-	// The table is a delta-encoded sequence of (value, pc) pairs.
-	// Each pair states the given value is in effect up to pc.
-	// The value deltas are signed, zig-zag encoded.
-	// The pc deltas are unsigned.
-	// The starting value is -1, the starting pc is the function entry.
-	// The table ends at a value delta of 0 except in the first pair.
-	if(off == 0)
-		return -1;
-	p = pclntab + off;
-	pc = f->entry;
-	value = -1;
-
-	if(debug && !runtime·panicking)
-		runtime·printf("pcvalue start f=%s [%p] pc=%p targetpc=%p value=%d tab=%p\n",
-			runtime·funcname(f), f, pc, targetpc, value, p);
-	
-	while(step(&p, &pc, &value, pc == f->entry)) {
-		if(debug)
-			runtime·printf("\tvalue=%d until pc=%p\n", value, pc);
-		if(targetpc < pc)
-			return value;
-	}
-	
-	// If there was a table, it should have covered all program counters.
-	// If not, something is wrong.
-	if(runtime·panicking || !strict)
-		return -1;
-	runtime·printf("runtime: invalid pc-encoded table f=%s pc=%p targetpc=%p tab=%p\n",
-		runtime·funcname(f), pc, targetpc, p);
-	p = (byte*)f + off;
-	pc = f->entry;
-	value = -1;
-	
-	while(step(&p, &pc, &value, pc == f->entry))
-		runtime·printf("\tvalue=%d until pc=%p\n", value, pc);
-	
-	runtime·throw("invalid runtime symbol table");
-	return -1;
-}
-
-static String unknown = { (uint8*)"?", 1 };
-
-int8*
-runtime·funcname(Func *f)
-{
-	if(f == nil || f->nameoff == 0)
-		return nil;
-	return (int8*)(pclntab + f->nameoff);
-}
-
-static int32
-funcline(Func *f, uintptr targetpc, String *file, bool strict)
-{
-	int32 line;
-	int32 fileno;
-
-	*file = unknown;
-	fileno = pcvalue(f, f->pcfile, targetpc, strict);
-	line = pcvalue(f, f->pcln, targetpc, strict);
-	if(fileno == -1 || line == -1 || fileno >= nfiletab) {
-		// runtime·printf("looking for %p in %S got file=%d line=%d\n", targetpc, *f->name, fileno, line);
-		return 0;
-	}
-	*file = runtime·gostringnocopy(pclntab + filetab[fileno]);
-	return line;
-}
-
-int32
-runtime·funcline(Func *f, uintptr targetpc, String *file)
-{
-	return funcline(f, targetpc, file, true);
-}
-
-int32
-runtime·funcspdelta(Func *f, uintptr targetpc)
-{
-	int32 x;
-	
-	x = pcvalue(f, f->pcsp, targetpc, true);
-	if(x&(sizeof(void*)-1))
-		runtime·printf("invalid spdelta %d %d\n", f->pcsp, x);
-	return x;
-}
-
-int32
-runtime·pcdatavalue(Func *f, int32 table, uintptr targetpc)
-{
-	if(table < 0 || table >= f->npcdata)
-		return -1;
-	return pcvalue(f, (&f->nfuncdata)[1+table], targetpc, true);
-}
-
-int32
-runtime·funcarglen(Func *f, uintptr targetpc)
-{
-	if(targetpc == f->entry)
-		return 0;
-	return runtime·pcdatavalue(f, PCDATA_ArgSize, targetpc-PCQuantum);
-}
-
-void
-runtime·funcline_go(Func *f, uintptr targetpc, String retfile, intgo retline)
-{
-	// Pass strict=false here, because anyone can call this function,
-	// and they might just be wrong about targetpc belonging to f.
-	retline = funcline(f, targetpc, &retfile, false);
-	FLUSH(&retline);
-}
-
-void
-runtime·funcname_go(Func *f, String ret)
-{
-	ret = runtime·gostringnocopy((uint8*)runtime·funcname(f));
-	FLUSH(&ret);
-}
-
-void
-runtime·funcentry_go(Func *f, uintptr ret)
-{
-	ret = f->entry;
-	FLUSH(&ret);
-}
-
-Func*
-runtime·findfunc(uintptr addr)
-{
-	Ftab *f;
-	int32 nf, n;
-
-	if(nftab == 0)
-		return nil;
-	if(addr < ftab[0].entry || addr >= ftab[nftab].entry)
-		return nil;
-
-	// binary search to find func with entry <= addr.
-	f = ftab;
-	nf = nftab;
-	while(nf > 0) {
-		n = nf/2;
-		if(f[n].entry <= addr && addr < f[n+1].entry)
-			return (Func*)(pclntab + f[n].funcoff);
-		else if(addr < f[n].entry)
-			nf = n;
-		else {
-			f += n+1;
-			nf -= n+1;
-		}
-	}
-
-	// can't get here -- we already checked above
-	// that the address was in the table bounds.
-	// this can only happen if the table isn't sorted
-	// by address or if the binary search above is buggy.
-	runtime·prints("findfunc unreachable\n");
-	return nil;
-}
-
-static bool
-hasprefix(String s, int8 *p)
-{
-	int32 i;
-
-	for(i=0; i<s.len; i++) {
-		if(p[i] == 0)
-			return 1;
-		if(p[i] != s.str[i])
-			return 0;
-	}
-	return p[i] == 0;
-}
-
-static bool
-contains(String s, int8 *p)
-{
-	int32 i;
-
-	if(p[0] == 0)
-		return 1;
-	for(i=0; i<s.len; i++) {
-		if(s.str[i] != p[0])
-			continue;
-		if(hasprefix((String){s.str + i, s.len - i}, p))
-			return 1;
-	}
-	return 0;
-}
-
-bool
-runtime·showframe(Func *f, G *gp)
-{
-	static int32 traceback = -1;
-	String name;
-
-	if(m->throwing > 0 && gp != nil && (gp == m->curg || gp == m->caughtsig))
-		return 1;
-	if(traceback < 0)
-		traceback = runtime·gotraceback(nil);
-	name = runtime·gostringnocopy((uint8*)runtime·funcname(f));
-
-	// Special case: always show runtime.panic frame, so that we can
-	// see where a panic started in the middle of a stack trace.
-	// See golang.org/issue/5832.
-	if(name.len == 7+1+5 && hasprefix(name, "runtime.panic"))
-		return 1;
-
-	return traceback > 1 || f != nil && contains(name, ".") && !hasprefix(name, "runtime.");
-}
diff --git a/src/pkg/runtime/symtab.goc b/src/pkg/runtime/symtab.goc
new file mode 100644
index 0000000..15e1d28
--- /dev/null
+++ b/src/pkg/runtime/symtab.goc
@@ -0,0 +1,332 @@
+// 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.
+
+// Runtime symbol table parsing.
+// See http://golang.org/s/go12symtab for an overview.
+
+package runtime
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+#include "funcdata.h"
+
+typedef struct Ftab Ftab;
+struct Ftab
+{
+	uintptr	entry;
+	uintptr	funcoff;
+};
+
+extern byte pclntab[];
+
+static Ftab *ftab;
+static uintptr nftab;
+static uint32 *filetab;
+static uint32 nfiletab;
+
+static String end = { (uint8*)"end", 3 };
+
+void
+runtime·symtabinit(void)
+{
+	int32 i, j;
+	Func *f1, *f2;
+	
+	// See golang.org/s/go12symtab for header: 0xfffffffb,
+	// two zero bytes, a byte giving the PC quantum,
+	// and a byte giving the pointer width in bytes.
+	if(*(uint32*)pclntab != 0xfffffffb || pclntab[4] != 0 || pclntab[5] != 0 || pclntab[6] != PCQuantum || pclntab[7] != sizeof(void*)) {
+		runtime·printf("runtime: function symbol table header: %x %x\n", *(uint32*)pclntab, *(uint32*)(pclntab+4));
+		runtime·throw("invalid function symbol table\n");
+	}
+
+	nftab = *(uintptr*)(pclntab+8);
+	ftab = (Ftab*)(pclntab+8+sizeof(void*));
+	for(i=0; i<nftab; i++) {
+		// NOTE: ftab[nftab].entry is legal; it is the address beyond the final function.
+		if(ftab[i].entry > ftab[i+1].entry) {
+			f1 = (Func*)(pclntab + ftab[i].funcoff);
+			f2 = (Func*)(pclntab + ftab[i+1].funcoff);
+			runtime·printf("function symbol table not sorted by program counter: %p %s > %p %s", ftab[i].entry, runtime·funcname(f1), ftab[i+1].entry, i+1 == nftab ? "end" : runtime·funcname(f2));
+			for(j=0; j<=i; j++)
+				runtime·printf("\t%p %s\n", ftab[j].entry, runtime·funcname((Func*)(pclntab + ftab[j].funcoff)));
+			runtime·throw("invalid runtime symbol table");
+		}
+	}
+	
+	filetab = (uint32*)(pclntab + *(uint32*)&ftab[nftab].funcoff);
+	nfiletab = filetab[0];
+}
+
+static uint32
+readvarint(byte **pp)
+{
+	byte *p;
+	uint32 v;
+	int32 shift;
+	
+	v = 0;
+	p = *pp;
+	for(shift = 0;; shift += 7) {
+		v |= (*p & 0x7F) << shift;
+		if(!(*p++ & 0x80))
+			break;
+	}
+	*pp = p;
+	return v;
+}
+
+void*
+runtime·funcdata(Func *f, int32 i)
+{
+	byte *p;
+
+	if(i < 0 || i >= f->nfuncdata)
+		return nil;
+	p = (byte*)&f->nfuncdata + 4 + f->npcdata*4;
+	if(sizeof(void*) == 8 && ((uintptr)p & 4)) {
+		if(((uintptr)f & 4))
+			runtime·printf("misaligned func %p\n", f);
+		p += 4;
+	}
+	return ((void**)p)[i];
+}
+
+static bool
+step(byte **pp, uintptr *pc, int32 *value, bool first)
+{
+	uint32 uvdelta, pcdelta;
+	int32 vdelta;
+
+	uvdelta = readvarint(pp);
+	if(uvdelta == 0 && !first)
+		return 0;
+	if(uvdelta&1)
+		uvdelta = ~(uvdelta>>1);
+	else
+		uvdelta >>= 1;
+	vdelta = (int32)uvdelta;
+	pcdelta = readvarint(pp) * PCQuantum;
+	*value += vdelta;
+	*pc += pcdelta;
+	return 1;
+}
+
+// Return associated data value for targetpc in func f.
+// (Source file is f->src.)
+static int32
+pcvalue(Func *f, int32 off, uintptr targetpc, bool strict)
+{
+	byte *p;
+	uintptr pc;
+	int32 value;
+
+	enum {
+		debug = 0
+	};
+
+	// The table is a delta-encoded sequence of (value, pc) pairs.
+	// Each pair states the given value is in effect up to pc.
+	// The value deltas are signed, zig-zag encoded.
+	// The pc deltas are unsigned.
+	// The starting value is -1, the starting pc is the function entry.
+	// The table ends at a value delta of 0 except in the first pair.
+	if(off == 0)
+		return -1;
+	p = pclntab + off;
+	pc = f->entry;
+	value = -1;
+
+	if(debug && !runtime·panicking)
+		runtime·printf("pcvalue start f=%s [%p] pc=%p targetpc=%p value=%d tab=%p\n",
+			runtime·funcname(f), f, pc, targetpc, value, p);
+	
+	while(step(&p, &pc, &value, pc == f->entry)) {
+		if(debug)
+			runtime·printf("\tvalue=%d until pc=%p\n", value, pc);
+		if(targetpc < pc)
+			return value;
+	}
+	
+	// If there was a table, it should have covered all program counters.
+	// If not, something is wrong.
+	if(runtime·panicking || !strict)
+		return -1;
+	runtime·printf("runtime: invalid pc-encoded table f=%s pc=%p targetpc=%p tab=%p\n",
+		runtime·funcname(f), pc, targetpc, p);
+	p = (byte*)f + off;
+	pc = f->entry;
+	value = -1;
+	
+	while(step(&p, &pc, &value, pc == f->entry))
+		runtime·printf("\tvalue=%d until pc=%p\n", value, pc);
+	
+	runtime·throw("invalid runtime symbol table");
+	return -1;
+}
+
+static String unknown = { (uint8*)"?", 1 };
+
+int8*
+runtime·funcname(Func *f)
+{
+	if(f == nil || f->nameoff == 0)
+		return nil;
+	return (int8*)(pclntab + f->nameoff);
+}
+
+static int32
+funcline(Func *f, uintptr targetpc, String *file, bool strict)
+{
+	int32 line;
+	int32 fileno;
+
+	*file = unknown;
+	fileno = pcvalue(f, f->pcfile, targetpc, strict);
+	line = pcvalue(f, f->pcln, targetpc, strict);
+	if(fileno == -1 || line == -1 || fileno >= nfiletab) {
+		// runtime·printf("looking for %p in %S got file=%d line=%d\n", targetpc, *f->name, fileno, line);
+		return 0;
+	}
+	*file = runtime·gostringnocopy(pclntab + filetab[fileno]);
+	return line;
+}
+
+int32
+runtime·funcline(Func *f, uintptr targetpc, String *file)
+{
+	return funcline(f, targetpc, file, true);
+}
+
+int32
+runtime·funcspdelta(Func *f, uintptr targetpc)
+{
+	int32 x;
+	
+	x = pcvalue(f, f->pcsp, targetpc, true);
+	if(x&(sizeof(void*)-1))
+		runtime·printf("invalid spdelta %d %d\n", f->pcsp, x);
+	return x;
+}
+
+int32
+runtime·pcdatavalue(Func *f, int32 table, uintptr targetpc)
+{
+	if(table < 0 || table >= f->npcdata)
+		return -1;
+	return pcvalue(f, (&f->nfuncdata)[1+table], targetpc, true);
+}
+
+int32
+runtime·funcarglen(Func *f, uintptr targetpc)
+{
+	if(targetpc == f->entry)
+		return 0;
+	return runtime·pcdatavalue(f, PCDATA_ArgSize, targetpc-PCQuantum);
+}
+
+func funcline_go(f *Func, targetpc uintptr) (retfile String, retline int) {
+	// Pass strict=false here, because anyone can call this function,
+	// and they might just be wrong about targetpc belonging to f.
+	retline = funcline(f, targetpc, &retfile, false);
+}
+
+func funcname_go(f *Func) (ret String) {
+	ret = runtime·gostringnocopy((uint8*)runtime·funcname(f));
+}
+
+func funcentry_go(f *Func) (ret uintptr) {
+	ret = f->entry;
+}
+
+Func*
+runtime·findfunc(uintptr addr)
+{
+	Ftab *f;
+	int32 nf, n;
+
+	if(nftab == 0)
+		return nil;
+	if(addr < ftab[0].entry || addr >= ftab[nftab].entry)
+		return nil;
+
+	// binary search to find func with entry <= addr.
+	f = ftab;
+	nf = nftab;
+	while(nf > 0) {
+		n = nf/2;
+		if(f[n].entry <= addr && addr < f[n+1].entry)
+			return (Func*)(pclntab + f[n].funcoff);
+		else if(addr < f[n].entry)
+			nf = n;
+		else {
+			f += n+1;
+			nf -= n+1;
+		}
+	}
+
+	// can't get here -- we already checked above
+	// that the address was in the table bounds.
+	// this can only happen if the table isn't sorted
+	// by address or if the binary search above is buggy.
+	runtime·prints("findfunc unreachable\n");
+	return nil;
+}
+
+func FuncForPC(pc uintptr) (ret *Func) {
+	ret = runtime·findfunc(pc);
+}
+
+static bool
+hasprefix(String s, int8 *p)
+{
+	int32 i;
+
+	for(i=0; i<s.len; i++) {
+		if(p[i] == 0)
+			return 1;
+		if(p[i] != s.str[i])
+			return 0;
+	}
+	return p[i] == 0;
+}
+
+static bool
+contains(String s, int8 *p)
+{
+	int32 i;
+
+	if(p[0] == 0)
+		return 1;
+	for(i=0; i<s.len; i++) {
+		if(s.str[i] != p[0])
+			continue;
+		if(hasprefix((String){s.str + i, s.len - i}, p))
+			return 1;
+	}
+	return 0;
+}
+
+bool
+runtime·showframe(Func *f, G *gp)
+{
+	static int32 traceback = -1;
+	String name;
+
+	if(m->throwing > 0 && gp != nil && (gp == m->curg || gp == m->caughtsig))
+		return 1;
+	if(traceback < 0)
+		traceback = runtime·gotraceback(nil);
+	name = runtime·gostringnocopy((uint8*)runtime·funcname(f));
+
+	// Special case: always show runtime.panic frame, so that we can
+	// see where a panic started in the middle of a stack trace.
+	// See golang.org/issue/5832.
+	if(name.len == 7+1+5 && hasprefix(name, "runtime.panic"))
+		return 1;
+
+	return traceback > 1 || f != nil && contains(name, ".") && !hasprefix(name, "runtime.");
+}
diff --git a/src/pkg/runtime/sys_darwin_386.s b/src/pkg/runtime/sys_darwin_386.s
index c2a259e..bfaaa00 100644
--- a/src/pkg/runtime/sys_darwin_386.s
+++ b/src/pkg/runtime/sys_darwin_386.s
@@ -457,8 +457,7 @@ TEXT runtime·setldt(SB),NOSPLIT,$32
 	 * we use its pthread_create and let it set up %gs
 	 * for us.  When we do that, the private storage
 	 * we get is not at 0(GS) but at 0x468(GS).
-	 * To insulate the rest of the tool chain from this ugliness,
-	 * 8l rewrites 0(GS) into 0x468(GS) for us.
+	 * 8l rewrites 0(TLS) into 0x468(GS) for us.
 	 * To accommodate that rewrite, we translate the
 	 * address and limit here so that 0x468(GS) maps to 0(address).
 	 *
diff --git a/src/pkg/runtime/sys_dragonfly_386.s b/src/pkg/runtime/sys_dragonfly_386.s
index 9085ded..20e6999 100644
--- a/src/pkg/runtime/sys_dragonfly_386.s
+++ b/src/pkg/runtime/sys_dragonfly_386.s
@@ -155,7 +155,7 @@ TEXT runtime·setitimer(SB), NOSPLIT, $-4
 TEXT time·now(SB), NOSPLIT, $32
 	MOVL	$232, AX
 	LEAL	12(SP), BX
-	MOVL	$0, 4(SP)
+	MOVL	$0, 4(SP)	// CLOCK_REALTIME
 	MOVL	BX, 8(SP)
 	INT	$0x80
 	MOVL	12(SP), AX	// sec
@@ -172,7 +172,7 @@ TEXT time·now(SB), NOSPLIT, $32
 TEXT runtime·nanotime(SB), NOSPLIT, $32
 	MOVL	$232, AX
 	LEAL	12(SP), BX
-	MOVL	$0, 4(SP)
+	MOVL	$4, 4(SP)	// CLOCK_MONOTONIC
 	MOVL	BX, 8(SP)
 	INT	$0x80
 	MOVL	12(SP), AX	// sec
diff --git a/src/pkg/runtime/sys_dragonfly_amd64.s b/src/pkg/runtime/sys_dragonfly_amd64.s
index 2fa97f2..d70d2e8 100644
--- a/src/pkg/runtime/sys_dragonfly_amd64.s
+++ b/src/pkg/runtime/sys_dragonfly_amd64.s
@@ -125,7 +125,7 @@ TEXT runtime·setitimer(SB), NOSPLIT, $-8
 // func now() (sec int64, nsec int32)
 TEXT time·now(SB), NOSPLIT, $32
 	MOVL	$232, AX
-	MOVQ	$0, DI
+	MOVQ	$0, DI  	// CLOCK_REALTIME
 	LEAQ	8(SP), SI
 	SYSCALL
 	MOVQ	8(SP), AX	// sec
@@ -138,7 +138,7 @@ TEXT time·now(SB), NOSPLIT, $32
 
 TEXT runtime·nanotime(SB), NOSPLIT, $32
 	MOVL	$232, AX
-	MOVQ	$0, DI
+	MOVQ	$4, DI  	// CLOCK_MONOTONIC
 	LEAQ	8(SP), SI
 	SYSCALL
 	MOVQ	8(SP), AX	// sec
diff --git a/src/pkg/runtime/sys_freebsd_386.s b/src/pkg/runtime/sys_freebsd_386.s
index 8b4d231..4c97eec 100644
--- a/src/pkg/runtime/sys_freebsd_386.s
+++ b/src/pkg/runtime/sys_freebsd_386.s
@@ -135,7 +135,7 @@ TEXT runtime·setitimer(SB), NOSPLIT, $-4
 TEXT time·now(SB), NOSPLIT, $32
 	MOVL	$232, AX
 	LEAL	12(SP), BX
-	MOVL	$0, 4(SP)
+	MOVL	$0, 4(SP)	// CLOCK_REALTIME
 	MOVL	BX, 8(SP)
 	INT	$0x80
 	MOVL	12(SP), AX	// sec
@@ -152,7 +152,9 @@ TEXT time·now(SB), NOSPLIT, $32
 TEXT runtime·nanotime(SB), NOSPLIT, $32
 	MOVL	$232, AX
 	LEAL	12(SP), BX
-	MOVL	$0, 4(SP)
+	// We can use CLOCK_MONOTONIC_FAST here when we drop
+	// support for FreeBSD 8-STABLE.
+	MOVL	$4, 4(SP)	// CLOCK_MONOTONIC
 	MOVL	BX, 8(SP)
 	INT	$0x80
 	MOVL	12(SP), AX	// sec
@@ -307,8 +309,7 @@ TEXT runtime·i386_set_ldt(SB),NOSPLIT,$16
 	MOVL	AX, 8(SP)
 	MOVL	$165, AX
 	INT	$0x80
-	CMPL	AX, $0xfffff001
-	JLS	2(PC)
+	JAE	2(PC)
 	INT	$3
 	RET
 
@@ -324,7 +325,7 @@ TEXT runtime·sysctl(SB),NOSPLIT,$28
 	MOVSL				// arg 6 - newlen
 	MOVL	$202, AX		// sys___sysctl
 	INT	$0x80
-	JCC	3(PC)
+	JAE	3(PC)
 	NEGL	AX
 	RET
 	MOVL	$0, AX
diff --git a/src/pkg/runtime/sys_freebsd_amd64.s b/src/pkg/runtime/sys_freebsd_amd64.s
index 63cd3ac..4c5b325 100644
--- a/src/pkg/runtime/sys_freebsd_amd64.s
+++ b/src/pkg/runtime/sys_freebsd_amd64.s
@@ -144,7 +144,7 @@ TEXT runtime·setitimer(SB), NOSPLIT, $-8
 // func now() (sec int64, nsec int32)
 TEXT time·now(SB), NOSPLIT, $32
 	MOVL	$232, AX
-	MOVQ	$0, DI
+	MOVQ	$0, DI		// CLOCK_REALTIME
 	LEAQ	8(SP), SI
 	SYSCALL
 	MOVQ	8(SP), AX	// sec
@@ -157,7 +157,9 @@ TEXT time·now(SB), NOSPLIT, $32
 
 TEXT runtime·nanotime(SB), NOSPLIT, $32
 	MOVL	$232, AX
-	MOVQ	$0, DI
+	// We can use CLOCK_MONOTONIC_FAST here when we drop
+	// support for FreeBSD 8-STABLE.
+	MOVQ	$4, DI		// CLOCK_MONOTONIC
 	LEAQ	8(SP), SI
 	SYSCALL
 	MOVQ	8(SP), AX	// sec
diff --git a/src/pkg/runtime/sys_freebsd_arm.s b/src/pkg/runtime/sys_freebsd_arm.s
index 106d727..3ec95a6 100644
--- a/src/pkg/runtime/sys_freebsd_arm.s
+++ b/src/pkg/runtime/sys_freebsd_arm.s
@@ -162,7 +162,9 @@ TEXT time·now(SB), NOSPLIT, $32
 // int64 nanotime(void) so really
 // void nanotime(int64 *nsec)
 TEXT runtime·nanotime(SB), NOSPLIT, $32
-	MOVW $0, R0 // CLOCK_REALTIME
+	// We can use CLOCK_MONOTONIC_FAST here when we drop
+	// support for FreeBSD 8-STABLE.
+	MOVW $4, R0 // CLOCK_MONOTONIC
 	MOVW $8(R13), R1
 	MOVW $SYS_clock_gettime, R7
 	SWI $0
@@ -365,6 +367,7 @@ TEXT runtime·casp(SB),NOSPLIT,$0
 TEXT runtime·cas(SB),NOSPLIT,$0
 	B runtime·armcas(SB)
 
+// TODO(minux): this only supports ARMv6K+.
 TEXT runtime·read_tls_fallback(SB),NOSPLIT,$-4
-	MOVW $0xffff1000, R0
-	MOVW (R0), R0
+	WORD $0xee1d0f70 // mrc p15, 0, r0, c13, c0, 3
+	RET
diff --git a/src/pkg/runtime/sys_linux_386.s b/src/pkg/runtime/sys_linux_386.s
index fcda739..b7896f1 100644
--- a/src/pkg/runtime/sys_linux_386.s
+++ b/src/pkg/runtime/sys_linux_386.s
@@ -106,7 +106,7 @@ TEXT runtime·mincore(SB),NOSPLIT,$0-24
 // func now() (sec int64, nsec int32)
 TEXT time·now(SB), NOSPLIT, $32
 	MOVL	$265, AX			// syscall - clock_gettime
-	MOVL	$0, BX
+	MOVL	$0, BX		// CLOCK_REALTIME
 	LEAL	8(SP), CX
 	MOVL	$0, DX
 	CALL	*runtime·_vdso(SB)
@@ -123,7 +123,7 @@ TEXT time·now(SB), NOSPLIT, $32
 // void nanotime(int64 *nsec)
 TEXT runtime·nanotime(SB), NOSPLIT, $32
 	MOVL	$265, AX			// syscall - clock_gettime
-	MOVL	$0, BX
+	MOVL	$1, BX		// CLOCK_MONOTONIC
 	LEAL	8(SP), CX
 	MOVL	$0, DX
 	CALL	*runtime·_vdso(SB)
@@ -383,7 +383,7 @@ TEXT runtime·setldt(SB),NOSPLIT,$32
 	 * for us.  When we do that, the private storage
 	 * we get is not at 0(GS), 4(GS), but -8(GS), -4(GS).
 	 * To insulate the rest of the tool chain from this
-	 * ugliness, 8l rewrites 0(GS) into -8(GS) for us.
+	 * ugliness, 8l rewrites 0(TLS) into -8(GS) for us.
 	 * To accommodate that rewrite, we translate
 	 * the address here and bump the limit to 0xffffffff (no limit)
 	 * so that -8(GS) maps to 0(address).
diff --git a/src/pkg/runtime/sys_linux_amd64.s b/src/pkg/runtime/sys_linux_amd64.s
index 481841a..b340c4f 100644
--- a/src/pkg/runtime/sys_linux_amd64.s
+++ b/src/pkg/runtime/sys_linux_amd64.s
@@ -76,7 +76,7 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
 	SYSCALL
 	RET
 
-TEXT runtime·raise(SB),NOSPLIT,$12
+TEXT runtime·raise(SB),NOSPLIT,$0
 	MOVL	$186, AX	// syscall - gettid
 	SYSCALL
 	MOVL	AX, DI	// arg 1 tid
@@ -136,7 +136,7 @@ TEXT runtime·nanotime(SB),NOSPLIT,$16
 	MOVQ	runtime·__vdso_clock_gettime_sym(SB), AX
 	CMPQ	AX, $0
 	JEQ	fallback_gtod_nt
-	MOVL	$0, DI // CLOCK_REALTIME
+	MOVL	$1, DI // CLOCK_MONOTONIC
 	LEAQ	0(SP), SI
 	CALL	AX
 	MOVQ	0(SP), AX	// sec
diff --git a/src/pkg/runtime/sys_linux_arm.s b/src/pkg/runtime/sys_linux_arm.s
index 42aef56..c537a87 100644
--- a/src/pkg/runtime/sys_linux_arm.s
+++ b/src/pkg/runtime/sys_linux_arm.s
@@ -175,7 +175,7 @@ TEXT time·now(SB), NOSPLIT, $32
 // int64 nanotime(void) so really
 // void nanotime(int64 *nsec)
 TEXT runtime·nanotime(SB),NOSPLIT,$32
-	MOVW	$0, R0  // CLOCK_REALTIME
+	MOVW	$1, R0  // CLOCK_MONOTONIC
 	MOVW	$8(R13), R1  // timespec
 	MOVW	$SYS_clock_gettime, R7
 	SWI	$0
diff --git a/src/pkg/runtime/sys_nacl_386.s b/src/pkg/runtime/sys_nacl_386.s
new file mode 100644
index 0000000..42ba0e0
--- /dev/null
+++ b/src/pkg/runtime/sys_nacl_386.s
@@ -0,0 +1,243 @@
+// 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 "zasm_GOOS_GOARCH.h"
+#include "../../cmd/ld/textflag.h"
+#include "syscall_nacl.h"
+
+#define NACL_SYSCALL(code) \
+	MOVL $(0x10000 + ((code)<<5)), AX; CALL AX
+
+#define NACL_SYSJMP(code) \
+	MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
+
+TEXT runtime·exit(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_exit)
+
+TEXT runtime·exit1(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_thread_exit)
+
+TEXT runtime·open(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_open)
+
+TEXT runtime·close(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_close)
+
+TEXT runtime·read(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_read)
+
+TEXT syscall·naclWrite(SB), NOSPLIT, $12-16
+	MOVL arg1+0(FP), DI
+	MOVL arg2+4(FP), SI
+	MOVL arg3+8(FP), DX
+	MOVL DI, 0(SP)
+	MOVL SI, 4(SP)
+	MOVL DX, 8(SP)
+	CALL runtime·write(SB)
+	MOVL AX, ret+16(FP)
+	RET
+
+TEXT runtime·write(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_write)
+
+TEXT runtime·nacl_exception_stack(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_exception_stack)
+
+TEXT runtime·nacl_exception_handler(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_exception_handler)
+
+TEXT runtime·nacl_sem_create(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_sem_create)
+
+TEXT runtime·nacl_sem_wait(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_sem_wait)
+
+TEXT runtime·nacl_sem_post(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_sem_post)
+
+TEXT runtime·nacl_mutex_create(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_mutex_create)
+
+TEXT runtime·nacl_mutex_lock(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_mutex_lock)
+
+TEXT runtime·nacl_mutex_trylock(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_mutex_trylock)
+
+TEXT runtime·nacl_mutex_unlock(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_mutex_unlock)
+
+TEXT runtime·nacl_cond_create(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_cond_create)
+
+TEXT runtime·nacl_cond_wait(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_cond_wait)
+
+TEXT runtime·nacl_cond_signal(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_cond_signal)
+
+TEXT runtime·nacl_cond_broadcast(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_cond_broadcast)
+
+TEXT runtime·nacl_cond_timed_wait_abs(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_cond_timed_wait_abs)
+
+TEXT runtime·nacl_thread_create(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_thread_create)
+
+TEXT runtime·mstart_nacl(SB),NOSPLIT,$0
+	JMP runtime·mstart(SB)
+
+TEXT runtime·nacl_nanosleep(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_nanosleep)
+
+TEXT runtime·osyield(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_sched_yield)
+
+TEXT runtime·mmap(SB),NOSPLIT,$32
+	MOVL	arg1+0(FP), AX
+	MOVL	AX, 0(SP)
+	MOVL	arg2+4(FP), AX
+	MOVL	AX, 4(SP)
+	MOVL	arg3+8(FP), AX
+	MOVL	AX, 8(SP)
+	MOVL	arg4+12(FP), AX
+	MOVL	AX, 12(SP)
+	MOVL	arg5+16(FP), AX
+	MOVL	AX, 16(SP)
+	MOVL	arg6+20(FP), AX
+	MOVL	AX, 24(SP)
+	MOVL	$0, 28(SP)
+	LEAL	24(SP), AX
+	MOVL	AX, 20(SP)
+	NACL_SYSCALL(SYS_mmap)
+	RET
+
+TEXT time·now(SB),NOSPLIT,$20
+	MOVL $0, 0(SP) // real time clock
+	LEAL 8(SP), AX
+	MOVL AX, 4(SP) // timespec
+	NACL_SYSCALL(SYS_clock_gettime)
+	MOVL 8(SP), AX // low 32 sec
+	MOVL 12(SP), CX // high 32 sec
+	MOVL 16(SP), BX // nsec
+
+	// sec is in AX, nsec in BX
+	MOVL	AX, sec+0(FP)
+	MOVL	CX, sec+4(FP)
+	MOVL	BX, nsec+8(FP)
+	RET
+
+TEXT syscall·now(SB),NOSPLIT,$0
+	JMP time·now(SB)
+
+TEXT runtime·nacl_clock_gettime(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_clock_gettime)
+	
+TEXT runtime·nanotime(SB),NOSPLIT,$20
+	MOVL $0, 0(SP) // real time clock
+	LEAL 8(SP), AX
+	MOVL AX, 4(SP) // timespec
+	NACL_SYSCALL(SYS_clock_gettime)
+	MOVL 8(SP), AX // low 32 sec
+	MOVL 16(SP), BX // nsec
+
+	// sec is in AX, nsec in BX
+	// convert to DX:AX nsec
+	MOVL	$1000000000, CX
+	MULL	CX
+	ADDL	BX, AX
+	ADCL	$0, DX
+
+	MOVL	ret+0(FP), DI
+	MOVL	AX, 0(DI)
+	MOVL	DX, 4(DI)
+	RET
+
+TEXT runtime·setldt(SB),NOSPLIT,$8
+	MOVL	addr+4(FP), BX // aka base
+	ADDL	$0x8, BX
+	MOVL	BX, 0(SP)
+	NACL_SYSCALL(SYS_tls_init)
+	RET
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$0
+	get_tls(CX)
+
+	// check that m exists
+	MOVL	m(CX), BX
+	CMPL	BX, $0
+	JNE	6(PC)
+	MOVL	$11, BX
+	MOVL	BX, 0(SP)
+	MOVL	$runtime·badsignal(SB), AX
+	CALL	AX
+	JMP 	sigtramp_ret
+
+	// save g
+	MOVL	g(CX), DI
+	MOVL	DI, 20(SP)
+	
+	// g = m->gsignal
+	MOVL	m_gsignal(BX), BX
+	MOVL	BX, g(CX)
+	
+	// copy arguments for sighandler
+	MOVL	$11, 0(SP) // signal
+	MOVL	$0, 4(SP) // siginfo
+	LEAL	ctxt+4(FP), AX
+	MOVL	AX, 8(SP) // context
+	MOVL	DI, 12(SP) // g
+
+	CALL	runtime·sighandler(SB)
+
+	// restore g
+	get_tls(CX)
+	MOVL	20(SP), BX
+	MOVL	BX, g(CX)
+
+sigtramp_ret:
+	// Enable exceptions again.
+	NACL_SYSCALL(SYS_exception_clear_flag)
+
+	// NaCl has abidcated its traditional operating system responsibility
+	// and declined to implement 'sigreturn'. Instead the only way to return
+	// to the execution of our program is to restore the registers ourselves.
+	// Unfortunately, that is impossible to do with strict fidelity, because
+	// there is no way to do the final update of PC that ends the sequence
+	// without either (1) jumping to a register, in which case the register ends
+	// holding the PC value instead of its intended value or (2) storing the PC
+	// on the stack and using RET, which imposes the requirement that SP is
+	// valid and that is okay to smash the word below it. The second would
+	// normally be the lesser of the two evils, except that on NaCl, the linker
+	// must rewrite RET into "POP reg; AND $~31, reg; JMP reg", so either way
+	// we are going to lose a register as a result of the incoming signal.
+	// Similarly, there is no way to restore EFLAGS; the usual way is to use
+	// POPFL, but NaCl rejects that instruction. We could inspect the bits and
+	// execute a sequence of instructions designed to recreate those flag
+	// settings, but that's a lot of work.
+	//
+	// Thankfully, Go's signal handlers never try to return directly to the
+	// executing code, so all the registers and EFLAGS are dead and can be
+	// smashed. The only registers that matter are the ones that are setting
+	// up for the simulated call that the signal handler has created.
+	// Today those registers are just PC and SP, but in case additional registers
+	// are relevant in the future (for example DX is the Go func context register)
+	// we restore as many registers as possible.
+	// 
+	// We smash BP, because that's what the linker smashes during RET.
+	//
+	LEAL	ctxt+4(FP), BP
+	ADDL	$64, BP
+	MOVL	0(BP), AX
+	MOVL	4(BP), CX
+	MOVL	8(BP), DX
+	MOVL	12(BP), BX
+	MOVL	16(BP), SP
+	// 20(BP) is saved BP, never to be seen again
+	MOVL	24(BP), SI
+	MOVL	28(BP), DI
+	// 36(BP) is saved EFLAGS, never to be seen again
+	MOVL	32(BP), BP // saved PC
+	JMP	BP
diff --git a/src/pkg/runtime/sys_nacl_amd64p32.s b/src/pkg/runtime/sys_nacl_amd64p32.s
new file mode 100644
index 0000000..43c1723
--- /dev/null
+++ b/src/pkg/runtime/sys_nacl_amd64p32.s
@@ -0,0 +1,413 @@
+// 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 "zasm_GOOS_GOARCH.h"
+#include "../../cmd/ld/textflag.h"
+#include "syscall_nacl.h"
+
+#define NACL_SYSCALL(code) \
+	MOVL $(0x10000 + ((code)<<5)), AX; CALL AX
+
+#define NACL_SYSJMP(code) \
+	MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
+
+TEXT runtime·settls(SB),NOSPLIT,$0
+	MOVL	DI, TLS // really BP
+	RET
+
+TEXT runtime·exit(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	NACL_SYSJMP(SYS_exit)
+
+TEXT runtime·exit1(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	NACL_SYSJMP(SYS_thread_exit)
+
+TEXT runtime·open(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	MOVL arg2+4(FP), SI
+	MOVL arg3+8(FP), DX
+	NACL_SYSJMP(SYS_open)
+
+TEXT runtime·close(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	NACL_SYSJMP(SYS_close)
+
+TEXT runtime·read(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	MOVL arg2+4(FP), SI
+	MOVL arg3+8(FP), DX
+	NACL_SYSJMP(SYS_read)
+
+TEXT syscall·naclWrite(SB), NOSPLIT, $16-20
+	MOVL arg1+0(FP), DI
+	MOVL arg2+4(FP), SI
+	MOVL arg3+8(FP), DX
+	MOVL DI, 0(SP)
+	MOVL SI, 4(SP)
+	MOVL DX, 8(SP)
+	CALL runtime·write(SB)
+	MOVL AX, ret+16(FP)
+	RET
+
+TEXT runtime·write(SB),NOSPLIT,$16-12
+	// If using fake time and writing to stdout or stderr,
+	// emit playback header before actual data.
+	MOVQ runtime·timens(SB), AX
+	CMPQ AX, $0
+	JEQ write
+	MOVL arg1+0(FP), DI
+	CMPL DI, $1
+	JEQ playback
+	CMPL DI, $2
+	JEQ playback
+
+write:
+	// Ordinary write.
+	MOVL arg1+0(FP), DI
+	MOVL arg2+4(FP), SI
+	MOVL arg3+8(FP), DX
+	NACL_SYSCALL(SYS_write)
+	RET
+
+	// Write with playback header.
+	// First, lock to avoid interleaving writes.
+playback:
+	MOVL $1, BX
+	XCHGL	runtime·writelock(SB), BX
+	CMPL BX, $0
+	JNE playback
+
+	// Playback header: 0 0 P B <8-byte time> <4-byte data length>
+	MOVL $(('B'<<24) | ('P'<<16)), 0(SP)
+	BSWAPQ AX
+	MOVQ AX, 4(SP)
+	MOVL arg3+8(FP), DX
+	BSWAPL DX
+	MOVL DX, 12(SP)
+	MOVL $1, DI // standard output
+	MOVL SP, SI
+	MOVL $16, DX
+	NACL_SYSCALL(SYS_write)
+
+	// Write actual data.
+	MOVL $1, DI // standard output
+	MOVL arg2+4(FP), SI
+	MOVL arg3+8(FP), DX
+	NACL_SYSCALL(SYS_write)
+
+	// Unlock.
+	MOVL	$0, runtime·writelock(SB)
+
+	RET
+
+TEXT runtime·nacl_exception_stack(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	MOVL arg2+4(FP), SI
+	NACL_SYSJMP(SYS_exception_stack)
+
+TEXT runtime·nacl_exception_handler(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	MOVL arg2+4(FP), SI
+	NACL_SYSJMP(SYS_exception_handler)
+
+TEXT runtime·nacl_sem_create(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	NACL_SYSJMP(SYS_sem_create)
+
+TEXT runtime·nacl_sem_wait(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	NACL_SYSJMP(SYS_sem_wait)
+
+TEXT runtime·nacl_sem_post(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	NACL_SYSJMP(SYS_sem_post)
+
+TEXT runtime·nacl_mutex_create(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	NACL_SYSJMP(SYS_mutex_create)
+
+TEXT runtime·nacl_mutex_lock(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	NACL_SYSJMP(SYS_mutex_lock)
+
+TEXT runtime·nacl_mutex_trylock(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	NACL_SYSJMP(SYS_mutex_trylock)
+
+TEXT runtime·nacl_mutex_unlock(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	NACL_SYSJMP(SYS_mutex_unlock)
+
+TEXT runtime·nacl_cond_create(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	NACL_SYSJMP(SYS_cond_create)
+
+TEXT runtime·nacl_cond_wait(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	MOVL arg2+4(FP), SI
+	NACL_SYSJMP(SYS_cond_wait)
+
+TEXT runtime·nacl_cond_signal(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	NACL_SYSJMP(SYS_cond_signal)
+
+TEXT runtime·nacl_cond_broadcast(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	NACL_SYSJMP(SYS_cond_broadcast)
+
+TEXT runtime·nacl_cond_timed_wait_abs(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	MOVL arg2+4(FP), SI
+	MOVL arg3+8(FP), DX
+	NACL_SYSJMP(SYS_cond_timed_wait_abs)
+
+TEXT runtime·nacl_thread_create(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	MOVL arg2+4(FP), SI
+	MOVL arg3+8(FP), DX
+	MOVL arg4+12(FP), CX
+	NACL_SYSJMP(SYS_thread_create)
+
+TEXT runtime·mstart_nacl(SB),NOSPLIT,$0
+	NACL_SYSCALL(SYS_tls_get)
+	SUBL	$8, AX
+	MOVL	AX, TLS
+	JMP runtime·mstart(SB)
+
+TEXT runtime·nacl_nanosleep(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	MOVL arg2+4(FP), SI
+	NACL_SYSJMP(SYS_nanosleep)
+
+TEXT runtime·osyield(SB),NOSPLIT,$0
+	NACL_SYSJMP(SYS_sched_yield)
+
+TEXT runtime·mmap(SB),NOSPLIT,$8
+	MOVL arg1+0(FP), DI
+	MOVL arg2+4(FP), SI
+	MOVL arg3+8(FP), DX
+	MOVL arg4+12(FP), CX
+	MOVL arg5+16(FP), R8
+	MOVL arg6+20(FP), AX
+	MOVQ AX, 0(SP)
+	MOVL SP, R9
+	NACL_SYSCALL(SYS_mmap)
+	CMPL AX, $-4095
+	JNA 2(PC)
+	NEGL AX
+	RET
+
+TEXT time·now(SB),NOSPLIT,$16
+	MOVQ runtime·timens(SB), AX
+	CMPQ AX, $0
+	JEQ realtime
+	MOVQ $0, DX
+	MOVQ $1000000000, CX
+	DIVQ CX
+	MOVQ AX, sec+0(FP)
+	MOVL DX, nsec+8(FP)
+	RET
+realtime:
+	MOVL $0, DI // real time clock
+	LEAL 0(SP), AX
+	MOVL AX, SI // timespec
+	NACL_SYSCALL(SYS_clock_gettime)
+	MOVL 0(SP), AX // low 32 sec
+	MOVL 4(SP), CX // high 32 sec
+	MOVL 8(SP), BX // nsec
+
+	// sec is in AX, nsec in BX
+	MOVL	AX, sec+0(FP)
+	MOVL	CX, sec+4(FP)
+	MOVL	BX, nsec+8(FP)
+	RET
+
+TEXT syscall·now(SB),NOSPLIT,$0
+	JMP time·now(SB)
+
+TEXT runtime·nacl_clock_gettime(SB),NOSPLIT,$0
+	MOVL arg1+0(FP), DI
+	MOVL arg2+4(FP), SI
+	NACL_SYSJMP(SYS_clock_gettime)
+
+TEXT runtime·nanotime(SB),NOSPLIT,$16
+	MOVQ runtime·timens(SB), AX
+	CMPQ AX, $0
+	JEQ 2(PC)
+	RET
+	MOVL $0, DI // real time clock
+	LEAL 0(SP), AX
+	MOVL AX, SI // timespec
+	NACL_SYSCALL(SYS_clock_gettime)
+	MOVQ 0(SP), AX // sec
+	MOVL 8(SP), DX // nsec
+
+	// sec is in AX, nsec in DX
+	// return nsec in AX
+	IMULQ	$1000000000, AX
+	ADDQ	DX, AX
+	RET
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$80
+	// restore TLS register at time of execution,
+	// in case it's been smashed.
+	// the TLS register is really BP, but for consistency
+	// with non-NaCl systems it is referred to here as TLS.
+	// NOTE: Cannot use SYS_tls_get here (like we do in mstart_nacl),
+	// because the main thread never calls tls_set.
+	LEAL ctxt+0(FP), AX
+	MOVL (16*4+5*8)(AX), AX
+	MOVL	AX, TLS
+
+	// check that m exists
+	get_tls(CX)
+	MOVL	m(CX), BX
+	
+	CMPL	BX, $0
+	JEQ	nom
+
+	// save g
+	MOVL	g(CX), DI
+	MOVL	DI, 20(SP)
+	
+	// g = m->gsignal
+	MOVL	m_gsignal(BX), BX
+	MOVL	BX, g(CX)
+
+//JMP debughandler
+
+	// copy arguments for sighandler
+	MOVL	$11, 0(SP) // signal
+	MOVL	$0, 4(SP) // siginfo
+	LEAL	ctxt+0(FP), AX
+	MOVL	AX, 8(SP) // context
+	MOVL	DI, 12(SP) // g
+
+	CALL	runtime·sighandler(SB)
+
+	// restore g
+	get_tls(CX)
+	MOVL	20(SP), BX
+	MOVL	BX, g(CX)
+
+sigtramp_ret:
+	// Enable exceptions again.
+	NACL_SYSCALL(SYS_exception_clear_flag)
+
+	// Restore registers as best we can. Impossible to do perfectly.
+	// See comment in sys_nacl_386.s for extended rationale.
+	LEAL	ctxt+0(FP), SI
+	ADDL	$64, SI
+	MOVQ	0(SI), AX
+	MOVQ	8(SI), CX
+	MOVQ	16(SI), DX
+	MOVQ	24(SI), BX
+	MOVL	32(SI), SP	// MOVL for SP sandboxing
+	// 40(SI) is saved BP aka TLS, already restored above
+	// 48(SI) is saved SI, never to be seen again
+	MOVQ	56(SI), DI
+	MOVQ	64(SI), R8
+	MOVQ	72(SI), R9
+	MOVQ	80(SI), R10
+	MOVQ	88(SI), R11
+	MOVQ	96(SI), R12
+	MOVQ	104(SI), R13
+	MOVQ	112(SI), R14
+	// 120(SI) is R15, which is owned by Native Client and must not be modified
+	MOVQ	128(SI), SI // saved PC
+	// 136(SI) is saved EFLAGS, never to be seen again
+	JMP	SI
+
+debughandler:
+	// print basic information
+	LEAL	ctxt+0(FP), DI
+	MOVL	$runtime·sigtrampf(SB), AX
+	MOVL	AX, 0(SP)
+	MOVQ	(16*4+16*8)(DI), BX // rip
+	MOVQ	BX, 8(SP)
+	MOVQ	(16*4+0*8)(DI), BX // rax
+	MOVQ	BX, 16(SP)
+	MOVQ	(16*4+1*8)(DI), BX // rcx
+	MOVQ	BX, 24(SP)
+	MOVQ	(16*4+2*8)(DI), BX // rdx
+	MOVQ	BX, 32(SP)
+	MOVQ	(16*4+3*8)(DI), BX // rbx
+	MOVQ	BX, 40(SP)
+	MOVQ	(16*4+7*8)(DI), BX // rdi
+	MOVQ	BX, 48(SP)
+	MOVQ	(16*4+15*8)(DI), BX // r15
+	MOVQ	BX, 56(SP)
+	MOVQ	(16*4+4*8)(DI), BX // rsp
+	MOVQ	0(BX), BX
+	MOVQ	BX, 64(SP)
+	CALL	runtime·printf(SB)
+	
+	LEAL	ctxt+0(FP), DI
+	MOVQ	(16*4+16*8)(DI), BX // rip
+	MOVL	BX, 0(SP)
+	MOVQ	(16*4+4*8)(DI), BX // rsp
+	MOVL	BX, 4(SP)
+	MOVL	$0, 8(SP)	// lr
+	get_tls(CX)
+	MOVL	g(CX), BX
+	MOVL	BX, 12(SP)	// gp
+	CALL	runtime·traceback(SB)
+
+notls:
+	MOVL	0, AX
+	RET
+
+nom:
+	MOVL	0, AX
+	RET
+
+// cannot do real signal handling yet, because gsignal has not been allocated.
+MOVL $1, DI; NACL_SYSCALL(SYS_exit)
+
+TEXT runtime·nacl_sysinfo(SB),NOSPLIT,$16
+/*
+	MOVL	di+0(FP), DI
+	LEAL	12(DI), BX
+	MOVL	8(DI), AX
+	ADDL	4(DI), AX
+	ADDL	$2, AX
+	LEAL	(BX)(AX*4), BX
+	MOVL	BX, runtime·nacl_irt_query(SB)
+auxloop:
+	MOVL	0(BX), DX
+	CMPL	DX, $0
+	JNE	2(PC)
+	RET
+	CMPL	DX, $32
+	JEQ	auxfound
+	ADDL	$8, BX
+	JMP	auxloop
+auxfound:
+	MOVL	4(BX), BX
+	MOVL	BX, runtime·nacl_irt_query(SB)
+
+	LEAL	runtime·nacl_irt_basic_v0_1_str(SB), DI
+	LEAL	runtime·nacl_irt_basic_v0_1(SB), SI
+	MOVL	runtime·nacl_irt_basic_v0_1_size(SB), DX
+	MOVL	runtime·nacl_irt_query(SB), BX
+	CALL	BX
+
+	LEAL	runtime·nacl_irt_memory_v0_3_str(SB), DI
+	LEAL	runtime·nacl_irt_memory_v0_3(SB), SI
+	MOVL	runtime·nacl_irt_memory_v0_3_size(SB), DX
+	MOVL	runtime·nacl_irt_query(SB), BX
+	CALL	BX
+
+	LEAL	runtime·nacl_irt_thread_v0_1_str(SB), DI
+	LEAL	runtime·nacl_irt_thread_v0_1(SB), SI
+	MOVL	runtime·nacl_irt_thread_v0_1_size(SB), DX
+	MOVL	runtime·nacl_irt_query(SB), BX
+	CALL	BX
+
+	// TODO: Once we have a NaCl SDK with futex syscall support,
+	// try switching to futex syscalls and here load the
+	// nacl-irt-futex-0.1 table.
+*/
+	RET
diff --git a/src/pkg/runtime/sys_openbsd_386.s b/src/pkg/runtime/sys_openbsd_386.s
index e1ec533..8f0da5c 100644
--- a/src/pkg/runtime/sys_openbsd_386.s
+++ b/src/pkg/runtime/sys_openbsd_386.s
@@ -9,6 +9,8 @@
 #include "zasm_GOOS_GOARCH.h"
 #include "../../cmd/ld/textflag.h"
 
+#define	CLOCK_MONOTONIC	$3
+
 // Exit the entire program (like C exit)
 TEXT runtime·exit(SB),NOSPLIT,$-4
 	MOVL	$1, AX
@@ -45,21 +47,22 @@ TEXT runtime·write(SB),NOSPLIT,$-4
 	INT	$0x80
 	RET
 
-TEXT runtime·usleep(SB),NOSPLIT,$20
+TEXT runtime·usleep(SB),NOSPLIT,$24
 	MOVL	$0, DX
 	MOVL	usec+0(FP), AX
 	MOVL	$1000000, CX
 	DIVL	CX
-	MOVL	AX, 12(SP)		// tv_sec
+	MOVL	AX, 12(SP)		// tv_sec - l32
+	MOVL	$0, 16(SP)		// tv_sec - h32
 	MOVL	$1000, AX
 	MULL	DX
-	MOVL	AX, 16(SP)		// tv_nsec
+	MOVL	AX, 20(SP)		// tv_nsec
 
 	MOVL	$0, 0(SP)
 	LEAL	12(SP), AX
 	MOVL	AX, 4(SP)		// arg 1 - rqtp
 	MOVL	$0, 8(SP)		// arg 2 - rmtp
-	MOVL	$240, AX		// sys_nanosleep
+	MOVL	$91, AX			// sys_nanosleep
 	INT	$0x80
 	RET
 
@@ -107,43 +110,46 @@ TEXT runtime·madvise(SB),NOSPLIT,$-4
 	RET
 
 TEXT runtime·setitimer(SB),NOSPLIT,$-4
-	MOVL	$83, AX
+	MOVL	$69, AX
 	INT	$0x80
 	RET
 
 // func now() (sec int64, nsec int32)
 TEXT time·now(SB), NOSPLIT, $32
-	MOVL	$232, AX
 	LEAL	12(SP), BX
-	MOVL	$0, 4(SP)
-	MOVL	BX, 8(SP)
+	MOVL	$0, 4(SP)		// arg 1 - clock_id
+	MOVL	BX, 8(SP)		// arg 2 - tp
+	MOVL	$87, AX			// sys_clock_gettime
 	INT	$0x80
-	MOVL	12(SP), AX		// sec
-	MOVL	16(SP), BX		// nsec
 
-	// sec is in AX, nsec in BX
+	MOVL	12(SP), AX		// sec - l32
 	MOVL	AX, sec+0(FP)
-	MOVL	$0, sec+4(FP)
+	MOVL	16(SP), AX		// sec - h32
+	MOVL	AX, sec+4(FP)
+
+	MOVL	20(SP), BX		// nsec
 	MOVL	BX, nsec+8(FP)
 	RET
 
 // int64 nanotime(void) so really
 // void nanotime(int64 *nsec)
 TEXT runtime·nanotime(SB),NOSPLIT,$32
-	MOVL	$232, AX
 	LEAL	12(SP), BX
-	MOVL	$0, 4(SP)
-	MOVL	BX, 8(SP)
+	MOVL	CLOCK_MONOTONIC, 4(SP)	// arg 1 - clock_id
+	MOVL	BX, 8(SP)		// arg 2 - tp
+	MOVL	$87, AX			// sys_clock_gettime
 	INT	$0x80
-	MOVL	12(SP), AX		// sec
-	MOVL	16(SP), BX		// nsec
 
-	// sec is in AX, nsec in BX
-	// convert to DX:AX nsec
-	MOVL	$1000000000, CX
-	MULL	CX
+	MOVL    16(SP), CX		// sec - h32
+	IMULL   $1000000000, CX
+
+	MOVL    12(SP), AX		// sec - l32
+	MOVL    $1000000000, BX
+	MULL    BX			// result in dx:ax
+
+	MOVL	20(SP), BX		// nsec
 	ADDL	BX, AX
-	ADCL	$0, DX
+	ADCL	CX, DX			// add high bits with carry
 
 	MOVL	ret+0(FP), DI
 	MOVL	AX, 0(DI)
@@ -325,7 +331,7 @@ TEXT runtime·osyield(SB),NOSPLIT,$-4
 	RET
 
 TEXT runtime·thrsleep(SB),NOSPLIT,$-4
-	MOVL	$300, AX		// sys___thrsleep
+	MOVL	$94, AX			// sys___thrsleep
 	INT	$0x80
 	RET
 
@@ -362,7 +368,7 @@ TEXT runtime·kqueue(SB),NOSPLIT,$0
 
 // int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
 TEXT runtime·kevent(SB),NOSPLIT,$0
-	MOVL	$270, AX
+	MOVL	$72, AX			// sys_kevent
 	INT	$0x80
 	JAE	2(PC)
 	NEGL	AX
@@ -370,7 +376,7 @@ TEXT runtime·kevent(SB),NOSPLIT,$0
 
 // int32 runtime·closeonexec(int32 fd);
 TEXT runtime·closeonexec(SB),NOSPLIT,$32
-	MOVL	$92, AX		// fcntl
+	MOVL	$92, AX			// sys_fcntl
 	// 0(SP) is where the caller PC would be; kernel skips it
 	MOVL	fd+0(FP), BX
 	MOVL	BX, 4(SP)	// fd
diff --git a/src/pkg/runtime/sys_openbsd_amd64.s b/src/pkg/runtime/sys_openbsd_amd64.s
index 26dc61f..b2a6182 100644
--- a/src/pkg/runtime/sys_openbsd_amd64.s
+++ b/src/pkg/runtime/sys_openbsd_amd64.s
@@ -9,6 +9,8 @@
 #include "zasm_GOOS_GOARCH.h"
 #include "../../cmd/ld/textflag.h"
 
+#define CLOCK_MONOTONIC	$3
+
 // int64 tfork(void *param, uintptr psize, M *mp, G *gp, void (*fn)(void));
 TEXT runtime·tfork(SB),NOSPLIT,$32
 
@@ -62,7 +64,7 @@ TEXT runtime·thrsleep(SB),NOSPLIT,$0
 	MOVQ	24(SP), DX		// arg 3 - tp
 	MOVQ	32(SP), R10		// arg 4 - lock
 	MOVQ	40(SP), R8		// arg 5 - abort
-	MOVL	$300, AX		// sys___thrsleep
+	MOVL	$94, AX			// sys___thrsleep
 	SYSCALL
 	RET
 
@@ -130,7 +132,7 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
 
 	MOVQ	SP, DI			// arg 1 - rqtp
 	MOVQ	$0, SI			// arg 2 - rmtp
-	MOVL	$240, AX		// sys_nanosleep
+	MOVL	$91, AX			// sys_nanosleep
 	SYSCALL
 	RET
 
@@ -138,7 +140,7 @@ TEXT runtime·raise(SB),NOSPLIT,$16
 	MOVL	$299, AX		// sys_getthrid
 	SYSCALL
 	MOVQ	AX, DI			// arg 1 - pid
-	MOVL	sig+0(FP), SI			// arg 2 - signum
+	MOVL	sig+0(FP), SI		// arg 2 - signum
 	MOVL	$37, AX			// sys_kill
 	SYSCALL
 	RET
@@ -147,7 +149,7 @@ TEXT runtime·setitimer(SB),NOSPLIT,$-8
 	MOVL	8(SP), DI		// arg 1 - which
 	MOVQ	16(SP), SI		// arg 2 - itv
 	MOVQ	24(SP), DX		// arg 3 - oitv
-	MOVL	$83, AX			// sys_setitimer
+	MOVL	$69, AX			// sys_setitimer
 	SYSCALL
 	RET
 
@@ -155,9 +157,9 @@ TEXT runtime·setitimer(SB),NOSPLIT,$-8
 TEXT time·now(SB), NOSPLIT, $32
 	MOVQ	$0, DI			// arg 1 - clock_id
 	LEAQ	8(SP), SI		// arg 2 - tp
-	MOVL	$232, AX		// sys_clock_gettime
+	MOVL	$87, AX			// sys_clock_gettime
 	SYSCALL
-	MOVL	8(SP), AX		// sec
+	MOVQ	8(SP), AX		// sec
 	MOVQ	16(SP), DX		// nsec
 
 	// sec is in AX, nsec in DX
@@ -166,11 +168,11 @@ TEXT time·now(SB), NOSPLIT, $32
 	RET
 
 TEXT runtime·nanotime(SB),NOSPLIT,$24
-	MOVQ	$0, DI			// arg 1 - clock_id
+	MOVQ	CLOCK_MONOTONIC, DI	// arg 1 - clock_id
 	LEAQ	8(SP), SI		// arg 2 - tp
-	MOVL	$232, AX		// sys_clock_gettime
+	MOVL	$87, AX			// sys_clock_gettime
 	SYSCALL
-	MOVL	8(SP), AX		// sec
+	MOVQ	8(SP), AX		// sec
 	MOVQ	16(SP), DX		// nsec
 
 	// sec is in AX, nsec in DX
@@ -318,7 +320,7 @@ TEXT runtime·kevent(SB),NOSPLIT,$0
 	MOVQ	32(SP), R10
 	MOVL	40(SP), R8
 	MOVQ	48(SP), R9
-	MOVL	$270, AX
+	MOVL	$72, AX
 	SYSCALL
 	JCC	2(PC)
 	NEGQ	AX
diff --git a/src/pkg/runtime/sys_plan9_386.s b/src/pkg/runtime/sys_plan9_386.s
index bed0f7e..143cd2e 100644
--- a/src/pkg/runtime/sys_plan9_386.s
+++ b/src/pkg/runtime/sys_plan9_386.s
@@ -81,6 +81,10 @@ TEXT runtime·plan9_semrelease(SB),NOSPLIT,$0
 	
 TEXT runtime·rfork(SB),NOSPLIT,$0
 	MOVL    $19, AX // rfork
+	MOVL	stack+8(SP), CX
+	MOVL	mm+12(SP), BX	// m
+	MOVL	gg+16(SP), DX	// g
+	MOVL	fn+20(SP), SI	// fn
 	INT     $64
 
 	// In parent, return.
@@ -88,13 +92,7 @@ TEXT runtime·rfork(SB),NOSPLIT,$0
 	JEQ	2(PC)
 	RET
 
-	// In child on old stack.
-	MOVL	mm+12(SP), BX	// m
-	MOVL	gg+16(SP), DX	// g
-	MOVL	fn+20(SP), SI	// fn
-
 	// set SP to be on the new child stack
-	MOVL	stack+8(SP), CX
 	MOVL	CX, SP
 
 	// Initialize m, g.
@@ -102,8 +100,9 @@ TEXT runtime·rfork(SB),NOSPLIT,$0
 	MOVL	DX, g(AX)
 	MOVL	BX, m(AX)
 
-	// Initialize AX from TOS struct.
-	MOVL	procid(AX), AX
+	// Initialize procid from TOS struct.
+	// TODO: Be explicit and insert a new MOVL _tos(SB), AX here.
+	MOVL	48(AX), AX // procid
 	MOVL	AX, m_procid(BX)	// save pid as m->procid
 	
 	CALL	runtime·stackcheck(SB)	// smashes AX, CX
diff --git a/src/pkg/runtime/sys_plan9_amd64.s b/src/pkg/runtime/sys_plan9_amd64.s
index d6702e8..e60459c 100644
--- a/src/pkg/runtime/sys_plan9_amd64.s
+++ b/src/pkg/runtime/sys_plan9_amd64.s
@@ -136,7 +136,7 @@ TEXT runtime·rfork(SB),NOSPLIT,$0
 	MOVQ	BX, m(AX)
 
 	// Initialize AX from pid in TLS.
-	MOVQ	procid(AX), AX
+	MOVQ	0(FS), AX
 	MOVQ	AX, m_procid(BX)	// save pid as m->procid
 	
 	CALL	runtime·stackcheck(SB)	// smashes AX, CX
diff --git a/src/pkg/runtime/sys_solaris_amd64.s b/src/pkg/runtime/sys_solaris_amd64.s
new file mode 100644
index 0000000..2151769
--- /dev/null
+++ b/src/pkg/runtime/sys_solaris_amd64.s
@@ -0,0 +1,267 @@
+// 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.
+//
+// System calls and other sys.stuff for AMD64, SunOS
+// /usr/include/sys/syscall.h for syscall numbers.
+//
+
+#include "zasm_GOOS_GOARCH.h"
+#include "../../cmd/ld/textflag.h"
+
+// This is needed by asm_amd64.s
+TEXT runtime·settls(SB),NOSPLIT,$8
+	RET
+
+// void libc·miniterrno(void *(*___errno)(void));
+//
+// Set the TLS errno pointer in M.
+//
+// Called using runtime·asmcgocall from os_solaris.c:/minit.
+TEXT runtime·miniterrno(SB),NOSPLIT,$0
+	// asmcgocall will put first argument into DI.
+	CALL	DI	// SysV ABI so returns in AX
+	get_tls(CX)
+	MOVQ	m(CX), BX
+	MOVQ	AX,	m_perrno(BX)
+	RET
+
+// int64 runtime·nanotime1(void);
+//
+// clock_gettime(3c) wrapper because Timespec is too large for
+// runtime·nanotime stack.
+//
+// Called using runtime·sysvicall6 from os_solaris.c:/nanotime.
+TEXT runtime·nanotime1(SB),NOSPLIT,$0
+	// need space for the timespec argument.
+	SUBQ	$64, SP	// 16 bytes will do, but who knows in the future?
+	MOVQ	$3, DI	// CLOCK_REALTIME from <sys/time_impl.h>
+	MOVQ	SP, SI
+	MOVQ	libc·clock_gettime(SB), AX
+	CALL	AX
+	MOVQ	(SP), AX	// tv_sec from struct timespec
+	IMULQ	$1000000000, AX	// multiply into nanoseconds
+	ADDQ	8(SP), AX	// tv_nsec, offset should be stable.
+	ADDQ	$64, SP
+	RET
+
+// pipe(3c) wrapper that returns fds in AX, DX.
+TEXT runtime·pipe1(SB),NOSPLIT,$0
+	SUBQ	$16, SP // 8 bytes will do, but stack has to be 16-byte alligned
+	MOVQ	SP, DI
+	MOVQ	libc·pipe(SB), AX
+	CALL	AX
+	MOVL	0(SP), AX
+	MOVL	4(SP), DX
+	ADDQ	$16, SP
+	RET
+
+// Call a library function with SysV calling conventions.
+// The called function can take a maximum of 6 INTEGER class arguments,
+// see 
+//   Michael Matz, Jan Hubicka, Andreas Jaeger, and Mark Mitchell
+//   System V Application Binary Interface 
+//   AMD64 Architecture Processor Supplement
+// section 3.2.3.
+//
+// Called by runtime·asmcgocall or runtime·cgocall.
+TEXT runtime·asmsysvicall6(SB),NOSPLIT,$0
+	// asmcgocall will put first argument into DI.
+	PUSHQ	DI			// save for later
+	MOVQ	libcall_fn(DI), AX
+	MOVQ	libcall_args(DI), R11
+	MOVQ	libcall_n(DI), R10
+
+	get_tls(CX)
+	MOVQ	m(CX), BX
+	MOVQ	m_perrno(BX), DX
+	CMPQ	DX, $0
+	JEQ	skiperrno1
+	MOVL	$0, 0(DX)
+
+skiperrno1:
+	CMPQ	R11, $0
+	JEQ	skipargs
+	// Load 6 args into correspondent registers.
+	MOVQ	0(R11), DI
+	MOVQ	8(R11), SI
+	MOVQ	16(R11), DX
+	MOVQ	24(R11), CX
+	MOVQ	32(R11), R8
+	MOVQ	40(R11), R9
+skipargs:
+
+	// Call SysV function
+	CALL	AX
+
+	// Return result
+	POPQ	DI
+	MOVQ	AX, libcall_r1(DI)
+	MOVQ	DX, libcall_r2(DI)
+
+	get_tls(CX)
+	MOVQ	m(CX), BX
+	MOVQ	m_perrno(BX), AX
+	CMPQ	AX, $0
+	JEQ	skiperrno2
+	MOVL	0(AX), AX
+	MOVQ	AX, libcall_err(DI)
+
+skiperrno2:	
+	RET
+
+// uint32 tstart_sysvicall(M *newm);
+TEXT runtime·tstart_sysvicall(SB),NOSPLIT,$0
+	// DI contains first arg newm
+	MOVQ	m_g0(DI), DX		// g
+
+	// Make TLS entries point at g and m.
+	get_tls(BX)
+	MOVQ	DX, g(BX)
+	MOVQ	DI, m(BX)
+
+	// Layout new m scheduler stack on os stack.
+	MOVQ	SP, AX
+	MOVQ	AX, g_stackbase(DX)
+	SUBQ	$(0x100000), AX		// stack size
+	MOVQ	AX, g_stackguard(DX)
+	MOVQ	AX, g_stackguard0(DX)
+
+	// Someday the convention will be D is always cleared.
+	CLD
+
+	CALL	runtime·stackcheck(SB)	// clobbers AX,CX
+	CALL	runtime·mstart(SB)
+
+	XORL	AX, AX			// return 0 == success
+	RET
+
+// Careful, this is called by __sighndlr, a libc function. We must preserve
+// registers as per AMD 64 ABI.
+TEXT runtime·sigtramp(SB),NOSPLIT,$0
+	// Note that we are executing on altsigstack here, so we have
+	// more stack available than NOSPLIT would have us believe.
+	// To defeat the linker, we make our own stack frame with
+	// more space:
+	SUBQ    $184, SP
+
+	// save registers
+	MOVQ    BX, 32(SP)
+	MOVQ    BP, 40(SP)
+	MOVQ	R12, 48(SP)
+	MOVQ	R13, 56(SP)
+	MOVQ	R14, 64(SP)
+	MOVQ	R15, 72(SP)
+
+	get_tls(BX)
+	// check that m exists
+	MOVQ	m(BX), BP
+	CMPQ	BP, $0
+	JNE	allgood
+	MOVQ	DI, 0(SP)
+	MOVQ	$runtime·badsignal(SB), AX
+	CALL	AX
+	RET
+
+allgood:
+	// save g
+	MOVQ	g(BX), R10
+	MOVQ	R10, 80(SP)
+
+	// Save m->libcall and m->scratch. We need to do this because we
+	// might get interrupted by a signal in runtime·asmcgocall.
+
+	// save m->libcall 
+	LEAQ	m_libcall(BP), R11
+	MOVQ	libcall_fn(R11), R10
+	MOVQ	R10, 88(SP)
+	MOVQ	libcall_args(R11), R10
+	MOVQ	R10, 96(SP)
+	MOVQ	libcall_n(R11), R10
+	MOVQ	R10, 104(SP)
+	MOVQ    libcall_r1(R11), R10
+	MOVQ    R10, 168(SP)
+	MOVQ    libcall_r2(R11), R10
+	MOVQ    R10, 176(SP)
+
+	// save m->scratch
+	LEAQ	m_scratch(BP), R11
+	MOVQ	0(R11), R10
+	MOVQ	R10, 112(SP)
+	MOVQ	8(R11), R10
+	MOVQ	R10, 120(SP)
+	MOVQ	16(R11), R10
+	MOVQ	R10, 128(SP)
+	MOVQ	24(R11), R10
+	MOVQ	R10, 136(SP)
+	MOVQ	32(R11), R10
+	MOVQ	R10, 144(SP)
+	MOVQ	40(R11), R10
+	MOVQ	R10, 152(SP)
+
+	// save errno, it might be EINTR; stuff we do here might reset it.
+	MOVQ	m_perrno(BP), R10
+	MOVL	0(R10), R10
+	MOVQ	R10, 160(SP)
+
+	MOVQ	g(BX), R10
+	// g = m->gsignal
+	MOVQ	m_gsignal(BP), BP
+	MOVQ	BP, g(BX)
+
+	// prepare call
+	MOVQ	DI, 0(SP)
+	MOVQ	SI, 8(SP)
+	MOVQ	DX, 16(SP)
+	MOVQ	R10, 24(SP)
+	CALL	runtime·sighandler(SB)
+
+	get_tls(BX)
+	MOVQ	m(BX), BP
+	// restore libcall
+	LEAQ	m_libcall(BP), R11
+	MOVQ	88(SP), R10
+	MOVQ	R10, libcall_fn(R11)
+	MOVQ	96(SP), R10
+	MOVQ	R10, libcall_args(R11)
+	MOVQ	104(SP), R10
+	MOVQ	R10, libcall_n(R11)
+	MOVQ    168(SP), R10
+	MOVQ    R10, libcall_r1(R11)
+	MOVQ    176(SP), R10
+	MOVQ    R10, libcall_r2(R11)
+
+	// restore scratch
+	LEAQ	m_scratch(BP), R11
+	MOVQ	112(SP), R10
+	MOVQ	R10, 0(R11)
+	MOVQ	120(SP), R10
+	MOVQ	R10, 8(R11)
+	MOVQ	128(SP), R10
+	MOVQ	R10, 16(R11)
+	MOVQ	136(SP), R10
+	MOVQ	R10, 24(R11)
+	MOVQ	144(SP), R10
+	MOVQ	R10, 32(R11)
+	MOVQ	152(SP), R10
+	MOVQ	R10, 40(R11)
+
+	// restore errno
+	MOVQ	m_perrno(BP), R11
+	MOVQ	160(SP), R10
+	MOVL	R10, 0(R11)
+
+	// restore g
+	MOVQ	80(SP), R10
+	MOVQ	R10, g(BX)
+
+	// restore registers
+	MOVQ	32(SP), BX
+	MOVQ	40(SP), BP
+	MOVQ	48(SP), R12
+	MOVQ	56(SP), R13
+	MOVQ	64(SP), R14
+	MOVQ	72(SP), R15
+
+	ADDQ    $184, SP
+	RET
diff --git a/src/pkg/runtime/sys_windows_386.s b/src/pkg/runtime/sys_windows_386.s
index 2075363..e0c0631 100644
--- a/src/pkg/runtime/sys_windows_386.s
+++ b/src/pkg/runtime/sys_windows_386.s
@@ -14,28 +14,28 @@ TEXT runtime·asmstdcall(SB),NOSPLIT,$0
 
 	// Copy args to the stack.
 	MOVL	SP, BP
-	MOVL	wincall_n(BX), CX	// words
+	MOVL	libcall_n(BX), CX	// words
 	MOVL	CX, AX
 	SALL	$2, AX
 	SUBL	AX, SP			// room for args
 	MOVL	SP, DI
-	MOVL	wincall_args(BX), SI
+	MOVL	libcall_args(BX), SI
 	CLD
 	REP; MOVSL
 
 	// Call stdcall or cdecl function.
 	// DI SI BP BX are preserved, SP is not
-	CALL	wincall_fn(BX)
+	CALL	libcall_fn(BX)
 	MOVL	BP, SP
 
 	// Return result.
 	MOVL	c+0(FP), BX
-	MOVL	AX, wincall_r1(BX)
-	MOVL	DX, wincall_r2(BX)
+	MOVL	AX, libcall_r1(BX)
+	MOVL	DX, libcall_r2(BX)
 
 	// GetLastError().
 	MOVL	0x34(FS), AX
-	MOVL	AX, wincall_err(BX)
+	MOVL	AX, libcall_err(BX)
 
 	RET
 
@@ -69,43 +69,47 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0
 	MOVL	AX, 0x34(FS)
 	RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$28
-	// unwinding?
-	MOVL	info+0(FP), CX
-	TESTL	$6, 4(CX)		// exception flags
-	MOVL	$1, AX
-	JNZ	sigdone
-
-	// copy arguments for call to sighandler
-	MOVL	CX, 0(SP)
-	MOVL	context+8(FP), CX
-	MOVL	CX, 4(SP)
-
-	get_tls(CX)
-
-	// check that m exists
-	MOVL	m(CX), AX
-	CMPL	AX, $0
-	JNE	2(PC)
-	CALL	runtime·badsignal2(SB)
-
-	MOVL	g(CX), CX
-	MOVL	CX, 8(SP)
+// Called by Windows as a Vectored Exception Handler (VEH).
+// First argument is pointer to struct containing
+// exception record and context pointers.
+// Return 0 for 'not handled', -1 for handled.
+TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
+	MOVL	ptrs+0(FP), CX
+	SUBL	$28, SP
 
+	// save callee-saved registers
 	MOVL	BX, 12(SP)
 	MOVL	BP, 16(SP)
 	MOVL	SI, 20(SP)
 	MOVL	DI, 24(SP)
 
+	MOVL	0(CX), BX // ExceptionRecord*
+	MOVL	4(CX), CX // Context*
+
+	// fetch g
+	get_tls(DX)
+	MOVL	m(DX), AX
+	CMPL	AX, $0
+	JNE	2(PC)
+	CALL	runtime·badsignal2(SB)
+	MOVL	g(DX), DX
+	// call sighandler(ExceptionRecord*, Context*, G*)
+	MOVL	BX, 0(SP)
+	MOVL	CX, 4(SP)
+	MOVL	DX, 8(SP)
 	CALL	runtime·sighandler(SB)
 	// AX is set to report result back to Windows
 
+	// restore callee-saved registers
 	MOVL	24(SP), DI
 	MOVL	20(SP), SI
 	MOVL	16(SP), BP
 	MOVL	12(SP), BX
-sigdone:
-	RET
+
+	ADDL	$28, SP
+	// RET 4 (return and pop 4 bytes parameters)
+	BYTE $0xC2; WORD $4
+	RET // unreached; make assembler happy
 
 TEXT runtime·ctrlhandler(SB),NOSPLIT,$0
 	PUSHL	$runtime·ctrlhandler1(SB)
@@ -182,11 +186,6 @@ TEXT runtime·callbackasm1+0(SB),NOSPLIT,$0
 	PUSHL	BP
 	PUSHL	BX
 
-	// set up SEH frame again
-	PUSHL	$runtime·sigtramp(SB)
-	PUSHL	0(FS)
-	MOVL	SP, 0(FS)
-
 	// determine index into runtime·cbctxts table
 	SUBL	$runtime·callbackasm(SB), AX
 	MOVL	$0, DX
@@ -232,10 +231,6 @@ TEXT runtime·callbackasm1+0(SB),NOSPLIT,$0
 
 	MOVL	BX, CX			// cannot use BX anymore
 
-	// pop SEH frame
-	POPL	0(FS)
-	POPL	BX
-
 	// restore registers as required for windows callback
 	POPL	BX
 	POPL	BP
@@ -299,35 +294,6 @@ TEXT runtime·setldt(SB),NOSPLIT,$0
 	MOVL	CX, 0x14(FS)
 	RET
 
-// void install_exception_handler()
-TEXT runtime·install_exception_handler(SB),NOSPLIT,$0
-	get_tls(CX)
-	MOVL	m(CX), CX		// m
-
-	// Set up SEH frame
-	MOVL	m_seh(CX), DX
-	MOVL	$runtime·sigtramp(SB), AX
-	MOVL	AX, seh_handler(DX)
-	MOVL	0(FS), AX
-	MOVL	AX, seh_prev(DX)
-
-	// Install it
-	MOVL	DX, 0(FS)
-
-	RET
-
-// void remove_exception_handler()
-TEXT runtime·remove_exception_handler(SB),NOSPLIT,$0
-	get_tls(CX)
-	MOVL	m(CX), CX		// m
-
-	// Remove SEH frame
-	MOVL	m_seh(CX), DX
-	MOVL	seh_prev(DX), AX
-	MOVL	AX, 0(FS)
-
-	RET
-
 // Sleep duration is in 100ns units.
 TEXT runtime·usleep1(SB),NOSPLIT,$0
 	MOVL	duration+0(FP), BX
@@ -343,19 +309,36 @@ TEXT runtime·usleep1(SB),NOSPLIT,$0
 	RET
 
 	MOVL	m(CX), BP
+
+	// leave pc/sp for cpu profiler
+	MOVL	(SP), SI
+	MOVL	SI, m_libcallpc(BP)
+	MOVL	g(CX), SI
+	MOVL	SI, m_libcallg(BP)
+	// sp must be the last, because once async cpu profiler finds
+	// all three values to be non-zero, it will use them
+	LEAL	4(SP), SI
+	MOVL	SI, m_libcallsp(BP)
+
 	MOVL	m_g0(BP), SI
 	CMPL	g(CX), SI
-	JNE	3(PC)
+	JNE	usleep1_switch
 	// executing on m->g0 already
 	CALL	AX
-	RET
+	JMP	usleep1_ret
 
+usleep1_switch:
 	// Switch to m->g0 stack and back.
 	MOVL	(g_sched+gobuf_sp)(SI), SI
 	MOVL	SP, -4(SI)
 	LEAL	-4(SI), SP
 	CALL	AX
 	MOVL	0(SP), SP
+
+usleep1_ret:
+	get_tls(CX)
+	MOVL	m(CX), BP
+	MOVL	$0, m_libcallsp(BP)
 	RET
 
 // Runs on OS stack. duration (in 100ns units) is in BX.
diff --git a/src/pkg/runtime/sys_windows_amd64.s b/src/pkg/runtime/sys_windows_amd64.s
index 8c4caf8..9484590 100644
--- a/src/pkg/runtime/sys_windows_amd64.s
+++ b/src/pkg/runtime/sys_windows_amd64.s
@@ -13,9 +13,9 @@
 TEXT runtime·asmstdcall(SB),NOSPLIT,$0
 	// asmcgocall will put first argument into CX.
 	PUSHQ	CX			// save for later
-	MOVQ	wincall_fn(CX), AX
-	MOVQ	wincall_args(CX), SI
-	MOVQ	wincall_n(CX), CX
+	MOVQ	libcall_fn(CX), AX
+	MOVQ	libcall_args(CX), SI
+	MOVQ	libcall_n(CX), CX
 
 	// SetLastError(0).
 	MOVQ	0x30(GS), DI
@@ -52,12 +52,12 @@ loadregs:
 
 	// Return result.
 	POPQ	CX
-	MOVQ	AX, wincall_r1(CX)
+	MOVQ	AX, libcall_r1(CX)
 
 	// GetLastError().
 	MOVQ	0x30(GS), DI
 	MOVL	0x68(DI), AX
-	MOVQ	AX, wincall_err(CX)
+	MOVQ	AX, libcall_err(CX)
 
 	RET
 
@@ -95,49 +95,55 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0
 	MOVL	AX, 0x68(CX)
 	RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$0
-	// CX: exception record
-	// R8: context
+// Called by Windows as a Vectored Exception Handler (VEH).
+// First argument is pointer to struct containing
+// exception record and context pointers.
+// Return 0 for 'not handled', -1 for handled.
+TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
+	// CX: PEXCEPTION_POINTERS ExceptionInfo
 
-	// unwinding?
-	TESTL	$6, 4(CX)		// exception flags
-	MOVL	$1, AX
-	JNZ	sigdone
-
-	// copy arguments for call to sighandler.
-
-	// Stack adjustment is here to hide from 6l,
-	// which doesn't understand that sigtramp
-	// runs on essentially unlimited stack.
-	SUBQ	$56, SP
-	MOVQ	CX, 0(SP)
-	MOVQ	R8, 8(SP)
-
-	get_tls(CX)
-
-	// check that m exists
-	MOVQ	m(CX), AX
+	// DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved
+	// as required by windows callback convention.
+	PUSHFQ
+	SUBQ	$88, SP
+	MOVQ	DI, 80(SP)
+	MOVQ	SI, 72(SP)
+	MOVQ	BP, 64(SP)
+	MOVQ	BX, 56(SP)
+	MOVQ	R12, 48(SP)
+	MOVQ	R13, 40(SP)
+	MOVQ	R14, 32(SP)
+	MOVQ	R15, 24(SP)
+
+	MOVQ	0(CX), BX // ExceptionRecord*
+	MOVQ	8(CX), CX // Context*
+
+	// fetch g
+	get_tls(DX)
+	MOVQ	m(DX), AX
 	CMPQ	AX, $0
 	JNE	2(PC)
 	CALL	runtime·badsignal2(SB)
-
-	MOVQ	g(CX), CX
-	MOVQ	CX, 16(SP)
-
-	MOVQ	BX, 24(SP)
-	MOVQ	BP, 32(SP)
-	MOVQ	SI, 40(SP)
-	MOVQ	DI, 48(SP)
-
+	MOVQ	g(DX), DX
+	// call sighandler(ExceptionRecord*, Context*, G*)
+	MOVQ	BX, 0(SP)
+	MOVQ	CX, 8(SP)
+	MOVQ	DX, 16(SP)
 	CALL	runtime·sighandler(SB)
+	// AX is set to report result back to Windows
 
-	MOVQ	24(SP), BX
-	MOVQ	32(SP), BP
-	MOVQ	40(SP), SI
-	MOVQ	48(SP), DI
-	ADDQ	$56, SP
+	// restore registers as required for windows callback
+	MOVQ	24(SP), R15
+	MOVQ	32(SP), R14
+	MOVQ	40(SP), R13
+	MOVQ	48(SP), R12
+	MOVQ	56(SP), BX
+	MOVQ	64(SP), BP
+	MOVQ	72(SP), SI
+	MOVQ	80(SP), DI
+	ADDQ	$88, SP
+	POPFQ
 
-sigdone:
 	RET
 
 TEXT runtime·ctrlhandler(SB),NOSPLIT,$8
@@ -277,13 +283,6 @@ TEXT runtime·callbackasm1(SB),NOSPLIT,$0
 	POPQ	-8(CX)(DX*1)      // restore bytes just after the args
 	RET
 
-TEXT runtime·setstacklimits(SB),NOSPLIT,$0
-	MOVQ	0x30(GS), CX
-	MOVQ	$0, 0x10(CX)
-	MOVQ	$0xffffffffffff, AX
-	MOVQ	AX, 0x08(CX)
-	RET
-
 // uint32 tstart_stdcall(M *newm);
 TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0
 	// CX contains first arg newm
@@ -315,14 +314,6 @@ TEXT runtime·settls(SB),NOSPLIT,$0
 	MOVQ	DI, 0x28(GS)
 	RET
 
-// void install_exception_handler()
-TEXT runtime·install_exception_handler(SB),NOSPLIT,$0
-	CALL	runtime·setstacklimits(SB)
-	RET
-
-TEXT runtime·remove_exception_handler(SB),NOSPLIT,$0
-	RET
-
 // Sleep duration is in 100ns units.
 TEXT runtime·usleep1(SB),NOSPLIT,$0
 	MOVL	duration+0(FP), BX
@@ -337,20 +328,35 @@ TEXT runtime·usleep1(SB),NOSPLIT,$0
 	CALL	AX
 	RET
 
-	MOVQ	m(R15), R14
-	MOVQ	m_g0(R14), R14
+	MOVQ	m(R15), R13
+
+	// leave pc/sp for cpu profiler
+	MOVQ	(SP), R12
+	MOVQ	R12, m_libcallpc(R13)
+	MOVQ	g(R15), R12
+	MOVQ	R12, m_libcallg(R13)
+	// sp must be the last, because once async cpu profiler finds
+	// all three values to be non-zero, it will use them
+	LEAQ	8(SP), R12
+	MOVQ	R12, m_libcallsp(R13)
+
+	MOVQ	m_g0(R13), R14
 	CMPQ	g(R15), R14
-	JNE	3(PC)
+	JNE	usleep1_switch
 	// executing on m->g0 already
 	CALL	AX
-	RET
+	JMP	usleep1_ret
 
+usleep1_switch:
 	// Switch to m->g0 stack and back.
 	MOVQ	(g_sched+gobuf_sp)(R14), R14
 	MOVQ	SP, -8(R14)
 	LEAQ	-8(R14), SP
 	CALL	AX
 	MOVQ	0(SP), SP
+
+usleep1_ret:
+	MOVQ	$0, m_libcallsp(R13)
 	RET
 
 // Runs on OS stack. duration (in 100ns units) is in BX.
diff --git a/src/pkg/runtime/sys_x86.c b/src/pkg/runtime/sys_x86.c
index 0df6dfb..a450b3e 100644
--- a/src/pkg/runtime/sys_x86.c
+++ b/src/pkg/runtime/sys_x86.c
@@ -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 amd64 386
+// +build amd64 amd64p32 386
 
 #include "runtime.h"
 
@@ -14,6 +14,8 @@ runtime·gostartcall(Gobuf *gobuf, void (*fn)(void), void *ctxt)
 	uintptr *sp;
 	
 	sp = (uintptr*)gobuf->sp;
+	if(sizeof(uintreg) > sizeof(uintptr))
+		*--sp = 0;
 	*--sp = (uintptr)gobuf->pc;
 	gobuf->sp = (uintptr)sp;
 	gobuf->pc = (uintptr)fn;
@@ -27,7 +29,7 @@ void
 runtime·rewindmorestack(Gobuf *gobuf)
 {
 	byte *pc;
-	
+
 	pc = (byte*)gobuf->pc;
 	if(pc[0] == 0xe9) { // jmp 4-byte offset
 		gobuf->pc = gobuf->pc + 5 + *(int32*)(pc+1);
@@ -37,18 +39,18 @@ runtime·rewindmorestack(Gobuf *gobuf)
 		gobuf->pc = gobuf->pc + 2 + *(int8*)(pc+1);
 		return;
 	}
- 	if(pc[0] == 0xcc) {
- 		// This is a breakpoint inserted by gdb.  We could use
- 		// runtime·findfunc to find the function.  But if we
- 		// do that, then we will continue execution at the
- 		// function entry point, and we will not hit the gdb
- 		// breakpoint.  So for this case we don't change
- 		// gobuf->pc, so that when we return we will execute
- 		// the jump instruction and carry on.  This means that
- 		// stack unwinding may not work entirely correctly
- 		// (http://golang.org/issue/5723) but the user is
- 		// running under gdb anyhow.
- 		return;
+	if(pc[0] == 0xcc) {
+		// This is a breakpoint inserted by gdb.  We could use
+		// runtime·findfunc to find the function.  But if we
+		// do that, then we will continue execution at the
+		// function entry point, and we will not hit the gdb
+		// breakpoint.  So for this case we don't change
+		// gobuf->pc, so that when we return we will execute
+		// the jump instruction and carry on.  This means that
+		// stack unwinding may not work entirely correctly
+		// (http://golang.org/issue/5723) but the user is
+		// running under gdb anyhow.
+		return;
 	}
 	runtime·printf("runtime: pc=%p %x %x %x %x %x\n", pc, pc[0], pc[1], pc[2], pc[3], pc[4]);
 	runtime·throw("runtime: misuse of rewindmorestack");
diff --git a/src/pkg/runtime/syscall_nacl.h b/src/pkg/runtime/syscall_nacl.h
new file mode 100644
index 0000000..b33852e
--- /dev/null
+++ b/src/pkg/runtime/syscall_nacl.h
@@ -0,0 +1,71 @@
+// generated by mknacl.sh - do not edit
+#define SYS_null 1
+#define SYS_nameservice 2
+#define SYS_dup 8
+#define SYS_dup2 9
+#define SYS_open 10
+#define SYS_close 11
+#define SYS_read 12
+#define SYS_write 13
+#define SYS_lseek 14
+#define SYS_ioctl 15
+#define SYS_stat 16
+#define SYS_fstat 17
+#define SYS_chmod 18
+#define SYS_brk 20
+#define SYS_mmap 21
+#define SYS_munmap 22
+#define SYS_getdents 23
+#define SYS_mprotect 24
+#define SYS_list_mappings 25
+#define SYS_exit 30
+#define SYS_getpid 31
+#define SYS_sched_yield 32
+#define SYS_sysconf 33
+#define SYS_gettimeofday 40
+#define SYS_clock 41
+#define SYS_nanosleep 42
+#define SYS_clock_getres 43
+#define SYS_clock_gettime 44
+#define SYS_mkdir 45
+#define SYS_rmdir 46
+#define SYS_chdir 47
+#define SYS_getcwd 48
+#define SYS_unlink 49
+#define SYS_imc_makeboundsock 60
+#define SYS_imc_accept 61
+#define SYS_imc_connect 62
+#define SYS_imc_sendmsg 63
+#define SYS_imc_recvmsg 64
+#define SYS_imc_mem_obj_create 65
+#define SYS_imc_socketpair 66
+#define SYS_mutex_create 70
+#define SYS_mutex_lock 71
+#define SYS_mutex_trylock 72
+#define SYS_mutex_unlock 73
+#define SYS_cond_create 74
+#define SYS_cond_wait 75
+#define SYS_cond_signal 76
+#define SYS_cond_broadcast 77
+#define SYS_cond_timed_wait_abs 79
+#define SYS_thread_create 80
+#define SYS_thread_exit 81
+#define SYS_tls_init 82
+#define SYS_thread_nice 83
+#define SYS_tls_get 84
+#define SYS_second_tls_set 85
+#define SYS_second_tls_get 86
+#define SYS_exception_handler 87
+#define SYS_exception_stack 88
+#define SYS_exception_clear_flag 89
+#define SYS_sem_create 100
+#define SYS_sem_wait 101
+#define SYS_sem_post 102
+#define SYS_sem_get_value 103
+#define SYS_dyncode_create 104
+#define SYS_dyncode_modify 105
+#define SYS_dyncode_delete 106
+#define SYS_test_infoleak 109
+#define SYS_test_crash 110
+#define SYS_test_syscall_1 111
+#define SYS_test_syscall_2 112
diff --git a/src/pkg/runtime/syscall_solaris.goc b/src/pkg/runtime/syscall_solaris.goc
new file mode 100644
index 0000000..21bcce4
--- /dev/null
+++ b/src/pkg/runtime/syscall_solaris.goc
@@ -0,0 +1,374 @@
+// 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 syscall
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "cgocall.h"
+#include "../../cmd/ld/textflag.h"
+
+#pragma dynimport libc·chdir chdir "libc.so"
+#pragma dynimport libc·chroot chroot "libc.so"
+#pragma dynimport libc·close close "libc.so"
+#pragma dynimport libc·dlclose dlclose "libc.so"
+#pragma dynimport libc·dlopen dlopen "libc.so"
+#pragma dynimport libc·dlsym dlsym "libc.so"
+#pragma dynimport libc·execve execve "libc.so"
+#pragma dynimport libc·fcntl fcntl "libc.so"
+#pragma dynimport libc·gethostname gethostname "libc.so"
+#pragma dynimport libc·ioctl ioctl "libc.so"
+#pragma dynimport libc·pipe pipe "libc.so"
+#pragma dynimport libc·setgid setgid "libc.so"
+#pragma dynimport libc·setgroups setgroups "libc.so"
+#pragma dynimport libc·setsid setsid "libc.so"
+#pragma dynimport libc·setuid setuid "libc.so"
+#pragma dynimport libc·setpgid setsid "libc.so"
+#pragma dynimport libc·syscall syscall "libc.so"
+#pragma dynimport libc·forkx forkx "libc.so"
+#pragma dynimport libc·wait4 wait4 "libc.so"
+extern uintptr libc·chdir;
+extern uintptr libc·chroot;
+extern uintptr libc·close;
+extern uintptr libc·dlclose;
+extern uintptr libc·dlopen;
+extern uintptr libc·dlsym;
+extern uintptr libc·execve;
+extern uintptr libc·exit;
+extern uintptr libc·fcntl;
+extern uintptr libc·gethostname;
+extern uintptr libc·ioctl;
+extern uintptr libc·pipe;
+extern uintptr libc·setgid;
+extern uintptr libc·setgroups;
+extern uintptr libc·setsid;
+extern uintptr libc·setuid;
+extern uintptr libc·setpgid;
+extern uintptr libc·syscall;
+extern uintptr libc·forkx;
+extern uintptr libc·wait4;
+extern uintptr libc·write;
+
+func sysvicall6(func uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr) (r1 uintptr, r2 uintptr, err uintptr)
+{
+	LibCall c;
+
+	USED(a2);
+	USED(a3);
+	USED(a4);
+	USED(a5);
+	USED(a6);
+	c.fn = (void*)func;
+	c.n = nargs;
+	c.args = (void*)&a1;
+	runtime·cgocall(runtime·asmsysvicall6, &c);
+	err = c.err;
+	r1 = c.r1;
+	r2 = c.r2;
+}
+
+#pragma textflag NOSPLIT
+func rawSysvicall6(func uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr) (r1 uintptr, r2 uintptr, err uintptr)
+{
+	LibCall c;
+
+	USED(a2);
+	USED(a3);
+	USED(a4);
+	USED(a5);
+	USED(a6);
+	c.fn = (void*)func;
+	c.n = nargs;
+	c.args = (void*)&a1;
+	runtime·asmcgocall(runtime·asmsysvicall6, &c);
+	err = c.err;
+	r1 = c.r1;
+	r2 = c.r2;
+}
+
+#pragma textflag NOSPLIT
+func chdir(path uintptr) (err uintptr) {
+	LibCall c;
+
+	c.fn = (void*)libc·chdir;
+	c.n = 1;
+	c.args = (void*)&path;
+	runtime·asmcgocall(runtime·asmsysvicall6, &c);
+	err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func chroot1(path uintptr) (err uintptr) {
+	LibCall c;
+
+	c.fn = (void*)libc·chroot;
+	c.n = 1;
+	c.args = (void*)&path;
+	runtime·asmcgocall(runtime·asmsysvicall6, &c);
+	err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func close(fd uintptr) (err uintptr) {
+	LibCall c;
+
+	c.fn = (void*)libc·close;
+	c.n = 1;
+	c.args = (void*)&fd;
+	runtime·asmcgocall(runtime·asmsysvicall6, &c);
+	err = c.err;
+}
+
+func dlclose(handle uintptr) (err uintptr) {
+	LibCall c;
+
+	USED(handle);
+	c.fn = (void*)libc·dlclose;
+	c.n = 1;
+	c.args = (void*)&handle;
+	runtime·cgocall(runtime·asmsysvicall6, &c);
+	err = c.r1;
+}
+
+func dlopen(name *uint8, mode uintptr) (handle uintptr, err uintptr) {
+	LibCall c;
+
+	USED(mode);
+	c.fn = (void*)libc·dlopen;
+	c.n = 2;
+	c.args = (void*)&name;
+	runtime·cgocall(runtime·asmsysvicall6, &c);
+	handle = c.r1;
+	if(handle == 0)
+		err = c.err;
+	else
+		err = 0;
+}
+
+func dlsym(handle uintptr, name *uint8) (proc uintptr, err uintptr) {
+	LibCall c;
+
+	USED(name);
+	c.fn = (void*)libc·dlsym;
+	c.n = 2;
+	c.args = &handle;
+	runtime·cgocall(runtime·asmsysvicall6, &c);
+	proc = c.r1;
+	if(proc == 0)
+		err = c.err;
+	else
+		err = 0;
+}
+
+#pragma textflag NOSPLIT
+func execve(path uintptr, argv uintptr, envp uintptr) (err uintptr) {
+	LibCall c;
+
+	USED(argv);
+	USED(envp);
+	c.fn = (void*)libc·execve;
+	c.n = 3;
+	c.args = (void*)&path;
+	runtime·asmcgocall(runtime·asmsysvicall6, &c);
+	err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func exit(code uintptr) {
+	LibCall c;
+
+	c.fn = (void*)libc·exit;
+	c.n = 1;
+	c.args = (void*)&code;
+	runtime·asmcgocall(runtime·asmsysvicall6, &c);
+}
+
+#pragma textflag NOSPLIT
+func fcntl1(fd uintptr, cmd uintptr, arg uintptr) (val uintptr, err uintptr) {
+	LibCall c;
+
+	USED(cmd);
+	USED(arg);
+	c.fn = (void*)libc·fcntl;
+	c.n = 3;
+	c.args = (void*)&fd;
+	runtime·asmcgocall(runtime·asmsysvicall6, &c);
+	err = c.err;
+	val = c.r1;
+}
+
+func gethostname() (name String, err uintptr) {
+	struct { uintptr v[2]; } args;
+	uint8 cname[MAXHOSTNAMELEN];
+	LibCall c;
+
+	c.fn = (void*)libc·gethostname;
+	c.n = 2;
+	args.v[0] = (uintptr)&cname[0];
+	args.v[1] = MAXHOSTNAMELEN;
+	c.args = (void*)&args;
+	runtime·cgocall(runtime·asmsysvicall6, &c);
+	err = c.err;
+	if(c.r1) {
+		name = runtime·emptystring;
+		return;
+	}
+	cname[MAXHOSTNAMELEN - 1] = 0;
+	name = runtime·gostring(cname);
+}
+
+#pragma textflag NOSPLIT
+func ioctl(fd uintptr, req uintptr, arg uintptr) (err uintptr) {
+	LibCall c;
+
+	USED(req);
+	USED(arg);
+	c.fn = (void*)libc·ioctl;
+	c.n = 3;
+	c.args = (void*)&fd;
+	runtime·asmcgocall(runtime·asmsysvicall6, &c);
+	err = c.err;
+}
+
+func wait4(pid uintptr, wstatus *uint32, options uintptr, rusage *void) (wpid int, err uintptr) {
+	LibCall c;
+
+	USED(wstatus);
+	USED(options);
+	USED(rusage);
+	c.fn = (void*)libc·wait4;
+	c.n = 4;
+	c.args = (void*)&pid;
+	runtime·cgocall(runtime·asmsysvicall6, &c);
+	err = c.err;
+	wpid = c.r1;
+}
+
+#pragma textflag NOSPLIT
+func setgid(gid uintptr) (err uintptr) {
+	LibCall c;
+
+	c.fn = (void*)libc·setgid;
+	c.n = 1;
+	c.args = (void*)&gid;
+	runtime·asmcgocall(runtime·asmsysvicall6, &c);
+	err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func setgroups1(ngid uintptr, gid uintptr) (err uintptr) {
+	LibCall c;
+
+	USED(gid);
+	c.fn = (void*)libc·setgroups;
+	c.n = 2;
+	c.args = (void*)&ngid;
+	runtime·asmcgocall(runtime·asmsysvicall6, &c);
+	err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func setsid() (pid uintptr, err uintptr) {
+	LibCall c;
+
+	c.fn = (void*)libc·setsid;
+	c.n = 0;
+	c.args = (void*)0;
+	runtime·asmcgocall(runtime·asmsysvicall6, &c);
+	err = c.err;
+	pid = c.r1;
+}
+
+#pragma textflag NOSPLIT
+func setuid(uid uintptr) (err uintptr) {
+	LibCall c;
+
+	c.fn = (void*)libc·setuid;
+	c.n = 1;
+	c.args = (void*)&uid;
+	runtime·asmcgocall(runtime·asmsysvicall6, &c);
+	err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func setpgid(pid uintptr, pgid uintptr) (err uintptr) {
+	LibCall c;
+
+	USED(pgid);
+	c.fn = (void*)libc·setpgid;
+	c.n = 2;
+	c.args = (void*)&pid;
+	runtime·asmcgocall(runtime·asmsysvicall6, &c);
+	err = c.err;
+}
+
+#pragma textflag NOSPLIT
+func forkx(flags uintptr) (pid uintptr, err uintptr) {
+	LibCall c;
+
+	c.fn = (void*)libc·forkx;
+	c.n = 1;
+	c.args = (void*)&flags;
+	runtime·asmcgocall(runtime·asmsysvicall6, &c);
+	err = c.err;
+	pid = c.r1;
+}
+
+void runtime·pipe1(void);
+
+func pipe() (r uintptr, w uintptr, err uintptr) {
+	LibCall c;
+
+	c.fn = (void*)runtime·pipe1;
+	c.n = 0;
+	c.args = (void*)0;
+	runtime·cgocall(runtime·asmsysvicall6, &c);
+	err = c.err;
+	r = c.r1;
+	w = c.r2;
+}
+
+#pragma textflag NOSPLIT
+func write1(fd uintptr, buf uintptr, nbyte uintptr) (n uintptr, err uintptr) {
+	LibCall c;
+
+	USED(buf);
+	USED(nbyte);
+	c.fn = (void*)libc·write;
+	c.n = 3;
+	c.args = (void*)fd;
+	runtime·asmcgocall(runtime·asmsysvicall6, &c);
+	err = c.err;
+	n = c.r1;
+}
+
+func Syscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
+	LibCall c;
+
+	USED(a1);
+	USED(a2);
+	USED(a3);
+	c.fn = (void*)libc·syscall;
+	c.n = 4;
+	c.args = &trap;
+	runtime·cgocall(runtime·asmsysvicall6, &c);
+	err = c.err;
+	r1 = c.r1;
+	r2 = c.r2;
+}
+
+func RawSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
+	LibCall c;
+
+	USED(a1);
+	USED(a2);
+	USED(a3);
+	c.fn = (void*)libc·syscall;
+	c.n = 4;
+	c.args = &trap;
+	runtime·asmcgocall(runtime·asmsysvicall6, &c);
+	err = c.err;
+	r1 = c.r1;
+	r2 = c.r2;
+}
diff --git a/src/pkg/runtime/syscall_windows.goc b/src/pkg/runtime/syscall_windows.goc
index 173d3ed..5282453 100644
--- a/src/pkg/runtime/syscall_windows.goc
+++ b/src/pkg/runtime/syscall_windows.goc
@@ -8,7 +8,7 @@ package syscall
 #include "cgocall.h"
 
 func loadlibrary(filename *uint16) (handle uintptr, err uintptr) {
-	WinCall c;
+	LibCall c;
 
 	c.fn = runtime·LoadLibrary;
 	c.n = 1;
@@ -22,7 +22,7 @@ func loadlibrary(filename *uint16) (handle uintptr, err uintptr) {
 }
 
 func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err uintptr) {
-	WinCall c;
+	LibCall c;
 
 	USED(procname);
 	c.fn = runtime·GetProcAddress;
@@ -40,17 +40,12 @@ func NewCallback(fn Eface) (code uintptr) {
 	code = (uintptr)runtime·compilecallback(fn, true);
 }
 
-/*
- * If this is needed, uncomment here and add a declaration in package syscall
- * next to the NewCallback declaration.
- *
 func NewCallbackCDecl(fn Eface) (code uintptr) {
 	code = (uintptr)runtime·compilecallback(fn, false);
 }
- */
 
 func Syscall(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
-	WinCall c;
+	LibCall c;
 
 	USED(a2);
 	USED(a3);
@@ -64,7 +59,7 @@ func Syscall(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1
 }
 
 func Syscall6(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
-	WinCall c;
+	LibCall c;
 
 	USED(a2);
 	USED(a3);
@@ -81,7 +76,7 @@ func Syscall6(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4
 }
 
 func Syscall9(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
-	WinCall c;
+	LibCall c;
 
 	USED(a2);
 	USED(a3);
@@ -101,7 +96,7 @@ func Syscall9(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4
 }
 
 func Syscall12(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr, a10 uintptr, a11 uintptr, a12 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
-	WinCall c;
+	LibCall c;
 
 	USED(a2);
 	USED(a3);
@@ -124,7 +119,7 @@ func Syscall12(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4
 }
 
 func Syscall15(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr, a10 uintptr, a11 uintptr, a12 uintptr, a13 uintptr, a14 uintptr, a15 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
-	WinCall c;
+	LibCall c;
 
 	USED(a2);
 	USED(a3);
diff --git a/src/pkg/runtime/syscall_windows_test.go b/src/pkg/runtime/syscall_windows_test.go
index f04d2cd..fabf935 100644
--- a/src/pkg/runtime/syscall_windows_test.go
+++ b/src/pkg/runtime/syscall_windows_test.go
@@ -5,7 +5,13 @@
 package runtime_test
 
 import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
 	"runtime"
+	"strings"
 	"syscall"
 	"testing"
 	"unsafe"
@@ -171,10 +177,12 @@ func TestCallbackGC(t *testing.T) {
 	nestedCall(t, runtime.GC)
 }
 
-func TestCallbackPanic(t *testing.T) {
-	// Make sure panic during callback unwinds properly.
-	if runtime.LockedOSThread() {
-		t.Fatal("locked OS thread on entry to TestCallbackPanic")
+func TestCallbackPanicLocked(t *testing.T) {
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	if !runtime.LockedOSThread() {
+		t.Fatal("runtime.LockOSThread didn't")
 	}
 	defer func() {
 		s := recover()
@@ -184,27 +192,18 @@ func TestCallbackPanic(t *testing.T) {
 		if s.(string) != "callback panic" {
 			t.Fatal("wrong panic:", s)
 		}
-		if runtime.LockedOSThread() {
-			t.Fatal("locked OS thread on exit from TestCallbackPanic")
+		if !runtime.LockedOSThread() {
+			t.Fatal("lost lock on OS thread after panic")
 		}
 	}()
 	nestedCall(t, func() { panic("callback panic") })
 	panic("nestedCall returned")
 }
 
-func TestCallbackPanicLoop(t *testing.T) {
-	// Make sure we don't blow out m->g0 stack.
-	for i := 0; i < 100000; i++ {
-		TestCallbackPanic(t)
-	}
-}
-
-func TestCallbackPanicLocked(t *testing.T) {
-	runtime.LockOSThread()
-	defer runtime.UnlockOSThread()
-
-	if !runtime.LockedOSThread() {
-		t.Fatal("runtime.LockOSThread didn't")
+func TestCallbackPanic(t *testing.T) {
+	// Make sure panic during callback unwinds properly.
+	if runtime.LockedOSThread() {
+		t.Fatal("locked OS thread on entry to TestCallbackPanic")
 	}
 	defer func() {
 		s := recover()
@@ -214,14 +213,21 @@ func TestCallbackPanicLocked(t *testing.T) {
 		if s.(string) != "callback panic" {
 			t.Fatal("wrong panic:", s)
 		}
-		if !runtime.LockedOSThread() {
-			t.Fatal("lost lock on OS thread after panic")
+		if runtime.LockedOSThread() {
+			t.Fatal("locked OS thread on exit from TestCallbackPanic")
 		}
 	}()
 	nestedCall(t, func() { panic("callback panic") })
 	panic("nestedCall returned")
 }
 
+func TestCallbackPanicLoop(t *testing.T) {
+	// Make sure we don't blow out m->g0 stack.
+	for i := 0; i < 100000; i++ {
+		TestCallbackPanic(t)
+	}
+}
+
 func TestBlockingCallback(t *testing.T) {
 	c := make(chan int)
 	go func() {
@@ -242,3 +248,204 @@ func TestBlockingCallback(t *testing.T) {
 func TestCallbackInAnotherThread(t *testing.T) {
 	// TODO: test a function which calls back in another thread: QueueUserAPC() or CreateThread()
 }
+
+type cbDLLFunc int // int determines number of callback parameters
+
+func (f cbDLLFunc) stdcallName() string {
+	return fmt.Sprintf("stdcall%d", f)
+}
+
+func (f cbDLLFunc) cdeclName() string {
+	return fmt.Sprintf("cdecl%d", f)
+}
+
+func (f cbDLLFunc) buildOne(stdcall bool) string {
+	var funcname, attr string
+	if stdcall {
+		funcname = f.stdcallName()
+		attr = "__stdcall"
+	} else {
+		funcname = f.cdeclName()
+		attr = "__cdecl"
+	}
+	typename := "t" + funcname
+	p := make([]string, f)
+	for i := range p {
+		p[i] = "void*"
+	}
+	params := strings.Join(p, ",")
+	for i := range p {
+		p[i] = fmt.Sprintf("%d", i+1)
+	}
+	args := strings.Join(p, ",")
+	return fmt.Sprintf(`
+typedef void %s (*%s)(%s);
+void %s(%s f, void *n) {
+	int i;
+	for(i=0;i<(int)n;i++){
+		f(%s);
+	}
+}
+	`, attr, typename, params, funcname, typename, args)
+}
+
+func (f cbDLLFunc) build() string {
+	return f.buildOne(false) + f.buildOne(true)
+}
+
+var cbFuncs = [...]interface{}{
+	2: func(i1, i2 uintptr) uintptr {
+		if i1+i2 != 3 {
+			panic("bad input")
+		}
+		return 0
+	},
+	3: func(i1, i2, i3 uintptr) uintptr {
+		if i1+i2+i3 != 6 {
+			panic("bad input")
+		}
+		return 0
+	},
+	4: func(i1, i2, i3, i4 uintptr) uintptr {
+		if i1+i2+i3+i4 != 10 {
+			panic("bad input")
+		}
+		return 0
+	},
+	5: func(i1, i2, i3, i4, i5 uintptr) uintptr {
+		if i1+i2+i3+i4+i5 != 15 {
+			panic("bad input")
+		}
+		return 0
+	},
+	6: func(i1, i2, i3, i4, i5, i6 uintptr) uintptr {
+		if i1+i2+i3+i4+i5+i6 != 21 {
+			panic("bad input")
+		}
+		return 0
+	},
+	7: func(i1, i2, i3, i4, i5, i6, i7 uintptr) uintptr {
+		if i1+i2+i3+i4+i5+i6+i7 != 28 {
+			panic("bad input")
+		}
+		return 0
+	},
+	8: func(i1, i2, i3, i4, i5, i6, i7, i8 uintptr) uintptr {
+		if i1+i2+i3+i4+i5+i6+i7+i8 != 36 {
+			panic("bad input")
+		}
+		return 0
+	},
+	9: func(i1, i2, i3, i4, i5, i6, i7, i8, i9 uintptr) uintptr {
+		if i1+i2+i3+i4+i5+i6+i7+i8+i9 != 45 {
+			panic("bad input")
+		}
+		return 0
+	},
+}
+
+type cbDLL struct {
+	name      string
+	buildArgs func(out, src string) []string
+}
+
+func (d *cbDLL) buildSrc(t *testing.T, path string) {
+	f, err := os.Create(path)
+	if err != nil {
+		t.Fatalf("failed to create source file: %v", err)
+	}
+	defer f.Close()
+
+	for i := 2; i < 10; i++ {
+		fmt.Fprint(f, cbDLLFunc(i).build())
+	}
+}
+
+func (d *cbDLL) build(t *testing.T, dir string) string {
+	srcname := d.name + ".c"
+	d.buildSrc(t, filepath.Join(dir, srcname))
+	outname := d.name + ".dll"
+	args := d.buildArgs(outname, srcname)
+	cmd := exec.Command(args[0], args[1:]...)
+	cmd.Dir = dir
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("failed to build dll: %v - %v", err, string(out))
+	}
+	return filepath.Join(dir, outname)
+}
+
+var cbDLLs = []cbDLL{
+	{
+		"test",
+		func(out, src string) []string {
+			return []string{"gcc", "-shared", "-s", "-o", out, src}
+		},
+	},
+	{
+		"testO2",
+		func(out, src string) []string {
+			return []string{"gcc", "-shared", "-s", "-o", out, "-O2", src}
+		},
+	},
+}
+
+type cbTest struct {
+	n     int     // number of callback parameters
+	param uintptr // dll function parameter
+}
+
+func (test *cbTest) run(t *testing.T, dllpath string) {
+	dll := syscall.MustLoadDLL(dllpath)
+	defer dll.Release()
+	cb := cbFuncs[test.n]
+	stdcall := syscall.NewCallback(cb)
+	f := cbDLLFunc(test.n)
+	test.runOne(t, dll, f.stdcallName(), stdcall)
+	cdecl := syscall.NewCallbackCDecl(cb)
+	test.runOne(t, dll, f.cdeclName(), cdecl)
+}
+
+func (test *cbTest) runOne(t *testing.T, dll *syscall.DLL, proc string, cb uintptr) {
+	defer func() {
+		if r := recover(); r != nil {
+			t.Errorf("dll call %v(..., %d) failed: %v", proc, test.param, r)
+		}
+	}()
+	dll.MustFindProc(proc).Call(cb, test.param)
+}
+
+var cbTests = []cbTest{
+	{2, 1},
+	{2, 10000},
+	{3, 3},
+	{4, 5},
+	{4, 6},
+	{5, 2},
+	{6, 7},
+	{6, 8},
+	{7, 6},
+	{8, 1},
+	{9, 8},
+	{9, 10000},
+	{3, 4},
+	{5, 3},
+	{7, 7},
+	{8, 2},
+	{9, 9},
+}
+
+func TestStdcallAndCDeclCallbacks(t *testing.T) {
+	tmp, err := ioutil.TempDir("", "TestCDeclCallback")
+	if err != nil {
+		t.Fatal("TempDir failed: ", err)
+	}
+	defer os.RemoveAll(tmp)
+
+	for _, dll := range cbDLLs {
+		dllPath := dll.build(t, tmp)
+		for _, test := range cbTests {
+			test.run(t, dllPath)
+		}
+	}
+}
diff --git a/src/pkg/runtime/time.goc b/src/pkg/runtime/time.goc
index b575696..712e03e 100644
--- a/src/pkg/runtime/time.goc
+++ b/src/pkg/runtime/time.goc
@@ -21,11 +21,19 @@ static Timers timers;
 static void addtimer(Timer*);
 static void dumptimers(int8*);
 
+// nacl fake time support. 
+int64 runtime·timens;
+
 // Package time APIs.
 // Godoc uses the comments in package time, not these.
 
 // time.now is implemented in assembly.
 
+// runtimeNano returns the current value of the runtime clock in nanoseconds.
+func runtimeNano() (ns int64) {
+	ns = runtime·nanotime();
+}
+
 // Sleep puts the current goroutine to sleep for at least ns nanoseconds.
 func Sleep(ns int64) {
 	runtime·tsleep(ns, "sleep");
@@ -46,6 +54,16 @@ func stopTimer(t *Timer) (stopped bool) {
 
 // C runtime.
 
+void runtime·gc_unixnanotime(int64 *now);
+
+int64 runtime·unixnanotime(void)
+{
+	int64 now;
+
+	runtime·gc_unixnanotime(&now);
+	return now;
+}
+
 static void timerproc(void);
 static void siftup(int32);
 static void siftdown(int32);
@@ -76,7 +94,7 @@ runtime·tsleep(int64 ns, int8 *reason)
 	t.arg.data = g;
 	runtime·lock(&timers);
 	addtimer(&t);
-	runtime·park(runtime·unlock, &timers, reason);
+	runtime·parkunlock(&timers, reason);
 }
 
 static FuncVal timerprocv = {timerproc};
@@ -217,12 +235,22 @@ timerproc(void)
 			if(raceenabled)
 				runtime·raceacquire(t);
 			f(now, arg);
+
+			// clear f and arg to avoid leak while sleeping for next timer
+			f = nil;
+			USED(f);
+			arg.type = nil;
+			arg.data = nil;
+			USED(&arg);
+
 			runtime·lock(&timers);
 		}
 		if(delta < 0) {
 			// No timers left - put goroutine to sleep.
 			timers.rescheduling = true;
-			runtime·park(runtime·unlock, &timers, "timer goroutine (idle)");
+			g->isbackground = true;
+			runtime·parkunlock(&timers, "timer goroutine (idle)");
+			g->isbackground = false;
 			continue;
 		}
 		// At least one timer pending.  Sleep until then.
diff --git a/src/pkg/runtime/traceback_arm.c b/src/pkg/runtime/traceback_arm.c
index 8a3685e..d15244c 100644
--- a/src/pkg/runtime/traceback_arm.c
+++ b/src/pkg/runtime/traceback_arm.c
@@ -8,17 +8,23 @@
 #include "funcdata.h"
 
 void runtime·sigpanic(void);
+void runtime·newproc(void);
+void runtime·deferproc(void);
 
 int32
-runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, void (*callback)(Stkframe*, void*), void *v, bool printall)
+runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, bool (*callback)(Stkframe*, void*), void *v, bool printall)
 {
-	int32 i, n, nprint, line;
-	uintptr x, tracepc;
-	bool waspanic, printing;
+	int32 i, n, nprint, line, gotraceback;
+	uintptr x, tracepc, sparg;
+	bool waspanic, wasnewproc, printing;
 	Func *f, *flr;
 	Stkframe frame;
 	Stktop *stk;
 	String file;
+	Panic *panic;
+	Defer *defer;
+
+	gotraceback = runtime·gotraceback(nil);
 
 	if(pc0 == ~(uintptr)0 && sp0 == ~(uintptr)0) { // Signal to fetch saved values from gp.
 		if(gp->syscallstack != (uintptr)nil) {
@@ -38,8 +44,17 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 	frame.lr = lr0;
 	frame.sp = sp0;
 	waspanic = false;
+	wasnewproc = false;
 	printing = pcbuf==nil && callback==nil;
 
+	panic = gp->panic;
+	defer = gp->defer;
+
+	while(defer != nil && defer->argp == NoArgs)
+		defer = defer->link;	
+	while(panic != nil && panic->defer == nil)
+		panic = panic->link;
+
 	// If the PC is zero, it's likely a nil function call.
 	// Start in the caller's frame.
 	if(frame.pc == 0) {
@@ -95,6 +110,19 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 		if(runtime·topofstack(f)) {
 			frame.lr = 0;
 			flr = nil;
+		} else if(f->entry == (uintptr)runtime·jmpdefer) {
+			// jmpdefer modifies SP/LR/PC non-atomically.
+			// If a profiling interrupt arrives during jmpdefer,
+			// the stack unwind may see a mismatched register set
+			// and get confused. Stop if we see PC within jmpdefer
+			// to avoid that confusion.
+			// See golang.org/issue/8153.
+			// This check can be deleted if jmpdefer is changed
+			// to restore all three atomically using pop.
+			if(callback != nil)
+				runtime·throw("traceback_arm: found jmpdefer when tracing with callback");
+			frame.lr = 0;
+			flr = nil;
 		} else {
 			if((n == 0 && frame.sp < frame.fp) || frame.lr == 0)
 				frame.lr = *(uintptr*)frame.sp;
@@ -133,6 +161,47 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 			}
 		}
 
+		// Determine function SP where deferproc would find its arguments.
+		// On ARM that's just the standard bottom-of-stack plus 1 word for
+		// the saved LR. If the previous frame was a direct call to newproc/deferproc,
+		// however, the SP is three words lower than normal.
+		// If the function has no frame at all - perhaps it just started, or perhaps
+		// it is a leaf with no local variables - then we cannot possibly find its
+		// SP in a defer, and we might confuse its SP for its caller's SP, so
+		// set sparg=0 in that case.
+		sparg = 0;
+		if(frame.fp != frame.sp) {
+			sparg = frame.sp + sizeof(uintreg);
+			if(wasnewproc)
+				sparg += 3*sizeof(uintreg);
+		}
+
+		// Determine frame's 'continuation PC', where it can continue.
+		// Normally this is the return address on the stack, but if sigpanic
+		// is immediately below this function on the stack, then the frame
+		// stopped executing due to a trap, and frame.pc is probably not
+		// a safe point for looking up liveness information. In this panicking case,
+		// the function either doesn't return at all (if it has no defers or if the
+		// defers do not recover) or it returns from one of the calls to 
+		// deferproc a second time (if the corresponding deferred func recovers).
+		// It suffices to assume that the most recent deferproc is the one that
+		// returns; everything live at earlier deferprocs is still live at that one.
+		frame.continpc = frame.pc;
+		if(waspanic) {
+			if(panic != nil && panic->defer->argp == (byte*)sparg)
+				frame.continpc = (uintptr)panic->defer->pc;
+			else if(defer != nil && defer->argp == (byte*)sparg)
+				frame.continpc = (uintptr)defer->pc;
+			else
+				frame.continpc = 0;
+		}
+
+		// Unwind our local panic & defer stacks past this frame.
+		while(panic != nil && (panic->defer == nil || panic->defer->argp == (byte*)sparg || panic->defer->argp == NoArgs))
+			panic = panic->link;
+		while(defer != nil && (defer->argp == (byte*)sparg || defer->argp == NoArgs))
+			defer = defer->link;	
+
 		if(skip > 0) {
 			skip--;
 			goto skipped;
@@ -140,8 +209,10 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 
 		if(pcbuf != nil)
 			pcbuf[n] = frame.pc;
-		if(callback != nil)
-			callback(&frame, v);
+		if(callback != nil) {
+			if(!callback(&frame, v))
+				return n;
+		}
 		if(printing) {
 			if(printall || runtime·showframe(f, gp)) {
 				// Print during crash.
@@ -152,7 +223,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 					tracepc -= sizeof(uintptr);
 				runtime·printf("%s(", runtime·funcname(f));
 				for(i = 0; i < frame.arglen/sizeof(uintptr); i++) {
-					if(i >= 5) {
+					if(i >= 10) {
 						runtime·prints(", ...");
 						break;
 					}
@@ -165,8 +236,8 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 				runtime·printf("\t%S:%d", file, line);
 				if(frame.pc > f->entry)
 					runtime·printf(" +%p", (uintptr)(frame.pc - f->entry));
-				if(m->throwing > 0 && gp == m->curg)
-					runtime·printf(" fp=%p", frame.fp);
+				if(m->throwing > 0 && gp == m->curg || gotraceback >= 2)
+					runtime·printf(" fp=%p sp=%p", frame.fp, frame.sp);
 				runtime·printf("\n");
 				nprint++;
 			}
@@ -175,6 +246,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 		
 	skipped:
 		waspanic = f->entry == (uintptr)runtime·sigpanic;
+		wasnewproc = f->entry == (uintptr)runtime·newproc || f->entry == (uintptr)runtime·deferproc;
 
 		// Do not unwind past the bottom of the stack.
 		if(flr == nil)
@@ -202,6 +274,23 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 	if(pcbuf == nil && callback == nil)
 		n = nprint;
 
+	// For rationale, see long comment in traceback_x86.c.
+	if(callback != nil && n < max && defer != nil) {
+		if(defer != nil)
+			runtime·printf("runtime: g%D: leftover defer argp=%p pc=%p\n", gp->goid, defer->argp, defer->pc);
+		if(panic != nil)
+			runtime·printf("runtime: g%D: leftover panic argp=%p pc=%p\n", gp->goid, panic->defer->argp, panic->defer->pc);
+		for(defer = gp->defer; defer != nil; defer = defer->link)
+			runtime·printf("\tdefer %p argp=%p pc=%p\n", defer, defer->argp, defer->pc);
+		for(panic = gp->panic; panic != nil; panic = panic->link) {
+			runtime·printf("\tpanic %p defer %p", panic, panic->defer);
+			if(panic->defer != nil)
+				runtime·printf(" argp=%p pc=%p", panic->defer->argp, panic->defer->pc);
+			runtime·printf("\n");
+		}
+		runtime·throw("traceback has leftover defers or panics");
+	}
+
 	return n;		
 }
 
@@ -231,6 +320,8 @@ runtime·printcreatedby(G *gp)
 void
 runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G *gp)
 {
+	int32 n;
+
 	if(gp->status == Gsyscall) {
 		// Override signal registers if blocked in system call.
 		pc = gp->syscallpc;
@@ -240,8 +331,11 @@ runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G *gp)
 
 	// Print traceback. By default, omits runtime frames.
 	// If that means we print nothing at all, repeat forcing all frames printed.
-	if(runtime·gentraceback(pc, sp, lr, gp, 0, nil, 100, nil, nil, false) == 0)
-		runtime·gentraceback(pc, sp, lr, gp, 0, nil, 100, nil, nil, true);
+	n = runtime·gentraceback(pc, sp, lr, gp, 0, nil, TracebackMaxFrames, nil, nil, false);
+	if(n == 0)
+		runtime·gentraceback(pc, sp, lr, gp, 0, nil, TracebackMaxFrames, nil, nil, true);
+	if(n == TracebackMaxFrames)
+		runtime·printf("...additional frames elided...\n");
 	runtime·printcreatedby(gp);
 }
 
diff --git a/src/pkg/runtime/traceback_x86.c b/src/pkg/runtime/traceback_x86.c
index 8e3063f..851504f 100644
--- a/src/pkg/runtime/traceback_x86.c
+++ b/src/pkg/runtime/traceback_x86.c
@@ -2,14 +2,23 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build amd64 386
+// +build amd64 amd64p32 386
 
 #include "runtime.h"
 #include "arch_GOARCH.h"
 #include "malloc.h"
 #include "funcdata.h"
+#ifdef GOOS_windows
+#include "defs_GOOS_GOARCH.h"
+#endif
 
 void runtime·sigpanic(void);
+void runtime·newproc(void);
+void runtime·deferproc(void);
+
+#ifdef GOOS_windows
+void runtime·sigtramp(void);
+#endif
 
 // This code is also used for the 386 tracebacks.
 // Use uintptr for an appropriate word-sized integer.
@@ -19,18 +28,22 @@ void runtime·sigpanic(void);
 // collector (callback != nil).  A little clunky to merge these, but avoids
 // duplicating the code and all its subtlety.
 int32
-runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, void (*callback)(Stkframe*, void*), void *v, bool printall)
+runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, bool (*callback)(Stkframe*, void*), void *v, bool printall)
 {
-	int32 i, n, nprint, line;
-	uintptr tracepc;
-	bool waspanic, printing;
+	int32 i, n, nprint, line, gotraceback;
+	uintptr tracepc, sparg;
+	bool waspanic, wasnewproc, printing;
 	Func *f, *flr;
 	Stkframe frame;
 	Stktop *stk;
 	String file;
+	Panic *panic;
+	Defer *defer;
 
 	USED(lr0);
 	
+	gotraceback = runtime·gotraceback(nil);
+	
 	if(pc0 == ~(uintptr)0 && sp0 == ~(uintptr)0) { // Signal to fetch saved values from gp.
 		if(gp->syscallstack != (uintptr)nil) {
 			pc0 = gp->syscallpc;
@@ -46,13 +59,21 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 	frame.pc = pc0;
 	frame.sp = sp0;
 	waspanic = false;
+	wasnewproc = false;
 	printing = pcbuf==nil && callback==nil;
-	
+	panic = gp->panic;
+	defer = gp->defer;
+
+	while(defer != nil && defer->argp == NoArgs)
+		defer = defer->link;	
+	while(panic != nil && panic->defer == nil)
+		panic = panic->link;
+
 	// If the PC is zero, it's likely a nil function call.
 	// Start in the caller's frame.
 	if(frame.pc == 0) {
 		frame.pc = *(uintptr*)frame.sp;
-		frame.sp += sizeof(uintptr);
+		frame.sp += sizeof(uintreg);
 	}
 	
 	f = runtime·findfunc(frame.pc);
@@ -95,20 +116,63 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 			frame.fn = f;
 			continue;
 		}
+		
 		f = frame.fn;
 
+#ifdef GOOS_windows
+		// Windows exception handlers run on the actual g stack (there is room
+		// dedicated to this below the usual "bottom of stack"), not on a separate
+		// stack. As a result, we have to be able to unwind past the exception
+		// handler when called to unwind during stack growth inside the handler.
+		// Recognize the frame at the call to sighandler in sigtramp and unwind
+		// using the context argument passed to the call. This is awful.
+		if(f != nil && f->entry == (uintptr)runtime·sigtramp && frame.pc > f->entry) {
+			Context *r;
+			
+			// Invoke callback so that stack copier sees an uncopyable frame.
+			if(callback != nil) {
+				frame.continpc = frame.pc;
+				frame.argp = nil;
+				frame.arglen = 0;
+				if(!callback(&frame, v))
+					return n;
+			}
+			r = (Context*)((uintptr*)frame.sp)[1];
+#ifdef GOARCH_amd64
+			frame.pc = r->Rip;
+			frame.sp = r->Rsp;
+#else
+			frame.pc = r->Eip;
+			frame.sp = r->Esp;
+#endif
+			frame.lr = 0;
+			frame.fp = 0;
+			frame.fn = nil;
+			if(printing && runtime·showframe(nil, gp))
+				runtime·printf("----- exception handler -----\n");
+			f = runtime·findfunc(frame.pc);
+			if(f == nil) {
+				runtime·printf("runtime: unknown pc %p after exception handler\n", frame.pc);
+				if(callback != nil)
+					runtime·throw("unknown pc");
+			}
+			frame.fn = f;
+			continue;
+		}
+#endif
+
 		// Found an actual function.
 		// Derive frame pointer and link register.
 		if(frame.fp == 0) {
 			frame.fp = frame.sp + runtime·funcspdelta(f, frame.pc);
-			frame.fp += sizeof(uintptr); // caller PC
+			frame.fp += sizeof(uintreg); // caller PC
 		}
 		if(runtime·topofstack(f)) {
 			frame.lr = 0;
 			flr = nil;
 		} else {
 			if(frame.lr == 0)
-				frame.lr = ((uintptr*)frame.fp)[-1];
+				frame.lr = ((uintreg*)frame.fp)[-1];
 			flr = runtime·findfunc(frame.lr);
 			if(flr == nil) {
 				runtime·printf("runtime: unexpected return pc for %s called from %p\n", runtime·funcname(f), frame.lr);
@@ -117,7 +181,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 			}
 		}
 		
-		frame.varp = (byte*)frame.fp - sizeof(uintptr);
+		frame.varp = (byte*)frame.fp - sizeof(uintreg);
 
 		// Derive size of arguments.
 		// Most functions have a fixed-size argument block,
@@ -143,6 +207,40 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 				frame.arglen = 0;
 			}
 		}
+		
+		// Determine function SP where deferproc would find its arguments.
+		// On x86 that's just the standard bottom-of-stack, so SP exactly.
+		// If the previous frame was a direct call to newproc/deferproc, however,
+		// the SP is two words lower than normal.
+		sparg = frame.sp;
+		if(wasnewproc)
+			sparg += 2*sizeof(uintreg);
+
+		// Determine frame's 'continuation PC', where it can continue.
+		// Normally this is the return address on the stack, but if sigpanic
+		// is immediately below this function on the stack, then the frame
+		// stopped executing due to a trap, and frame.pc is probably not
+		// a safe point for looking up liveness information. In this panicking case,
+		// the function either doesn't return at all (if it has no defers or if the
+		// defers do not recover) or it returns from one of the calls to 
+		// deferproc a second time (if the corresponding deferred func recovers).
+		// It suffices to assume that the most recent deferproc is the one that
+		// returns; everything live at earlier deferprocs is still live at that one.
+		frame.continpc = frame.pc;
+		if(waspanic) {
+			if(panic != nil && panic->defer->argp == (byte*)sparg)
+				frame.continpc = (uintptr)panic->defer->pc;
+			else if(defer != nil && defer->argp == (byte*)sparg)
+				frame.continpc = (uintptr)defer->pc;
+			else
+				frame.continpc = 0;
+		}
+
+		// Unwind our local panic & defer stacks past this frame.
+		while(panic != nil && (panic->defer == nil || panic->defer->argp == (byte*)sparg || panic->defer->argp == NoArgs))
+			panic = panic->link;
+		while(defer != nil && (defer->argp == (byte*)sparg || defer->argp == NoArgs))
+			defer = defer->link;	
 
 		if(skip > 0) {
 			skip--;
@@ -151,8 +249,10 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 
 		if(pcbuf != nil)
 			pcbuf[n] = frame.pc;
-		if(callback != nil)
-			callback(&frame, v);
+		if(callback != nil) {
+			if(!callback(&frame, v))
+				return n;
+		}
 		if(printing) {
 			if(printall || runtime·showframe(f, gp)) {
 				// Print during crash.
@@ -164,7 +264,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 					tracepc--;
 				runtime·printf("%s(", runtime·funcname(f));
 				for(i = 0; i < frame.arglen/sizeof(uintptr); i++) {
-					if(i >= 5) {
+					if(i >= 10) {
 						runtime·prints(", ...");
 						break;
 					}
@@ -177,8 +277,8 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 				runtime·printf("\t%S:%d", file, line);
 				if(frame.pc > f->entry)
 					runtime·printf(" +%p", (uintptr)(frame.pc - f->entry));
-				if(m->throwing > 0 && gp == m->curg)
-					runtime·printf(" fp=%p", frame.fp);
+				if(m->throwing > 0 && gp == m->curg || gotraceback >= 2)
+					runtime·printf(" fp=%p sp=%p", frame.fp, frame.sp);
 				runtime·printf("\n");
 				nprint++;
 			}
@@ -187,6 +287,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 	
 	skipped:
 		waspanic = f->entry == (uintptr)runtime·sigpanic;
+		wasnewproc = f->entry == (uintptr)runtime·newproc || f->entry == (uintptr)runtime·deferproc;
 
 		// Do not unwind past the bottom of the stack.
 		if(flr == nil)
@@ -202,7 +303,72 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
 	
 	if(pcbuf == nil && callback == nil)
 		n = nprint;
-	
+
+	// If callback != nil, we're being called to gather stack information during
+	// garbage collection or stack growth. In that context, require that we used
+	// up the entire defer stack. If not, then there is a bug somewhere and the
+	// garbage collection or stack growth may not have seen the correct picture
+	// of the stack. Crash now instead of silently executing the garbage collection
+	// or stack copy incorrectly and setting up for a mysterious crash later.
+	//
+	// Note that panic != nil is okay here: there can be leftover panics,
+	// because the defers on the panic stack do not nest in frame order as
+	// they do on the defer stack. If you have:
+	//
+	//	frame 1 defers d1
+	//	frame 2 defers d2
+	//	frame 3 defers d3
+	//	frame 4 panics
+	//	frame 4's panic starts running defers
+	//	frame 5, running d3, defers d4
+	//	frame 5 panics
+	//	frame 5's panic starts running defers
+	//	frame 6, running d4, garbage collects
+	//	frame 6, running d2, garbage collects
+	//
+	// During the execution of d4, the panic stack is d4 -> d3, which
+	// is nested properly, and we'll treat frame 3 as resumable, because we
+	// can find d3. (And in fact frame 3 is resumable. If d4 recovers
+	// and frame 5 continues running, d3, d3 can recover and we'll
+	// resume execution in (returning from) frame 3.)
+	//
+	// During the execution of d2, however, the panic stack is d2 -> d3,
+	// which is inverted. The scan will match d2 to frame 2 but having
+	// d2 on the stack until then means it will not match d3 to frame 3.
+	// This is okay: if we're running d2, then all the defers after d2 have
+	// completed and their corresponding frames are dead. Not finding d3
+	// for frame 3 means we'll set frame 3's continpc == 0, which is correct
+	// (frame 3 is dead). At the end of the walk the panic stack can thus
+	// contain defers (d3 in this case) for dead frames. The inversion here
+	// always indicates a dead frame, and the effect of the inversion on the
+	// scan is to hide those dead frames, so the scan is still okay:
+	// what's left on the panic stack are exactly (and only) the dead frames.
+	//
+	// We require callback != nil here because only when callback != nil
+	// do we know that gentraceback is being called in a "must be correct"
+	// context as opposed to a "best effort" context. The tracebacks with
+	// callbacks only happen when everything is stopped nicely.
+	// At other times, such as when gathering a stack for a profiling signal
+	// or when printing a traceback during a crash, everything may not be
+	// stopped nicely, and the stack walk may not be able to complete.
+	// It's okay in those situations not to use up the entire defer stack:
+	// incomplete information then is still better than nothing.
+	if(callback != nil && n < max && defer != nil) {
+		if(defer != nil)
+			runtime·printf("runtime: g%D: leftover defer argp=%p pc=%p\n", gp->goid, defer->argp, defer->pc);
+		if(panic != nil)
+			runtime·printf("runtime: g%D: leftover panic argp=%p pc=%p\n", gp->goid, panic->defer->argp, panic->defer->pc);
+		for(defer = gp->defer; defer != nil; defer = defer->link)
+			runtime·printf("\tdefer %p argp=%p pc=%p\n", defer, defer->argp, defer->pc);
+		for(panic = gp->panic; panic != nil; panic = panic->link) {
+			runtime·printf("\tpanic %p defer %p", panic, panic->defer);
+			if(panic->defer != nil)
+				runtime·printf(" argp=%p pc=%p", panic->defer->argp, panic->defer->pc);
+			runtime·printf("\n");
+		}
+		runtime·throw("traceback has leftover defers or panics");
+	}
+
 	return n;
 }
 
@@ -232,6 +398,8 @@ runtime·printcreatedby(G *gp)
 void
 runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G *gp)
 {
+	int32 n;
+
 	USED(lr);
 
 	if(gp->status == Gsyscall) {
@@ -242,8 +410,11 @@ runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G *gp)
 	
 	// Print traceback. By default, omits runtime frames.
 	// If that means we print nothing at all, repeat forcing all frames printed.
-	if(runtime·gentraceback(pc, sp, 0, gp, 0, nil, 100, nil, nil, false) == 0)
-		runtime·gentraceback(pc, sp, 0, gp, 0, nil, 100, nil, nil, true);
+	n = runtime·gentraceback(pc, sp, 0, gp, 0, nil, TracebackMaxFrames, nil, nil, false);
+	if(n == 0)
+		n = runtime·gentraceback(pc, sp, 0, gp, 0, nil, TracebackMaxFrames, nil, nil, true);
+	if(n == TracebackMaxFrames)
+		runtime·printf("...additional frames elided...\n");
 	runtime·printcreatedby(gp);
 }
 
diff --git a/src/pkg/runtime/type.go b/src/pkg/runtime/type.go
index 374754a..276dbc0 100644
--- a/src/pkg/runtime/type.go
+++ b/src/pkg/runtime/type.go
@@ -26,6 +26,7 @@ type rtype struct {
 	string     *string
 	*uncommonType
 	ptrToThis *rtype
+	zero      unsafe.Pointer
 }
 
 type _method struct {
diff --git a/src/pkg/runtime/type.h b/src/pkg/runtime/type.h
index 3093604..1598acc 100644
--- a/src/pkg/runtime/type.h
+++ b/src/pkg/runtime/type.h
@@ -15,9 +15,8 @@ typedef struct Method Method;
 typedef struct IMethod IMethod;
 typedef struct SliceType SliceType;
 typedef struct FuncType FuncType;
-typedef struct PtrType PtrType;
 
-// Needs to be in sync with typekind.h/CommonSize
+// Needs to be in sync with ../../cmd/ld/decodesym.c:/^commonsize
 struct Type
 {
 	uintptr size;
@@ -31,6 +30,7 @@ struct Type
 	String *string;
 	UncommonType *x;
 	Type *ptrto;
+	byte *zero;  // ptr to the zero value for this type
 };
 
 struct Method
@@ -100,7 +100,3 @@ struct PtrType
 	Type;
 	Type *elem;
 };
-
-// Here instead of in runtime.h because it uses the type names.
-bool	runtime·addfinalizer(void*, FuncVal *fn, uintptr, Type*, PtrType*);
-bool	runtime·getfinalizer(void *p, bool del, FuncVal **fn, uintptr *nret, Type**, PtrType**);
diff --git a/src/pkg/runtime/typekind.h b/src/pkg/runtime/typekind.h
index 9bae2a8..3f0ba9a 100644
--- a/src/pkg/runtime/typekind.h
+++ b/src/pkg/runtime/typekind.h
@@ -34,8 +34,5 @@ enum {
 	KindUnsafePointer,
 
 	KindNoPointers = 1<<7,
-
-	// size of Type structure.
-	CommonSize = 6*PtrSize + 8,
 };
 
diff --git a/src/pkg/runtime/vlop_arm.s b/src/pkg/runtime/vlop_arm.s
index d7c566a..80f516e 100644
--- a/src/pkg/runtime/vlop_arm.s
+++ b/src/pkg/runtime/vlop_arm.s
@@ -75,10 +75,14 @@ TEXT _sfloat(SB), NOSPLIT, $64-0 // 4 arg + 14*4 saved regs + cpsr
 	MOVW	m_locks(m), R1
 	ADD	$1, R1
 	MOVW	R1, m_locks(m)
+	MOVW	$1, R1
+	MOVW	R1, m_softfloat(m)
 	BL	runtime·_sfloat2(SB)
 	MOVW	m_locks(m), R1
 	SUB	$1, R1
 	MOVW	R1, m_locks(m)
+	MOVW	$0, R1
+	MOVW	R1, m_softfloat(m)
 	MOVW	R0, 0(R13)
 	MOVW	64(R13), R1
 	WORD	$0xe128f001	// msr cpsr_f, r1
@@ -255,7 +259,7 @@ TEXT _div(SB),NOSPLIT,$16
 d0:
 	BL  	udiv<>(SB)  		/* none/both neg */
 	MOVW	R(q), R(TMP)
-	B		out
+	B		out1
 d1:
 	CMP 	$0, R(q)
 	BGE 	d0
@@ -263,7 +267,12 @@ d1:
 d2:
 	BL  	udiv<>(SB)  		/* one neg */
 	RSB		$0, R(q), R(TMP)
-	B   	out
+out1:
+	MOVW	4(R13), R(q)
+	MOVW	8(R13), R(r)
+	MOVW	12(R13), R(s)
+	MOVW	16(R13), R(M)
+	RET
 
 TEXT _mod(SB),NOSPLIT,$16
 	MOVW	R(q), 4(R13)
diff --git a/src/pkg/runtime/vlrt_386.c b/src/pkg/runtime/vlrt_386.c
index 8d965c0..ace1beb 100644
--- a/src/pkg/runtime/vlrt_386.c
+++ b/src/pkg/runtime/vlrt_386.c
@@ -32,6 +32,8 @@
  * to generate the code directly now.  Find and remove.
  */
 
+extern void runtime·panicdivide(void);
+
 typedef	unsigned long	ulong;
 typedef	unsigned int	uint;
 typedef	unsigned short	ushort;
@@ -240,6 +242,8 @@ dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
 		}
 	} else {
 		if(num.hi >= den.lo){
+			if(den.lo == 0)
+				runtime·panicdivide();
 			q.hi = n = num.hi/den.lo;
 			num.hi -= den.lo*n;
 		} else {
@@ -263,6 +267,8 @@ _divvu(Vlong *q, Vlong n, Vlong d)
 {
 
 	if(n.hi == 0 && d.hi == 0) {
+		if(d.lo == 0)
+			runtime·panicdivide();
 		q->hi = 0;
 		q->lo = n.lo / d.lo;
 		return;
@@ -281,6 +287,8 @@ _modvu(Vlong *r, Vlong n, Vlong d)
 {
 
 	if(n.hi == 0 && d.hi == 0) {
+		if(d.lo == 0)
+			runtime·panicdivide();
 		r->hi = 0;
 		r->lo = n.lo % d.lo;
 		return;
@@ -319,6 +327,8 @@ _divv(Vlong *q, Vlong n, Vlong d)
 			q->hi = 0;
 			return;
 		}
+		if(d.lo == 0)
+			runtime·panicdivide();
 		q->lo = (long)n.lo / (long)d.lo;
 		q->hi = ((long)q->lo) >> 31;
 		return;
@@ -353,6 +363,8 @@ _modv(Vlong *r, Vlong n, Vlong d)
 			r->hi = 0;
 			return;
 		}
+		if(d.lo == 0)
+			runtime·panicdivide();
 		r->lo = (long)n.lo % (long)d.lo;
 		r->hi = ((long)r->lo) >> 31;
 		return;
diff --git a/src/pkg/runtime/vlrt_arm.c b/src/pkg/runtime/vlrt_arm.c
index 219163c..7dd71b4 100644
--- a/src/pkg/runtime/vlrt_arm.c
+++ b/src/pkg/runtime/vlrt_arm.c
@@ -27,6 +27,7 @@
 
 // declared here to avoid include of runtime.h
 void	runtime·panicstring(char*);
+void	runtime·panicdivide(void);
 
 typedef unsigned long   ulong;
 typedef unsigned int    uint;
@@ -36,12 +37,6 @@ typedef signed char     schar;
 
 #define SIGN(n) (1UL<<(n-1))
 
-void
-runtime·panicdivide(void)
-{
-	runtime·panicstring("integer divide by zero");
-}
-
 typedef struct  Vlong   Vlong;
 struct  Vlong
 {
diff --git a/src/pkg/sort/sort.go b/src/pkg/sort/sort.go
index f06eb38..e980c29 100644
--- a/src/pkg/sort/sort.go
+++ b/src/pkg/sort/sort.go
@@ -287,9 +287,9 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
 // Notes on stable sorting:
 // The used algorithms are simple and provable correct on all input and use
 // only logarithmic additional stack space.  They perform well if compared
-// experimentaly to other stable in-place sorting algorithms.
+// experimentally to other stable in-place sorting algorithms.
 //
-// Remarks on other algoritms evaluated:
+// Remarks on other algorithms evaluated:
 //  - GCC's 4.6.3 stable_sort with merge_without_buffer from libstdc++:
 //    Not faster.
 //  - GCC's __rotate for block rotations: Not faster.
@@ -349,7 +349,7 @@ func Stable(data Interface) {
 // The algorithm needs O((M+N)*log(M)) calls to data.Swap.
 //
 // The paper gives O((M+N)*log(M)) as the number of assignments assuming a
-// rotation algorithm wich uses O(M+N+gcd(M+N)) assignments. The argumentation
+// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation
 // in the paper carries through for Swap operations, especially as the block
 // swapping rotate uses only O(M+N) Swaps.
 func symMerge(data Interface, a, m, b int) {
diff --git a/src/pkg/strconv/atob_test.go b/src/pkg/strconv/atob_test.go
index a7c1454..28f469f 100644
--- a/src/pkg/strconv/atob_test.go
+++ b/src/pkg/strconv/atob_test.go
@@ -5,6 +5,7 @@
 package strconv_test
 
 import (
+	"bytes"
 	. "strconv"
 	"testing"
 )
@@ -55,3 +56,36 @@ func TestParseBool(t *testing.T) {
 		}
 	}
 }
+
+var boolString = map[bool]string{
+	true:  "true",
+	false: "false",
+}
+
+func TestFormatBool(t *testing.T) {
+	for b, s := range boolString {
+		if f := FormatBool(b); f != s {
+			t.Errorf(`FormatBool(%v): expected %q but got %q`, b, s, f)
+		}
+	}
+}
+
+type appendBoolTest struct {
+	b   bool
+	in  []byte
+	out []byte
+}
+
+var appendBoolTests = []appendBoolTest{
+	{true, []byte("foo "), []byte("foo true")},
+	{false, []byte("foo "), []byte("foo false")},
+}
+
+func TestAppendBool(t *testing.T) {
+	for _, test := range appendBoolTests {
+		b := AppendBool(test.in, test.b)
+		if !bytes.Equal(b, test.out) {
+			t.Errorf("AppendBool(%q, %v): expected %q but got %q", test.in, test.b, test.out, b)
+		}
+	}
+}
diff --git a/src/pkg/strconv/atof.go b/src/pkg/strconv/atof.go
index 1b3f8fb..2862064 100644
--- a/src/pkg/strconv/atof.go
+++ b/src/pkg/strconv/atof.go
@@ -353,17 +353,6 @@ out:
 	return bits, overflow
 }
 
-func (d *decimal) atof32int() float32 {
-	f := float32(0)
-	for i := 0; i < d.nd; i++ {
-		f = f*10 + float32(d.d[i]-'0')
-	}
-	if d.neg {
-		f = -f
-	}
-	return f
-}
-
 // Exact powers of 10.
 var float64pow10 = []float64{
 	1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
diff --git a/src/pkg/strconv/atoi.go b/src/pkg/strconv/atoi.go
index 2d0db71..cbf0380 100644
--- a/src/pkg/strconv/atoi.go
+++ b/src/pkg/strconv/atoi.go
@@ -142,9 +142,11 @@ Error:
 //
 // The errors that ParseInt returns have concrete type *NumError
 // and include err.Num = s.  If s is empty or contains invalid
-// digits, err.Err = ErrSyntax; if the value corresponding
-// to s cannot be represented by a signed integer of the
-// given size, err.Err = ErrRange.
+// digits, err.Err = ErrSyntax and the returned value is 0;
+// if the value corresponding to s cannot be represented by a
+// signed integer of the given size, err.Err = ErrRange and the
+// returned value is the maximum magnitude integer of the
+// appropriate bitSize and sign.
 func ParseInt(s string, base int, bitSize int) (i int64, err error) {
 	const fnParseInt = "ParseInt"
 
diff --git a/src/pkg/strconv/isprint.go b/src/pkg/strconv/isprint.go
index db5f0fb..91f1795 100644
--- a/src/pkg/strconv/isprint.go
+++ b/src/pkg/strconv/isprint.go
@@ -1,3 +1,7 @@
+// 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.
+
 // DO NOT EDIT.  GENERATED BY
 //     go run makeisprint.go >x && mv x isprint.go
 
diff --git a/src/pkg/strconv/makeisprint.go b/src/pkg/strconv/makeisprint.go
index 8a6699b..216159c 100644
--- a/src/pkg/strconv/makeisprint.go
+++ b/src/pkg/strconv/makeisprint.go
@@ -122,6 +122,9 @@ func main() {
 		}
 	}
 
+	fmt.Printf(`// 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.` + "\n\n")
 	fmt.Printf("// DO NOT EDIT.  GENERATED BY\n")
 	fmt.Printf("//     go run makeisprint.go >x && mv x isprint.go\n\n")
 	fmt.Printf("package strconv\n\n")
diff --git a/src/pkg/strconv/quote.go b/src/pkg/strconv/quote.go
index 7d6cdcf..aded7e5 100644
--- a/src/pkg/strconv/quote.go
+++ b/src/pkg/strconv/quote.go
@@ -144,7 +144,8 @@ func AppendQuoteRuneToASCII(dst []byte, r rune) []byte {
 // characters other than space and tab.
 func CanBackquote(s string) bool {
 	for i := 0; i < len(s); i++ {
-		if (s[i] < ' ' && s[i] != '\t') || s[i] == '`' {
+		c := s[i]
+		if (c < ' ' && c != '\t') || c == '`' || c == '\u007F' {
 			return false
 		}
 	}
diff --git a/src/pkg/strconv/quote_example_test.go b/src/pkg/strconv/quote_example_test.go
new file mode 100644
index 0000000..405a57e
--- /dev/null
+++ b/src/pkg/strconv/quote_example_test.go
@@ -0,0 +1,35 @@
+// 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 strconv_test
+
+import (
+	"fmt"
+	"strconv"
+)
+
+func ExampleUnquote() {
+	test := func(s string) {
+		t, err := strconv.Unquote(s)
+		if err != nil {
+			fmt.Printf("Unquote(%#v): %v\n", s, err)
+		} else {
+			fmt.Printf("Unquote(%#v) = %v\n", s, t)
+		}
+	}
+
+	s := `cafe\u0301`
+	// If the string doesn't have quotes, it can't be unquoted.
+	test(s) // invalid syntax
+	test("`" + s + "`")
+	test(`"` + s + `"`)
+
+	test(`'\u00e9'`)
+
+	// Output:
+	// Unquote("cafe\\u0301"): invalid syntax
+	// Unquote("`cafe\\u0301`") = cafe\u0301
+	// Unquote("\"cafe\\u0301\"") = café
+	// Unquote("'\\u00e9'") = é
+}
diff --git a/src/pkg/strconv/quote_test.go b/src/pkg/strconv/quote_test.go
index 61d9bf9..e4b5b6b 100644
--- a/src/pkg/strconv/quote_test.go
+++ b/src/pkg/strconv/quote_test.go
@@ -140,6 +140,7 @@ var canbackquotetests = []canBackquoteTest{
 	{string(29), false},
 	{string(30), false},
 	{string(31), false},
+	{string(0x7F), false},
 	{`' !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, true},
 	{`0123456789`, true},
 	{`ABCDEFGHIJKLMNOPQRSTUVWXYZ`, true},
diff --git a/src/pkg/strings/example_test.go b/src/pkg/strings/example_test.go
index 36e0a42..7243e16 100644
--- a/src/pkg/strings/example_test.go
+++ b/src/pkg/strings/example_test.go
@@ -7,6 +7,7 @@ package strings_test
 import (
 	"fmt"
 	"strings"
+	"unicode"
 )
 
 func ExampleFields() {
@@ -14,6 +15,14 @@ func ExampleFields() {
 	// Output: Fields are: ["foo" "bar" "baz"]
 }
 
+func ExampleFieldsFunc() {
+	f := func(c rune) bool {
+		return !unicode.IsLetter(c) && !unicode.IsNumber(c)
+	}
+	fmt.Printf("Fields are: %q", strings.FieldsFunc("  foo1;bar2,baz3...", f))
+	// Output: Fields are: ["foo1" "bar2" "baz3"]
+}
+
 func ExampleContains() {
 	fmt.Println(strings.Contains("seafood", "foo"))
 	fmt.Println(strings.Contains("seafood", "bar"))
@@ -59,6 +68,25 @@ func ExampleIndex() {
 	// -1
 }
 
+func ExampleIndexFunc() {
+	f := func(c rune) bool {
+		return unicode.Is(unicode.Han, c)
+	}
+	fmt.Println(strings.IndexFunc("Hello, 世界", f))
+	fmt.Println(strings.IndexFunc("Hello, world", f))
+	// Output:
+	// 7
+	// -1
+}
+
+func ExampleIndexAny() {
+	fmt.Println(strings.IndexAny("chicken", "aeiouy"))
+	fmt.Println(strings.IndexAny("crwth", "aeiouy"))
+	// Output:
+	// 2
+	// -1
+}
+
 func ExampleIndexRune() {
 	fmt.Println(strings.IndexRune("chicken", 'k'))
 	fmt.Println(strings.IndexRune("chicken", 'd'))
@@ -141,8 +169,8 @@ func ExampleToTitle() {
 }
 
 func ExampleTrim() {
-	fmt.Printf("[%q]", strings.Trim(" !!! Achtung !!! ", "! "))
-	// Output: ["Achtung"]
+	fmt.Printf("[%q]", strings.Trim(" !!! Achtung! Achtung! !!! ", "! "))
+	// Output: ["Achtung! Achtung"]
 }
 
 func ExampleMap() {
diff --git a/src/pkg/strings/reader.go b/src/pkg/strings/reader.go
index 11240ef..82df974 100644
--- a/src/pkg/strings/reader.go
+++ b/src/pkg/strings/reader.go
@@ -15,40 +15,41 @@ import (
 // from a string.
 type Reader struct {
 	s        string
-	i        int // current reading index
-	prevRune int // index of previous rune; or < 0
+	i        int64 // current reading index
+	prevRune int   // index of previous rune; or < 0
 }
 
 // Len returns the number of bytes of the unread portion of the
 // string.
 func (r *Reader) Len() int {
-	if r.i >= len(r.s) {
+	if r.i >= int64(len(r.s)) {
 		return 0
 	}
-	return len(r.s) - r.i
+	return int(int64(len(r.s)) - r.i)
 }
 
 func (r *Reader) Read(b []byte) (n int, err error) {
 	if len(b) == 0 {
 		return 0, nil
 	}
-	if r.i >= len(r.s) {
+	if r.i >= int64(len(r.s)) {
 		return 0, io.EOF
 	}
-	n = copy(b, r.s[r.i:])
-	r.i += n
 	r.prevRune = -1
+	n = copy(b, r.s[r.i:])
+	r.i += int64(n)
 	return
 }
 
 func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
+	// cannot modify state - see io.ReaderAt
 	if off < 0 {
-		return 0, errors.New("strings: invalid offset")
+		return 0, errors.New("strings.Reader.ReadAt: negative offset")
 	}
 	if off >= int64(len(r.s)) {
 		return 0, io.EOF
 	}
-	n = copy(b, r.s[int(off):])
+	n = copy(b, r.s[off:])
 	if n < len(b) {
 		err = io.EOF
 	}
@@ -56,49 +57,51 @@ func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
 }
 
 func (r *Reader) ReadByte() (b byte, err error) {
-	if r.i >= len(r.s) {
+	r.prevRune = -1
+	if r.i >= int64(len(r.s)) {
 		return 0, io.EOF
 	}
 	b = r.s[r.i]
 	r.i++
-	r.prevRune = -1
 	return
 }
 
 func (r *Reader) UnreadByte() error {
+	r.prevRune = -1
 	if r.i <= 0 {
-		return errors.New("strings.Reader: at beginning of string")
+		return errors.New("strings.Reader.UnreadByte: at beginning of string")
 	}
 	r.i--
-	r.prevRune = -1
 	return nil
 }
 
 func (r *Reader) ReadRune() (ch rune, size int, err error) {
-	if r.i >= len(r.s) {
+	if r.i >= int64(len(r.s)) {
+		r.prevRune = -1
 		return 0, 0, io.EOF
 	}
-	r.prevRune = r.i
+	r.prevRune = int(r.i)
 	if c := r.s[r.i]; c < utf8.RuneSelf {
 		r.i++
 		return rune(c), 1, nil
 	}
 	ch, size = utf8.DecodeRuneInString(r.s[r.i:])
-	r.i += size
+	r.i += int64(size)
 	return
 }
 
 func (r *Reader) UnreadRune() error {
 	if r.prevRune < 0 {
-		return errors.New("strings.Reader: previous operation was not ReadRune")
+		return errors.New("strings.Reader.UnreadRune: previous operation was not ReadRune")
 	}
-	r.i = r.prevRune
+	r.i = int64(r.prevRune)
 	r.prevRune = -1
 	return nil
 }
 
 // Seek implements the io.Seeker interface.
 func (r *Reader) Seek(offset int64, whence int) (int64, error) {
+	r.prevRune = -1
 	var abs int64
 	switch whence {
 	case 0:
@@ -108,22 +111,19 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) {
 	case 2:
 		abs = int64(len(r.s)) + offset
 	default:
-		return 0, errors.New("strings: invalid whence")
+		return 0, errors.New("strings.Reader.Seek: invalid whence")
 	}
 	if abs < 0 {
-		return 0, errors.New("strings: negative position")
-	}
-	if abs >= 1<<31 {
-		return 0, errors.New("strings: position out of range")
+		return 0, errors.New("strings.Reader.Seek: negative position")
 	}
-	r.i = int(abs)
+	r.i = abs
 	return abs, nil
 }
 
 // WriteTo implements the io.WriterTo interface.
 func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
 	r.prevRune = -1
-	if r.i >= len(r.s) {
+	if r.i >= int64(len(r.s)) {
 		return 0, nil
 	}
 	s := r.s[r.i:]
@@ -131,7 +131,7 @@ func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
 	if m > len(s) {
 		panic("strings.Reader.WriteTo: invalid WriteString count")
 	}
-	r.i += m
+	r.i += int64(m)
 	n = int64(m)
 	if m != len(s) && err == nil {
 		err = io.ErrShortWrite
diff --git a/src/pkg/strings/reader_test.go b/src/pkg/strings/reader_test.go
index 4fdddcd..bee90eb 100644
--- a/src/pkg/strings/reader_test.go
+++ b/src/pkg/strings/reader_test.go
@@ -10,6 +10,7 @@ import (
 	"io"
 	"os"
 	"strings"
+	"sync"
 	"testing"
 )
 
@@ -26,9 +27,9 @@ func TestReader(t *testing.T) {
 		{seek: os.SEEK_SET, off: 0, n: 20, want: "0123456789"},
 		{seek: os.SEEK_SET, off: 1, n: 1, want: "1"},
 		{seek: os.SEEK_CUR, off: 1, wantpos: 3, n: 2, want: "34"},
-		{seek: os.SEEK_SET, off: -1, seekerr: "strings: negative position"},
-		{seek: os.SEEK_SET, off: 1<<31 - 1},
-		{seek: os.SEEK_CUR, off: 1, seekerr: "strings: position out of range"},
+		{seek: os.SEEK_SET, off: -1, seekerr: "strings.Reader.Seek: negative position"},
+		{seek: os.SEEK_SET, off: 1 << 33, wantpos: 1 << 33},
+		{seek: os.SEEK_CUR, off: 1, wantpos: 1<<33 + 1},
 		{seek: os.SEEK_SET, n: 5, want: "01234"},
 		{seek: os.SEEK_CUR, n: 5, want: "56789"},
 		{seek: os.SEEK_END, off: -1, n: 1, wantpos: 9, want: "9"},
@@ -60,6 +61,16 @@ func TestReader(t *testing.T) {
 	}
 }
 
+func TestReadAfterBigSeek(t *testing.T) {
+	r := strings.NewReader("0123456789")
+	if _, err := r.Seek(1<<31+5, os.SEEK_SET); err != nil {
+		t.Fatal(err)
+	}
+	if n, err := r.Read(make([]byte, 10)); n != 0 || err != io.EOF {
+		t.Errorf("Read = %d, %v; want 0, EOF", n, err)
+	}
+}
+
 func TestReaderAt(t *testing.T) {
 	r := strings.NewReader("0123456789")
 	tests := []struct {
@@ -73,7 +84,7 @@ func TestReaderAt(t *testing.T) {
 		{1, 9, "123456789", nil},
 		{11, 10, "", io.EOF},
 		{0, 0, "", nil},
-		{-1, 0, "", "strings: invalid offset"},
+		{-1, 0, "", "strings.Reader.ReadAt: negative offset"},
 	}
 	for i, tt := range tests {
 		b := make([]byte, tt.n)
@@ -88,6 +99,43 @@ func TestReaderAt(t *testing.T) {
 	}
 }
 
+func TestReaderAtConcurrent(t *testing.T) {
+	// Test for the race detector, to verify ReadAt doesn't mutate
+	// any state.
+	r := strings.NewReader("0123456789")
+	var wg sync.WaitGroup
+	for i := 0; i < 5; i++ {
+		wg.Add(1)
+		go func(i int) {
+			defer wg.Done()
+			var buf [1]byte
+			r.ReadAt(buf[:], int64(i))
+		}(i)
+	}
+	wg.Wait()
+}
+
+func TestEmptyReaderConcurrent(t *testing.T) {
+	// Test for the race detector, to verify a Read that doesn't yield any bytes
+	// is okay to use from multiple goroutines. This was our historic behavior.
+	// See golang.org/issue/7856
+	r := strings.NewReader("")
+	var wg sync.WaitGroup
+	for i := 0; i < 5; i++ {
+		wg.Add(2)
+		go func() {
+			defer wg.Done()
+			var buf [1]byte
+			r.Read(buf[:])
+		}()
+		go func() {
+			defer wg.Done()
+			r.Read(nil)
+		}()
+	}
+	wg.Wait()
+}
+
 func TestWriteTo(t *testing.T) {
 	const str = "0123456789"
 	for i := 0; i <= len(str); i++ {
diff --git a/src/pkg/strings/replace.go b/src/pkg/strings/replace.go
index 54c9323..3e05d20 100644
--- a/src/pkg/strings/replace.go
+++ b/src/pkg/strings/replace.go
@@ -492,7 +492,7 @@ func (r *byteStringReplacer) Replace(s string) string {
 	for i := 0; i < len(s); i++ {
 		b := s[i]
 		if r.old[b>>5]&uint32(1<<(b&31)) != 0 {
-			n := copy(bi[:], r.new[b])
+			n := copy(bi, r.new[b])
 			bi = bi[n:]
 		} else {
 			bi[0] = b
diff --git a/src/pkg/strings/strings_test.go b/src/pkg/strings/strings_test.go
index df0dd71..e40a180 100644
--- a/src/pkg/strings/strings_test.go
+++ b/src/pkg/strings/strings_test.go
@@ -652,7 +652,7 @@ func equal(m string, s1, s2 string, t *testing.T) bool {
 	e1 := Split(s1, "")
 	e2 := Split(s2, "")
 	for i, c1 := range e1 {
-		if i > len(e2) {
+		if i >= len(e2) {
 			break
 		}
 		r1, _ := utf8.DecodeRuneInString(c1)
@@ -858,6 +858,32 @@ func TestReadRune(t *testing.T) {
 	}
 }
 
+var UnreadRuneErrorTests = []struct {
+	name string
+	f    func(*Reader)
+}{
+	{"Read", func(r *Reader) { r.Read([]byte{0}) }},
+	{"ReadByte", func(r *Reader) { r.ReadByte() }},
+	{"UnreadRune", func(r *Reader) { r.UnreadRune() }},
+	{"Seek", func(r *Reader) { r.Seek(0, 1) }},
+	{"WriteTo", func(r *Reader) { r.WriteTo(&bytes.Buffer{}) }},
+}
+
+func TestUnreadRuneError(t *testing.T) {
+	for _, tt := range UnreadRuneErrorTests {
+		reader := NewReader("0123456789")
+		if _, _, err := reader.ReadRune(); err != nil {
+			// should not happen
+			t.Fatal(err)
+		}
+		tt.f(reader)
+		err := reader.UnreadRune()
+		if err == nil {
+			t.Errorf("Unreading after %s: expected error", tt.name)
+		}
+	}
+}
+
 var ReplaceTests = []struct {
 	in       string
 	old, new string
@@ -903,6 +929,8 @@ var TitleTests = []struct {
 	{"123a456", "123a456"},
 	{"double-blind", "Double-Blind"},
 	{"ÿøû", "Ÿøû"},
+	{"with_underscore", "With_underscore"},
+	{"unicode \xe2\x80\xa8 line separator", "Unicode \xe2\x80\xa8 Line Separator"},
 }
 
 func TestTitle(t *testing.T) {
diff --git a/src/pkg/sync/atomic/asm_386.s b/src/pkg/sync/atomic/asm_386.s
index eaa72ea..807c2f8 100644
--- a/src/pkg/sync/atomic/asm_386.s
+++ b/src/pkg/sync/atomic/asm_386.s
@@ -13,7 +13,7 @@ TEXT ·SwapUint32(SB),NOSPLIT,$0-12
 	MOVL	addr+0(FP), BP
 	MOVL	new+4(FP), AX
 	XCHGL	AX, 0(BP)
-	MOVL	AX, new+8(FP)
+	MOVL	AX, old+8(FP)
 	RET
 
 TEXT ·SwapInt64(SB),NOSPLIT,$0-20
@@ -43,8 +43,8 @@ swaploop:
 
 	// success
 	// return DX:AX
-	MOVL	AX, new_lo+12(FP)
-	MOVL	DX, new_hi+16(FP)
+	MOVL	AX, old_lo+12(FP)
+	MOVL	DX, old_hi+16(FP)
 	RET
 
 TEXT ·SwapUintptr(SB),NOSPLIT,$0-12
@@ -155,10 +155,10 @@ TEXT ·LoadUint32(SB),NOSPLIT,$0-8
 	MOVL	AX, val+4(FP)
 	RET
 
-TEXT ·LoadInt64(SB),NOSPLIT,$0-16
+TEXT ·LoadInt64(SB),NOSPLIT,$0-12
 	JMP	·LoadUint64(SB)
 
-TEXT ·LoadUint64(SB),NOSPLIT,$0-16
+TEXT ·LoadUint64(SB),NOSPLIT,$0-12
 	MOVL	addr+0(FP), AX
 	TESTL	$7, AX
 	JZ	2(PC)
@@ -186,10 +186,10 @@ TEXT ·StoreUint32(SB),NOSPLIT,$0-8
 	XCHGL	AX, 0(BP)
 	RET
 
-TEXT ·StoreInt64(SB),NOSPLIT,$0-16
+TEXT ·StoreInt64(SB),NOSPLIT,$0-12
 	JMP	·StoreUint64(SB)
 
-TEXT ·StoreUint64(SB),NOSPLIT,$0-16
+TEXT ·StoreUint64(SB),NOSPLIT,$0-12
 	MOVL	addr+0(FP), AX
 	TESTL	$7, AX
 	JZ	2(PC)
diff --git a/src/pkg/sync/atomic/asm_amd64.s b/src/pkg/sync/atomic/asm_amd64.s
index 0900492..77afa12 100644
--- a/src/pkg/sync/atomic/asm_amd64.s
+++ b/src/pkg/sync/atomic/asm_amd64.s
@@ -13,7 +13,7 @@ TEXT ·SwapUint32(SB),NOSPLIT,$0-20
 	MOVQ	addr+0(FP), BP
 	MOVL	new+8(FP), AX
 	XCHGL	AX, 0(BP)
-	MOVL	AX, new+16(FP)
+	MOVL	AX, old+16(FP)
 	RET
 
 TEXT ·SwapInt64(SB),NOSPLIT,$0-24
@@ -23,7 +23,7 @@ TEXT ·SwapUint64(SB),NOSPLIT,$0-24
 	MOVQ	addr+0(FP), BP
 	MOVQ	new+8(FP), AX
 	XCHGQ	AX, 0(BP)
-	MOVQ	AX, new+16(FP)
+	MOVQ	AX, old+16(FP)
 	RET
 
 TEXT ·SwapUintptr(SB),NOSPLIT,$0-24
diff --git a/src/pkg/sync/atomic/asm_amd64p32.s b/src/pkg/sync/atomic/asm_amd64p32.s
new file mode 100644
index 0000000..b24ae7a
--- /dev/null
+++ b/src/pkg/sync/atomic/asm_amd64p32.s
@@ -0,0 +1,159 @@
+// 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.
+
+#include "../../../cmd/ld/textflag.h"
+
+TEXT ·SwapInt32(SB),NOSPLIT,$0-12
+	JMP	·SwapUint32(SB)
+
+TEXT ·SwapUint32(SB),NOSPLIT,$0-12
+	MOVL	addr+0(FP), BX
+	MOVL	new+4(FP), AX
+	XCHGL	AX, 0(BX)
+	MOVL	AX, old+8(FP)
+	RET
+
+TEXT ·SwapInt64(SB),NOSPLIT,$0-24
+	JMP	·SwapUint64(SB)
+
+TEXT ·SwapUint64(SB),NOSPLIT,$0-24
+	MOVL	addr+0(FP), BX
+	TESTL	$7, BX
+	JZ	2(PC)
+	MOVL	0, BX // crash with nil ptr deref
+	MOVQ	new+8(FP), AX
+	XCHGQ	AX, 0(BX)
+	MOVQ	AX, old+16(FP)
+	RET
+
+TEXT ·SwapUintptr(SB),NOSPLIT,$0-12
+	JMP	·SwapUint32(SB)
+
+TEXT ·SwapPointer(SB),NOSPLIT,$0-12
+	JMP	·SwapUint32(SB)
+
+TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0-17
+	JMP	·CompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0-17
+	MOVL	addr+0(FP), BX
+	MOVL	old+4(FP), AX
+	MOVL	new+8(FP), CX
+	LOCK
+	CMPXCHGL	CX, 0(BX)
+	SETEQ	swapped+16(FP)
+	RET
+
+TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0-17
+	JMP	·CompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapPointer(SB),NOSPLIT,$0-17
+	JMP	·CompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0-25
+	JMP	·CompareAndSwapUint64(SB)
+
+TEXT ·CompareAndSwapUint64(SB),NOSPLIT,$0-25
+	MOVL	addr+0(FP), BX
+	TESTL	$7, BX
+	JZ	2(PC)
+	MOVL	0, BX // crash with nil ptr deref
+	MOVQ	old+8(FP), AX
+	MOVQ	new+16(FP), CX
+	LOCK
+	CMPXCHGQ	CX, 0(BX)
+	SETEQ	swapped+24(FP)
+	RET
+
+TEXT ·AddInt32(SB),NOSPLIT,$0-12
+	JMP	·AddUint32(SB)
+
+TEXT ·AddUint32(SB),NOSPLIT,$0-12
+	MOVL	addr+0(FP), BX
+	MOVL	delta+4(FP), AX
+	MOVL	AX, CX
+	LOCK
+	XADDL	AX, 0(BX)
+	ADDL	AX, CX
+	MOVL	CX, new+8(FP)
+	RET
+
+TEXT ·AddUintptr(SB),NOSPLIT,$0-12
+	JMP	·AddUint32(SB)
+
+TEXT ·AddInt64(SB),NOSPLIT,$0-24
+	JMP	·AddUint64(SB)
+
+TEXT ·AddUint64(SB),NOSPLIT,$0-24
+	MOVL	addr+0(FP), BX
+	TESTL	$7, BX
+	JZ	2(PC)
+	MOVL	0, BX // crash with nil ptr deref
+	MOVQ	delta+8(FP), AX
+	MOVQ	AX, CX
+	LOCK
+	XADDQ	AX, 0(BX)
+	ADDQ	AX, CX
+	MOVQ	CX, new+16(FP)
+	RET
+
+TEXT ·LoadInt32(SB),NOSPLIT,$0-12
+	JMP	·LoadUint32(SB)
+
+TEXT ·LoadUint32(SB),NOSPLIT,$0-12
+	MOVL	addr+0(FP), AX
+	MOVL	0(AX), AX
+	MOVL	AX, val+8(FP)
+	RET
+
+TEXT ·LoadInt64(SB),NOSPLIT,$0-16
+	JMP	·LoadUint64(SB)
+
+TEXT ·LoadUint64(SB),NOSPLIT,$0-16
+	MOVL	addr+0(FP), AX
+	TESTL	$7, AX
+	JZ	2(PC)
+	MOVL	0, AX // crash with nil ptr deref
+	MOVQ	0(AX), AX
+	MOVQ	AX, val+8(FP)
+	RET
+
+TEXT ·LoadUintptr(SB),NOSPLIT,$0-12
+	JMP	·LoadPointer(SB)
+
+TEXT ·LoadPointer(SB),NOSPLIT,$0-12
+	MOVL	addr+0(FP), AX
+	MOVL	0(AX), AX
+	MOVL	AX, val+8(FP)
+	RET
+
+TEXT ·StoreInt32(SB),NOSPLIT,$0-8
+	JMP	·StoreUint32(SB)
+
+TEXT ·StoreUint32(SB),NOSPLIT,$0-8
+	MOVL	addr+0(FP), BX
+	MOVL	val+4(FP), AX
+	XCHGL	AX, 0(BX)
+	RET
+
+TEXT ·StoreInt64(SB),NOSPLIT,$0-16
+	JMP	·StoreUint64(SB)
+
+TEXT ·StoreUint64(SB),NOSPLIT,$0-16
+	MOVL	addr+0(FP), BX
+	TESTL	$7, BX
+	JZ	2(PC)
+	MOVL	0, BX // crash with nil ptr deref
+	MOVQ	val+8(FP), AX
+	XCHGQ	AX, 0(BX)
+	RET
+
+TEXT ·StoreUintptr(SB),NOSPLIT,$0-8
+	JMP	·StorePointer(SB)
+
+TEXT ·StorePointer(SB),NOSPLIT,$0-8
+	MOVL	addr+0(FP), BX
+	MOVL	val+4(FP), AX
+	XCHGL	AX, 0(BX)
+	RET
diff --git a/src/pkg/sync/atomic/asm_linux_arm.s b/src/pkg/sync/atomic/asm_linux_arm.s
index b85ca0a..27be57a 100644
--- a/src/pkg/sync/atomic/asm_linux_arm.s
+++ b/src/pkg/sync/atomic/asm_linux_arm.s
@@ -42,7 +42,7 @@ casagain:
 	BCC	cascheck
 	MOVW	$1, R0
 casret:
-	MOVW	R0, ret+12(FP)
+	MOVB	R0, swapped+12(FP)
 	RET
 cascheck:
 	// Kernel lies; double-check.
@@ -73,7 +73,7 @@ addloop1:
 	ADD	R4, R1
 	BL	cas<>(SB)
 	BCC	addloop1
-	MOVW	R1, ret+8(FP)
+	MOVW	R1, new+8(FP)
 	RET
 
 TEXT ·AddUintptr(SB),NOSPLIT,$0
@@ -132,13 +132,13 @@ TEXT ·generalCAS64(SB),NOSPLIT,$20-21
 	BEQ 	2(PC)
 	MOVW	R1, (R1)
 	MOVW	R0, 4(R13)
-	MOVW	oldlo+4(FP), R1
+	MOVW	old_lo+4(FP), R1
 	MOVW	R1, 8(R13)
-	MOVW	oldhi+8(FP), R1
+	MOVW	old_hi+8(FP), R1
 	MOVW	R1, 12(R13)
-	MOVW	newlo+12(FP), R2
+	MOVW	new_lo+12(FP), R2
 	MOVW	R2, 16(R13)
-	MOVW	newhi+16(FP), R3
+	MOVW	new_hi+16(FP), R3
 	MOVW	R3, 20(R13)
 	BL  	runtime·cas64(SB)
 	MOVB	R0, ret+20(FP)
diff --git a/src/pkg/sync/atomic/atomic_test.go b/src/pkg/sync/atomic/atomic_test.go
index e10effe..a5f44f7 100644
--- a/src/pkg/sync/atomic/atomic_test.go
+++ b/src/pkg/sync/atomic/atomic_test.go
@@ -813,7 +813,7 @@ func hammerSwapUintptr32(uaddr *uint32, count int) {
 		new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16
 		old := SwapUintptr(addr, new)
 		if old>>16 != old<<16>>16 {
-			panic(fmt.Sprintf("SwapUintptr is not atomic: %v", old))
+			panic(fmt.Sprintf("SwapUintptr is not atomic: %#08x", old))
 		}
 	}
 }
@@ -827,7 +827,7 @@ func hammerSwapPointer32(uaddr *uint32, count int) {
 		new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16
 		old := uintptr(SwapPointer(addr, unsafe.Pointer(new)))
 		if old>>16 != old<<16>>16 {
-			panic(fmt.Sprintf("SwapPointer is not atomic: %v", old))
+			panic(fmt.Sprintf("SwapPointer is not atomic: %#08x", old))
 		}
 	}
 }
@@ -1463,6 +1463,9 @@ func TestUnaligned64(t *testing.T) {
 }
 
 func TestNilDeref(t *testing.T) {
+	if p := runtime.GOOS + "/" + runtime.GOARCH; p == "freebsd/arm" || p == "netbsd/arm" {
+		t.Skipf("issue 7338: skipping test on %q", p)
+	}
 	funcs := [...]func(){
 		func() { CompareAndSwapInt32(nil, 0, 0) },
 		func() { CompareAndSwapInt64(nil, 0, 0) },
diff --git a/src/pkg/sync/atomic/export_linux_arm_test.go b/src/pkg/sync/atomic/export_linux_arm_test.go
index 8c0b5a7..5cd4335 100644
--- a/src/pkg/sync/atomic/export_linux_arm_test.go
+++ b/src/pkg/sync/atomic/export_linux_arm_test.go
@@ -4,6 +4,6 @@
 
 package atomic
 
-func generalCAS64(*uint64, uint64, uint64) bool
+func generalCAS64(addr *uint64, old uint64, new uint64) bool
 
 var GeneralCAS64 = generalCAS64
diff --git a/src/pkg/sync/mutex_test.go b/src/pkg/sync/mutex_test.go
index bf78c6f..151b25c 100644
--- a/src/pkg/sync/mutex_test.go
+++ b/src/pkg/sync/mutex_test.go
@@ -9,7 +9,6 @@ package sync_test
 import (
 	"runtime"
 	. "sync"
-	"sync/atomic"
 	"testing"
 )
 
@@ -90,63 +89,34 @@ func BenchmarkMutexUncontended(b *testing.B) {
 		Mutex
 		pad [128]uint8
 	}
-	const CallsPerSched = 1000
-	procs := runtime.GOMAXPROCS(-1)
-	N := int32(b.N / CallsPerSched)
-	c := make(chan bool, procs)
-	for p := 0; p < procs; p++ {
-		go func() {
-			var mu PaddedMutex
-			for atomic.AddInt32(&N, -1) >= 0 {
-				runtime.Gosched()
-				for g := 0; g < CallsPerSched; g++ {
-					mu.Lock()
-					mu.Unlock()
-				}
-			}
-			c <- true
-		}()
-	}
-	for p := 0; p < procs; p++ {
-		<-c
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		var mu PaddedMutex
+		for pb.Next() {
+			mu.Lock()
+			mu.Unlock()
+		}
+	})
 }
 
 func benchmarkMutex(b *testing.B, slack, work bool) {
-	const (
-		CallsPerSched  = 1000
-		LocalWork      = 100
-		GoroutineSlack = 10
-	)
-	procs := runtime.GOMAXPROCS(-1)
+	var mu Mutex
 	if slack {
-		procs *= GoroutineSlack
+		b.SetParallelism(10)
 	}
-	N := int32(b.N / CallsPerSched)
-	c := make(chan bool, procs)
-	var mu Mutex
-	for p := 0; p < procs; p++ {
-		go func() {
-			foo := 0
-			for atomic.AddInt32(&N, -1) >= 0 {
-				runtime.Gosched()
-				for g := 0; g < CallsPerSched; g++ {
-					mu.Lock()
-					mu.Unlock()
-					if work {
-						for i := 0; i < LocalWork; i++ {
-							foo *= 2
-							foo /= 2
-						}
-					}
+	b.RunParallel(func(pb *testing.PB) {
+		foo := 0
+		for pb.Next() {
+			mu.Lock()
+			mu.Unlock()
+			if work {
+				for i := 0; i < 100; i++ {
+					foo *= 2
+					foo /= 2
 				}
 			}
-			c <- foo == 42
-		}()
-	}
-	for p := 0; p < procs; p++ {
-		<-c
-	}
+		}
+		_ = foo
+	})
 }
 
 func BenchmarkMutex(b *testing.B) {
diff --git a/src/pkg/sync/once_test.go b/src/pkg/sync/once_test.go
index 183069a..8afda82 100644
--- a/src/pkg/sync/once_test.go
+++ b/src/pkg/sync/once_test.go
@@ -5,9 +5,7 @@
 package sync_test
 
 import (
-	"runtime"
 	. "sync"
-	"sync/atomic"
 	"testing"
 )
 
@@ -62,24 +60,11 @@ func TestOncePanic(t *testing.T) {
 }
 
 func BenchmarkOnce(b *testing.B) {
-	const CallsPerSched = 1000
-	procs := runtime.GOMAXPROCS(-1)
-	N := int32(b.N / CallsPerSched)
 	var once Once
 	f := func() {}
-	c := make(chan bool, procs)
-	for p := 0; p < procs; p++ {
-		go func() {
-			for atomic.AddInt32(&N, -1) >= 0 {
-				runtime.Gosched()
-				for g := 0; g < CallsPerSched; g++ {
-					once.Do(f)
-				}
-			}
-			c <- true
-		}()
-	}
-	for p := 0; p < procs; p++ {
-		<-c
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			once.Do(f)
+		}
+	})
 }
diff --git a/src/pkg/sync/pool.go b/src/pkg/sync/pool.go
new file mode 100644
index 0000000..1f08707
--- /dev/null
+++ b/src/pkg/sync/pool.go
@@ -0,0 +1,223 @@
+// 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 sync
+
+import (
+	"runtime"
+	"sync/atomic"
+	"unsafe"
+)
+
+// A Pool is a set of temporary objects that may be individually saved and
+// retrieved.
+//
+// Any item stored in the Pool may be removed automatically at any time without
+// notification. If the Pool holds the only reference when this happens, the
+// item might be deallocated.
+//
+// A Pool is safe for use by multiple goroutines simultaneously.
+//
+// Pool's purpose is to cache allocated but unused items for later reuse,
+// relieving pressure on the garbage collector. That is, it makes it easy to
+// build efficient, thread-safe free lists. However, it is not suitable for all
+// free lists.
+//
+// An appropriate use of a Pool is to manage a group of temporary items
+// silently shared among and potentially reused by concurrent independent
+// clients of a package. Pool provides a way to amortize allocation overhead
+// across many clients.
+//
+// An example of good use of a Pool is in the fmt package, which maintains a
+// dynamically-sized store of temporary output buffers. The store scales under
+// load (when many goroutines are actively printing) and shrinks when
+// quiescent.
+//
+// On the other hand, a free list maintained as part of a short-lived object is
+// not a suitable use for a Pool, since the overhead does not amortize well in
+// that scenario. It is more efficient to have such objects implement their own
+// free list.
+//
+type Pool struct {
+	local     unsafe.Pointer // local fixed-size per-P pool, actual type is [P]poolLocal
+	localSize uintptr        // size of the local array
+
+	// New optionally specifies a function to generate
+	// a value when Get would otherwise return nil.
+	// It may not be changed concurrently with calls to Get.
+	New func() interface{}
+}
+
+// Local per-P Pool appendix.
+type poolLocal struct {
+	private interface{}   // Can be used only by the respective P.
+	shared  []interface{} // Can be used by any P.
+	Mutex                 // Protects shared.
+	pad     [128]byte     // Prevents false sharing.
+}
+
+// Put adds x to the pool.
+func (p *Pool) Put(x interface{}) {
+	if raceenabled {
+		// Under race detector the Pool degenerates into no-op.
+		// It's conforming, simple and does not introduce excessive
+		// happens-before edges between unrelated goroutines.
+		return
+	}
+	if x == nil {
+		return
+	}
+	l := p.pin()
+	if l.private == nil {
+		l.private = x
+		x = nil
+	}
+	runtime_procUnpin()
+	if x == nil {
+		return
+	}
+	l.Lock()
+	l.shared = append(l.shared, x)
+	l.Unlock()
+}
+
+// Get selects an arbitrary item from the Pool, removes it from the
+// Pool, and returns it to the caller.
+// Get may choose to ignore the pool and treat it as empty.
+// Callers should not assume any relation between values passed to Put and
+// the values returned by Get.
+//
+// If Get would otherwise return nil and p.New is non-nil, Get returns
+// the result of calling p.New.
+func (p *Pool) Get() interface{} {
+	if raceenabled {
+		if p.New != nil {
+			return p.New()
+		}
+		return nil
+	}
+	l := p.pin()
+	x := l.private
+	l.private = nil
+	runtime_procUnpin()
+	if x != nil {
+		return x
+	}
+	l.Lock()
+	last := len(l.shared) - 1
+	if last >= 0 {
+		x = l.shared[last]
+		l.shared = l.shared[:last]
+	}
+	l.Unlock()
+	if x != nil {
+		return x
+	}
+	return p.getSlow()
+}
+
+func (p *Pool) getSlow() (x interface{}) {
+	// See the comment in pin regarding ordering of the loads.
+	size := atomic.LoadUintptr(&p.localSize) // load-acquire
+	local := p.local                         // load-consume
+	// Try to steal one element from other procs.
+	pid := runtime_procPin()
+	runtime_procUnpin()
+	for i := 0; i < int(size); i++ {
+		l := indexLocal(local, (pid+i+1)%int(size))
+		l.Lock()
+		last := len(l.shared) - 1
+		if last >= 0 {
+			x = l.shared[last]
+			l.shared = l.shared[:last]
+			l.Unlock()
+			break
+		}
+		l.Unlock()
+	}
+
+	if x == nil && p.New != nil {
+		x = p.New()
+	}
+	return x
+}
+
+// pin pins the current goroutine to P, disables preemption and returns poolLocal pool for the P.
+// Caller must call runtime_procUnpin() when done with the pool.
+func (p *Pool) pin() *poolLocal {
+	pid := runtime_procPin()
+	// In pinSlow we store to localSize and then to local, here we load in opposite order.
+	// Since we've disabled preemption, GC can not happen in between.
+	// Thus here we must observe local at least as large localSize.
+	// We can observe a newer/larger local, it is fine (we must observe its zero-initialized-ness).
+	s := atomic.LoadUintptr(&p.localSize) // load-acquire
+	l := p.local                          // load-consume
+	if uintptr(pid) < s {
+		return indexLocal(l, pid)
+	}
+	return p.pinSlow()
+}
+
+func (p *Pool) pinSlow() *poolLocal {
+	// Retry under the mutex.
+	// Can not lock the mutex while pinned.
+	runtime_procUnpin()
+	allPoolsMu.Lock()
+	defer allPoolsMu.Unlock()
+	pid := runtime_procPin()
+	// poolCleanup won't be called while we are pinned.
+	s := p.localSize
+	l := p.local
+	if uintptr(pid) < s {
+		return indexLocal(l, pid)
+	}
+	if p.local == nil {
+		allPools = append(allPools, p)
+	}
+	// If GOMAXPROCS changes between GCs, we re-allocate the array and lose the old one.
+	size := runtime.GOMAXPROCS(0)
+	local := make([]poolLocal, size)
+	atomic.StorePointer((*unsafe.Pointer)(&p.local), unsafe.Pointer(&local[0])) // store-release
+	atomic.StoreUintptr(&p.localSize, uintptr(size))                            // store-release
+	return &local[pid]
+}
+
+func poolCleanup() {
+	// This function is called with the world stopped, at the beginning of a garbage collection.
+	// It must not allocate and probably should not call any runtime functions.
+	// Defensively zero out everything, 2 reasons:
+	// 1. To prevent false retention of whole Pools.
+	// 2. If GC happens while a goroutine works with l.shared in Put/Get,
+	//    it will retain whole Pool. So next cycle memory consumption would be doubled.
+	for i, p := range allPools {
+		allPools[i] = nil
+		for i := 0; i < int(p.localSize); i++ {
+			l := indexLocal(p.local, i)
+			l.private = nil
+			for j := range l.shared {
+				l.shared[j] = nil
+			}
+			l.shared = nil
+		}
+	}
+	allPools = []*Pool{}
+}
+
+var (
+	allPoolsMu Mutex
+	allPools   []*Pool
+)
+
+func init() {
+	runtime_registerPoolCleanup(poolCleanup)
+}
+
+func indexLocal(l unsafe.Pointer, i int) *poolLocal {
+	return &(*[1000000]poolLocal)(l)[i]
+}
+
+// Implemented in runtime.
+func runtime_registerPoolCleanup(cleanup func())
+func runtime_procPin() int
+func runtime_procUnpin()
diff --git a/src/pkg/sync/pool_test.go b/src/pkg/sync/pool_test.go
new file mode 100644
index 0000000..509448b
--- /dev/null
+++ b/src/pkg/sync/pool_test.go
@@ -0,0 +1,151 @@
+// 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.
+
+// Pool is no-op under race detector, so all these tests do not work.
+// +build !race
+
+package sync_test
+
+import (
+	"runtime"
+	"runtime/debug"
+	. "sync"
+	"sync/atomic"
+	"testing"
+	"time"
+)
+
+func TestPool(t *testing.T) {
+	// disable GC so we can control when it happens.
+	defer debug.SetGCPercent(debug.SetGCPercent(-1))
+	var p Pool
+	if p.Get() != nil {
+		t.Fatal("expected empty")
+	}
+	p.Put("a")
+	p.Put("b")
+	if g := p.Get(); g != "a" {
+		t.Fatalf("got %#v; want a", g)
+	}
+	if g := p.Get(); g != "b" {
+		t.Fatalf("got %#v; want b", g)
+	}
+	if g := p.Get(); g != nil {
+		t.Fatalf("got %#v; want nil", g)
+	}
+
+	p.Put("c")
+	debug.SetGCPercent(100) // to allow following GC to actually run
+	runtime.GC()
+	if g := p.Get(); g != nil {
+		t.Fatalf("got %#v; want nil after GC", g)
+	}
+}
+
+func TestPoolNew(t *testing.T) {
+	// disable GC so we can control when it happens.
+	defer debug.SetGCPercent(debug.SetGCPercent(-1))
+
+	i := 0
+	p := Pool{
+		New: func() interface{} {
+			i++
+			return i
+		},
+	}
+	if v := p.Get(); v != 1 {
+		t.Fatalf("got %v; want 1", v)
+	}
+	if v := p.Get(); v != 2 {
+		t.Fatalf("got %v; want 2", v)
+	}
+	p.Put(42)
+	if v := p.Get(); v != 42 {
+		t.Fatalf("got %v; want 42", v)
+	}
+	if v := p.Get(); v != 3 {
+		t.Fatalf("got %v; want 3", v)
+	}
+}
+
+// Test that Pool does not hold pointers to previously cached
+// resources
+func TestPoolGC(t *testing.T) {
+	var p Pool
+	var fin uint32
+	const N = 100
+	for i := 0; i < N; i++ {
+		v := new(string)
+		runtime.SetFinalizer(v, func(vv *string) {
+			atomic.AddUint32(&fin, 1)
+		})
+		p.Put(v)
+	}
+	for i := 0; i < N; i++ {
+		p.Get()
+	}
+	for i := 0; i < 5; i++ {
+		runtime.GC()
+		time.Sleep(time.Duration(i*100+10) * time.Millisecond)
+		// 1 pointer can remain on stack or elsewhere
+		if atomic.LoadUint32(&fin) >= N-1 {
+			return
+		}
+	}
+	t.Fatalf("only %v out of %v resources are finalized",
+		atomic.LoadUint32(&fin), N)
+}
+
+func TestPoolStress(t *testing.T) {
+	const P = 10
+	N := int(1e6)
+	if testing.Short() {
+		N /= 100
+	}
+	var p Pool
+	done := make(chan bool)
+	for i := 0; i < P; i++ {
+		go func() {
+			var v interface{} = 0
+			for j := 0; j < N; j++ {
+				if v == nil {
+					v = 0
+				}
+				p.Put(v)
+				v = p.Get()
+				if v != nil && v.(int) != 0 {
+					t.Fatalf("expect 0, got %v", v)
+				}
+			}
+			done <- true
+		}()
+	}
+	for i := 0; i < P; i++ {
+		<-done
+	}
+}
+
+func BenchmarkPool(b *testing.B) {
+	var p Pool
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			p.Put(1)
+			p.Get()
+		}
+	})
+}
+
+func BenchmarkPoolOverlflow(b *testing.B) {
+	var p Pool
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			for b := 0; b < 100; b++ {
+				p.Put(1)
+			}
+			for b := 0; b < 100; b++ {
+				p.Get()
+			}
+		}
+	})
+}
diff --git a/src/pkg/sync/runtime_sema_test.go b/src/pkg/sync/runtime_sema_test.go
index 57a8dbe..5b7dd3d 100644
--- a/src/pkg/sync/runtime_sema_test.go
+++ b/src/pkg/sync/runtime_sema_test.go
@@ -7,7 +7,6 @@ package sync_test
 import (
 	"runtime"
 	. "sync"
-	"sync/atomic"
 	"testing"
 )
 
@@ -16,72 +15,44 @@ func BenchmarkSemaUncontended(b *testing.B) {
 		sem uint32
 		pad [32]uint32
 	}
-	const CallsPerSched = 1000
-	procs := runtime.GOMAXPROCS(-1)
-	N := int32(b.N / CallsPerSched)
-	c := make(chan bool, procs)
-	for p := 0; p < procs; p++ {
-		go func() {
-			sem := new(PaddedSem)
-			for atomic.AddInt32(&N, -1) >= 0 {
-				runtime.Gosched()
-				for g := 0; g < CallsPerSched; g++ {
-					Runtime_Semrelease(&sem.sem)
-					Runtime_Semacquire(&sem.sem)
-				}
-			}
-			c <- true
-		}()
-	}
-	for p := 0; p < procs; p++ {
-		<-c
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		sem := new(PaddedSem)
+		for pb.Next() {
+			Runtime_Semrelease(&sem.sem)
+			Runtime_Semacquire(&sem.sem)
+		}
+	})
 }
 
 func benchmarkSema(b *testing.B, block, work bool) {
-	const CallsPerSched = 1000
-	const LocalWork = 100
-	procs := runtime.GOMAXPROCS(-1)
-	N := int32(b.N / CallsPerSched)
-	c := make(chan bool, procs)
-	c2 := make(chan bool, procs/2)
 	sem := uint32(0)
 	if block {
-		for p := 0; p < procs/2; p++ {
-			go func() {
-				Runtime_Semacquire(&sem)
-				c2 <- true
-			}()
-		}
-	}
-	for p := 0; p < procs; p++ {
+		done := make(chan bool)
 		go func() {
-			foo := 0
-			for atomic.AddInt32(&N, -1) >= 0 {
-				runtime.Gosched()
-				for g := 0; g < CallsPerSched; g++ {
-					Runtime_Semrelease(&sem)
-					if work {
-						for i := 0; i < LocalWork; i++ {
-							foo *= 2
-							foo /= 2
-						}
-					}
-					Runtime_Semacquire(&sem)
-				}
+			for p := 0; p < runtime.GOMAXPROCS(0)/2; p++ {
+				Runtime_Semacquire(&sem)
 			}
-			c <- foo == 42
-			Runtime_Semrelease(&sem)
+			done <- true
+		}()
+		defer func() {
+			<-done
 		}()
 	}
-	if block {
-		for p := 0; p < procs/2; p++ {
-			<-c2
+	b.RunParallel(func(pb *testing.PB) {
+		foo := 0
+		for pb.Next() {
+			Runtime_Semrelease(&sem)
+			if work {
+				for i := 0; i < 100; i++ {
+					foo *= 2
+					foo /= 2
+				}
+			}
+			Runtime_Semacquire(&sem)
 		}
-	}
-	for p := 0; p < procs; p++ {
-		<-c
-	}
+		_ = foo
+		Runtime_Semrelease(&sem)
+	})
 }
 
 func BenchmarkSemaSyntNonblock(b *testing.B) {
diff --git a/src/pkg/sync/rwmutex_test.go b/src/pkg/sync/rwmutex_test.go
index 39d5d65..0436f97 100644
--- a/src/pkg/sync/rwmutex_test.go
+++ b/src/pkg/sync/rwmutex_test.go
@@ -160,64 +160,39 @@ func BenchmarkRWMutexUncontended(b *testing.B) {
 		RWMutex
 		pad [32]uint32
 	}
-	const CallsPerSched = 1000
-	procs := runtime.GOMAXPROCS(-1)
-	N := int32(b.N / CallsPerSched)
-	c := make(chan bool, procs)
-	for p := 0; p < procs; p++ {
-		go func() {
-			var rwm PaddedRWMutex
-			for atomic.AddInt32(&N, -1) >= 0 {
-				runtime.Gosched()
-				for g := 0; g < CallsPerSched; g++ {
-					rwm.RLock()
-					rwm.RLock()
-					rwm.RUnlock()
-					rwm.RUnlock()
-					rwm.Lock()
-					rwm.Unlock()
-				}
-			}
-			c <- true
-		}()
-	}
-	for p := 0; p < procs; p++ {
-		<-c
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		var rwm PaddedRWMutex
+		for pb.Next() {
+			rwm.RLock()
+			rwm.RLock()
+			rwm.RUnlock()
+			rwm.RUnlock()
+			rwm.Lock()
+			rwm.Unlock()
+		}
+	})
 }
 
 func benchmarkRWMutex(b *testing.B, localWork, writeRatio int) {
-	const CallsPerSched = 1000
-	procs := runtime.GOMAXPROCS(-1)
-	N := int32(b.N / CallsPerSched)
-	c := make(chan bool, procs)
 	var rwm RWMutex
-	for p := 0; p < procs; p++ {
-		go func() {
-			foo := 0
-			for atomic.AddInt32(&N, -1) >= 0 {
-				runtime.Gosched()
-				for g := 0; g < CallsPerSched; g++ {
-					foo++
-					if foo%writeRatio == 0 {
-						rwm.Lock()
-						rwm.Unlock()
-					} else {
-						rwm.RLock()
-						for i := 0; i != localWork; i += 1 {
-							foo *= 2
-							foo /= 2
-						}
-						rwm.RUnlock()
-					}
+	b.RunParallel(func(pb *testing.PB) {
+		foo := 0
+		for pb.Next() {
+			foo++
+			if foo%writeRatio == 0 {
+				rwm.Lock()
+				rwm.Unlock()
+			} else {
+				rwm.RLock()
+				for i := 0; i != localWork; i += 1 {
+					foo *= 2
+					foo /= 2
 				}
+				rwm.RUnlock()
 			}
-			c <- foo == 42
-		}()
-	}
-	for p := 0; p < procs; p++ {
-		<-c
-	}
+		}
+		_ = foo
+	})
 }
 
 func BenchmarkRWMutexWrite100(b *testing.B) {
diff --git a/src/pkg/sync/waitgroup.go b/src/pkg/sync/waitgroup.go
index 2268111..4c64dca 100644
--- a/src/pkg/sync/waitgroup.go
+++ b/src/pkg/sync/waitgroup.go
@@ -67,11 +67,13 @@ func (wg *WaitGroup) Add(delta int) {
 		return
 	}
 	wg.m.Lock()
-	for i := int32(0); i < wg.waiters; i++ {
-		runtime_Semrelease(wg.sema)
+	if atomic.LoadInt32(&wg.counter) == 0 {
+		for i := int32(0); i < wg.waiters; i++ {
+			runtime_Semrelease(wg.sema)
+		}
+		wg.waiters = 0
+		wg.sema = nil
 	}
-	wg.waiters = 0
-	wg.sema = nil
 	wg.m.Unlock()
 }
 
diff --git a/src/pkg/sync/waitgroup_test.go b/src/pkg/sync/waitgroup_test.go
index 84c4cfc..4c0a043 100644
--- a/src/pkg/sync/waitgroup_test.go
+++ b/src/pkg/sync/waitgroup_test.go
@@ -5,7 +5,6 @@
 package sync_test
 
 import (
-	"runtime"
 	. "sync"
 	"sync/atomic"
 	"testing"
@@ -61,60 +60,60 @@ func TestWaitGroupMisuse(t *testing.T) {
 	t.Fatal("Should panic")
 }
 
+func TestWaitGroupRace(t *testing.T) {
+	// Run this test for about 1ms.
+	for i := 0; i < 1000; i++ {
+		wg := &WaitGroup{}
+		n := new(int32)
+		// spawn goroutine 1
+		wg.Add(1)
+		go func() {
+			atomic.AddInt32(n, 1)
+			wg.Done()
+		}()
+		// spawn goroutine 2
+		wg.Add(1)
+		go func() {
+			atomic.AddInt32(n, 1)
+			wg.Done()
+		}()
+		// Wait for goroutine 1 and 2
+		wg.Wait()
+		if atomic.LoadInt32(n) != 2 {
+			t.Fatal("Spurious wakeup from Wait")
+		}
+	}
+}
+
 func BenchmarkWaitGroupUncontended(b *testing.B) {
 	type PaddedWaitGroup struct {
 		WaitGroup
 		pad [128]uint8
 	}
-	const CallsPerSched = 1000
-	procs := runtime.GOMAXPROCS(-1)
-	N := int32(b.N / CallsPerSched)
-	c := make(chan bool, procs)
-	for p := 0; p < procs; p++ {
-		go func() {
-			var wg PaddedWaitGroup
-			for atomic.AddInt32(&N, -1) >= 0 {
-				runtime.Gosched()
-				for g := 0; g < CallsPerSched; g++ {
-					wg.Add(1)
-					wg.Done()
-					wg.Wait()
-				}
-			}
-			c <- true
-		}()
-	}
-	for p := 0; p < procs; p++ {
-		<-c
-	}
+	b.RunParallel(func(pb *testing.PB) {
+		var wg PaddedWaitGroup
+		for pb.Next() {
+			wg.Add(1)
+			wg.Done()
+			wg.Wait()
+		}
+	})
 }
 
 func benchmarkWaitGroupAddDone(b *testing.B, localWork int) {
-	const CallsPerSched = 1000
-	procs := runtime.GOMAXPROCS(-1)
-	N := int32(b.N / CallsPerSched)
-	c := make(chan bool, procs)
 	var wg WaitGroup
-	for p := 0; p < procs; p++ {
-		go func() {
-			foo := 0
-			for atomic.AddInt32(&N, -1) >= 0 {
-				runtime.Gosched()
-				for g := 0; g < CallsPerSched; g++ {
-					wg.Add(1)
-					for i := 0; i < localWork; i++ {
-						foo *= 2
-						foo /= 2
-					}
-					wg.Done()
-				}
+	b.RunParallel(func(pb *testing.PB) {
+		foo := 0
+		for pb.Next() {
+			wg.Add(1)
+			for i := 0; i < localWork; i++ {
+				foo *= 2
+				foo /= 2
 			}
-			c <- foo == 42
-		}()
-	}
-	for p := 0; p < procs; p++ {
-		<-c
-	}
+			wg.Done()
+		}
+		_ = foo
+	})
 }
 
 func BenchmarkWaitGroupAddDone(b *testing.B) {
@@ -126,34 +125,18 @@ func BenchmarkWaitGroupAddDoneWork(b *testing.B) {
 }
 
 func benchmarkWaitGroupWait(b *testing.B, localWork int) {
-	const CallsPerSched = 1000
-	procs := runtime.GOMAXPROCS(-1)
-	N := int32(b.N / CallsPerSched)
-	c := make(chan bool, procs)
 	var wg WaitGroup
-	wg.Add(procs)
-	for p := 0; p < procs; p++ {
-		go wg.Done()
-	}
-	for p := 0; p < procs; p++ {
-		go func() {
-			foo := 0
-			for atomic.AddInt32(&N, -1) >= 0 {
-				runtime.Gosched()
-				for g := 0; g < CallsPerSched; g++ {
-					wg.Wait()
-					for i := 0; i < localWork; i++ {
-						foo *= 2
-						foo /= 2
-					}
-				}
+	b.RunParallel(func(pb *testing.PB) {
+		foo := 0
+		for pb.Next() {
+			wg.Wait()
+			for i := 0; i < localWork; i++ {
+				foo *= 2
+				foo /= 2
 			}
-			c <- foo == 42
-		}()
-	}
-	for p := 0; p < procs; p++ {
-		<-c
-	}
+		}
+		_ = foo
+	})
 }
 
 func BenchmarkWaitGroupWait(b *testing.B) {
diff --git a/src/pkg/syscall/asm_darwin_386.s b/src/pkg/syscall/asm_darwin_386.s
index 2ddfb3b..9b4dfa8 100644
--- a/src/pkg/syscall/asm_darwin_386.s
+++ b/src/pkg/syscall/asm_darwin_386.s
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
 #include "../../cmd/ld/textflag.h"
 
 //
@@ -12,7 +15,7 @@
 // func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
 // Trap # in AX, args on stack above caller pc.
 
-TEXT	·Syscall(SB),NOSPLIT,$0-32
+TEXT	·Syscall(SB),NOSPLIT,$0-28
 	CALL	runtime·entersyscall(SB)
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
@@ -36,7 +39,7 @@ ok:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT	·Syscall6(SB),NOSPLIT,$0-44
+TEXT	·Syscall6(SB),NOSPLIT,$0-40
 	CALL	runtime·entersyscall(SB)
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
@@ -63,7 +66,7 @@ ok6:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT	·Syscall9(SB),NOSPLIT,$0-56
+TEXT	·Syscall9(SB),NOSPLIT,$0-52
 	CALL	runtime·entersyscall(SB)
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
@@ -93,7 +96,7 @@ ok9:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
 	LEAL		8(SP), SI
@@ -114,7 +117,7 @@ ok1:
 	MOVL	$0, 28(SP)	// errno
 	RET
 
-TEXT	·RawSyscall6(SB),NOSPLIT,$0-44
+TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
 	LEAL		8(SP), SI
diff --git a/src/pkg/syscall/asm_darwin_amd64.s b/src/pkg/syscall/asm_darwin_amd64.s
index c1970b7..19ea05b 100644
--- a/src/pkg/syscall/asm_darwin_amd64.s
+++ b/src/pkg/syscall/asm_darwin_amd64.s
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
 #include "../../cmd/ld/textflag.h"
 
 //
@@ -12,7 +15,7 @@
 // func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64);
 // Trap # in AX, args in DI SI DX, return in AX DX
 
-TEXT	·Syscall(SB),NOSPLIT,$0-64
+TEXT	·Syscall(SB),NOSPLIT,$0-56
 	CALL	runtime·entersyscall(SB)
 	MOVQ	16(SP), DI
 	MOVQ	24(SP), SI
@@ -36,7 +39,7 @@ ok:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT	·Syscall6(SB),NOSPLIT,$0-88
+TEXT	·Syscall6(SB),NOSPLIT,$0-80
 	CALL	runtime·entersyscall(SB)
 	MOVQ	16(SP), DI
 	MOVQ	24(SP), SI
@@ -60,7 +63,7 @@ ok6:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT ·RawSyscall(SB),NOSPLIT,$0-64
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
 	MOVQ	16(SP), DI
 	MOVQ	24(SP), SI
 	MOVQ	32(SP), DX
@@ -81,7 +84,7 @@ ok1:
 	MOVQ	$0, 56(SP)	// errno
 	RET
 
-TEXT	·RawSyscall6(SB),NOSPLIT,$0-88
+TEXT	·RawSyscall6(SB),NOSPLIT,$0-80
 	MOVQ	16(SP), DI
 	MOVQ	24(SP), SI
 	MOVQ	32(SP), DX
diff --git a/src/pkg/syscall/asm_freebsd_386.s b/src/pkg/syscall/asm_freebsd_386.s
index d24216f..91a46b1 100644
--- a/src/pkg/syscall/asm_freebsd_386.s
+++ b/src/pkg/syscall/asm_freebsd_386.s
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
 #include "../../cmd/ld/textflag.h"
 
 //
@@ -12,7 +15,7 @@
 // func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
 // Trap # in AX, args on stack above caller pc.
 
-TEXT	·Syscall(SB),NOSPLIT,$0-32
+TEXT	·Syscall(SB),NOSPLIT,$0-28
 	CALL	runtime·entersyscall(SB)
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
@@ -36,7 +39,7 @@ ok:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT	·Syscall6(SB),NOSPLIT,$0-44
+TEXT	·Syscall6(SB),NOSPLIT,$0-40
 	CALL	runtime·entersyscall(SB)
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
@@ -63,7 +66,7 @@ ok6:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT	·Syscall9(SB),NOSPLIT,$0-56
+TEXT	·Syscall9(SB),NOSPLIT,$0-52
 	CALL	runtime·entersyscall(SB)
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
@@ -93,7 +96,7 @@ ok9:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
 	LEAL		8(SP), SI
@@ -114,7 +117,7 @@ ok1:
 	MOVL	$0, 28(SP)	// errno
 	RET
 
-TEXT	·RawSyscall6(SB),NOSPLIT,$0-44
+TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
 	LEAL		8(SP), SI
diff --git a/src/pkg/syscall/asm_freebsd_amd64.s b/src/pkg/syscall/asm_freebsd_amd64.s
index fca7f37..7abb368 100644
--- a/src/pkg/syscall/asm_freebsd_amd64.s
+++ b/src/pkg/syscall/asm_freebsd_amd64.s
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
 #include "../../cmd/ld/textflag.h"
 
 //
@@ -18,7 +21,7 @@
 // func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64)
 // Trap # in AX, args in DI SI DX, return in AX DX
 
-TEXT	·Syscall(SB),NOSPLIT,$0-64
+TEXT	·Syscall(SB),NOSPLIT,$0-56
 	CALL	runtime·entersyscall(SB)
 	MOVQ	16(SP), DI
 	MOVQ	24(SP), SI
@@ -41,7 +44,7 @@ ok:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT	·Syscall6(SB),NOSPLIT,$0-88
+TEXT	·Syscall6(SB),NOSPLIT,$0-80
 	CALL	runtime·entersyscall(SB)
 	MOVQ	16(SP), DI
 	MOVQ	24(SP), SI
@@ -64,7 +67,7 @@ ok6:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT	·Syscall9(SB),NOSPLIT,$0-112
+TEXT	·Syscall9(SB),NOSPLIT,$0-104
 	CALL	runtime·entersyscall(SB)
 	MOVQ	8(SP), AX
 	MOVQ	16(SP), DI
@@ -97,7 +100,7 @@ ok9:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT ·RawSyscall(SB),NOSPLIT,$0-64
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
 	MOVQ	16(SP), DI
 	MOVQ	24(SP), SI
 	MOVQ	32(SP), DX
@@ -117,7 +120,7 @@ ok1:
 	MOVQ	$0, 56(SP)	// errno
 	RET
 
-TEXT	·RawSyscall6(SB),NOSPLIT,$0-88
+TEXT	·RawSyscall6(SB),NOSPLIT,$0-80
 	MOVQ	16(SP), DI
 	MOVQ	24(SP), SI
 	MOVQ	32(SP), DX
diff --git a/src/pkg/syscall/asm_freebsd_arm.s b/src/pkg/syscall/asm_freebsd_arm.s
index 9283d07..c01ce6f 100644
--- a/src/pkg/syscall/asm_freebsd_arm.s
+++ b/src/pkg/syscall/asm_freebsd_arm.s
@@ -8,13 +8,13 @@
 // System call support for ARM, FreeBSD
 //
 
-// func Syscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
-// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
-// func Syscall9(trap int32, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int32)
+// func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, errno uintptr);
+// func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, errno uintptr);
+// func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, errno uintptr)
 
 TEXT	·Syscall(SB),NOSPLIT,$0-28
 	BL runtime·entersyscall(SB)
-	MOVW 0(FP), R7 // sigcall num
+	MOVW 0(FP), R7 // syscall number
 	MOVW 4(FP), R0 // a1
 	MOVW 8(FP), R1 // a2
 	MOVW 12(FP), R2 // a3
@@ -23,69 +23,71 @@ TEXT	·Syscall(SB),NOSPLIT,$0-28
 	BCS error
 	MOVW R0, 16(FP) // r1
 	MOVW R1, 20(FP) // r2
-	MOVW R2, 24(FP) // err
+	MOVW R2, 24(FP) // errno
 	BL runtime·exitsyscall(SB)
 	RET
 error:
 	MOVW $-1, R3
 	MOVW R3, 16(FP) // r1
 	MOVW R2, 20(FP) // r2
-	MOVW R0, 24(FP) // err
+	MOVW R0, 24(FP) // errno
 	BL runtime·exitsyscall(SB)
 	RET
 
 TEXT	·Syscall6(SB),NOSPLIT,$0-40
 	BL runtime·entersyscall(SB)
-	MOVW 0(FP), R7 // sigcall num
+	MOVW 0(FP), R7 // syscall number
 	MOVW 4(FP), R0 // a1
 	MOVW 8(FP), R1 // a2
 	MOVW 12(FP), R2 // a3
 	MOVW 16(FP), R3 // a4
-	ADD $24, R13 // a5 to a6 are passed on stack
+	MOVW R13, R4
+	MOVW $20(FP), R13 // a5 to a6 are passed on stack
 	SWI $0 // syscall
-	SUB $24, R13
+	MOVW R4, R13
 	MOVW $0, R2
 	BCS error6
 	MOVW R0, 28(FP) // r1
 	MOVW R1, 32(FP) // r2
-	MOVW R2, 36(FP) // err
+	MOVW R2, 36(FP) // errno
 	BL runtime·exitsyscall(SB)
 	RET
 error6:
 	MOVW $-1, R3
 	MOVW R3, 28(FP) // r1
 	MOVW R2, 32(FP) // r2
-	MOVW R0, 36(FP) // err
+	MOVW R0, 36(FP) // errno
 	BL runtime·exitsyscall(SB)
 	RET
 
 TEXT	·Syscall9(SB),NOSPLIT,$0-52
 	BL runtime·entersyscall(SB)
-	MOVW 0(FP), R7 // sigcall num
+	MOVW 0(FP), R7 // syscall number
 	MOVW 4(FP), R0 // a1
 	MOVW 8(FP), R1 // a2
 	MOVW 12(FP), R2 // a3
 	MOVW 16(FP), R3 // a4
-	ADD $24, R13 // a5 to a9 are passed on stack
+	MOVW R13, R4
+	MOVW $20(FP), R13 // a5 to a9 are passed on stack
 	SWI $0 // syscall
-	SUB $24, R13
+	MOVW R4, R13
 	MOVW $0, R2
 	BCS error9
 	MOVW R0, 40(FP) // r1
 	MOVW R1, 44(FP) // r2
-	MOVW R2, 48(FP) // err
+	MOVW R2, 48(FP) // errno
 	BL runtime·exitsyscall(SB)
 	RET
 error9:
 	MOVW $-1, R3
 	MOVW R3, 40(FP) // r1
 	MOVW R2, 44(FP) // r2
-	MOVW R0, 48(FP) // err
+	MOVW R0, 48(FP) // errno
 	BL runtime·exitsyscall(SB)
 	RET
 
 TEXT	·RawSyscall(SB),NOSPLIT,$0-28
-	MOVW 0(FP), R7 // sigcall num
+	MOVW 0(FP), R7 // syscall number
 	MOVW 4(FP), R0 // a1
 	MOVW 8(FP), R1 // a2
 	MOVW 12(FP), R2 // a3
@@ -94,33 +96,34 @@ TEXT	·RawSyscall(SB),NOSPLIT,$0-28
 	BCS errorr
 	MOVW R0, 16(FP) // r1
 	MOVW R1, 20(FP) // r2
-	MOVW R2, 24(FP) // err
+	MOVW R2, 24(FP) // errno
 	RET
 errorr:
 	MOVW $-1, R3
 	MOVW R3, 16(FP) // r1
 	MOVW R2, 20(FP) // r2
-	MOVW R0, 24(FP) // err
+	MOVW R0, 24(FP) // errno
 	RET
 
 TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
-	MOVW 0(FP), R7 // sigcall num
+	MOVW 0(FP), R7 // syscall number
 	MOVW 4(FP), R0 // a1
 	MOVW 8(FP), R1 // a2
 	MOVW 12(FP), R2 // a3
 	MOVW 16(FP), R3 // a4
-	ADD $24, R13 // a5 to a6 are passed on stack
+	MOVW R13, R4
+	MOVW $20(FP), R13 // a5 to a6 are passed on stack
 	SWI $0 // syscall
-	SUB $24, R13
+	MOVW R4, R13
 	MOVW $0, R2
 	BCS errorr6
 	MOVW R0, 28(FP) // r1
 	MOVW R1, 32(FP) // r2
-	MOVW R2, 36(FP) // err
+	MOVW R2, 36(FP) // errno
 	RET
 errorr6:
 	MOVW $-1, R3
 	MOVW R3, 28(FP) // r1
 	MOVW R2, 32(FP) // r2
-	MOVW R0, 36(FP) // err
+	MOVW R0, 36(FP) // errno
 	RET
diff --git a/src/pkg/syscall/asm_linux_386.s b/src/pkg/syscall/asm_linux_386.s
index cf2ab02..30b2207 100644
--- a/src/pkg/syscall/asm_linux_386.s
+++ b/src/pkg/syscall/asm_linux_386.s
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
 #include "../../cmd/ld/textflag.h"
 
 //
@@ -11,7 +14,7 @@
 // func Syscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
 // Trap # in AX, args in BX CX DX SI DI, return in AX
 
-TEXT	·Syscall(SB),NOSPLIT,$0-32
+TEXT	·Syscall(SB),NOSPLIT,$0-28
 	CALL	runtime·entersyscall(SB)
 	MOVL	4(SP), AX	// syscall entry
 	MOVL	8(SP), BX
@@ -36,7 +39,7 @@ ok:
 	RET
 
 // func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
-TEXT	·Syscall6(SB),NOSPLIT,$0-44
+TEXT	·Syscall6(SB),NOSPLIT,$0-40
 	CALL	runtime·entersyscall(SB)
 	MOVL	4(SP), AX	// syscall entry
 	MOVL	8(SP), BX
@@ -62,7 +65,7 @@ ok6:
 	RET
 
 // func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
-TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
 	MOVL	4(SP), AX	// syscall entry
 	MOVL	8(SP), BX
 	MOVL	12(SP), CX
@@ -84,7 +87,7 @@ ok1:
 	RET
 
 // func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
-TEXT	·RawSyscall6(SB),NOSPLIT,$0-44
+TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
 	MOVL	4(SP), AX	// syscall entry
 	MOVL	8(SP), BX
 	MOVL	12(SP), CX
@@ -110,7 +113,7 @@ ok2:
 
 // func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
 // Kernel interface gets call sub-number and pointer to a0.
-TEXT ·socketcall(SB),NOSPLIT,$0-40
+TEXT ·socketcall(SB),NOSPLIT,$0-36
 	CALL	runtime·entersyscall(SB)
 	MOVL	$SYS_SOCKETCALL, AX	// syscall entry
 	MOVL	4(SP), BX	// socket call number
@@ -134,7 +137,7 @@ oksock:
 
 // func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
 // Kernel interface gets call sub-number and pointer to a0.
-TEXT ·rawsocketcall(SB),NOSPLIT,$0-40
+TEXT ·rawsocketcall(SB),NOSPLIT,$0-36
 	MOVL	$SYS_SOCKETCALL, AX	// syscall entry
 	MOVL	4(SP), BX	// socket call number
 	LEAL		8(SP), CX	// pointer to call arguments
@@ -159,7 +162,7 @@ oksock1:
 // taking the address of the return value newoffset.
 // Underlying system call is
 //	llseek(int fd, int offhi, int offlo, int64 *result, int whence)
-TEXT ·Seek(SB),NOSPLIT,$0-32
+TEXT ·seek(SB),NOSPLIT,$0-28
 	CALL	runtime·entersyscall(SB)
 	MOVL	$SYS__LLSEEK, AX	// syscall entry
 	MOVL	4(SP), BX	// fd
diff --git a/src/pkg/syscall/asm_linux_amd64.s b/src/pkg/syscall/asm_linux_amd64.s
index 28a2a58..995b60e 100644
--- a/src/pkg/syscall/asm_linux_amd64.s
+++ b/src/pkg/syscall/asm_linux_amd64.s
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
 #include "../../cmd/ld/textflag.h"
 
 //
@@ -13,7 +16,7 @@
 // Note that this differs from "standard" ABI convention, which
 // would pass 4th arg in CX, not R10.
 
-TEXT	·Syscall(SB),NOSPLIT,$0-64
+TEXT	·Syscall(SB),NOSPLIT,$0-56
 	CALL	runtime·entersyscall(SB)
 	MOVQ	16(SP), DI
 	MOVQ	24(SP), SI
@@ -38,7 +41,7 @@ ok:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT ·Syscall6(SB),NOSPLIT,$0-88
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
 	CALL	runtime·entersyscall(SB)
 	MOVQ	16(SP), DI
 	MOVQ	24(SP), SI
@@ -63,7 +66,7 @@ ok6:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT ·RawSyscall(SB),NOSPLIT,$0-64
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
 	MOVQ	16(SP), DI
 	MOVQ	24(SP), SI
 	MOVQ	32(SP), DX
@@ -85,7 +88,7 @@ ok1:
 	MOVQ	$0, 56(SP)	// errno
 	RET
 
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-88
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
 	MOVQ	16(SP), DI
 	MOVQ	24(SP), SI
 	MOVQ	32(SP), DX
@@ -107,7 +110,7 @@ ok2:
 	MOVQ	$0, 80(SP)	// errno
 	RET
 
-TEXT ·Gettimeofday(SB),NOSPLIT,$0-24
+TEXT ·gettimeofday(SB),NOSPLIT,$0-16
 	MOVQ	8(SP), DI
 	MOVQ	$0, SI
 	MOVQ	runtime·__vdso_gettimeofday_sym(SB), AX
@@ -121,11 +124,3 @@ TEXT ·Gettimeofday(SB),NOSPLIT,$0-24
 ok7:
 	MOVQ	$0, 16(SP)  // errno
 	RET
-
-TEXT ·Time(SB),NOSPLIT,$0-32
-	MOVQ	8(SP), DI
-	MOVQ	runtime·__vdso_time_sym(SB), AX
-	CALL	AX
-	MOVQ	AX, 16(SP)  // tt
-	MOVQ	$0, 24(SP)  // errno
-	RET
diff --git a/src/pkg/syscall/asm_linux_arm.s b/src/pkg/syscall/asm_linux_arm.s
index bf54b4f..a28bc6c 100644
--- a/src/pkg/syscall/asm_linux_arm.s
+++ b/src/pkg/syscall/asm_linux_arm.s
@@ -98,12 +98,12 @@ ok2:
 	RET
 
 #define SYS__LLSEEK 140  /* from zsysnum_linux_arm.go */
-// func Seek(fd int, offset int64, whence int) (newoffset int64, errno int)
+// func seek(fd int, offset int64, whence int) (newoffset int64, errno int)
 // Implemented in assembly to avoid allocation when
 // taking the address of the return value newoffset.
 // Underlying system call is
 //	llseek(int fd, int offhi, int offlo, int64 *result, int whence)
-TEXT ·Seek(SB),NOSPLIT,$0-32
+TEXT ·seek(SB),NOSPLIT,$0-32
 	BL	runtime·entersyscall(SB)
 	MOVW	$SYS__LLSEEK, R7	// syscall entry
 	MOVW	4(SP), R0	// fd
diff --git a/src/pkg/syscall/asm_nacl_386.s b/src/pkg/syscall/asm_nacl_386.s
new file mode 100644
index 0000000..de7c3cc
--- /dev/null
+++ b/src/pkg/syscall/asm_nacl_386.s
@@ -0,0 +1,43 @@
+// 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 "../../cmd/ld/textflag.h"
+#include "../runtime/syscall_nacl.h"
+
+//
+// System call support for 386, Native Client
+//
+
+#define NACL_SYSCALL(code) \
+	MOVL $(0x10000 + ((code)<<5)), AX; CALL AX
+
+#define NACL_SYSJMP(code) \
+	MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
+
+TEXT syscall·Syscall(SB),NOSPLIT,$12-28
+	CALL	runtime·entersyscall(SB)
+	MOVL	trap+0(FP), AX
+	MOVL	a1+4(FP), BX
+	MOVL	BX, 0(SP)
+	MOVL	a2+8(FP), BX
+	MOVL	BX, 4(SP)
+	MOVL	a3+12(FP), BX
+	MOVL	BX, 8(SP)
+	SHLL	$5, AX
+	ADDL	$0x10000, AX
+	CALL	AX
+	CMPL	AX, $0
+	JGE	ok
+	MOVL	$-1, r1+16(FP)
+	MOVL	$-1, r2+20(FP)
+	NEGL	AX
+	MOVL	AX, err+24(FP)
+	CALL	runtime·exitsyscall(SB)
+	RET
+ok:
+	MOVL	AX, r1+16(FP)
+	MOVL	DX, r2+20(FP)
+	MOVL	$0, err+24(FP)
+	CALL	runtime·exitsyscall(SB)
+	RET	
diff --git a/src/pkg/syscall/asm_nacl_amd64p32.s b/src/pkg/syscall/asm_nacl_amd64p32.s
new file mode 100644
index 0000000..de030ec
--- /dev/null
+++ b/src/pkg/syscall/asm_nacl_amd64p32.s
@@ -0,0 +1,41 @@
+// 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 "../../cmd/ld/textflag.h"
+#include "../runtime/syscall_nacl.h"
+
+//
+// System call support for amd64, Native Client
+//
+
+#define NACL_SYSCALL(code) \
+	MOVL $(0x10000 + ((code)<<5)), AX; CALL AX
+
+#define NACL_SYSJMP(code) \
+	MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
+
+TEXT syscall·Syscall(SB),NOSPLIT,$0-28
+	CALL	runtime·entersyscall(SB)
+	MOVL	trap+0(FP), AX
+	MOVL	a1+4(FP), DI
+	MOVL	a2+8(FP), SI
+	MOVL	a3+12(FP), DX
+	// more args would use CX, R8, R9
+	SHLL	$5, AX
+	ADDL	$0x10000, AX
+	CALL	AX
+	CMPL	AX, $0
+	JGE	ok
+	MOVL	$-1, r1+16(FP)
+	MOVL	$-1, r2+20(FP)
+	NEGL	AX
+	MOVL	AX, err+24(FP)
+	CALL	runtime·exitsyscall(SB)
+	RET
+ok:
+	MOVL	AX, r1+16(FP)
+	MOVL	DX, r2+20(FP)
+	MOVL	$0, err+24(FP)
+	CALL	runtime·exitsyscall(SB)
+	RET	
diff --git a/src/pkg/syscall/asm_netbsd_386.s b/src/pkg/syscall/asm_netbsd_386.s
index 8caade2..40b30b4 100644
--- a/src/pkg/syscall/asm_netbsd_386.s
+++ b/src/pkg/syscall/asm_netbsd_386.s
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
 #include "../../cmd/ld/textflag.h"
 
 //
@@ -12,7 +15,7 @@
 // func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
 // Trap # in AX, args on stack above caller pc.
 
-TEXT	·Syscall(SB),NOSPLIT,$0-32
+TEXT	·Syscall(SB),NOSPLIT,$0-28
 	CALL	runtime·entersyscall(SB)
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
@@ -36,7 +39,7 @@ ok:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT	·Syscall6(SB),NOSPLIT,$0-44
+TEXT	·Syscall6(SB),NOSPLIT,$0-40
 	CALL	runtime·entersyscall(SB)
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
@@ -63,7 +66,7 @@ ok6:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT	·Syscall9(SB),NOSPLIT,$0-56
+TEXT	·Syscall9(SB),NOSPLIT,$0-52
 	CALL	runtime·entersyscall(SB)
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
@@ -93,7 +96,7 @@ ok9:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
 	LEAL		8(SP), SI
@@ -114,7 +117,7 @@ ok1:
 	MOVL	$0, 28(SP)	// errno
 	RET
 
-TEXT	·RawSyscall6(SB),NOSPLIT,$0-44
+TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
 	LEAL		8(SP), SI
diff --git a/src/pkg/syscall/asm_netbsd_amd64.s b/src/pkg/syscall/asm_netbsd_amd64.s
index e0b8b3c..94ad028 100644
--- a/src/pkg/syscall/asm_netbsd_amd64.s
+++ b/src/pkg/syscall/asm_netbsd_amd64.s
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
 #include "../../cmd/ld/textflag.h"
 
 //
@@ -13,7 +16,7 @@
 // func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64);
 // Trap # in AX, args in DI SI DX, return in AX DX
 
-TEXT	·Syscall(SB),NOSPLIT,$0-64
+TEXT	·Syscall(SB),NOSPLIT,$0-56
 	CALL	runtime·entersyscall(SB)
 	MOVQ	8(SP), AX	// syscall entry
 	MOVQ	16(SP), DI
@@ -36,7 +39,7 @@ ok:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT	·Syscall6(SB),NOSPLIT,$0-88
+TEXT	·Syscall6(SB),NOSPLIT,$0-80
 	CALL	runtime·entersyscall(SB)
 	MOVQ	8(SP), AX	// syscall entry
 	MOVQ	16(SP), DI
@@ -59,7 +62,7 @@ ok6:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT	·Syscall9(SB),NOSPLIT,$0-112
+TEXT	·Syscall9(SB),NOSPLIT,$0-104
 	CALL	runtime·entersyscall(SB)
 	MOVQ	8(SP), AX	// syscall entry
 	MOVQ	16(SP), DI
@@ -91,7 +94,7 @@ ok9:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT	·RawSyscall(SB),NOSPLIT,$0-64
+TEXT	·RawSyscall(SB),NOSPLIT,$0-56
 	MOVQ	16(SP), DI
 	MOVQ	24(SP), SI
 	MOVQ	32(SP), DX
@@ -111,7 +114,7 @@ ok1:
 	MOVQ	$0, 56(SP)	// errno
 	RET
 
-TEXT	·RawSyscall6(SB),NOSPLIT,$0-88
+TEXT	·RawSyscall6(SB),NOSPLIT,$0-80
 	MOVQ	16(SP), DI
 	MOVQ	24(SP), SI
 	MOVQ	32(SP), DX
diff --git a/src/pkg/syscall/asm_openbsd_386.s b/src/pkg/syscall/asm_openbsd_386.s
index a383496..7dd2e37 100644
--- a/src/pkg/syscall/asm_openbsd_386.s
+++ b/src/pkg/syscall/asm_openbsd_386.s
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
 #include "../../cmd/ld/textflag.h"
 
 //
@@ -12,7 +15,7 @@
 // func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
 // Trap # in AX, args on stack above caller pc.
 
-TEXT	·Syscall(SB),NOSPLIT,$0-32
+TEXT	·Syscall(SB),NOSPLIT,$0-28
 	CALL	runtime·entersyscall(SB)
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
@@ -36,7 +39,7 @@ ok:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT	·Syscall6(SB),NOSPLIT,$0-44
+TEXT	·Syscall6(SB),NOSPLIT,$0-40
 	CALL	runtime·entersyscall(SB)
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
@@ -63,7 +66,7 @@ ok6:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT	·Syscall9(SB),NOSPLIT,$0-56
+TEXT	·Syscall9(SB),NOSPLIT,$0-52
 	CALL	runtime·entersyscall(SB)
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
@@ -93,7 +96,7 @@ ok9:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
 	LEAL		8(SP), SI
@@ -114,7 +117,7 @@ ok1:
 	MOVL	$0, 28(SP)	// errno
 	RET
 
-TEXT	·RawSyscall6(SB),NOSPLIT,$0-44
+TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
 	LEAL		8(SP), SI
diff --git a/src/pkg/syscall/asm_openbsd_amd64.s b/src/pkg/syscall/asm_openbsd_amd64.s
index 1bf25f1..e127bf2 100644
--- a/src/pkg/syscall/asm_openbsd_amd64.s
+++ b/src/pkg/syscall/asm_openbsd_amd64.s
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
 #include "../../cmd/ld/textflag.h"
 
 //
@@ -13,7 +16,7 @@
 // func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64);
 // Trap # in AX, args in DI SI DX, return in AX DX
 
-TEXT	·Syscall(SB),NOSPLIT,$0-64
+TEXT	·Syscall(SB),NOSPLIT,$0-56
 	CALL	runtime·entersyscall(SB)
 	MOVQ	8(SP), AX	// syscall entry
 	MOVQ	16(SP), DI
@@ -36,7 +39,7 @@ ok:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT	·Syscall6(SB),NOSPLIT,$0-88
+TEXT	·Syscall6(SB),NOSPLIT,$0-80
 	CALL	runtime·entersyscall(SB)
 	MOVQ	8(SP), AX	// syscall entry
 	MOVQ	16(SP), DI
@@ -59,7 +62,7 @@ ok6:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT	·Syscall9(SB),NOSPLIT,$0-112
+TEXT	·Syscall9(SB),NOSPLIT,$0-104
 	CALL	runtime·entersyscall(SB)
 	MOVQ	8(SP), AX	// syscall entry
 	MOVQ	16(SP), DI
@@ -91,7 +94,7 @@ ok9:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT	·RawSyscall(SB),NOSPLIT,$0-64
+TEXT	·RawSyscall(SB),NOSPLIT,$0-56
 	MOVQ	16(SP), DI
 	MOVQ	24(SP), SI
 	MOVQ	32(SP), DX
@@ -111,7 +114,7 @@ ok1:
 	MOVQ	$0, 56(SP)	// errno
 	RET
 
-TEXT	·RawSyscall6(SB),NOSPLIT,$0-88
+TEXT	·RawSyscall6(SB),NOSPLIT,$0-80
 	MOVQ	16(SP), DI
 	MOVQ	24(SP), SI
 	MOVQ	32(SP), DX
diff --git a/src/pkg/syscall/asm_plan9_386.s b/src/pkg/syscall/asm_plan9_386.s
index 7ebd206..f8c07c4 100644
--- a/src/pkg/syscall/asm_plan9_386.s
+++ b/src/pkg/syscall/asm_plan9_386.s
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
 #include "../../cmd/ld/textflag.h"
 
 //
@@ -87,7 +90,7 @@ copyresult4:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
 	LEAL		8(SP), SI
@@ -102,7 +105,7 @@ TEXT ·RawSyscall(SB),NOSPLIT,$0-32
 	MOVL	AX, err+28(SP)
 	RET
 
-TEXT	·RawSyscall6(SB),NOSPLIT,$0-44
+TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
 	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
 	LEAL		8(SP), SI
@@ -123,7 +126,7 @@ TEXT	·RawSyscall6(SB),NOSPLIT,$0-44
 #define SYS_SEEK 39	/* from zsysnum_plan9_386.go */
 
 //func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
-TEXT ·seek(SB),NOSPLIT,$0-40
+TEXT ·seek(SB),NOSPLIT,$0-36
 	LEAL	newoffset+24(SP), AX
 	MOVL	AX, placeholder+4(SP)
 	
diff --git a/src/pkg/syscall/asm_plan9_amd64.s b/src/pkg/syscall/asm_plan9_amd64.s
index 880bf7c..2154a87 100644
--- a/src/pkg/syscall/asm_plan9_amd64.s
+++ b/src/pkg/syscall/asm_plan9_amd64.s
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
 #include "../../cmd/ld/textflag.h"
 
 //
@@ -91,7 +94,7 @@ copyresult4:
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-TEXT ·RawSyscall(SB),NOSPLIT,$0-64
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
 	MOVQ	$0x8000, AX	// for NxM
 	MOVQ	8(SP), BP	// syscall entry
 	// slide args down on top of system call number
@@ -107,7 +110,7 @@ TEXT ·RawSyscall(SB),NOSPLIT,$0-64
 	MOVQ	AX, err+56(SP)
 	RET
 
-TEXT	·RawSyscall6(SB),NOSPLIT,$0-88
+TEXT	·RawSyscall6(SB),NOSPLIT,$0-80
 	MOVQ	$0x8000, AX	// for NxM
 	MOVQ	8(SP), BP	// syscall entry
 	// slide args down on top of system call number
@@ -129,7 +132,7 @@ TEXT	·RawSyscall6(SB),NOSPLIT,$0-88
 #define SYS_SEEK 39	/* from zsysnum_plan9_amd64.go */
 
 //func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
-TEXT ·seek(SB),NOSPLIT,$0-64
+TEXT ·seek(SB),NOSPLIT,$0-56
 	LEAQ	newoffset+40(SP), AX
 	MOVQ	AX, placeholder+8(SP)
 	
@@ -160,7 +163,7 @@ copyresult6:
 
 //func exit(code int)
 // Import runtime·exit for cleanly exiting.
-TEXT ·exit(SB),NOSPLIT,$8-4
+TEXT ·exit(SB),NOSPLIT,$8-8
 	MOVQ	code+0(FP), AX
 	MOVQ	AX, 0(SP)
 	CALL	runtime·exit(SB)
diff --git a/src/pkg/syscall/asm_solaris_amd64.s b/src/pkg/syscall/asm_solaris_amd64.s
new file mode 100644
index 0000000..3735890
--- /dev/null
+++ b/src/pkg/syscall/asm_solaris_amd64.s
@@ -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.
+
+//
+// System calls for amd64, Solaris are implemented in ../runtime/syscall_solaris.goc
+//
diff --git a/src/pkg/syscall/consistency_unix_test.go b/src/pkg/syscall/consistency_unix_test.go
deleted file mode 100644
index 73630bc..0000000
--- a/src/pkg/syscall/consistency_unix_test.go
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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 freebsd dragonfly darwin linux netbsd openbsd
-
-// This file tests that some basic syscalls are consistent across
-// all Unixes.
-
-package syscall_test
-
-import "syscall"
-
-// {Set,Get}priority and needed constants for them
-func _() {
-	var (
-		_ func(int, int, int) error   = syscall.Setpriority
-		_ func(int, int) (int, error) = syscall.Getpriority
-	)
-	const (
-		_ int = syscall.PRIO_USER
-		_ int = syscall.PRIO_PROCESS
-		_ int = syscall.PRIO_PGRP
-	)
-}
-
-// termios functions and constants
-func _() {
-	const (
-		_ int = syscall.TCIFLUSH
-		_ int = syscall.TCIOFLUSH
-		_ int = syscall.TCOFLUSH
-	)
-}
diff --git a/src/pkg/syscall/dir_plan9.go b/src/pkg/syscall/dir_plan9.go
index b7ab4cd..697bf54 100644
--- a/src/pkg/syscall/dir_plan9.go
+++ b/src/pkg/syscall/dir_plan9.go
@@ -11,6 +11,7 @@ import "errors"
 var (
 	ErrShortStat = errors.New("stat buffer too short")
 	ErrBadStat   = errors.New("malformed stat buffer")
+	ErrBadName   = errors.New("bad character in file name")
 )
 
 // A Qid represents a 9P server's unique identification for a file.
@@ -53,7 +54,7 @@ var nullDir = Dir{
 }
 
 // Null assigns special "don't touch" values to members of d to
-// avoid modifiying them during syscall.Wstat.
+// avoid modifying them during syscall.Wstat.
 func (d *Dir) Null() { *d = nullDir }
 
 // Marshal encodes a 9P stat message corresponding to d into b
@@ -65,6 +66,12 @@ func (d *Dir) Marshal(b []byte) (n int, err error) {
 		return n, ErrShortStat
 	}
 
+	for _, c := range d.Name {
+		if c == '/' {
+			return n, ErrBadName
+		}
+	}
+
 	b = pbit16(b, uint16(n)-2)
 	b = pbit16(b, d.Type)
 	b = pbit32(b, d.Dev)
diff --git a/src/pkg/syscall/env_unix.go b/src/pkg/syscall/env_unix.go
index 5970df8..ad354ed 100644
--- a/src/pkg/syscall/env_unix.go
+++ b/src/pkg/syscall/env_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
 
 // Unix environment variables.
 
diff --git a/src/pkg/syscall/exec_linux.go b/src/pkg/syscall/exec_linux.go
index a1656e8..f27950f 100644
--- a/src/pkg/syscall/exec_linux.go
+++ b/src/pkg/syscall/exec_linux.go
@@ -131,11 +131,11 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 	// User and groups
 	if cred := sys.Credential; cred != nil {
 		ngroups := uintptr(len(cred.Groups))
-		groups := uintptr(0)
+		var groups unsafe.Pointer
 		if ngroups > 0 {
-			groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
+			groups = unsafe.Pointer(&cred.Groups[0])
 		}
-		_, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0)
+		_, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, uintptr(groups), 0)
 		if err1 != 0 {
 			goto childerror
 		}
diff --git a/src/pkg/syscall/exec_plan9.go b/src/pkg/syscall/exec_plan9.go
index 99ad2f1..45ee542 100644
--- a/src/pkg/syscall/exec_plan9.go
+++ b/src/pkg/syscall/exec_plan9.go
@@ -486,7 +486,7 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
 
 	if err != nil || n != 0 {
 		if n != 0 {
-			err = NewError(string(errbuf[:]))
+			err = NewError(string(errbuf[:n]))
 		}
 
 		// Child failed; wait for it to exit, to make sure
diff --git a/src/pkg/syscall/exec_solaris.go b/src/pkg/syscall/exec_solaris.go
new file mode 100644
index 0000000..97de6ca
--- /dev/null
+++ b/src/pkg/syscall/exec_solaris.go
@@ -0,0 +1,243 @@
+// 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.
+
+package syscall
+
+import (
+	"unsafe"
+)
+
+type SysProcAttr struct {
+	Chroot     string      // Chroot.
+	Credential *Credential // Credential.
+	Setsid     bool        // Create session.
+	Setpgid    bool        // Set process group ID to new pid (SYSV setpgrp)
+	Setctty    bool        // Set controlling terminal to fd 0
+	Noctty     bool        // Detach fd 0 from controlling terminal
+}
+
+// Implemented in runtime package.
+func runtime_BeforeFork()
+func runtime_AfterFork()
+
+func chdir(path uintptr) (err Errno)
+func chroot1(path uintptr) (err Errno)
+func close(fd uintptr) (err Errno)
+func execve(path uintptr, argv uintptr, envp uintptr) (err Errno)
+func exit(code uintptr)
+func fcntl1(fd uintptr, cmd uintptr, arg uintptr) (val uintptr, err Errno)
+func forkx(flags uintptr) (pid uintptr, err Errno)
+func ioctl(fd uintptr, req uintptr, arg uintptr) (err Errno)
+func setgid(gid uintptr) (err Errno)
+func setgroups1(ngid uintptr, gid uintptr) (err Errno)
+func setsid() (pid uintptr, err Errno)
+func setuid(uid uintptr) (err Errno)
+func setpgid(pid uintptr, pgid uintptr) (err Errno)
+func write1(fd uintptr, buf uintptr, nbyte uintptr) (n uintptr, err Errno)
+
+// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
+// If a dup or exec fails, write the errno error to pipe.
+// (Pipe is close-on-exec so if exec succeeds, it will be closed.)
+// In the child, this function must not acquire any locks, because
+// they might have been locked at the time of the fork.  This means
+// no rescheduling, no malloc calls, and no new stack segments.
+//
+// We call hand-crafted syscalls, implemented in
+// ../runtime/syscall_solaris.goc, rather than generated libc wrappers
+// because we need to avoid lazy-loading the functions (might malloc,
+// split the stack, or acquire mutexes). We can't call RawSyscall
+// because it's not safe even for BSD-subsystem calls.
+func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
+	// Declare all variables at top in case any
+	// declarations require heap allocation (e.g., err1).
+	var (
+		r1     uintptr
+		err1   Errno
+		nextfd int
+		i      int
+	)
+
+	// guard against side effects of shuffling fds below.
+	// Make sure that nextfd is beyond any currently open files so
+	// that we can't run the risk of overwriting any of them.
+	fd := make([]int, len(attr.Files))
+	nextfd = len(attr.Files)
+	for i, ufd := range attr.Files {
+		if nextfd < int(ufd) {
+			nextfd = int(ufd)
+		}
+		fd[i] = int(ufd)
+	}
+	nextfd++
+
+	// About to call fork.
+	// No more allocation or calls of non-assembly functions.
+	runtime_BeforeFork()
+	r1, err1 = forkx(0x1) // FORK_NOSIGCHLD
+	if err1 != 0 {
+		runtime_AfterFork()
+		return 0, err1
+	}
+
+	if r1 != 0 {
+		// parent; return PID
+		runtime_AfterFork()
+		return int(r1), 0
+	}
+
+	// Fork succeeded, now in child.
+
+	// Session ID
+	if sys.Setsid {
+		_, err1 = setsid()
+		if err1 != 0 {
+			goto childerror
+		}
+	}
+
+	// Set process group
+	if sys.Setpgid {
+		err1 = setpgid(0, 0)
+		if err1 != 0 {
+			goto childerror
+		}
+	}
+
+	// Chroot
+	if chroot != nil {
+		err1 = chroot1(uintptr(unsafe.Pointer(chroot)))
+		if err1 != 0 {
+			goto childerror
+		}
+	}
+
+	// User and groups
+	if cred := sys.Credential; cred != nil {
+		ngroups := uintptr(len(cred.Groups))
+		groups := uintptr(0)
+		if ngroups > 0 {
+			groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
+		}
+		err1 = setgroups1(ngroups, groups)
+		if err1 != 0 {
+			goto childerror
+		}
+		err1 = setgid(uintptr(cred.Gid))
+		if err1 != 0 {
+			goto childerror
+		}
+		err1 = setuid(uintptr(cred.Uid))
+		if err1 != 0 {
+			goto childerror
+		}
+	}
+
+	// Chdir
+	if dir != nil {
+		err1 = chdir(uintptr(unsafe.Pointer(dir)))
+		if err1 != 0 {
+			goto childerror
+		}
+	}
+
+	// Pass 1: look for fd[i] < i and move those up above len(fd)
+	// so that pass 2 won't stomp on an fd it needs later.
+	if pipe < nextfd {
+		_, err1 = fcntl1(uintptr(pipe), F_DUP2FD, uintptr(nextfd))
+		if err1 != 0 {
+			goto childerror
+		}
+		fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC)
+		pipe = nextfd
+		nextfd++
+	}
+	for i = 0; i < len(fd); i++ {
+		if fd[i] >= 0 && fd[i] < int(i) {
+			_, err1 = fcntl1(uintptr(fd[i]), F_DUP2FD, uintptr(nextfd))
+			if err1 != 0 {
+				goto childerror
+			}
+			fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC)
+			fd[i] = nextfd
+			nextfd++
+			if nextfd == pipe { // don't stomp on pipe
+				nextfd++
+			}
+		}
+	}
+
+	// Pass 2: dup fd[i] down onto i.
+	for i = 0; i < len(fd); i++ {
+		if fd[i] == -1 {
+			close(uintptr(i))
+			continue
+		}
+		if fd[i] == int(i) {
+			// dup2(i, i) won't clear close-on-exec flag on Linux,
+			// probably not elsewhere either.
+			_, err1 = fcntl1(uintptr(fd[i]), F_SETFD, 0)
+			if err1 != 0 {
+				goto childerror
+			}
+			continue
+		}
+		// The new fd is created NOT close-on-exec,
+		// which is exactly what we want.
+		_, err1 = fcntl1(uintptr(fd[i]), F_DUP2FD, uintptr(i))
+		if err1 != 0 {
+			goto childerror
+		}
+	}
+
+	// By convention, we don't close-on-exec the fds we are
+	// started with, so if len(fd) < 3, close 0, 1, 2 as needed.
+	// Programs that know they inherit fds >= 3 will need
+	// to set them close-on-exec.
+	for i = len(fd); i < 3; i++ {
+		close(uintptr(i))
+	}
+
+	// Detach fd 0 from tty
+	if sys.Noctty {
+		err1 = ioctl(0, uintptr(TIOCNOTTY), 0)
+		if err1 != 0 {
+			goto childerror
+		}
+	}
+
+	// Make fd 0 the tty
+	if sys.Setctty {
+		err1 = ioctl(0, uintptr(TIOCSCTTY), 0)
+		if err1 != 0 {
+			goto childerror
+		}
+	}
+
+	// Time to exec.
+	err1 = execve(
+		uintptr(unsafe.Pointer(argv0)),
+		uintptr(unsafe.Pointer(&argv[0])),
+		uintptr(unsafe.Pointer(&envv[0])))
+
+childerror:
+	// send error code on pipe
+	write1(uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1))
+	for {
+		exit(253)
+	}
+}
+
+// Try to open a pipe with O_CLOEXEC set on both file descriptors.
+func forkExecPipe(p []int) error {
+	err := Pipe(p)
+	if err != nil {
+		return err
+	}
+	_, err = fcntl(p[0], F_SETFD, FD_CLOEXEC)
+	if err != nil {
+		return err
+	}
+	_, err = fcntl(p[1], F_SETFD, FD_CLOEXEC)
+	return err
+}
diff --git a/src/pkg/syscall/exec_unix.go b/src/pkg/syscall/exec_unix.go
index b82e397..890bfdc 100644
--- a/src/pkg/syscall/exec_unix.go
+++ b/src/pkg/syscall/exec_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 netbsd openbsd solaris
 
 // Fork, exec, wait, etc.
 
@@ -158,7 +158,7 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
 		return 0, err
 	}
 
-	if runtime.GOOS == "freebsd" && len(argv[0]) > len(argv0) {
+	if (runtime.GOOS == "freebsd" || runtime.GOOS == "dragonfly") && len(argv[0]) > len(argv0) {
 		argvp[0] = argv0p
 	}
 
diff --git a/src/pkg/syscall/fd_nacl.go b/src/pkg/syscall/fd_nacl.go
new file mode 100644
index 0000000..7432414
--- /dev/null
+++ b/src/pkg/syscall/fd_nacl.go
@@ -0,0 +1,326 @@
+// 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.
+
+// File descriptor support for Native Client.
+// We want to provide access to a broader range of (simulated) files than
+// Native Client allows, so we maintain our own file descriptor table exposed
+// to higher-level packages.
+
+package syscall
+
+import (
+	"sync"
+)
+
+// files is the table indexed by a file descriptor.
+var files struct {
+	sync.RWMutex
+	tab []*file
+}
+
+// A file is an open file, something with a file descriptor.
+// A particular *file may appear in files multiple times, due to use of Dup or Dup2.
+type file struct {
+	fdref int      // uses in files.tab
+	impl  fileImpl // underlying implementation
+}
+
+// A fileImpl is the implementation of something that can be a file.
+type fileImpl interface {
+	// Standard operations.
+	// These can be called concurrently from multiple goroutines.
+	stat(*Stat_t) error
+	read([]byte) (int, error)
+	write([]byte) (int, error)
+	seek(int64, int) (int64, error)
+	pread([]byte, int64) (int, error)
+	pwrite([]byte, int64) (int, error)
+
+	// Close is called when the last reference to a *file is removed
+	// from the file descriptor table. It may be called concurrently
+	// with active operations such as blocked read or write calls.
+	close() error
+}
+
+// newFD adds impl to the file descriptor table,
+// returning the new file descriptor.
+// Like Unix, it uses the lowest available descriptor.
+func newFD(impl fileImpl) int {
+	files.Lock()
+	defer files.Unlock()
+	f := &file{impl: impl, fdref: 1}
+	for fd, oldf := range files.tab {
+		if oldf == nil {
+			files.tab[fd] = f
+			return fd
+		}
+	}
+	fd := len(files.tab)
+	files.tab = append(files.tab, f)
+	return fd
+}
+
+// Install Native Client stdin, stdout, stderr.
+func init() {
+	newFD(&naclFile{naclFD: 0})
+	newFD(&naclFile{naclFD: 1})
+	newFD(&naclFile{naclFD: 2})
+}
+
+// fdToFile retrieves the *file corresponding to a file descriptor.
+func fdToFile(fd int) (*file, error) {
+	files.Lock()
+	defer files.Unlock()
+	if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
+		return nil, EBADF
+	}
+	return files.tab[fd], nil
+}
+
+func Close(fd int) error {
+	files.Lock()
+	if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
+		files.Unlock()
+		return EBADF
+	}
+	f := files.tab[fd]
+	files.tab[fd] = nil
+	f.fdref--
+	fdref := f.fdref
+	files.Unlock()
+	if fdref > 0 {
+		return nil
+	}
+	return f.impl.close()
+}
+
+func CloseOnExec(fd int) {
+	// nothing to do - no exec
+}
+
+func Dup(fd int) (int, error) {
+	files.Lock()
+	defer files.Unlock()
+	if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
+		return -1, EBADF
+	}
+	f := files.tab[fd]
+	f.fdref++
+	for newfd, oldf := range files.tab {
+		if oldf == nil {
+			files.tab[newfd] = f
+			return newfd, nil
+		}
+	}
+	newfd := len(files.tab)
+	files.tab = append(files.tab, f)
+	return newfd, nil
+}
+
+func Dup2(fd, newfd int) error {
+	files.Lock()
+	defer files.Unlock()
+	if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil || newfd < 0 || newfd >= len(files.tab)+100 {
+		files.Unlock()
+		return EBADF
+	}
+	f := files.tab[fd]
+	f.fdref++
+	for cap(files.tab) <= newfd {
+		files.tab = append(files.tab[:cap(files.tab)], nil)
+	}
+	oldf := files.tab[newfd]
+	var oldfdref int
+	if oldf != nil {
+		oldf.fdref--
+		oldfdref = oldf.fdref
+	}
+	files.tab[newfd] = f
+	files.Unlock()
+	if oldf != nil {
+		if oldfdref == 0 {
+			oldf.impl.close()
+		}
+	}
+	return nil
+}
+
+func Fstat(fd int, st *Stat_t) error {
+	f, err := fdToFile(fd)
+	if err != nil {
+		return err
+	}
+	return f.impl.stat(st)
+}
+
+func Read(fd int, b []byte) (int, error) {
+	f, err := fdToFile(fd)
+	if err != nil {
+		return 0, err
+	}
+	return f.impl.read(b)
+}
+
+var zerobuf [0]byte
+
+func Write(fd int, b []byte) (int, error) {
+	if b == nil {
+		// avoid nil in syscalls; nacl doesn't like that.
+		b = zerobuf[:]
+	}
+	f, err := fdToFile(fd)
+	if err != nil {
+		return 0, err
+	}
+	return f.impl.write(b)
+}
+
+func Pread(fd int, b []byte, offset int64) (int, error) {
+	f, err := fdToFile(fd)
+	if err != nil {
+		return 0, err
+	}
+	return f.impl.pread(b, offset)
+}
+
+func Pwrite(fd int, b []byte, offset int64) (int, error) {
+	f, err := fdToFile(fd)
+	if err != nil {
+		return 0, err
+	}
+	return f.impl.pwrite(b, offset)
+}
+
+func Seek(fd int, offset int64, whence int) (int64, error) {
+	f, err := fdToFile(fd)
+	if err != nil {
+		return 0, err
+	}
+	return f.impl.seek(offset, whence)
+}
+
+// defaulFileImpl implements fileImpl.
+// It can be embedded to complete a partial fileImpl implementation.
+type defaultFileImpl struct{}
+
+func (*defaultFileImpl) close() error                      { return nil }
+func (*defaultFileImpl) stat(*Stat_t) error                { return ENOSYS }
+func (*defaultFileImpl) read([]byte) (int, error)          { return 0, ENOSYS }
+func (*defaultFileImpl) write([]byte) (int, error)         { return 0, ENOSYS }
+func (*defaultFileImpl) seek(int64, int) (int64, error)    { return 0, ENOSYS }
+func (*defaultFileImpl) pread([]byte, int64) (int, error)  { return 0, ENOSYS }
+func (*defaultFileImpl) pwrite([]byte, int64) (int, error) { return 0, ENOSYS }
+
+// naclFile is the fileImpl implementation for a Native Client file descriptor.
+type naclFile struct {
+	defaultFileImpl
+	naclFD int
+}
+
+func (f *naclFile) stat(st *Stat_t) error {
+	return naclFstat(f.naclFD, st)
+}
+
+func (f *naclFile) read(b []byte) (int, error) {
+	n, err := naclRead(f.naclFD, b)
+	if err != nil {
+		n = 0
+	}
+	return n, err
+}
+
+// implemented in package runtime, to add time header on playground
+func naclWrite(fd int, b []byte) int
+
+func (f *naclFile) write(b []byte) (int, error) {
+	n := naclWrite(f.naclFD, b)
+	if n < 0 {
+		return 0, Errno(-n)
+	}
+	return n, nil
+}
+
+func (f *naclFile) seek(off int64, whence int) (int64, error) {
+	old := off
+	err := naclSeek(f.naclFD, &off, whence)
+	if err != nil {
+		return old, err
+	}
+	return off, nil
+}
+
+func (f *naclFile) prw(b []byte, offset int64, rw func([]byte) (int, error)) (int, error) {
+	// NaCl has no pread; simulate with seek and hope for no races.
+	old, err := f.seek(0, 1)
+	if err != nil {
+		return 0, err
+	}
+	if _, err := f.seek(offset, 0); err != nil {
+		return 0, err
+	}
+	n, err := rw(b)
+	f.seek(old, 0)
+	return n, err
+}
+
+func (f *naclFile) pread(b []byte, offset int64) (int, error) {
+	return f.prw(b, offset, f.read)
+}
+
+func (f *naclFile) pwrite(b []byte, offset int64) (int, error) {
+	return f.prw(b, offset, f.write)
+}
+
+func (f *naclFile) close() error {
+	err := naclClose(f.naclFD)
+	f.naclFD = -1
+	return err
+}
+
+// A pipeFile is an in-memory implementation of a pipe.
+// The byteq implementation is in net_nacl.go.
+type pipeFile struct {
+	defaultFileImpl
+	rd *byteq
+	wr *byteq
+}
+
+func (f *pipeFile) close() error {
+	if f.rd != nil {
+		f.rd.close()
+	}
+	if f.wr != nil {
+		f.wr.close()
+	}
+	return nil
+}
+
+func (f *pipeFile) read(b []byte) (int, error) {
+	if f.rd == nil {
+		return 0, EINVAL
+	}
+	n, err := f.rd.read(b, 0)
+	if err == EAGAIN {
+		err = nil
+	}
+	return n, err
+}
+
+func (f *pipeFile) write(b []byte) (int, error) {
+	if f.wr == nil {
+		return 0, EINVAL
+	}
+	n, err := f.wr.write(b, 0)
+	if err == EAGAIN {
+		err = EPIPE
+	}
+	return n, err
+}
+
+func Pipe(fd []int) error {
+	q := newByteq()
+	fd[0] = newFD(&pipeFile{rd: q})
+	fd[1] = newFD(&pipeFile{wr: q})
+	return nil
+}
diff --git a/src/pkg/syscall/flock.go b/src/pkg/syscall/flock.go
new file mode 100644
index 0000000..62736ae
--- /dev/null
+++ b/src/pkg/syscall/flock.go
@@ -0,0 +1,22 @@
+// +build linux darwin freebsd openbsd netbsd dragonfly
+
+// 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 syscall
+
+import "unsafe"
+
+// fcntl64Syscall is usually SYS_FCNTL, but is overridden on 32-bit Linux
+// systems by flock_linux_32bit.go to be SYS_FCNTL64.
+var fcntl64Syscall uintptr = SYS_FCNTL
+
+// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
+func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
+	_, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(unsafe.Pointer(lk)))
+	if errno == 0 {
+		return nil
+	}
+	return errno
+}
diff --git a/src/pkg/syscall/flock_linux_32bit.go b/src/pkg/syscall/flock_linux_32bit.go
new file mode 100644
index 0000000..500a973
--- /dev/null
+++ b/src/pkg/syscall/flock_linux_32bit.go
@@ -0,0 +1,13 @@
+// +build linux,386 linux,arm
+
+// 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 syscall
+
+func init() {
+	// On 32-bit Linux systems, the fcntl syscall that matches Go's
+	// Flock_t type is SYS_FCNTL64, not SYS_FCNTL.
+	fcntl64Syscall = SYS_FCNTL64
+}
diff --git a/src/pkg/syscall/fs_nacl.go b/src/pkg/syscall/fs_nacl.go
new file mode 100644
index 0000000..ac92394
--- /dev/null
+++ b/src/pkg/syscall/fs_nacl.go
@@ -0,0 +1,815 @@
+// 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.
+
+// A simulated Unix-like file system for use within NaCl.
+//
+// The simulation is not particularly tied to NaCl other than the reuse
+// of NaCl's definition for the Stat_t structure.
+//
+// The file system need never be written to disk, so it is represented as
+// in-memory Go data structures, never in a serialized form.
+//
+// TODO: Perhaps support symlinks, although they muck everything up.
+
+package syscall
+
+import (
+	"sync"
+	"unsafe"
+)
+
+// Provided by package runtime.
+func now() (sec int64, nsec int32)
+
+// An fsys is a file system.
+// Since there is no I/O (everything is in memory),
+// the global lock mu protects the whole file system state,
+// and that's okay.
+type fsys struct {
+	mu   sync.Mutex
+	root *inode                    // root directory
+	cwd  *inode                    // process current directory
+	inum uint64                    // number of inodes created
+	dev  []func() (devFile, error) // table for opening devices
+}
+
+// A devFile is the implementation required of device files
+// like /dev/null or /dev/random.
+type devFile interface {
+	pread([]byte, int64) (int, error)
+	pwrite([]byte, int64) (int, error)
+}
+
+// An inode is a (possibly special) file in the file system.
+type inode struct {
+	Stat_t
+	data []byte
+	dir  []dirent
+}
+
+// A dirent describes a single directory entry.
+type dirent struct {
+	name  string
+	inode *inode
+}
+
+// An fsysFile is the fileImpl implementation backed by the file system.
+type fsysFile struct {
+	defaultFileImpl
+	fsys     *fsys
+	inode    *inode
+	openmode int
+	offset   int64
+	dev      devFile
+}
+
+// newFsys creates a new file system.
+func newFsys() *fsys {
+	fs := &fsys{}
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	ip := fs.newInode()
+	ip.Mode = 0555 | S_IFDIR
+	fs.dirlink(ip, ".", ip)
+	fs.dirlink(ip, "..", ip)
+	fs.cwd = ip
+	fs.root = ip
+	return fs
+}
+
+var fs = newFsys()
+
+func init() {
+	Mkdir("/dev", 0555)
+	Mkdir("/tmp", 0777)
+	mkdev("/dev/null", 0666, openNull)
+	mkdev("/dev/random", 0444, openRandom)
+	mkdev("/dev/urandom", 0444, openRandom)
+	mkdev("/dev/zero", 0666, openZero)
+	chdirEnv()
+}
+
+func chdirEnv() {
+	pwd, ok := Getenv("NACLPWD")
+	if ok {
+		Chdir(pwd)
+	}
+}
+
+// Except where indicated otherwise, unexported methods on fsys
+// expect fs.mu to have been locked by the caller.
+
+// newInode creates a new inode.
+func (fs *fsys) newInode() *inode {
+	fs.inum++
+	ip := &inode{
+		Stat_t: Stat_t{
+			Ino:     fs.inum,
+			Blksize: 512,
+		},
+	}
+	return ip
+}
+
+// atime sets ip.Atime to the current time.
+func (fs *fsys) atime(ip *inode) {
+	sec, nsec := now()
+	ip.Atime, ip.AtimeNsec = sec, int64(nsec)
+}
+
+// mtime sets ip.Mtime to the current time.
+func (fs *fsys) mtime(ip *inode) {
+	sec, nsec := now()
+	ip.Mtime, ip.MtimeNsec = sec, int64(nsec)
+}
+
+// dirlookup looks for an entry in the directory dp with the given name.
+// It returns the directory entry and its index within the directory.
+func (fs *fsys) dirlookup(dp *inode, name string) (de *dirent, index int, err error) {
+	fs.atime(dp)
+	for i := range dp.dir {
+		de := &dp.dir[i]
+		if de.name == name {
+			fs.atime(de.inode)
+			return de, i, nil
+		}
+	}
+	return nil, 0, ENOENT
+}
+
+// dirlink adds to the directory dp an entry for name pointing at the inode ip.
+// If dp already contains an entry for name, that entry is overwritten.
+func (fs *fsys) dirlink(dp *inode, name string, ip *inode) {
+	fs.mtime(dp)
+	fs.atime(ip)
+	ip.Nlink++
+	for i := range dp.dir {
+		if dp.dir[i].name == name {
+			dp.dir[i] = dirent{name, ip}
+			return
+		}
+	}
+	dp.dir = append(dp.dir, dirent{name, ip})
+	dp.dirSize()
+}
+
+func (dp *inode) dirSize() {
+	dp.Size = int64(len(dp.dir)) * (8 + 8 + 2 + 256) // Dirent
+}
+
+// skipelem splits path into the first element and the remainder.
+// the returned first element contains no slashes, and the returned
+// remainder does not begin with a slash.
+func skipelem(path string) (elem, rest string) {
+	for len(path) > 0 && path[0] == '/' {
+		path = path[1:]
+	}
+	if len(path) == 0 {
+		return "", ""
+	}
+	i := 0
+	for i < len(path) && path[i] != '/' {
+		i++
+	}
+	elem, path = path[:i], path[i:]
+	for len(path) > 0 && path[0] == '/' {
+		path = path[1:]
+	}
+	return elem, path
+}
+
+// namei translates a file system path name into an inode.
+// If parent is false, the returned ip corresponds to the given name, and elem is the empty string.
+// If parent is false, the walk stops at the next-to-last element in the name,
+// so that ip is the parent directory and elem is the final element in the path.
+func (fs *fsys) namei(path string, parent bool) (ip *inode, elem string, err error) {
+	// Reject NUL in name.
+	for i := 0; i < len(path); i++ {
+		if path[i] == '\x00' {
+			return nil, "", EINVAL
+		}
+	}
+
+	// Reject empty name.
+	if path == "" {
+		return nil, "", EINVAL
+	}
+
+	if path[0] == '/' {
+		ip = fs.root
+	} else {
+		ip = fs.cwd
+	}
+
+	for len(path) > 0 && path[len(path)-1] == '/' {
+		path = path[:len(path)-1]
+	}
+
+	for {
+		elem, rest := skipelem(path)
+		if elem == "" {
+			if parent && ip.Mode&S_IFMT == S_IFDIR {
+				return ip, ".", nil
+			}
+			break
+		}
+		if ip.Mode&S_IFMT != S_IFDIR {
+			return nil, "", ENOTDIR
+		}
+		if len(elem) >= 256 {
+			return nil, "", ENAMETOOLONG
+		}
+		if parent && rest == "" {
+			// Stop one level early.
+			return ip, elem, nil
+		}
+		de, _, err := fs.dirlookup(ip, elem)
+		if err != nil {
+			return nil, "", err
+		}
+		ip = de.inode
+		path = rest
+	}
+	if parent {
+		return nil, "", ENOTDIR
+	}
+	return ip, "", nil
+}
+
+// open opens or creates a file with the given name, open mode,
+// and permission mode bits.
+func (fs *fsys) open(name string, openmode int, mode uint32) (fileImpl, error) {
+	dp, elem, err := fs.namei(name, true)
+	if err != nil {
+		return nil, err
+	}
+	var (
+		ip  *inode
+		dev devFile
+	)
+	de, _, err := fs.dirlookup(dp, elem)
+	if err != nil {
+		if openmode&O_CREATE == 0 {
+			return nil, err
+		}
+		ip = fs.newInode()
+		ip.Mode = mode
+		fs.dirlink(dp, elem, ip)
+		if ip.Mode&S_IFMT == S_IFDIR {
+			fs.dirlink(ip, ".", ip)
+			fs.dirlink(ip, "..", dp)
+		}
+	} else {
+		ip = de.inode
+		if openmode&(O_CREATE|O_EXCL) == O_CREATE|O_EXCL {
+			return nil, EEXIST
+		}
+		if openmode&O_TRUNC != 0 {
+			if ip.Mode&S_IFMT == S_IFDIR {
+				return nil, EISDIR
+			}
+			ip.data = nil
+		}
+		if ip.Mode&S_IFMT == S_IFCHR {
+			if ip.Rdev < 0 || ip.Rdev >= int64(len(fs.dev)) || fs.dev[ip.Rdev] == nil {
+				return nil, ENODEV
+			}
+			dev, err = fs.dev[ip.Rdev]()
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	switch openmode & O_ACCMODE {
+	case O_WRONLY, O_RDWR:
+		if ip.Mode&S_IFMT == S_IFDIR {
+			return nil, EISDIR
+		}
+	}
+
+	switch ip.Mode & S_IFMT {
+	case S_IFDIR:
+		if openmode&O_ACCMODE != O_RDONLY {
+			return nil, EISDIR
+		}
+
+	case S_IFREG:
+		// ok
+
+	case S_IFCHR:
+		// handled above
+
+	default:
+		// TODO: some kind of special file
+		return nil, EPERM
+	}
+
+	f := &fsysFile{
+		fsys:     fs,
+		inode:    ip,
+		openmode: openmode,
+		dev:      dev,
+	}
+	if openmode&O_APPEND != 0 {
+		f.offset = ip.Size
+	}
+	return f, nil
+}
+
+// fsysFile methods to implement fileImpl.
+
+func (f *fsysFile) stat(st *Stat_t) error {
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	*st = f.inode.Stat_t
+	return nil
+}
+
+func (f *fsysFile) read(b []byte) (int, error) {
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	n, err := f.preadLocked(b, f.offset)
+	f.offset += int64(n)
+	return n, err
+}
+
+func ReadDirent(fd int, buf []byte) (int, error) {
+	f, err := fdToFsysFile(fd)
+	if err != nil {
+		return 0, err
+	}
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	if f.inode.Mode&S_IFMT != S_IFDIR {
+		return 0, EINVAL
+	}
+	n, err := f.preadLocked(buf, f.offset)
+	f.offset += int64(n)
+	return n, err
+}
+
+func (f *fsysFile) write(b []byte) (int, error) {
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	n, err := f.pwriteLocked(b, f.offset)
+	f.offset += int64(n)
+	return n, err
+}
+
+func (f *fsysFile) seek(offset int64, whence int) (int64, error) {
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	switch whence {
+	case 1:
+		offset += f.offset
+	case 2:
+		offset += f.inode.Size
+	}
+	if offset < 0 {
+		return 0, EINVAL
+	}
+	if offset > f.inode.Size {
+		return 0, EINVAL
+	}
+	f.offset = offset
+	return offset, nil
+}
+
+func (f *fsysFile) pread(b []byte, offset int64) (int, error) {
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	return f.preadLocked(b, offset)
+}
+
+func (f *fsysFile) pwrite(b []byte, offset int64) (int, error) {
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	return f.pwriteLocked(b, offset)
+}
+
+func (f *fsysFile) preadLocked(b []byte, offset int64) (int, error) {
+	if f.openmode&O_ACCMODE == O_WRONLY {
+		return 0, EINVAL
+	}
+	if offset < 0 {
+		return 0, EINVAL
+	}
+	if f.dev != nil {
+		f.fsys.atime(f.inode)
+		f.fsys.mu.Unlock()
+		defer f.fsys.mu.Lock()
+		return f.dev.pread(b, offset)
+	}
+	if offset > f.inode.Size {
+		return 0, nil
+	}
+	if int64(len(b)) > f.inode.Size-offset {
+		b = b[:f.inode.Size-offset]
+	}
+
+	if f.inode.Mode&S_IFMT == S_IFDIR {
+		if offset%direntSize != 0 || len(b) != 0 && len(b) < direntSize {
+			return 0, EINVAL
+		}
+		fs.atime(f.inode)
+		n := 0
+		for len(b) >= direntSize {
+			src := f.inode.dir[int(offset/direntSize)]
+			dst := (*Dirent)(unsafe.Pointer(&b[0]))
+			dst.Ino = int64(src.inode.Ino)
+			dst.Off = offset
+			dst.Reclen = direntSize
+			for i := range dst.Name {
+				dst.Name[i] = 0
+			}
+			copy(dst.Name[:], src.name)
+			n += direntSize
+			offset += direntSize
+			b = b[direntSize:]
+		}
+		return n, nil
+	}
+
+	fs.atime(f.inode)
+	n := copy(b, f.inode.data[offset:])
+	return n, nil
+}
+
+func (f *fsysFile) pwriteLocked(b []byte, offset int64) (int, error) {
+	if f.openmode&O_ACCMODE == O_RDONLY {
+		return 0, EINVAL
+	}
+	if offset < 0 {
+		return 0, EINVAL
+	}
+	if f.dev != nil {
+		f.fsys.atime(f.inode)
+		f.fsys.mu.Unlock()
+		defer f.fsys.mu.Lock()
+		return f.dev.pwrite(b, offset)
+	}
+	if offset > f.inode.Size {
+		return 0, EINVAL
+	}
+	f.fsys.mtime(f.inode)
+	n := copy(f.inode.data[offset:], b)
+	if n < len(b) {
+		f.inode.data = append(f.inode.data, b[n:]...)
+		f.inode.Size = int64(len(f.inode.data))
+	}
+	return len(b), nil
+}
+
+// Standard Unix system calls.
+
+func Open(path string, openmode int, perm uint32) (fd int, err error) {
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	f, err := fs.open(path, openmode, perm&0777|S_IFREG)
+	if err != nil {
+		return -1, err
+	}
+	return newFD(f), nil
+}
+
+func Mkdir(path string, perm uint32) error {
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	_, err := fs.open(path, O_CREATE|O_EXCL, perm&0777|S_IFDIR)
+	return err
+}
+
+func Getcwd(buf []byte) (n int, err error) {
+	// Force package os to default to the old algorithm using .. and directory reads.
+	return 0, ENOSYS
+}
+
+func Stat(path string, st *Stat_t) error {
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	ip, _, err := fs.namei(path, false)
+	if err != nil {
+		return err
+	}
+	*st = ip.Stat_t
+	return nil
+}
+
+func Lstat(path string, st *Stat_t) error {
+	return Stat(path, st)
+}
+
+func unlink(path string, isdir bool) error {
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	dp, elem, err := fs.namei(path, true)
+	if err != nil {
+		return err
+	}
+	if elem == "." || elem == ".." {
+		return EINVAL
+	}
+	de, _, err := fs.dirlookup(dp, elem)
+	if err != nil {
+		return err
+	}
+	if isdir {
+		if de.inode.Mode&S_IFMT != S_IFDIR {
+			return ENOTDIR
+		}
+		if len(de.inode.dir) != 2 {
+			return ENOTEMPTY
+		}
+	} else {
+		if de.inode.Mode&S_IFMT == S_IFDIR {
+			return EISDIR
+		}
+	}
+	de.inode.Nlink--
+	*de = dp.dir[len(dp.dir)-1]
+	dp.dir = dp.dir[:len(dp.dir)-1]
+	dp.dirSize()
+	return nil
+}
+
+func Unlink(path string) error {
+	return unlink(path, false)
+}
+
+func Rmdir(path string) error {
+	return unlink(path, true)
+}
+
+func Chmod(path string, mode uint32) error {
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	ip, _, err := fs.namei(path, false)
+	if err != nil {
+		return err
+	}
+	ip.Mode = ip.Mode&^0777 | mode&0777
+	return nil
+}
+
+func Fchmod(fd int, mode uint32) error {
+	f, err := fdToFsysFile(fd)
+	if err != nil {
+		return err
+	}
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	f.inode.Mode = f.inode.Mode&^0777 | mode&0777
+	return nil
+}
+
+func Chown(path string, uid, gid int) error {
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	ip, _, err := fs.namei(path, false)
+	if err != nil {
+		return err
+	}
+	ip.Uid = uint32(uid)
+	ip.Gid = uint32(gid)
+	return nil
+}
+
+func Fchown(fd int, uid, gid int) error {
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	f, err := fdToFsysFile(fd)
+	if err != nil {
+		return err
+	}
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	f.inode.Uid = uint32(uid)
+	f.inode.Gid = uint32(gid)
+	return nil
+}
+
+func Lchown(path string, uid, gid int) error {
+	return Chown(path, uid, gid)
+}
+
+func UtimesNano(path string, ts []Timespec) error {
+	if len(ts) != 2 {
+		return EINVAL
+	}
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	ip, _, err := fs.namei(path, false)
+	if err != nil {
+		return err
+	}
+	ip.Atime = ts[0].Sec
+	ip.AtimeNsec = int64(ts[0].Nsec)
+	ip.Mtime = ts[1].Sec
+	ip.MtimeNsec = int64(ts[1].Nsec)
+	return nil
+}
+
+func Link(path, link string) error {
+	ip, _, err := fs.namei(path, false)
+	if err != nil {
+		return err
+	}
+	dp, elem, err := fs.namei(link, true)
+	if err != nil {
+		return err
+	}
+	if ip.Mode&S_IFMT == S_IFDIR {
+		return EPERM
+	}
+	fs.dirlink(dp, elem, ip)
+	return nil
+}
+
+func Rename(from, to string) error {
+	fdp, felem, err := fs.namei(from, true)
+	if err != nil {
+		return err
+	}
+	fde, _, err := fs.dirlookup(fdp, felem)
+	if err != nil {
+		return err
+	}
+	tdp, telem, err := fs.namei(to, true)
+	if err != nil {
+		return err
+	}
+	fs.dirlink(tdp, telem, fde.inode)
+	fde.inode.Nlink--
+	*fde = fdp.dir[len(fdp.dir)-1]
+	fdp.dir = fdp.dir[:len(fdp.dir)-1]
+	fdp.dirSize()
+	return nil
+}
+
+func (fs *fsys) truncate(ip *inode, length int64) error {
+	if length > 1e9 || ip.Mode&S_IFMT != S_IFREG {
+		return EINVAL
+	}
+	if length < int64(len(ip.data)) {
+		ip.data = ip.data[:length]
+	} else {
+		data := make([]byte, length)
+		copy(data, ip.data)
+		ip.data = data
+	}
+	ip.Size = int64(len(ip.data))
+	return nil
+}
+
+func Truncate(path string, length int64) error {
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	ip, _, err := fs.namei(path, false)
+	if err != nil {
+		return err
+	}
+	return fs.truncate(ip, length)
+}
+
+func Ftruncate(fd int, length int64) error {
+	f, err := fdToFsysFile(fd)
+	if err != nil {
+		return err
+	}
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	return f.fsys.truncate(f.inode, length)
+}
+
+func Chdir(path string) error {
+	fs.mu.Lock()
+	defer fs.mu.Unlock()
+	ip, _, err := fs.namei(path, false)
+	if err != nil {
+		return err
+	}
+	fs.cwd = ip
+	return nil
+}
+
+func Fchdir(fd int) error {
+	f, err := fdToFsysFile(fd)
+	if err != nil {
+		return err
+	}
+	f.fsys.mu.Lock()
+	defer f.fsys.mu.Unlock()
+	if f.inode.Mode&S_IFMT != S_IFDIR {
+		return ENOTDIR
+	}
+	fs.cwd = f.inode
+	return nil
+}
+
+func Readlink(path string, buf []byte) (n int, err error) {
+	return 0, ENOSYS
+}
+
+func Symlink(path, link string) error {
+	return ENOSYS
+}
+
+func Fsync(fd int) error {
+	return nil
+}
+
+// Special devices.
+
+func mkdev(path string, mode uint32, open func() (devFile, error)) error {
+	fs.mu.Lock()
+	fs.mu.Unlock()
+	f, err := fs.open(path, O_CREATE|O_RDONLY|O_EXCL, S_IFCHR|mode)
+	if err != nil {
+		return err
+	}
+	ip := f.(*fsysFile).inode
+	ip.Rdev = int64(len(fs.dev))
+	fs.dev = append(fs.dev, open)
+	return nil
+}
+
+type nullFile struct{}
+
+func openNull() (devFile, error)                               { return &nullFile{}, nil }
+func (f *nullFile) close() error                               { return nil }
+func (f *nullFile) pread(b []byte, offset int64) (int, error)  { return 0, nil }
+func (f *nullFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil }
+
+type zeroFile struct{}
+
+func openZero() (devFile, error)                               { return &zeroFile{}, nil }
+func (f *zeroFile) close() error                               { return nil }
+func (f *zeroFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil }
+
+func (f *zeroFile) pread(b []byte, offset int64) (int, error) {
+	for i := range b {
+		b[i] = 0
+	}
+	return len(b), nil
+}
+
+type randomFile struct {
+	naclFD int
+}
+
+func openRandom() (devFile, error) {
+	fd, err := openNamedService("SecureRandom", O_RDONLY)
+	if err != nil {
+		return nil, err
+	}
+	return &randomFile{naclFD: fd}, nil
+}
+
+func (f *randomFile) close() error {
+	naclClose(f.naclFD)
+	f.naclFD = -1
+	return nil
+}
+
+func (f *randomFile) pread(b []byte, offset int64) (int, error) {
+	return naclRead(f.naclFD, b)
+}
+
+func (f *randomFile) pwrite(b []byte, offset int64) (int, error) {
+	return 0, EPERM
+}
+
+func fdToFsysFile(fd int) (*fsysFile, error) {
+	f, err := fdToFile(fd)
+	if err != nil {
+		return nil, err
+	}
+	impl := f.impl
+	fsysf, ok := impl.(*fsysFile)
+	if !ok {
+		return nil, EINVAL
+	}
+	return fsysf, nil
+}
+
+// create creates a file in the file system with the given name, mode, time, and data.
+// It is meant to be called when initializing the file system image.
+func create(name string, mode uint32, sec int64, data []byte) error {
+	fs.mu.Lock()
+	fs.mu.Unlock()
+	f, err := fs.open(name, O_CREATE|O_EXCL, mode)
+	if err != nil {
+		return err
+	}
+	ip := f.(*fsysFile).inode
+	ip.Atime = sec
+	ip.Mtime = sec
+	ip.Ctime = sec
+	if len(data) > 0 {
+		ip.Size = int64(len(data))
+		ip.data = data
+	}
+	return nil
+}
diff --git a/src/pkg/syscall/lsf_linux.go b/src/pkg/syscall/lsf_linux.go
index 05d653b..ee07fea 100644
--- a/src/pkg/syscall/lsf_linux.go
+++ b/src/pkg/syscall/lsf_linux.go
@@ -69,10 +69,10 @@ func AttachLsf(fd int, i []SockFilter) error {
 	var p SockFprog
 	p.Len = uint16(len(i))
 	p.Filter = (*SockFilter)(unsafe.Pointer(&i[0]))
-	return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, uintptr(unsafe.Pointer(&p)), unsafe.Sizeof(p))
+	return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, unsafe.Pointer(&p), unsafe.Sizeof(p))
 }
 
 func DetachLsf(fd int) error {
 	var dummy int
-	return setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, uintptr(unsafe.Pointer(&dummy)), unsafe.Sizeof(dummy))
+	return setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, unsafe.Pointer(&dummy), unsafe.Sizeof(dummy))
 }
diff --git a/src/pkg/syscall/mkall.sh b/src/pkg/syscall/mkall.sh
index a3139d6..886db13 100755
--- a/src/pkg/syscall/mkall.sh
+++ b/src/pkg/syscall/mkall.sh
@@ -81,6 +81,8 @@ mkerrors="./mkerrors.sh"
 zerrors="zerrors_$GOOSARCH.go"
 mksysctl=""
 zsysctl="zsysctl_$GOOSARCH.go"
+mksysnum=
+mktypes=
 run="sh"
 
 case "$1" in
@@ -136,19 +138,21 @@ dragonfly_amd64)
 freebsd_386)
 	mkerrors="$mkerrors -m32"
 	mksyscall="./mksyscall.pl -l32"
-	mksysnum="curl -s 'http://svn.freebsd.org/base/head/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
+	mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
 freebsd_amd64)
 	mkerrors="$mkerrors -m64"
-	mksysnum="curl -s 'http://svn.freebsd.org/base/head/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
+	mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
 freebsd_arm)
 	mkerrors="$mkerrors"
 	mksyscall="./mksyscall.pl -l32 -arm"
-	mksysnum="curl -s 'http://svn.freebsd.org/base/head/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
-	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+	mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
+	# Let the type of C char be singed for making the bare syscall
+	# API consistent across over platforms.
+	mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
 	;;
 linux_386)
 	mkerrors="$mkerrors -m32"
@@ -172,6 +176,18 @@ linux_arm)
 	mksysnum="curl -s 'http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/arch/arm/include/uapi/asm/unistd.h' | ./mksysnum_linux.pl"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
+nacl_386)
+	mkerrors=""
+	mksyscall="./mksyscall.pl -l32 -nacl"
+	mksysnum=""
+	mktypes=""
+	;;
+nacl_amd64p32)
+	mkerrors=""
+	mksyscall="./mksyscall.pl -nacl"
+	mksysnum=""
+	mktypes=""
+	;;
 netbsd_386)
 	mkerrors="$mkerrors -m32"
 	mksyscall="./mksyscall.pl -l32 -netbsd"
@@ -206,19 +222,16 @@ plan9_386)
 	mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h"
 	mktypes="XXX"
 	;;
-windows_386)
-	mksyscall="./mksyscall_windows.pl -l32"
+solaris_amd64)
+	mksyscall="./mksyscall_solaris.pl"
+	mkerrors="$mkerrors -m64"
 	mksysnum=
-	mktypes=
-	mkerrors="./mkerrors_windows.sh -m32"
-	zerrors="zerrors_windows.go"
+	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
-windows_amd64)
-	mksyscall="./mksyscall_windows.pl"
-	mksysnum=
-	mktypes=
-	mkerrors="./mkerrors_windows.sh -m32"
-	zerrors="zerrors_windows.go"
+windows_*)
+	mksyscall=
+	mkerrors=
+	zerrors=
 	;;
 *)
 	echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
@@ -228,17 +241,23 @@ esac
 
 (
 	if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi
-	syscall_goos="syscall_$GOOS.go"
 	case "$GOOS" in
-	darwin | dragonfly | freebsd | netbsd | openbsd)
-		syscall_goos="syscall_bsd.go $syscall_goos"
-		;;
 	windows)
-		syscall_goos="$syscall_goos security_windows.go"
+		echo "GOOS= GOARCH= go build mksyscall_windows.go"
+		echo "./mksyscall_windows syscall_windows.go security_windows.go syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"
+		echo "rm -f ./mksyscall_windows"
+		;;
+	*)
+		syscall_goos="syscall_$GOOS.go"
+		case "$GOOS" in
+		darwin | dragonfly | freebsd | netbsd | openbsd)
+			syscall_goos="syscall_bsd.go $syscall_goos"
+			;;
+		esac
+		if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"; fi
 		;;
 	esac
 	if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
-	if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"; fi
 	if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
 	if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go |gofmt >ztypes_$GOOSARCH.go"; fi
 ) | $run
diff --git a/src/pkg/syscall/mkall_windows.bat b/src/pkg/syscall/mkall_windows.bat
new file mode 100644
index 0000000..a4a3f16
--- /dev/null
+++ b/src/pkg/syscall/mkall_windows.bat
@@ -0,0 +1,21 @@
+:: 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.
+ at echo off
+
+if exist mkall.sh goto dirok
+echo mkall_windows.bat must be run from src\pkg\syscall directory
+goto :end
+:dirok
+
+if "%1"=="386" goto :paramok
+if "%1"=="amd64" goto :paramok
+echo parameters must be 386 or amd64
+goto :end
+:paramok
+
+go build mksyscall_windows.go
+.\mksyscall_windows syscall_windows.go security_windows.go syscall_windows_%1.go |gofmt >zsyscall_windows_%1.go
+del mksyscall_windows.exe
+
+:end
\ No newline at end of file
diff --git a/src/pkg/syscall/mkerrors.sh b/src/pkg/syscall/mkerrors.sh
index 20b2b98..cf0afe0 100755
--- a/src/pkg/syscall/mkerrors.sh
+++ b/src/pkg/syscall/mkerrors.sh
@@ -11,7 +11,7 @@ unset LANG
 export LC_ALL=C
 export LC_CTYPE=C
 
-GCC=gcc
+CC=${CC:-gcc}
 
 uname=$(uname)
 
@@ -57,6 +57,7 @@ includes_DragonFly='
 '
 
 includes_FreeBSD='
+#include <sys/param.h>
 #include <sys/types.h>
 #include <sys/event.h>
 #include <sys/socket.h>
@@ -73,6 +74,14 @@ includes_FreeBSD='
 #include <termios.h>
 #include <netinet/ip.h>
 #include <netinet/ip_mroute.h>
+
+#if __FreeBSD__ >= 10
+#define IFT_CARP	0xf8	// IFT_CARP is deprecated in FreeBSD 10
+#undef SIOCAIFADDR
+#define SIOCAIFADDR	_IOW(105, 26, struct oifaliasreq)	// ifaliasreq contains if_data
+#undef SIOCSIFPHYADDR
+#define SIOCSIFPHYADDR	_IOW(105, 70, struct oifaliasreq)	// ifaliasreq contains if_data
+#endif
 '
 
 includes_Linux='
@@ -92,9 +101,12 @@ includes_Linux='
 #include <sys/types.h>
 #include <sys/time.h>
 #include <sys/socket.h>
-#include <linux/if_addr.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/if_tun.h>
+#include <linux/if_packet.h>
+#include <linux/if_addr.h>
 #include <linux/filter.h>
 #include <linux/netlink.h>
 #include <linux/reboot.h>
@@ -103,10 +115,7 @@ includes_Linux='
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/icmpv6.h>
-#include <net/if.h>
-#include <net/if_arp.h>
 #include <net/route.h>
-#include <netpacket/packet.h>
 #include <termios.h>
 
 #ifndef MSG_FASTOPEN
@@ -118,6 +127,7 @@ includes_NetBSD='
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/event.h>
+#include <sys/mman.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
 #include <sys/sysctl.h>
@@ -142,6 +152,7 @@ includes_OpenBSD='
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/event.h>
+#include <sys/mman.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
 #include <sys/sysctl.h>
@@ -151,6 +162,7 @@ includes_OpenBSD='
 #include <net/bpf.h>
 #include <net/if.h>
 #include <net/if_types.h>
+#include <net/if_var.h>
 #include <net/route.h>
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
@@ -158,6 +170,36 @@ includes_OpenBSD='
 #include <netinet/ip_mroute.h>
 #include <netinet/if_ether.h>
 #include <net/if_bridge.h>
+
+// We keep some constants not supported in OpenBSD 5.5 and beyond for
+// the promise of compatibility.
+#define EMUL_ENABLED		0x1
+#define EMUL_NATIVE		0x2
+#define IPV6_FAITH		0x1d
+#define IPV6_OPTIONS		0x1
+#define IPV6_RTHDR_STRICT	0x1
+#define IPV6_SOCKOPT_RESERVED1	0x3
+#define SIOCGIFGENERIC		0xc020693a
+#define SIOCSIFGENERIC		0x80206939
+#define WALTSIG			0x4
+'
+
+includes_SunOS='
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_types.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <termios.h>
+#include <netinet/ip.h>
+#include <netinet/ip_mroute.h>
 '
 
 includes='
@@ -192,7 +234,7 @@ ccflags="$@"
 
 	# The gcc command line prints all the #defines
 	# it encounters while processing the input
-	echo "${!indirect} $includes" | $GCC -x c - -E -dM $ccflags |
+	echo "${!indirect} $includes" | $CC -x c - -E -dM $ccflags |
 	awk '
 		$1 != "#define" || $2 ~ /\(/ || $3 == "" {next}
 
@@ -240,6 +282,7 @@ ccflags="$@"
 		$2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P)_/ ||
 		$2 ~ /^SIOC/ ||
 		$2 ~ /^TIOC/ ||
+		$2 !~ "RTF_BITS" &&
 		$2 ~ /^(IFF|IFT|NET_RT|RTM|RTF|RTV|RTA|RTAX)_/ ||
 		$2 ~ /^BIOC/ ||
 		$2 ~ /^RUSAGE_(SELF|CHILDREN|THREAD)/ ||
@@ -261,24 +304,24 @@ ccflags="$@"
 
 # Pull out the error names for later.
 errors=$(
-	echo '#include <errno.h>' | $GCC -x c - -E -dM $ccflags |
+	echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
 	awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print $2 }' |
 	sort
 )
 
 # Pull out the signal names for later.
 signals=$(
-	echo '#include <signal.h>' | $GCC -x c - -E -dM $ccflags |
+	echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
 	awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' |
 	egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' |
 	sort
 )
 
 # Again, writing regexps to a file.
-echo '#include <errno.h>' | $GCC -x c - -E -dM $ccflags |
+echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
 	awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print "^\t" $2 "[ \t]*=" }' |
 	sort >_error.grep
-echo '#include <signal.h>' | $GCC -x c - -E -dM $ccflags |
+echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
 	awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' |
 	egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' |
 	sort >_signal.grep
@@ -302,8 +345,9 @@ echo ')'
 
 # Run C program to print error and syscall strings.
 (
-	/bin/echo "
+	echo -E "
 #include <stdio.h>
+#include <stdlib.h>
 #include <errno.h>
 #include <ctype.h>
 #include <string.h>
@@ -317,22 +361,21 @@ int errors[] = {
 "
 	for i in $errors
 	do
-		/bin/echo '	'$i,
+		echo -E '	'$i,
 	done
 
-	/bin/echo "
+	echo -E "
 };
 
 int signals[] = {
 "
 	for i in $signals
 	do
-		/bin/echo '	'$i,
+		echo -E '	'$i,
 	done
 
-	# Use /bin/echo to avoid builtin echo,
-	# which interprets \n itself
-	/bin/echo '
+	# Use -E because on some systems bash builtin interprets \n itself.
+	echo -E '
 };
 
 static int
@@ -387,4 +430,4 @@ main(void)
 '
 ) >_errors.c
 
-$GCC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.go _error.grep _signal.grep _error.out
+$CC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.go _error.grep _signal.grep _error.out
diff --git a/src/pkg/syscall/mkerrors_windows.sh b/src/pkg/syscall/mkerrors_windows.sh
deleted file mode 100755
index 13badcd..0000000
--- a/src/pkg/syscall/mkerrors_windows.sh
+++ /dev/null
@@ -1,202 +0,0 @@
-#!/usr/bin/env bash
-# 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.
-
-# Generate Go code listing errors and other #defined constant
-# values (ENAMETOOLONG etc.), by asking the preprocessor
-# about the definitions.
-
-unset LANG
-export LC_ALL=C
-export LC_CTYPE=C
-
-case "$GOARCH" in
-arm)
-	GCC=arm-gcc
-	;;
-*)
-	GCC=gcc
-	;;
-esac
-
-uname=$(uname)
-
-includes_Linux='
-#define _LARGEFILE_SOURCE
-#define _LARGEFILE64_SOURCE
-#define _FILE_OFFSET_BITS 64
-#define _GNU_SOURCE
-
-#include <sys/types.h>
-#include <sys/epoll.h>
-#include <linux/ptrace.h>
-#include <linux/wait.h>
-'
-
-includes_Darwin='
-#define __DARWIN_UNIX03 0
-#define KERNEL
-#define _DARWIN_USE_64_BIT_INODE
-#include <sys/wait.h>
-#include <sys/event.h>
-'
-
-includes_FreeBSD='
-#include <sys/wait.h>
-#include <sys/event.h>
-'
-
-includes='
-#include <sys/types.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/ip6.h>
-#include <netinet/tcp.h>
-#include <errno.h>
-#include <sys/signal.h>
-#include <signal.h>
-'
-
-ccflags=""
-next=false
-for i
-do
-	if $next; then
-		ccflags="$ccflags $i"
-		next=false
-	elif [ "$i" = "-f" ]; then
-		next=true
-	fi
-done
-
-# These are go errors that will be mapped directly to windows errors
-goerrors='
-ENOENT:ERROR_FILE_NOT_FOUND
-ENOTDIR:ERROR_PATH_NOT_FOUND
-'
-
-# Pull out just the error names for later.
-i=$(
-	for j in "$goerrors"
-	do
-		echo "$j"
-	done |
-	awk -F: '
-		{ if (NR > 1) printf("|") }
-		{ printf("%s", $1) }
-	'
-)
-errors=$(
-	echo '#include <errno.h>' | $GCC -x c - -E -dM $ccflags |
-	awk '
-		$1 != "#define" || $2 ~ /\(/ {next}
-		$2 ~ /^('$i')$/ {next}
-		$2 ~ /^E[A-Z0-9_]+$/ { print $2 }
-		{next}
-	' | sort
-)
-
-echo '// mkerrors_windows.sh' "$@"
-echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT'
-echo
-echo 'package syscall'
-
-# Run C program to print error strings.
-(
-	/bin/echo "
-#include <stdio.h>
-#include <errno.h>
-#include <ctype.h>
-#include <string.h>
-
-#define nelem(x) (sizeof(x)/sizeof((x)[0]))
-
-enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below
-
-struct {
-	char *goname;
-	char *winname;
-} goerrors[] = {
-"
-	for i in $goerrors
-	do
-		j=`echo $i | cut -d: -f1`
-		k=`echo $i | cut -d: -f2`
-		echo '	{"'$j'", "'$k'"},'
-	done
-
-	# Use /bin/echo to avoid builtin echo,
-	# which interprets \n itself
-	/bin/echo '
-};
-
-struct {
-	char *name;
-	int value;
-} errors[] = {
-'
-	for i in $errors
-	do
-		echo '	{"'$i'",' $i'},'
-	done
-
-	# Use /bin/echo to avoid builtin echo,
-	# which interprets \n itself
-	/bin/echo '
-};
-
-int
-main(void)
-{
-	int i, e, iota = 1;
-	char buf[1024];
-
-	printf("\n// Go names for Windows errors.\n");
-	printf("const (\n");
-	for(i=0; i<nelem(goerrors); i++) {
-		printf("\t%s Errno = %s\n", goerrors[i].goname, goerrors[i].winname);
-			
-	}
-	printf(")\n");
-
-	printf("\n// Windows reserves errors >= 1<<29 for application use.\n");
-	printf("const APPLICATION_ERROR = 1 << 29\n");
-
-	printf("\n// Invented values to support what package os and others expects.\n");
-	printf("const (\n");
-	for(i=0; i<nelem(errors); i++) {
-		printf("\t%s", errors[i].name);
-		if(iota) {
-			printf(" Errno = APPLICATION_ERROR + iota");
-			iota = !iota;
-		}
-		printf("\n");
-			
-	}
-	printf("\tEWINDOWS\n");
-	printf(")\n");
-
-	printf("\n// Error strings for invented errors\n");
-	printf("var errors = [...]string {\n");
-	for(i=0; i<nelem(errors); i++) {
-		e = errors[i].value;
-		strcpy(buf, strerror(e));
-		// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
-		if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
-			buf[0] += a - A;
-		printf("\t%s - APPLICATION_ERROR: \"%s\",\n", errors[i].name, buf);
-	next:;
-	}
-	printf("\tEWINDOWS - APPLICATION_ERROR: \"not supported by windows\",\n");
-	printf("}\n\n");
-	return 0;
-}
-
-'
-) >_errors.c
-
-$GCC $ccflags -static -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors
diff --git a/src/pkg/syscall/mksyscall.pl b/src/pkg/syscall/mksyscall.pl
index b4ece9a..6d35fa6 100755
--- a/src/pkg/syscall/mksyscall.pl
+++ b/src/pkg/syscall/mksyscall.pl
@@ -28,6 +28,7 @@ my $plan9 = 0;
 my $openbsd = 0;
 my $netbsd = 0;
 my $dragonfly = 0;
+my $nacl = 0;
 my $arm = 0; # 64-bit value should use (even, odd)-pair
 
 if($ARGV[0] eq "-b32") {
@@ -53,6 +54,10 @@ if($ARGV[0] eq "-dragonfly") {
 	$dragonfly = 1;
 	shift;
 }
+if($ARGV[0] eq "-nacl") {
+	$nacl = 1;
+	shift;
+}
 if($ARGV[0] eq "-arm") {
 	$arm = 1;
 	shift;
@@ -95,7 +100,7 @@ while(<>) {
 	# Line must be of the form
 	#	func Open(path string, mode int, perm int) (fd int, errno error)
 	# Split into name, in params, out params.
-	if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(SYS_[A-Z0-9_]+))?$/) {
+	if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)SYS_[A-Z0-9_]+))?$/) {
 		print STDERR "$ARGV:$.: malformed //sys declaration\n";
 		$errors = 1;
 		next;
@@ -219,6 +224,9 @@ while(<>) {
 		$sysname = "SYS_$func";
 		$sysname =~ s/([a-z])([A-Z])/${1}_$2/g;	# turn FooBar into Foo_Bar
 		$sysname =~ y/a-z/A-Z/;
+		if($nacl) {
+			$sysname =~ y/A-Z/a-z/;
+		}
 	}
 
 	# Actual call.
diff --git a/src/pkg/syscall/mksyscall_solaris.pl b/src/pkg/syscall/mksyscall_solaris.pl
new file mode 100755
index 0000000..130d043
--- /dev/null
+++ b/src/pkg/syscall/mksyscall_solaris.pl
@@ -0,0 +1,279 @@
+#!/usr/bin/env perl
+# 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.
+
+# This program reads a file containing function prototypes
+# (like syscall_solaris.go) and generates system call bodies.
+# The prototypes are marked by lines beginning with "//sys"
+# and read like func declarations if //sys is replaced by func, but:
+#	* The parameter lists must give a name for each argument.
+#	  This includes return parameters.
+#	* The parameter lists must give a type for each argument:
+#	  the (x, y, z int) shorthand is not allowed.
+#	* If the return parameter is an error number, it must be named err.
+#	* If go func name needs to be different than its libc name, 
+#	* or the function is not in libc, name could be specified
+#	* at the end, after "=" sign, like
+#	  //sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt
+
+use strict;
+
+my $cmdline = "mksyscall_solaris.pl " . join(' ', @ARGV);
+my $errors = 0;
+my $_32bit = "";
+
+binmode STDOUT;
+
+if($ARGV[0] eq "-b32") {
+	$_32bit = "big-endian";
+	shift;
+} elsif($ARGV[0] eq "-l32") {
+	$_32bit = "little-endian";
+	shift;
+}
+
+if($ARGV[0] =~ /^-/) {
+	print STDERR "usage: mksyscall_solaris.pl [-b32 | -l32] [file ...]\n";
+	exit 1;
+}
+
+sub parseparamlist($) {
+	my ($list) = @_;
+	$list =~ s/^\s*//;
+	$list =~ s/\s*$//;
+	if($list eq "") {
+		return ();
+	}
+	return split(/\s*,\s*/, $list);
+}
+
+sub parseparam($) {
+	my ($p) = @_;
+	if($p !~ /^(\S*) (\S*)$/) {
+		print STDERR "$ARGV:$.: malformed parameter: $p\n";
+		$errors = 1;
+		return ("xx", "int");
+	}
+	return ($1, $2);
+}
+
+my $package = "";
+my $text = "";
+my $vars = "";
+my $mods = "";
+my $modnames = "";
+while(<>) {
+	chomp;
+	s/\s+/ /g;
+	s/^\s+//;
+	s/\s+$//;
+	$package = $1 if !$package && /^package (\S+)$/;
+	my $nonblock = /^\/\/sysnb /;
+	next if !/^\/\/sys / && !$nonblock;
+
+	my $syscalldot = "";
+	$syscalldot = "syscall." if $package ne "syscall";
+
+	# Line must be of the form
+	#	func Open(path string, mode int, perm int) (fd int, err error)
+	# Split into name, in params, out params.
+	if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) {
+		print STDERR "$ARGV:$.: malformed //sys declaration\n";
+		$errors = 1;
+		next;
+	}
+	my ($nb, $func, $in, $out, $modname, $sysname) = ($1, $2, $3, $4, $5, $6);
+
+	# Split argument lists on comma.
+	my @in = parseparamlist($in);
+	my @out = parseparamlist($out);
+
+	# So file name.
+	if($modname eq "") {
+		$modname = "libc";
+	}
+	my $modvname = "mod$modname";
+	if($modnames !~ /$modname/) {
+		$modnames .= ".$modname";
+		$mods .= "\t$modvname = ${syscalldot}newLazySO(\"$modname.so\")\n";
+	}
+
+	# System call name.
+	if($sysname eq "") {
+		$sysname = "$func";
+	}
+
+	# System call pointer variable name.
+	my $sysvarname = "proc$sysname";
+
+	my $strconvfunc = "BytePtrFromString";
+	my $strconvtype = "*byte";
+
+	# Library proc address variable.
+	$sysname =~ y/A-Z/a-z/; # All libc functions are lowercase.
+	$vars .= "\t$sysvarname = $modvname.NewProc(\"$sysname\")\n";
+
+	# Go function header.
+	$out = join(', ', @out);
+	if($out ne "") {
+		$out = " ($out)";
+	}
+	if($text ne "") {
+		$text .= "\n"
+	}
+	$text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out;
+
+	# Check if err return available
+	my $errvar = "";
+	foreach my $p (@out) {
+		my ($name, $type) = parseparam($p);
+		if($type eq "error") {
+			$errvar = $name;
+			last;
+		}
+	}
+
+	# Prepare arguments to Syscall.
+	my @args = ();
+	my $n = 0;
+	my @pin= ();
+	foreach my $p (@in) {
+		my ($name, $type) = parseparam($p);
+		if($type =~ /^\*/) {
+			push @args, "uintptr(unsafe.Pointer($name))";
+		} elsif($type eq "string" && $errvar ne "") {
+			$text .= "\tvar _p$n $strconvtype\n";
+			$text .= "\t_p$n, $errvar = $strconvfunc($name)\n";
+			$text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n";
+			push @args, "uintptr(unsafe.Pointer(_p$n))";
+			$n++;
+		} elsif($type eq "string") {
+			print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n";
+			$text .= "\tvar _p$n $strconvtype\n";
+			$text .= "\t_p$n, _ = $strconvfunc($name)\n";
+			push @args, "uintptr(unsafe.Pointer(_p$n))";
+			$n++;
+		} elsif($type =~ /^\[\](.*)/) {
+			# Convert slice into pointer, length.
+			# Have to be careful not to take address of &a[0] if len == 0:
+			# pass nil in that case.
+			$text .= "\tvar _p$n *$1\n";
+			$text .= "\tif len($name) > 0 {\n\t\t_p$n = \&$name\[0]\n\t}\n";
+			push @args, "uintptr(unsafe.Pointer(_p$n))", "uintptr(len($name))";
+			$n++;
+		} elsif($type eq "int64" && $_32bit ne "") {
+			if($_32bit eq "big-endian") {
+				push @args, "uintptr($name >> 32)", "uintptr($name)";
+			} else {
+				push @args, "uintptr($name)", "uintptr($name >> 32)";
+			}
+		} elsif($type eq "bool") {
+ 			$text .= "\tvar _p$n uint32\n";
+			$text .= "\tif $name {\n\t\t_p$n = 1\n\t} else {\n\t\t_p$n = 0\n\t}\n";
+			push @args, "uintptr(_p$n)";
+			$n++;
+		} else {
+			push @args, "uintptr($name)";
+		}
+		push @pin, sprintf "\"%s=\", %s, ", $name, $name;
+	}
+	my $nargs = @args;
+
+	# Determine which form to use; pad args with zeros.
+	my $asm = "${syscalldot}sysvicall6";
+	if ($nonblock) {
+		$asm = "${syscalldot}rawSysvicall6";
+	}
+	if(@args <= 6) {
+		while(@args < 6) {
+			push @args, "0";
+		}
+	} else {
+		print STDERR "$ARGV:$.: too many arguments to system call\n";
+	}
+
+	# Actual call.
+	my $args = join(', ', @args);
+	my $call = "$asm($sysvarname.Addr(), $nargs, $args)";
+
+	# Assign return values.
+	my $body = "";
+	my $failexpr = "";
+	my @ret = ("_", "_", "_");
+	my @pout= ();
+	my $do_errno = 0;
+	for(my $i=0; $i<@out; $i++) {
+		my $p = $out[$i];
+		my ($name, $type) = parseparam($p);
+		my $reg = "";
+		if($name eq "err") {
+			$reg = "e1";
+			$ret[2] = $reg;
+			$do_errno = 1;
+		} else {
+			$reg = sprintf("r%d", $i);
+			$ret[$i] = $reg;
+		}
+		if($type eq "bool") {
+			$reg = "$reg != 0";
+		}
+		if($type eq "int64" && $_32bit ne "") {
+			# 64-bit number in r1:r0 or r0:r1.
+			if($i+2 > @out) {
+				print STDERR "$ARGV:$.: not enough registers for int64 return\n";
+			}
+			if($_32bit eq "big-endian") {
+				$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1);
+			} else {
+				$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i);
+			}
+			$ret[$i] = sprintf("r%d", $i);
+			$ret[$i+1] = sprintf("r%d", $i+1);
+		}
+		if($reg ne "e1") {
+			$body .= "\t$name = $type($reg)\n";
+		}
+	}
+	if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") {
+		$text .= "\t$call\n";
+	} else {
+		$text .= "\t$ret[0], $ret[1], $ret[2] := $call\n";
+	}
+	$text .= $body;
+
+	if ($do_errno) {
+		$text .= "\tif e1 != 0 {\n";
+		$text .= "\t\terr = e1\n";
+		$text .= "\t}\n";
+	}
+	$text .= "\treturn\n";
+	$text .= "}\n";
+}
+
+if($errors) {
+	exit 1;
+}
+
+print <<EOF;
+// $cmdline
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package $package
+
+import "unsafe"
+EOF
+
+print "import \"syscall\"\n" if $package ne "syscall";
+
+print <<EOF;
+
+var (
+$mods
+$vars
+)
+
+$text
+
+EOF
+exit 0;
diff --git a/src/pkg/syscall/mksyscall_windows.go b/src/pkg/syscall/mksyscall_windows.go
new file mode 100644
index 0000000..4225588
--- /dev/null
+++ b/src/pkg/syscall/mksyscall_windows.go
@@ -0,0 +1,662 @@
+// 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
+
+/*
+mksyscall_windows generates windows system call bodies
+
+It parses all files specified on command line containing function
+prototypes (like syscall_windows.go) and prints system call bodies
+to standard output.
+
+The prototypes are marked by lines beginning with "//sys" and read
+like func declarations if //sys is replaced by func, but:
+
+* The parameter lists must give a name for each argument. This
+  includes return parameters.
+
+* The parameter lists must give a type for each argument:
+  the (x, y, z int) shorthand is not allowed.
+
+* If the return parameter is an error number, it must be named err.
+
+* If go func name needs to be different from it's winapi dll name,
+  the winapi name could be specified at the end, after "=" sign, like
+  //sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
+
+* Each function that returns err needs to supply a condition, that
+  return value of winapi will be tested against to detect failure.
+  This would set err to windows "last-error", otherwise it will be nil.
+  The value can be provided at end of //sys declaration, like
+  //sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
+  and is [failretval==0] by default.
+
+Usage:
+	mksyscall_windows [flags] [path ...]
+
+The flags are:
+	-trace
+		Generate print statement after every syscall.
+*/
+package main
+
+import (
+	"bufio"
+	"errors"
+	"flag"
+	"fmt"
+	"io"
+	"log"
+	"os"
+	"strconv"
+	"strings"
+	"text/template"
+)
+
+var PrintTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
+
+func trim(s string) string {
+	return strings.Trim(s, " \t")
+}
+
+// Param is function parameter
+type Param struct {
+	Name      string
+	Type      string
+	fn        *Fn
+	tmpVarIdx int
+}
+
+// tmpVar returns temp variable name that will be used to represent p during syscall.
+func (p *Param) tmpVar() string {
+	if p.tmpVarIdx < 0 {
+		p.tmpVarIdx = p.fn.curTmpVarIdx
+		p.fn.curTmpVarIdx++
+	}
+	return fmt.Sprintf("_p%d", p.tmpVarIdx)
+}
+
+// BoolTmpVarCode returns source code for bool temp variable.
+func (p *Param) BoolTmpVarCode() string {
+	const code = `var %s uint32
+	if %s {
+		%s = 1
+	} else {
+		%s = 0
+	}`
+	tmp := p.tmpVar()
+	return fmt.Sprintf(code, tmp, p.Name, tmp, tmp)
+}
+
+// SliceTmpVarCode returns source code for slice temp variable.
+func (p *Param) SliceTmpVarCode() string {
+	const code = `var %s *%s
+	if len(%s) > 0 {
+		%s = &%s[0]
+	}`
+	tmp := p.tmpVar()
+	return fmt.Sprintf(code, tmp, p.Type[2:], p.Name, tmp, p.Name)
+}
+
+// StringTmpVarCode returns source code for string temp variable.
+func (p *Param) StringTmpVarCode() string {
+	errvar := p.fn.Rets.ErrorVarName()
+	if errvar == "" {
+		errvar = "_"
+	}
+	tmp := p.tmpVar()
+	const code = `var %s %s
+	%s, %s = %s(%s)`
+	s := fmt.Sprintf(code, tmp, p.fn.StrconvType(), tmp, errvar, p.fn.StrconvFunc(), p.Name)
+	if errvar == "-" {
+		return s
+	}
+	const morecode = `
+	if %s != nil {
+		return
+	}`
+	return s + fmt.Sprintf(morecode, errvar)
+}
+
+// TmpVarCode returns source code for temp variable.
+func (p *Param) TmpVarCode() string {
+	switch {
+	case p.Type == "string":
+		return p.StringTmpVarCode()
+	case p.Type == "bool":
+		return p.BoolTmpVarCode()
+	case strings.HasPrefix(p.Type, "[]"):
+		return p.SliceTmpVarCode()
+	default:
+		return ""
+	}
+}
+
+// SyscallArgList returns source code fragments representing p parameter
+// in syscall. Slices are translated into 2 syscall parameters: pointer to
+// the first element and length.
+func (p *Param) SyscallArgList() []string {
+	var s string
+	switch {
+	case p.Type[0] == '*':
+		s = fmt.Sprintf("unsafe.Pointer(%s)", p.Name)
+	case p.Type == "string":
+		s = fmt.Sprintf("unsafe.Pointer(%s)", p.tmpVar())
+	case p.Type == "bool":
+		s = p.tmpVar()
+	case strings.HasPrefix(p.Type, "[]"):
+		return []string{
+			fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.tmpVar()),
+			fmt.Sprintf("uintptr(len(%s))", p.Name),
+		}
+	default:
+		s = p.Name
+	}
+	return []string{fmt.Sprintf("uintptr(%s)", s)}
+}
+
+// IsError determines if p parameter is used to return error.
+func (p *Param) IsError() bool {
+	return p.Name == "err" && p.Type == "error"
+}
+
+// join concatenates parameters ps into a string with sep separator.
+// Each parameter is converted into string by applying fn to it
+// before conversion.
+func join(ps []*Param, fn func(*Param) string, sep string) string {
+	if len(ps) == 0 {
+		return ""
+	}
+	a := make([]string, 0)
+	for _, p := range ps {
+		a = append(a, fn(p))
+	}
+	return strings.Join(a, sep)
+}
+
+// Rets describes function return parameters.
+type Rets struct {
+	Name         string
+	Type         string
+	ReturnsError bool
+	FailCond     string
+}
+
+// ErrorVarName returns error variable name for r.
+func (r *Rets) ErrorVarName() string {
+	if r.ReturnsError {
+		return "err"
+	}
+	if r.Type == "error" {
+		return r.Name
+	}
+	return ""
+}
+
+// ToParams converts r into slice of *Param.
+func (r *Rets) ToParams() []*Param {
+	ps := make([]*Param, 0)
+	if len(r.Name) > 0 {
+		ps = append(ps, &Param{Name: r.Name, Type: r.Type})
+	}
+	if r.ReturnsError {
+		ps = append(ps, &Param{Name: "err", Type: "error"})
+	}
+	return ps
+}
+
+// List returns source code of syscall return parameters.
+func (r *Rets) List() string {
+	s := join(r.ToParams(), func(p *Param) string { return p.Name + " " + p.Type }, ", ")
+	if len(s) > 0 {
+		s = "(" + s + ")"
+	}
+	return s
+}
+
+// PrintList returns source code of trace printing part correspondent
+// to syscall return values.
+func (r *Rets) PrintList() string {
+	return join(r.ToParams(), func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
+}
+
+// SetReturnValuesCode returns source code that accepts syscall return values.
+func (r *Rets) SetReturnValuesCode() string {
+	if r.Name == "" && !r.ReturnsError {
+		return ""
+	}
+	retvar := "r0"
+	if r.Name == "" {
+		retvar = "r1"
+	}
+	errvar := "_"
+	if r.ReturnsError {
+		errvar = "e1"
+	}
+	return fmt.Sprintf("%s, _, %s := ", retvar, errvar)
+}
+
+func (r *Rets) useLongHandleErrorCode(retvar string) string {
+	const code = `if %s {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = EINVAL
+		}
+	}`
+	cond := retvar + " == 0"
+	if r.FailCond != "" {
+		cond = strings.Replace(r.FailCond, "failretval", retvar, 1)
+	}
+	return fmt.Sprintf(code, cond)
+}
+
+// SetErrorCode returns source code that sets return parameters.
+func (r *Rets) SetErrorCode() string {
+	const code = `if r0 != 0 {
+		%s = Errno(r0)
+	}`
+	if r.Name == "" && !r.ReturnsError {
+		return ""
+	}
+	if r.Name == "" {
+		return r.useLongHandleErrorCode("r1")
+	}
+	if r.Type == "error" {
+		return fmt.Sprintf(code, r.Name)
+	}
+	s := ""
+	if r.Type[0] == '*' {
+		s = fmt.Sprintf("%s = (%s)(unsafe.Pointer(r0))", r.Name, r.Type)
+	} else {
+		s = fmt.Sprintf("%s = %s(r0)", r.Name, r.Type)
+	}
+	if !r.ReturnsError {
+		return s
+	}
+	return s + "\n\t" + r.useLongHandleErrorCode(r.Name)
+}
+
+// Fn describes syscall function.
+type Fn struct {
+	Name        string
+	Params      []*Param
+	Rets        *Rets
+	PrintTrace  bool
+	dllname     string
+	dllfuncname string
+	src         string
+	// TODO: get rid of this field and just use parameter index instead
+	curTmpVarIdx int // insure tmp variables have uniq names
+}
+
+// extractParams parses s to extract function parameters.
+func extractParams(s string, f *Fn) ([]*Param, error) {
+	s = trim(s)
+	if s == "" {
+		return nil, nil
+	}
+	a := strings.Split(s, ",")
+	ps := make([]*Param, len(a))
+	for i := range ps {
+		s2 := trim(a[i])
+		b := strings.Split(s2, " ")
+		if len(b) != 2 {
+			b = strings.Split(s2, "\t")
+			if len(b) != 2 {
+				return nil, errors.New("Could not extract function parameter from \"" + s2 + "\"")
+			}
+		}
+		ps[i] = &Param{
+			Name:      trim(b[0]),
+			Type:      trim(b[1]),
+			fn:        f,
+			tmpVarIdx: -1,
+		}
+	}
+	return ps, nil
+}
+
+// extractSection extracts text out of string s starting after start
+// and ending just before end. found return value will indicate success,
+// and prefix, body and suffix will contain correspondent parts of string s.
+func extractSection(s string, start, end rune) (prefix, body, suffix string, found bool) {
+	s = trim(s)
+	if strings.HasPrefix(s, string(start)) {
+		// no prefix
+		body = s[1:]
+	} else {
+		a := strings.SplitN(s, string(start), 2)
+		if len(a) != 2 {
+			return "", "", s, false
+		}
+		prefix = a[0]
+		body = a[1]
+	}
+	a := strings.SplitN(body, string(end), 2)
+	if len(a) != 2 {
+		return "", "", "", false
+	}
+	return prefix, a[0], a[1], true
+}
+
+// newFn parses string s and return created function Fn.
+func newFn(s string) (*Fn, error) {
+	s = trim(s)
+	f := &Fn{
+		Rets:       &Rets{},
+		src:        s,
+		PrintTrace: *PrintTraceFlag,
+	}
+	// function name and args
+	prefix, body, s, found := extractSection(s, '(', ')')
+	if !found || prefix == "" {
+		return nil, errors.New("Could not extract function name and parameters from \"" + f.src + "\"")
+	}
+	f.Name = prefix
+	var err error
+	f.Params, err = extractParams(body, f)
+	if err != nil {
+		return nil, err
+	}
+	// return values
+	_, body, s, found = extractSection(s, '(', ')')
+	if found {
+		r, err := extractParams(body, f)
+		if err != nil {
+			return nil, err
+		}
+		switch len(r) {
+		case 0:
+		case 1:
+			if r[0].IsError() {
+				f.Rets.ReturnsError = true
+			} else {
+				f.Rets.Name = r[0].Name
+				f.Rets.Type = r[0].Type
+			}
+		case 2:
+			if !r[1].IsError() {
+				return nil, errors.New("Only last windows error is allowed as second return value in \"" + f.src + "\"")
+			}
+			f.Rets.ReturnsError = true
+			f.Rets.Name = r[0].Name
+			f.Rets.Type = r[0].Type
+		default:
+			return nil, errors.New("Too many return values in \"" + f.src + "\"")
+		}
+	}
+	// fail condition
+	_, body, s, found = extractSection(s, '[', ']')
+	if found {
+		f.Rets.FailCond = body
+	}
+	// dll and dll function names
+	s = trim(s)
+	if s == "" {
+		return f, nil
+	}
+	if !strings.HasPrefix(s, "=") {
+		return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
+	}
+	s = trim(s[1:])
+	a := strings.Split(s, ".")
+	switch len(a) {
+	case 1:
+		f.dllfuncname = a[0]
+	case 2:
+		f.dllname = a[0]
+		f.dllfuncname = a[1]
+	default:
+		return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
+	}
+	return f, nil
+}
+
+// DLLName returns DLL name for function f.
+func (f *Fn) DLLName() string {
+	if f.dllname == "" {
+		return "kernel32"
+	}
+	return f.dllname
+}
+
+// DLLName returns DLL function name for function f.
+func (f *Fn) DLLFuncName() string {
+	if f.dllfuncname == "" {
+		return f.Name
+	}
+	return f.dllfuncname
+}
+
+// ParamList returns source code for function f parameters.
+func (f *Fn) ParamList() string {
+	return join(f.Params, func(p *Param) string { return p.Name + " " + p.Type }, ", ")
+}
+
+// ParamPrintList returns source code of trace printing part correspondent
+// to syscall input parameters.
+func (f *Fn) ParamPrintList() string {
+	return join(f.Params, func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
+}
+
+// ParamCount return number of syscall parameters for function f.
+func (f *Fn) ParamCount() int {
+	n := 0
+	for _, p := range f.Params {
+		n += len(p.SyscallArgList())
+	}
+	return n
+}
+
+// SyscallParamCount determines which version of Syscall/Syscall6/Syscall9/...
+// to use. It returns parameter count for correspondent SyscallX function.
+func (f *Fn) SyscallParamCount() int {
+	n := f.ParamCount()
+	switch {
+	case n <= 3:
+		return 3
+	case n <= 6:
+		return 6
+	case n <= 9:
+		return 9
+	case n <= 12:
+		return 12
+	case n <= 15:
+		return 15
+	default:
+		panic("too many arguments to system call")
+	}
+}
+
+// Syscall determines which SyscallX function to use for function f.
+func (f *Fn) Syscall() string {
+	c := f.SyscallParamCount()
+	if c == 3 {
+		return "Syscall"
+	}
+	return "Syscall" + strconv.Itoa(c)
+}
+
+// SyscallParamList returns source code for SyscallX parameters for function f.
+func (f *Fn) SyscallParamList() string {
+	a := make([]string, 0)
+	for _, p := range f.Params {
+		a = append(a, p.SyscallArgList()...)
+	}
+	for len(a) < f.SyscallParamCount() {
+		a = append(a, "0")
+	}
+	return strings.Join(a, ", ")
+}
+
+// IsUTF16 is true, if f is W (utf16) function. It is false
+// for all A (ascii) functions.
+func (f *Fn) IsUTF16() bool {
+	s := f.DLLFuncName()
+	return s[len(s)-1] == 'W'
+}
+
+// StrconvFunc returns name of Go string to OS string function for f.
+func (f *Fn) StrconvFunc() string {
+	if f.IsUTF16() {
+		return "UTF16PtrFromString"
+	}
+	return "BytePtrFromString"
+}
+
+// StrconvType returns Go type name used for OS string for f.
+func (f *Fn) StrconvType() string {
+	if f.IsUTF16() {
+		return "*uint16"
+	}
+	return "*byte"
+}
+
+// Source files and functions.
+type Source struct {
+	Funcs []*Fn
+	Files []string
+}
+
+// ParseFiles parses files listed in fs and extracts all syscall
+// functions listed in  sys comments. It returns source files
+// and functions collection *Source if successful.
+func ParseFiles(fs []string) (*Source, error) {
+	src := &Source{
+		Funcs: make([]*Fn, 0),
+		Files: make([]string, 0),
+	}
+	for _, file := range fs {
+		if err := src.ParseFile(file); err != nil {
+			return nil, err
+		}
+	}
+	return src, nil
+}
+
+// DLLs return dll names for a source set src.
+func (src *Source) DLLs() []string {
+	uniq := make(map[string]bool)
+	r := make([]string, 0)
+	for _, f := range src.Funcs {
+		name := f.DLLName()
+		if _, found := uniq[name]; !found {
+			uniq[name] = true
+			r = append(r, name)
+		}
+	}
+	return r
+}
+
+// ParseFile adds adition file path to a source set src.
+func (src *Source) ParseFile(path string) error {
+	file, err := os.Open(path)
+	if err != nil {
+		return err
+	}
+	defer file.Close()
+
+	s := bufio.NewScanner(file)
+	for s.Scan() {
+		t := trim(s.Text())
+		if len(t) < 7 {
+			continue
+		}
+		if !strings.HasPrefix(t, "//sys") {
+			continue
+		}
+		t = t[5:]
+		if !(t[0] == ' ' || t[0] == '\t') {
+			continue
+		}
+		f, err := newFn(t[1:])
+		if err != nil {
+			return err
+		}
+		src.Funcs = append(src.Funcs, f)
+	}
+	if err := s.Err(); err != nil {
+		return err
+	}
+	src.Files = append(src.Files, path)
+	return nil
+}
+
+// Generate output source file from a source set src.
+func (src *Source) Generate(w io.Writer) error {
+	t := template.Must(template.New("main").Parse(srcTemplate))
+	err := t.Execute(w, src)
+	if err != nil {
+		return errors.New("Failed to execute template: " + err.Error())
+	}
+	return nil
+}
+
+func usage() {
+	fmt.Fprintf(os.Stderr, "usage: mksyscall_windows [flags] [path ...]\n")
+	flag.PrintDefaults()
+	os.Exit(1)
+}
+
+func main() {
+	flag.Usage = usage
+	flag.Parse()
+	if len(os.Args) <= 1 {
+		fmt.Fprintf(os.Stderr, "no files to parse provided\n")
+		usage()
+	}
+	src, err := ParseFiles(os.Args[1:])
+	if err != nil {
+		log.Fatal(err)
+	}
+	if err := src.Generate(os.Stdout); err != nil {
+		log.Fatal(err)
+	}
+}
+
+// TODO: use println instead to print in the following template
+const srcTemplate = `
+
+{{define "main"}}// go build mksyscall_windows.go && ./mksyscall_windows{{range .Files}} {{.}}{{end}}
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+var (
+{{template "dlls" .}}
+{{template "funcnames" .}})
+{{range .Funcs}}{{template "funcbody" .}}{{end}}
+{{end}}
+
+{{/* help functions */}}
+
+{{define "dlls"}}{{range .DLLs}}	mod{{.}} = NewLazyDLL("{{.}}.dll")
+{{end}}{{end}}
+
+{{define "funcnames"}}{{range .Funcs}}	proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}")
+{{end}}{{end}}
+
+{{define "funcbody"}}
+func {{.Name}}({{.ParamList}}) {{if .Rets.List}}{{.Rets.List}} {{end}}{
+{{template "tmpvars" .}}	{{template "syscall" .}}
+{{template "seterror" .}}{{template "printtrace" .}}	return
+}
+{{end}}
+
+{{define "tmpvars"}}{{range .Params}}{{if .TmpVarCode}}	{{.TmpVarCode}}
+{{end}}{{end}}{{end}}
+
+{{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}}
+
+{{define "seterror"}}{{if .Rets.SetErrorCode}}	{{.Rets.SetErrorCode}}
+{{end}}{{end}}
+
+{{define "printtrace"}}{{if .PrintTrace}}	print("SYSCALL: {{.Name}}(", {{.ParamPrintList}}") (", {{.Rets.PrintList}}")\n")
+{{end}}{{end}}
+
+`
diff --git a/src/pkg/syscall/mksyscall_windows.pl b/src/pkg/syscall/mksyscall_windows.pl
deleted file mode 100755
index 65d6efc..0000000
--- a/src/pkg/syscall/mksyscall_windows.pl
+++ /dev/null
@@ -1,333 +0,0 @@
-#!/usr/bin/env perl
-# 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.
-
-# This program reads a file containing function prototypes
-# (like syscall_darwin.go) and generates system call bodies.
-# The prototypes are marked by lines beginning with "//sys"
-# and read like func declarations if //sys is replaced by func, but:
-#	* The parameter lists must give a name for each argument.
-#	  This includes return parameters.
-#	* The parameter lists must give a type for each argument:
-#	  the (x, y, z int) shorthand is not allowed.
-#	* If the return parameter is an error number, it must be named err.
-#	* If go func name needs to be different from it's winapi dll name,
-#	  the winapi name could be specified at the end, after "=" sign, like
-#	  //sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
-#	* Each function that returns err needs to supply a condition,
-#	  that return value of winapi will be tested against to
-#	  detect failure. This would set err to windows "last-error",
-#	  otherwise it will be nil. The value can be provided
-#	  at end of //sys declaration, like
-#	  //sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
-#	  and is [failretval==0] by default.
-
-use strict;
-
-my $cmdline = "mksyscall_windows.pl " . join(' ', @ARGV);
-my $errors = 0;
-my $_32bit = "";
-
-binmode STDOUT;
-
-if($ARGV[0] eq "-b32") {
-	$_32bit = "big-endian";
-	shift;
-} elsif($ARGV[0] eq "-l32") {
-	$_32bit = "little-endian";
-	shift;
-}
-
-if($ARGV[0] =~ /^-/) {
-	print STDERR "usage: mksyscall_windows.pl [-b32 | -l32] [file ...]\n";
-	exit 1;
-}
-
-sub parseparamlist($) {
-	my ($list) = @_;
-	$list =~ s/^\s*//;
-	$list =~ s/\s*$//;
-	if($list eq "") {
-		return ();
-	}
-	return split(/\s*,\s*/, $list);
-}
-
-sub parseparam($) {
-	my ($p) = @_;
-	if($p !~ /^(\S*) (\S*)$/) {
-		print STDERR "$ARGV:$.: malformed parameter: $p\n";
-		$errors = 1;
-		return ("xx", "int");
-	}
-	return ($1, $2);
-}
-
-my $package = "";
-my $text = "";
-my $vars = "";
-my $mods = "";
-my $modnames = "";
-while(<>) {
-	chomp;
-	s/\s+/ /g;
-	s/^\s+//;
-	s/\s+$//;
-	$package = $1 if !$package && /^package (\S+)$/;
-	next if !/^\/\/sys /;
-
-	my $syscalldot = "";
-	$syscalldot = "syscall." if $package ne "syscall";
-
-	# Line must be of the form
-	#	func Open(path string, mode int, perm int) (fd int, err error)
-	# Split into name, in params, out params.
-	if(!/^\/\/sys (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:\[failretval(.*)\])?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) {
-		print STDERR "$ARGV:$.: malformed //sys declaration\n";
-		$errors = 1;
-		next;
-	}
-	my ($func, $in, $out, $failcond, $modname, $sysname) = ($1, $2, $3, $4, $5, $6);
-
-	# Split argument lists on comma.
-	my @in = parseparamlist($in);
-	my @out = parseparamlist($out);
-
-	# Dll file name.
-	if($modname eq "") {
-		$modname = "kernel32";
-	}
-	my $modvname = "mod$modname";
-	if($modnames !~ /$modname/) {
-		$modnames .= ".$modname";
-		$mods .= "\t$modvname = ${syscalldot}NewLazyDLL(\"$modname.dll\")\n";
-	}
-
-	# System call name.
-	if($sysname eq "") {
-		$sysname = "$func";
-	}
-
-	# System call pointer variable name.
-	my $sysvarname = "proc$sysname";
-
-	# Returned value when failed
-	if($failcond eq "") {
-		$failcond = "== 0";
-	}
-
-	# Decide which version of api is used: ascii or unicode.
-	my $strconvfunc = $sysname !~ /W$/ ? "BytePtrFromString" : "UTF16PtrFromString";
-	my $strconvtype = $sysname !~ /W$/ ? "*byte" : "*uint16";
-
-	# Winapi proc address variable.
-	$vars .= "\t$sysvarname = $modvname.NewProc(\"$sysname\")\n";
-
-	# Go function header.
-	$out = join(', ', @out);
-	if($out ne "") {
-		$out = " ($out)";
-	}
-	if($text ne "") {
-		$text .= "\n"
-	}
-	$text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out;
-
-	# Check if err return available
-	my $errvar = "";
-	foreach my $p (@out) {
-		my ($name, $type) = parseparam($p);
-		if($type eq "error") {
-			$errvar = $name;
-			last;
-		}
-	}
-
-	# Prepare arguments to Syscall.
-	my @args = ();
-	my $n = 0;
-	my @pin= ();
-	foreach my $p (@in) {
-		my ($name, $type) = parseparam($p);
-		if($type =~ /^\*/) {
-			push @args, "uintptr(unsafe.Pointer($name))";
-		} elsif($type eq "string" && $errvar ne "") {
-			$text .= "\tvar _p$n $strconvtype\n";
-			$text .= "\t_p$n, $errvar = $strconvfunc($name)\n";
-			$text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n";
-			push @args, "uintptr(unsafe.Pointer(_p$n))";
-			$n++;
-		} elsif($type eq "string") {
-			print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n";
-			$text .= "\tvar _p$n $strconvtype\n";
-			$text .= "\t_p$n, _ = $strconvfunc($name)\n";
-			push @args, "uintptr(unsafe.Pointer(_p$n))";
-			$n++;
-		} elsif($type =~ /^\[\](.*)/) {
-			# Convert slice into pointer, length.
-			# Have to be careful not to take address of &a[0] if len == 0:
-			# pass nil in that case.
-			$text .= "\tvar _p$n *$1\n";
-			$text .= "\tif len($name) > 0 {\n\t\t_p$n = \&$name\[0]\n\t}\n";
-			push @args, "uintptr(unsafe.Pointer(_p$n))", "uintptr(len($name))";
-			$n++;
-		} elsif($type eq "int64" && $_32bit ne "") {
-			if($_32bit eq "big-endian") {
-				push @args, "uintptr($name >> 32)", "uintptr($name)";
-			} else {
-				push @args, "uintptr($name)", "uintptr($name >> 32)";
-			}
-		} elsif($type eq "bool") {
- 			$text .= "\tvar _p$n uint32\n";
-			$text .= "\tif $name {\n\t\t_p$n = 1\n\t} else {\n\t\t_p$n = 0\n\t}\n";
-			push @args, "uintptr(_p$n)";
-			$n++;
-		} else {
-			push @args, "uintptr($name)";
-		}
-		push @pin, sprintf "\"%s=\", %s, ", $name, $name;
-	}
-	my $nargs = @args;
-
-	# Determine which form to use; pad args with zeros.
-	my $asm = "${syscalldot}Syscall";
-	if(@args <= 3) {
-		while(@args < 3) {
-			push @args, "0";
-		}
-	} elsif(@args <= 6) {
-		$asm = "${syscalldot}Syscall6";
-		while(@args < 6) {
-			push @args, "0";
-		}
-	} elsif(@args <= 9) {
-		$asm = "${syscalldot}Syscall9";
-		while(@args < 9) {
-			push @args, "0";
-		}
-	} elsif(@args <= 12) {
-		$asm = "${syscalldot}Syscall12";
-		while(@args < 12) {
-			push @args, "0";
-		}
-	} elsif(@args <= 15) {
-		$asm = "${syscalldot}Syscall15";
-		while(@args < 15) {
-			push @args, "0";
-		}
-	} else {
-		print STDERR "$ARGV:$.: too many arguments to system call\n";
-	}
-
-	# Actual call.
-	my $args = join(', ', @args);
-	my $call = "$asm($sysvarname.Addr(), $nargs, $args)";
-
-	# Assign return values.
-	my $body = "";
-	my $failexpr = "";
-	my @ret = ("_", "_", "_");
-	my @pout= ();
-	for(my $i=0; $i<@out; $i++) {
-		my $p = $out[$i];
-		my ($name, $type) = parseparam($p);
-		my $reg = "";
-		if($name eq "err") {
-			$reg = "e1";
-			$ret[2] = $reg;
-		} else {
-			$reg = sprintf("r%d", $i);
-			$ret[$i] = $reg;
-		}
-		if($type eq "bool") {
-			$reg = "$reg != 0";
-		}
-		if($type eq "int64" && $_32bit ne "") {
-			# 64-bit number in r1:r0 or r0:r1.
-			if($i+2 > @out) {
-				print STDERR "$ARGV:$.: not enough registers for int64 return\n";
-			}
-			if($_32bit eq "big-endian") {
-				$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1);
-			} else {
-				$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i);
-			}
-			$ret[$i] = sprintf("r%d", $i);
-			$ret[$i+1] = sprintf("r%d", $i+1);
-		}
-		my $rettype = $type;
-		if($type =~ /^\*/) {
-			$reg = "unsafe.Pointer($reg)";
-			$rettype = "($rettype)";
-		}
-		if($i == 0) {
-			if($type eq "bool") {
-				$failexpr = "!$name";
-			} elsif($name eq "err") {
-				$ret[$i] = "r1";
-				$failexpr = "r1 $failcond";
-			} else {
-				$failexpr = "$name $failcond";
-			}
-		}
-		$failexpr =~ s/(=)([0-9A-Za-z\-+])/$1 $2/;  # gofmt compatible
-		if($name eq "err") {
-			# Set err to "last error" only if returned value indicate failure
-			$body .= "\tif $failexpr {\n";
-			$body .= "\t\tif $reg != 0 {\n";
-			$body .= "\t\t\t$name = $type($reg)\n";
-			$body .= "\t\t} else {\n";
-			$body .= "\t\t\t$name = ${syscalldot}EINVAL\n";
-			$body .= "\t\t}\n";
-			$body .= "\t}\n";
-		} elsif($rettype eq "error") {
-			# Set $reg to "error" only if returned value indicate failure
-			$body .= "\tif $reg != 0 {\n";
-			$body .= "\t\t$name = ${syscalldot}Errno($reg)\n";
-			$body .= "\t}\n";
-		} else {
-			$body .= "\t$name = $rettype($reg)\n";
-		}
-		push @pout, sprintf "\"%s=\", %s, ", $name, $name;
-	}
-	if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") {
-		$text .= "\t$call\n";
-	} else {
-		$text .= "\t$ret[0], $ret[1], $ret[2] := $call\n";
-	}
-	$text .= $body;
-	if(0) {
-		$text .= sprintf 'print("SYSCALL: %s(", %s") (", %s")\n")%s', $func, join('", ", ', @pin), join('", ", ', @pout), "\n";
-	}
-
-	$text .= "\treturn\n";
-	$text .= "}\n";
-}
-
-if($errors) {
-	exit 1;
-}
-
-print <<EOF;
-// $cmdline
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-
-package $package
-
-import "unsafe"
-EOF
-
-print "import \"syscall\"\n" if $package ne "syscall";
-
-print <<EOF;
-
-var (
-$mods
-$vars
-)
-
-$text
-
-EOF
-exit 0;
diff --git a/src/pkg/syscall/mksysnum_dragonfly.pl b/src/pkg/syscall/mksysnum_dragonfly.pl
index 769c29e..3eba3ab 100755
--- a/src/pkg/syscall/mksysnum_dragonfly.pl
+++ b/src/pkg/syscall/mksysnum_dragonfly.pl
@@ -20,7 +20,7 @@ const (
 EOF
 
 while(<>){
-	if(/^([0-9]+)\s+STD\s+\S+\s+({ \S+\s+(\w+).*)$/){
+	if(/^([0-9]+)\s+STD\s+({ \S+\s+(\w+).*)$/){
 		my $num = $1;
 		my $proto = $2;
 		my $name = "SYS_$3";
diff --git a/src/pkg/syscall/mksysnum_freebsd.pl b/src/pkg/syscall/mksysnum_freebsd.pl
index 5c15633..cd67578 100755
--- a/src/pkg/syscall/mksysnum_freebsd.pl
+++ b/src/pkg/syscall/mksysnum_freebsd.pl
@@ -33,8 +33,21 @@ while(<>){
 		if($name eq 'SYS_SYS_EXIT'){
 			$name = 'SYS_EXIT';
 		}
+		if($name =~ /^SYS_CAP_+/ || $name =~ /^SYS___CAP_+/){
+			next
+		}
 
 		print "	$name = $num;  // $proto\n";
+
+		# We keep Capsicum syscall numbers for FreeBSD
+		# 9-STABLE here because we are not sure whether they
+		# are mature and stable.
+		if($num == 513){
+			print " SYS_CAP_NEW = 514 // { int cap_new(int fd, uint64_t rights); }\n";
+			print " SYS_CAP_GETRIGHTS = 515 // { int cap_getrights(int fd, \\\n";
+			print " SYS_CAP_ENTER = 516 // { int cap_enter(void); }\n";
+			print " SYS_CAP_GETMODE = 517 // { int cap_getmode(u_int *modep); }\n";
+		}
 	}
 }
 
diff --git a/src/pkg/syscall/mmap_unix_test.go b/src/pkg/syscall/mmap_unix_test.go
new file mode 100644
index 0000000..01f7783
--- /dev/null
+++ b/src/pkg/syscall/mmap_unix_test.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.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+package syscall_test
+
+import (
+	"syscall"
+	"testing"
+)
+
+func TestMmap(t *testing.T) {
+	b, err := syscall.Mmap(-1, 0, syscall.Getpagesize(), syscall.PROT_NONE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
+	if err != nil {
+		t.Fatalf("Mmap: %v", err)
+	}
+	if err := syscall.Munmap(b); err != nil {
+		t.Fatalf("Munmap: %v", err)
+	}
+}
diff --git a/src/pkg/syscall/net_nacl.go b/src/pkg/syscall/net_nacl.go
new file mode 100644
index 0000000..b9488f4
--- /dev/null
+++ b/src/pkg/syscall/net_nacl.go
@@ -0,0 +1,912 @@
+// 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.
+
+// A simulated network for use within NaCl.
+// The simulation is not particularly tied to NaCl,
+// but other systems have real networks.
+
+package syscall
+
+import (
+	"sync"
+	"sync/atomic"
+)
+
+// Interface to timers implemented in package runtime.
+// Must be in sync with ../runtime/runtime.h:/^struct.Timer$
+// Really for use by package time, but we cannot import time here.
+
+type runtimeTimer struct {
+	i      int32
+	when   int64
+	period int64
+	f      func(int64, interface{}) // NOTE: must not be closure
+	arg    interface{}
+}
+
+func startTimer(*runtimeTimer)
+func stopTimer(*runtimeTimer) bool
+
+type timer struct {
+	expired bool
+	q       *queue
+	r       runtimeTimer
+}
+
+func (t *timer) start(q *queue, deadline int64) {
+	if deadline == 0 {
+		return
+	}
+	t.q = q
+	t.r.when = deadline
+	t.r.f = timerExpired
+	t.r.arg = t
+	startTimer(&t.r)
+}
+
+func (t *timer) stop() {
+	stopTimer(&t.r)
+}
+
+func timerExpired(now int64, i interface{}) {
+	t := i.(*timer)
+	go func() {
+		t.q.Lock()
+		defer t.q.Unlock()
+		t.expired = true
+		t.q.canRead.Broadcast()
+		t.q.canWrite.Broadcast()
+	}()
+}
+
+// Network constants and data structures. These match the traditional values.
+
+const (
+	AF_UNSPEC = iota
+	AF_UNIX
+	AF_INET
+	AF_INET6
+)
+
+const (
+	SHUT_RD = iota
+	SHUT_WR
+	SHUT_RDWR
+)
+
+const (
+	SOCK_STREAM = 1 + iota
+	SOCK_DGRAM
+	SOCK_RAW
+	SOCK_SEQPACKET
+)
+
+const (
+	IPPROTO_IP   = 0
+	IPPROTO_IPV4 = 4
+	IPPROTO_IPV6 = 0x29
+	IPPROTO_TCP  = 6
+	IPPROTO_UDP  = 0x11
+)
+
+// Misc constants expected by package net but not supported.
+const (
+	_ = iota
+	SOL_SOCKET
+	SO_TYPE
+	NET_RT_IFLIST
+	IFNAMSIZ
+	IFF_UP
+	IFF_BROADCAST
+	IFF_LOOPBACK
+	IFF_POINTOPOINT
+	IFF_MULTICAST
+	IPV6_V6ONLY
+	SOMAXCONN
+	F_DUPFD_CLOEXEC
+	SO_BROADCAST
+	SO_REUSEADDR
+	SO_REUSEPORT
+	SO_RCVBUF
+	SO_SNDBUF
+	SO_KEEPALIVE
+	SO_LINGER
+	SO_ERROR
+	IP_PORTRANGE
+	IP_PORTRANGE_DEFAULT
+	IP_PORTRANGE_LOW
+	IP_PORTRANGE_HIGH
+	IP_MULTICAST_IF
+	IP_MULTICAST_LOOP
+	IP_ADD_MEMBERSHIP
+	IPV6_PORTRANGE
+	IPV6_PORTRANGE_DEFAULT
+	IPV6_PORTRANGE_LOW
+	IPV6_PORTRANGE_HIGH
+	IPV6_MULTICAST_IF
+	IPV6_MULTICAST_LOOP
+	IPV6_JOIN_GROUP
+	TCP_NODELAY
+	TCP_KEEPINTVL
+	TCP_KEEPIDLE
+
+	SYS_FCNTL = 500 // unsupported
+)
+
+var SocketDisableIPv6 bool
+
+// A Sockaddr is one of the SockaddrXxx structs.
+type Sockaddr interface {
+	// copy returns a copy of the underlying data.
+	copy() Sockaddr
+
+	// key returns the value of the underlying data,
+	// for comparison as a map key.
+	key() interface{}
+}
+
+type SockaddrInet4 struct {
+	Port int
+	Addr [4]byte
+}
+
+func (sa *SockaddrInet4) copy() Sockaddr {
+	sa1 := *sa
+	return &sa1
+}
+
+func (sa *SockaddrInet4) key() interface{} { return *sa }
+
+type SockaddrInet6 struct {
+	Port   int
+	ZoneId uint32
+	Addr   [16]byte
+}
+
+func (sa *SockaddrInet6) copy() Sockaddr {
+	sa1 := *sa
+	return &sa1
+}
+
+func (sa *SockaddrInet6) key() interface{} { return *sa }
+
+type SockaddrUnix struct {
+	Name string
+}
+
+func (sa *SockaddrUnix) copy() Sockaddr {
+	sa1 := *sa
+	return &sa1
+}
+
+func (sa *SockaddrUnix) key() interface{} { return *sa }
+
+type SockaddrDatalink struct {
+	Len    uint8
+	Family uint8
+	Index  uint16
+	Type   uint8
+	Nlen   uint8
+	Alen   uint8
+	Slen   uint8
+	Data   [12]int8
+}
+
+func (sa *SockaddrDatalink) copy() Sockaddr {
+	sa1 := *sa
+	return &sa1
+}
+
+func (sa *SockaddrDatalink) key() interface{} { return *sa }
+
+// RoutingMessage represents a routing message.
+type RoutingMessage interface {
+	unimplemented()
+}
+
+type IPMreq struct {
+	Multiaddr [4]byte /* in_addr */
+	Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+	Multiaddr [16]byte /* in6_addr */
+	Interface uint32
+}
+
+type Linger struct {
+	Onoff  int32
+	Linger int32
+}
+
+type ICMPv6Filter struct {
+	Filt [8]uint32
+}
+
+// A queue is the bookkeeping for a synchronized buffered queue.
+// We do not use channels because we need to be able to handle
+// writes after and during close, and because a chan byte would
+// require too many send and receive operations in real use.
+type queue struct {
+	sync.Mutex
+	canRead  sync.Cond
+	canWrite sync.Cond
+	r        int // total read index
+	w        int // total write index
+	m        int // index mask
+	closed   bool
+}
+
+func (q *queue) init(size int) {
+	if size&(size-1) != 0 {
+		panic("invalid queue size - must be power of two")
+	}
+	q.canRead.L = &q.Mutex
+	q.canWrite.L = &q.Mutex
+	q.m = size - 1
+}
+
+func past(deadline int64) bool {
+	sec, nsec := now()
+	return deadline > 0 && deadline < sec*1e9+int64(nsec)
+}
+
+func (q *queue) waitRead(n int, deadline int64) (int, error) {
+	if past(deadline) {
+		return 0, EAGAIN
+	}
+	var t timer
+	t.start(q, deadline)
+	for q.w-q.r == 0 && !q.closed && !t.expired {
+		q.canRead.Wait()
+	}
+	t.stop()
+	m := q.w - q.r
+	if m == 0 && t.expired {
+		return 0, EAGAIN
+	}
+	if m > n {
+		m = n
+		q.canRead.Signal() // wake up next reader too
+	}
+	q.canWrite.Signal()
+	return m, nil
+}
+
+func (q *queue) waitWrite(n int, deadline int64) (int, error) {
+	if past(deadline) {
+		return 0, EAGAIN
+	}
+	var t timer
+	t.start(q, deadline)
+	for q.w-q.r > q.m && !q.closed && !t.expired {
+		q.canWrite.Wait()
+	}
+	t.stop()
+	m := q.m + 1 - (q.w - q.r)
+	if m == 0 && t.expired {
+		return 0, EAGAIN
+	}
+	if m == 0 {
+		return 0, EAGAIN
+	}
+	if m > n {
+		m = n
+		q.canWrite.Signal() // wake up next writer too
+	}
+	q.canRead.Signal()
+	return m, nil
+}
+
+func (q *queue) close() {
+	q.Lock()
+	defer q.Unlock()
+	q.closed = true
+	q.canRead.Broadcast()
+	q.canWrite.Broadcast()
+}
+
+// A byteq is a byte queue.
+type byteq struct {
+	queue
+	data []byte
+}
+
+func newByteq() *byteq {
+	q := &byteq{
+		data: make([]byte, 4096),
+	}
+	q.init(len(q.data))
+	return q
+}
+
+func (q *byteq) read(b []byte, deadline int64) (int, error) {
+	q.Lock()
+	defer q.Unlock()
+	n, err := q.waitRead(len(b), deadline)
+	if err != nil {
+		return 0, err
+	}
+	b = b[:n]
+	for len(b) > 0 {
+		m := copy(b, q.data[q.r&q.m:])
+		q.r += m
+		b = b[m:]
+	}
+	return n, nil
+}
+
+func (q *byteq) write(b []byte, deadline int64) (n int, err error) {
+	q.Lock()
+	defer q.Unlock()
+	for n < len(b) {
+		nn, err := q.waitWrite(len(b[n:]), deadline)
+		if err != nil {
+			return n, err
+		}
+		bb := b[n : n+nn]
+		n += nn
+		for len(bb) > 0 {
+			m := copy(q.data[q.w&q.m:], bb)
+			q.w += m
+			bb = bb[m:]
+		}
+	}
+	return n, nil
+}
+
+// A msgq is a queue of messages.
+type msgq struct {
+	queue
+	data []interface{}
+}
+
+func newMsgq() *msgq {
+	q := &msgq{
+		data: make([]interface{}, 32),
+	}
+	q.init(len(q.data))
+	return q
+}
+
+func (q *msgq) read(deadline int64) (interface{}, error) {
+	q.Lock()
+	defer q.Unlock()
+	n, err := q.waitRead(1, deadline)
+	if err != nil {
+		return nil, err
+	}
+	if n == 0 {
+		return nil, nil
+	}
+	m := q.data[q.r&q.m]
+	q.r++
+	return m, nil
+}
+
+func (q *msgq) write(m interface{}, deadline int64) error {
+	q.Lock()
+	defer q.Unlock()
+	_, err := q.waitWrite(1, deadline)
+	if err != nil {
+		return err
+	}
+	q.data[q.w&q.m] = m
+	q.w++
+	return nil
+}
+
+// An addr is a sequence of bytes uniquely identifying a network address.
+// It is not human-readable.
+type addr string
+
+// A conn is one side of a stream-based network connection.
+// That is, a stream-based network connection is a pair of cross-connected conns.
+type conn struct {
+	rd     *byteq
+	wr     *byteq
+	local  addr
+	remote addr
+}
+
+// A pktconn is one side of a packet-based network connection.
+// That is, a packet-based network connection is a pair of cross-connected pktconns.
+type pktconn struct {
+	rd     *msgq
+	wr     *msgq
+	local  addr
+	remote addr
+}
+
+// A listener accepts incoming stream-based network connections.
+type listener struct {
+	rd    *msgq
+	local addr
+}
+
+// A netFile is an open network file.
+type netFile struct {
+	defaultFileImpl
+	proto      *netproto
+	sotype     int
+	listener   *msgq
+	packet     *msgq
+	rd         *byteq
+	wr         *byteq
+	rddeadline int64
+	wrdeadline int64
+	addr       Sockaddr
+	raddr      Sockaddr
+}
+
+// A netAddr is a network address in the global listener map.
+// All the fields must have defined == operations.
+type netAddr struct {
+	proto  *netproto
+	sotype int
+	addr   interface{}
+}
+
+// net records the state of the network.
+// It maps a network address to the listener on that address.
+var net = struct {
+	sync.Mutex
+	listener map[netAddr]*netFile
+}{
+	listener: make(map[netAddr]*netFile),
+}
+
+// TODO(rsc): Some day, do a better job with port allocation.
+// For playground programs, incrementing is fine.
+var nextport = 2
+
+// A netproto contains protocol-specific functionality
+// (one for AF_INET, one for AF_INET6 and so on).
+// It is a struct instead of an interface because the
+// implementation needs no state, and I expect to
+// add some data fields at some point.
+type netproto struct {
+	bind func(*netFile, Sockaddr) error
+}
+
+var netprotoAF_INET = &netproto{
+	bind: func(f *netFile, sa Sockaddr) error {
+		if sa == nil {
+			f.addr = &SockaddrInet4{
+				Port: nextport,
+				Addr: [4]byte{127, 0, 0, 1},
+			}
+			nextport++
+			return nil
+		}
+		addr, ok := sa.(*SockaddrInet4)
+		if !ok {
+			return EINVAL
+		}
+		addr = addr.copy().(*SockaddrInet4)
+		if addr.Port == 0 {
+			addr.Port = nextport
+			nextport++
+		}
+		f.addr = addr
+		return nil
+	},
+}
+
+var netprotos = map[int]*netproto{
+	AF_INET: netprotoAF_INET,
+}
+
+// These functions implement the usual BSD socket operations.
+
+func (f *netFile) bind(sa Sockaddr) error {
+	if f.addr != nil {
+		return EISCONN
+	}
+	if err := f.proto.bind(f, sa); err != nil {
+		return err
+	}
+	if f.sotype == SOCK_DGRAM {
+		_, ok := net.listener[netAddr{f.proto, f.sotype, f.addr.key()}]
+		if ok {
+			f.addr = nil
+			return EADDRINUSE
+		}
+		net.listener[netAddr{f.proto, f.sotype, f.addr.key()}] = f
+		f.packet = newMsgq()
+	}
+	return nil
+}
+
+func (f *netFile) listen(backlog int) error {
+	net.Lock()
+	defer net.Unlock()
+	if f.listener != nil {
+		return EINVAL
+	}
+	_, ok := net.listener[netAddr{f.proto, f.sotype, f.addr.key()}]
+	if ok {
+		return EADDRINUSE
+	}
+	net.listener[netAddr{f.proto, f.sotype, f.addr.key()}] = f
+	f.listener = newMsgq()
+	return nil
+}
+
+func (f *netFile) accept() (fd int, sa Sockaddr, err error) {
+	msg, err := f.listener.read(f.readDeadline())
+	if err != nil {
+		return -1, nil, err
+	}
+	newf, ok := msg.(*netFile)
+	if !ok {
+		// must be eof
+		return -1, nil, EAGAIN
+	}
+	return newFD(newf), newf.raddr.copy(), nil
+}
+
+func (f *netFile) connect(sa Sockaddr) error {
+	if past(f.writeDeadline()) {
+		return EAGAIN
+	}
+	if f.addr == nil {
+		if err := f.bind(nil); err != nil {
+			return err
+		}
+	}
+	net.Lock()
+	if sa == nil {
+		net.Unlock()
+		return EINVAL
+	}
+	sa = sa.copy()
+	if f.raddr != nil {
+		net.Unlock()
+		return EISCONN
+	}
+	if f.sotype == SOCK_DGRAM {
+		net.Unlock()
+		f.raddr = sa
+		return nil
+	}
+	if f.listener != nil {
+		net.Unlock()
+		return EISCONN
+	}
+	l, ok := net.listener[netAddr{f.proto, f.sotype, sa.key()}]
+	if !ok {
+		net.Unlock()
+		return ECONNREFUSED
+	}
+	f.raddr = sa
+	f.rd = newByteq()
+	f.wr = newByteq()
+	newf := &netFile{
+		proto:  f.proto,
+		sotype: f.sotype,
+		addr:   f.raddr,
+		raddr:  f.addr,
+		rd:     f.wr,
+		wr:     f.rd,
+	}
+	net.Unlock()
+	l.listener.write(newf, f.writeDeadline())
+	return nil
+}
+
+func (f *netFile) read(b []byte) (int, error) {
+	if f.rd == nil {
+		if f.raddr != nil {
+			n, _, err := f.recvfrom(b, 0)
+			return n, err
+		}
+		return 0, ENOTCONN
+	}
+	return f.rd.read(b, f.readDeadline())
+}
+
+func (f *netFile) write(b []byte) (int, error) {
+	if f.wr == nil {
+		if f.raddr != nil {
+			err := f.sendto(b, 0, f.raddr)
+			var n int
+			if err == nil {
+				n = len(b)
+			}
+			return n, err
+		}
+		return 0, ENOTCONN
+	}
+	return f.wr.write(b, f.writeDeadline())
+}
+
+type pktmsg struct {
+	buf  []byte
+	addr Sockaddr
+}
+
+func (f *netFile) recvfrom(p []byte, flags int) (n int, from Sockaddr, err error) {
+	if f.sotype != SOCK_DGRAM {
+		return 0, nil, EINVAL
+	}
+	if f.packet == nil {
+		return 0, nil, ENOTCONN
+	}
+	msg1, err := f.packet.read(f.readDeadline())
+	if err != nil {
+		return 0, nil, err
+	}
+	msg, ok := msg1.(*pktmsg)
+	if !ok {
+		return 0, nil, EAGAIN
+	}
+	return copy(p, msg.buf), msg.addr, nil
+}
+
+func (f *netFile) sendto(p []byte, flags int, to Sockaddr) error {
+	if f.sotype != SOCK_DGRAM {
+		return EINVAL
+	}
+	if f.packet == nil {
+		if err := f.bind(nil); err != nil {
+			return err
+		}
+	}
+	net.Lock()
+	if to == nil {
+		net.Unlock()
+		return EINVAL
+	}
+	to = to.copy()
+	l, ok := net.listener[netAddr{f.proto, f.sotype, to.key()}]
+	if !ok || l.packet == nil {
+		net.Unlock()
+		return ECONNREFUSED
+	}
+	net.Unlock()
+	msg := &pktmsg{
+		buf:  make([]byte, len(p)),
+		addr: f.addr,
+	}
+	copy(msg.buf, p)
+	l.packet.write(msg, f.writeDeadline())
+	return nil
+}
+
+func (f *netFile) close() error {
+	if f.listener != nil {
+		f.listener.close()
+	}
+	if f.packet != nil {
+		f.packet.close()
+	}
+	if f.rd != nil {
+		f.rd.close()
+	}
+	if f.wr != nil {
+		f.wr.close()
+	}
+	return nil
+}
+
+func fdToNetFile(fd int) (*netFile, error) {
+	f, err := fdToFile(fd)
+	if err != nil {
+		return nil, err
+	}
+	impl := f.impl
+	netf, ok := impl.(*netFile)
+	if !ok {
+		return nil, EINVAL
+	}
+	return netf, nil
+}
+
+func Socket(proto, sotype, unused int) (fd int, err error) {
+	p := netprotos[proto]
+	if p == nil {
+		return -1, EPROTONOSUPPORT
+	}
+	if sotype != SOCK_STREAM && sotype != SOCK_DGRAM {
+		return -1, ESOCKTNOSUPPORT
+	}
+	f := &netFile{
+		proto:  p,
+		sotype: sotype,
+	}
+	return newFD(f), nil
+}
+
+func Bind(fd int, sa Sockaddr) error {
+	f, err := fdToNetFile(fd)
+	if err != nil {
+		return err
+	}
+	return f.bind(sa)
+}
+
+func StopIO(fd int) error {
+	f, err := fdToNetFile(fd)
+	if err != nil {
+		return err
+	}
+	f.close()
+	return nil
+}
+
+func Listen(fd int, backlog int) error {
+	f, err := fdToNetFile(fd)
+	if err != nil {
+		return err
+	}
+	return f.listen(backlog)
+}
+
+func Accept(fd int) (newfd int, sa Sockaddr, err error) {
+	f, err := fdToNetFile(fd)
+	if err != nil {
+		return 0, nil, err
+	}
+	return f.accept()
+}
+
+func Getsockname(fd int) (sa Sockaddr, err error) {
+	f, err := fdToNetFile(fd)
+	if err != nil {
+		return nil, err
+	}
+	if f.addr == nil {
+		return nil, ENOTCONN
+	}
+	return f.addr.copy(), nil
+}
+
+func Getpeername(fd int) (sa Sockaddr, err error) {
+	f, err := fdToNetFile(fd)
+	if err != nil {
+		return nil, err
+	}
+	if f.raddr == nil {
+		return nil, ENOTCONN
+	}
+	return f.raddr.copy(), nil
+}
+
+func Connect(fd int, sa Sockaddr) error {
+	f, err := fdToNetFile(fd)
+	if err != nil {
+		return err
+	}
+	return f.connect(sa)
+}
+
+func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
+	f, err := fdToNetFile(fd)
+	if err != nil {
+		return 0, nil, err
+	}
+	return f.recvfrom(p, flags)
+}
+
+func Sendto(fd int, p []byte, flags int, to Sockaddr) error {
+	f, err := fdToNetFile(fd)
+	if err != nil {
+		return err
+	}
+	return f.sendto(p, flags, to)
+}
+
+func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn, recvflags int, from Sockaddr, err error) {
+	f, err := fdToNetFile(fd)
+	if err != nil {
+		return
+	}
+	n, from, err = f.recvfrom(p, flags)
+	return
+}
+
+func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) error {
+	_, err := SendmsgN(fd, p, oob, to, flags)
+	return err
+}
+
+func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
+	f, err := fdToNetFile(fd)
+	if err != nil {
+		return 0, err
+	}
+	switch f.sotype {
+	case SOCK_STREAM:
+		n, err = f.write(p)
+	case SOCK_DGRAM:
+		n = len(p)
+		err = f.sendto(p, flags, to)
+	}
+	if err != nil {
+		return 0, err
+	}
+	return n, nil
+}
+
+func GetsockoptInt(fd, level, opt int) (value int, err error) {
+	f, err := fdToNetFile(fd)
+	if err != nil {
+		return 0, err
+	}
+	switch {
+	case level == SOL_SOCKET && opt == SO_TYPE:
+		return f.sotype, nil
+	}
+	return 0, ENOTSUP
+}
+
+func SetsockoptInt(fd, level, opt int, value int) error {
+	return nil
+}
+
+func SetsockoptByte(fd, level, opt int, value byte) error {
+	_, err := fdToNetFile(fd)
+	if err != nil {
+		return err
+	}
+	return ENOTSUP
+}
+
+func SetsockoptLinger(fd, level, opt int, l *Linger) error {
+	return nil
+}
+
+func SetReadDeadline(fd int, t int64) error {
+	f, err := fdToNetFile(fd)
+	if err != nil {
+		return err
+	}
+	atomic.StoreInt64(&f.rddeadline, t)
+	return nil
+}
+
+func (f *netFile) readDeadline() int64 {
+	return atomic.LoadInt64(&f.rddeadline)
+}
+
+func SetWriteDeadline(fd int, t int64) error {
+	f, err := fdToNetFile(fd)
+	if err != nil {
+		return err
+	}
+	atomic.StoreInt64(&f.wrdeadline, t)
+	return nil
+}
+
+func (f *netFile) writeDeadline() int64 {
+	return atomic.LoadInt64(&f.wrdeadline)
+}
+
+func Shutdown(fd int, how int) error {
+	f, err := fdToNetFile(fd)
+	if err != nil {
+		return err
+	}
+	switch how {
+	case SHUT_RD:
+		f.rd.close()
+	case SHUT_WR:
+		f.wr.close()
+	case SHUT_RDWR:
+		f.rd.close()
+		f.wr.close()
+	}
+	return nil
+}
+
+func SetsockoptICMPv6Filter(fd, level, opt int, filter *ICMPv6Filter) error { panic("SetsockoptICMPv") }
+func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) error               { panic("SetsockoptIPMreq") }
+func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) error           { panic("SetsockoptIPv") }
+func SetsockoptInet4Addr(fd, level, opt int, value [4]byte) error           { panic("SetsockoptInet") }
+func SetsockoptString(fd, level, opt int, s string) error                   { panic("SetsockoptString") }
+func SetsockoptTimeval(fd, level, opt int, tv *Timeval) error               { panic("SetsockoptTimeval") }
+func Socketpair(domain, typ, proto int) (fd [2]int, err error)              { panic("Socketpair") }
+
+func SetNonblock(fd int, nonblocking bool) error { return nil }
diff --git a/src/pkg/syscall/passfd_test.go b/src/pkg/syscall/passfd_test.go
deleted file mode 100644
index 53c7a1f..0000000
--- a/src/pkg/syscall/passfd_test.go
+++ /dev/null
@@ -1,202 +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.
-
-// +build linux dragonfly darwin freebsd netbsd openbsd
-
-package syscall_test
-
-import (
-	"flag"
-	"fmt"
-	"io/ioutil"
-	"net"
-	"os"
-	"os/exec"
-	"runtime"
-	"syscall"
-	"testing"
-	"time"
-)
-
-// TestPassFD tests passing a file descriptor over a Unix socket.
-//
-// This test involved both a parent and child process. The parent
-// process is invoked as a normal test, with "go test", which then
-// runs the child process by running the current test binary with args
-// "-test.run=^TestPassFD$" and an environment variable used to signal
-// that the test should become the child process instead.
-func TestPassFD(t *testing.T) {
-	if runtime.GOOS == "dragonfly" {
-		// TODO(jsing): Figure out why sendmsg is returning EINVAL.
-		t.Skip("Skipping test on dragonfly")
-	}
-	if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
-		passFDChild()
-		return
-	}
-
-	tempDir, err := ioutil.TempDir("", "TestPassFD")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(tempDir)
-
-	fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0)
-	if err != nil {
-		t.Fatalf("Socketpair: %v", err)
-	}
-	defer syscall.Close(fds[0])
-	defer syscall.Close(fds[1])
-	writeFile := os.NewFile(uintptr(fds[0]), "child-writes")
-	readFile := os.NewFile(uintptr(fds[1]), "parent-reads")
-	defer writeFile.Close()
-	defer readFile.Close()
-
-	cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir)
-	cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
-	cmd.ExtraFiles = []*os.File{writeFile}
-
-	out, err := cmd.CombinedOutput()
-	if len(out) > 0 || err != nil {
-		t.Fatalf("child process: %q, %v", out, err)
-	}
-
-	c, err := net.FileConn(readFile)
-	if err != nil {
-		t.Fatalf("FileConn: %v", err)
-	}
-	defer c.Close()
-
-	uc, ok := c.(*net.UnixConn)
-	if !ok {
-		t.Fatalf("unexpected FileConn type; expected UnixConn, got %T", c)
-	}
-
-	buf := make([]byte, 32) // expect 1 byte
-	oob := make([]byte, 32) // expect 24 bytes
-	closeUnix := time.AfterFunc(5*time.Second, func() {
-		t.Logf("timeout reading from unix socket")
-		uc.Close()
-	})
-	_, oobn, _, _, err := uc.ReadMsgUnix(buf, oob)
-	closeUnix.Stop()
-
-	scms, err := syscall.ParseSocketControlMessage(oob[:oobn])
-	if err != nil {
-		t.Fatalf("ParseSocketControlMessage: %v", err)
-	}
-	if len(scms) != 1 {
-		t.Fatalf("expected 1 SocketControlMessage; got scms = %#v", scms)
-	}
-	scm := scms[0]
-	gotFds, err := syscall.ParseUnixRights(&scm)
-	if err != nil {
-		t.Fatalf("syscall.ParseUnixRights: %v", err)
-	}
-	if len(gotFds) != 1 {
-		t.Fatalf("wanted 1 fd; got %#v", gotFds)
-	}
-
-	f := os.NewFile(uintptr(gotFds[0]), "fd-from-child")
-	defer f.Close()
-
-	got, err := ioutil.ReadAll(f)
-	want := "Hello from child process!\n"
-	if string(got) != want {
-		t.Errorf("child process ReadAll: %q, %v; want %q", got, err, want)
-	}
-}
-
-// passFDChild is the child process used by TestPassFD.
-func passFDChild() {
-	defer os.Exit(0)
-
-	// Look for our fd. It should be fd 3, but we work around an fd leak
-	// bug here (http://golang.org/issue/2603) to let it be elsewhere.
-	var uc *net.UnixConn
-	for fd := uintptr(3); fd <= 10; fd++ {
-		f := os.NewFile(fd, "unix-conn")
-		var ok bool
-		netc, _ := net.FileConn(f)
-		uc, ok = netc.(*net.UnixConn)
-		if ok {
-			break
-		}
-	}
-	if uc == nil {
-		fmt.Println("failed to find unix fd")
-		return
-	}
-
-	// Make a file f to send to our parent process on uc.
-	// We make it in tempDir, which our parent will clean up.
-	flag.Parse()
-	tempDir := flag.Arg(0)
-	f, err := ioutil.TempFile(tempDir, "")
-	if err != nil {
-		fmt.Printf("TempFile: %v", err)
-		return
-	}
-
-	f.Write([]byte("Hello from child process!\n"))
-	f.Seek(0, 0)
-
-	rights := syscall.UnixRights(int(f.Fd()))
-	dummyByte := []byte("x")
-	n, oobn, err := uc.WriteMsgUnix(dummyByte, rights, nil)
-	if err != nil {
-		fmt.Printf("WriteMsgUnix: %v", err)
-		return
-	}
-	if n != 1 || oobn != len(rights) {
-		fmt.Printf("WriteMsgUnix = %d, %d; want 1, %d", n, oobn, len(rights))
-		return
-	}
-}
-
-// TestUnixRightsRoundtrip tests that UnixRights, ParseSocketControlMessage,
-// and ParseUnixRights are able to successfully round-trip lists of file descriptors.
-func TestUnixRightsRoundtrip(t *testing.T) {
-	testCases := [...][][]int{
-		{{42}},
-		{{1, 2}},
-		{{3, 4, 5}},
-		{{}},
-		{{1, 2}, {3, 4, 5}, {}, {7}},
-	}
-	for _, testCase := range testCases {
-		b := []byte{}
-		var n int
-		for _, fds := range testCase {
-			// Last assignment to n wins
-			n = len(b) + syscall.CmsgLen(4*len(fds))
-			b = append(b, syscall.UnixRights(fds...)...)
-		}
-		// Truncate b
-		b = b[:n]
-
-		scms, err := syscall.ParseSocketControlMessage(b)
-		if err != nil {
-			t.Fatalf("ParseSocketControlMessage: %v", err)
-		}
-		if len(scms) != len(testCase) {
-			t.Fatalf("expected %v SocketControlMessage; got scms = %#v", len(testCase), scms)
-		}
-		for i, scm := range scms {
-			gotFds, err := syscall.ParseUnixRights(&scm)
-			if err != nil {
-				t.Fatalf("ParseUnixRights: %v", err)
-			}
-			wantFds := testCase[i]
-			if len(gotFds) != len(wantFds) {
-				t.Fatalf("expected %v fds, got %#v", len(wantFds), gotFds)
-			}
-			for j, fd := range gotFds {
-				if fd != wantFds[j] {
-					t.Fatalf("expected fd %v, got %v", wantFds[j], fd)
-				}
-			}
-		}
-	}
-}
diff --git a/src/pkg/syscall/rlimit_linux_test.go b/src/pkg/syscall/rlimit_linux_test.go
deleted file mode 100644
index 4ec720e..0000000
--- a/src/pkg/syscall/rlimit_linux_test.go
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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 syscall_test
-
-import (
-	"syscall"
-	"testing"
-)
-
-func TestRlimit(t *testing.T) {
-	var rlimit, zero syscall.Rlimit
-	err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit)
-	if err != nil {
-		t.Fatalf("Getrlimit: save failed: %v", err)
-	}
-	if zero == rlimit {
-		t.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit)
-	}
-	set := rlimit
-	set.Cur = set.Max - 1
-	err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &set)
-	if err != nil {
-		t.Fatalf("Setrlimit: set failed: %#v %v", set, err)
-	}
-	var get syscall.Rlimit
-	err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &get)
-	if err != nil {
-		t.Fatalf("Getrlimit: get failed: %v", err)
-	}
-	set = rlimit
-	set.Cur = set.Max - 1
-	if set != get {
-		t.Fatalf("Rlimit: change failed: wanted %#v got %#v", set, get)
-	}
-	err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit)
-	if err != nil {
-		t.Fatalf("Setrlimit: restore failed: %#v %v", rlimit, err)
-	}
-}
diff --git a/src/pkg/syscall/route_bsd.go b/src/pkg/syscall/route_bsd.go
index 6380735..48af587 100644
--- a/src/pkg/syscall/route_bsd.go
+++ b/src/pkg/syscall/route_bsd.go
@@ -199,14 +199,21 @@ func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
 // ParseRoutingMessage parses b as routing messages and returns the
 // slice containing the RoutingMessage interfaces.
 func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) {
+	msgCount := 0
 	for len(b) >= anyMessageLen {
+		msgCount++
 		any := (*anyMessage)(unsafe.Pointer(&b[0]))
 		if any.Version != RTM_VERSION {
-			return nil, EINVAL
+			b = b[any.Msglen:]
+			continue
 		}
 		msgs = append(msgs, any.toRoutingMessage(b))
 		b = b[any.Msglen:]
 	}
+	// We failed to parse any of the messages - version mismatch?
+	if msgCount > 0 && len(msgs) == 0 {
+		return nil, EINVAL
+	}
 	return msgs, nil
 }
 
diff --git a/src/pkg/syscall/route_dragonfly.go b/src/pkg/syscall/route_dragonfly.go
index acad7a2..79190d2 100644
--- a/src/pkg/syscall/route_dragonfly.go
+++ b/src/pkg/syscall/route_dragonfly.go
@@ -30,7 +30,7 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
 }
 
 // InterfaceAnnounceMessage represents a routing message containing
-// network interface arrival and depature information.
+// network interface arrival and departure information.
 type InterfaceAnnounceMessage struct {
 	Header IfAnnounceMsghdr
 }
diff --git a/src/pkg/syscall/route_freebsd.go b/src/pkg/syscall/route_freebsd.go
index d8f8031..15897b1 100644
--- a/src/pkg/syscall/route_freebsd.go
+++ b/src/pkg/syscall/route_freebsd.go
@@ -8,14 +8,20 @@ package syscall
 
 import "unsafe"
 
+// See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
+var freebsdVersion uint32
+
+func init() {
+	freebsdVersion, _ = SysctlUint32("kern.osreldate")
+}
+
 func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
 	switch any.Type {
 	case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
 		p := (*RouteMessage)(unsafe.Pointer(any))
 		return &RouteMessage{Header: p.Header, Data: b[SizeofRtMsghdr:any.Msglen]}
 	case RTM_IFINFO:
-		p := (*InterfaceMessage)(unsafe.Pointer(any))
-		return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
+		return any.parseInterfaceMessage(b)
 	case RTM_IFANNOUNCE:
 		p := (*InterfaceAnnounceMessage)(unsafe.Pointer(any))
 		return &InterfaceAnnounceMessage{Header: p.Header}
@@ -30,7 +36,7 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
 }
 
 // InterfaceAnnounceMessage represents a routing message containing
-// network interface arrival and depature information.
+// network interface arrival and departure information.
 type InterfaceAnnounceMessage struct {
 	Header IfAnnounceMsghdr
 }
diff --git a/src/pkg/syscall/route_freebsd_32bit.go b/src/pkg/syscall/route_freebsd_32bit.go
new file mode 100644
index 0000000..93efddd
--- /dev/null
+++ b/src/pkg/syscall/route_freebsd_32bit.go
@@ -0,0 +1,24 @@
+// 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 freebsd,386 freebsd,arm
+
+package syscall
+
+import "unsafe"
+
+func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage {
+	p := (*InterfaceMessage)(unsafe.Pointer(any))
+	// FreeBSD 10 and beyond have a restructured mbuf
+	// packet header view.
+	// See http://svnweb.freebsd.org/base?view=revision&revision=254804.
+	if freebsdVersion >= 1000000 {
+		m := (*ifMsghdr)(unsafe.Pointer(any))
+		p.Header.Data.Hwassist = uint32(m.Data.Hwassist)
+		p.Header.Data.Epoch = m.Data.Epoch
+		p.Header.Data.Lastchange = m.Data.Lastchange
+		return &InterfaceMessage{Header: p.Header, Data: b[sizeofIfMsghdr:any.Msglen]}
+	}
+	return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
+}
diff --git a/src/pkg/syscall/route_freebsd_64bit.go b/src/pkg/syscall/route_freebsd_64bit.go
new file mode 100644
index 0000000..9377f2f
--- /dev/null
+++ b/src/pkg/syscall/route_freebsd_64bit.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.
+
+// +build freebsd,amd64
+
+package syscall
+
+import "unsafe"
+
+func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage {
+	p := (*InterfaceMessage)(unsafe.Pointer(any))
+	return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
+}
diff --git a/src/pkg/syscall/route_netbsd.go b/src/pkg/syscall/route_netbsd.go
index a6baa02..9883aeb 100644
--- a/src/pkg/syscall/route_netbsd.go
+++ b/src/pkg/syscall/route_netbsd.go
@@ -27,7 +27,7 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
 }
 
 // InterfaceAnnounceMessage represents a routing message containing
-// network interface arrival and depature information.
+// network interface arrival and departure information.
 type InterfaceAnnounceMessage struct {
 	Header IfAnnounceMsghdr
 }
diff --git a/src/pkg/syscall/route_openbsd.go b/src/pkg/syscall/route_openbsd.go
index 223c157..19f902d 100644
--- a/src/pkg/syscall/route_openbsd.go
+++ b/src/pkg/syscall/route_openbsd.go
@@ -27,7 +27,7 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
 }
 
 // InterfaceAnnounceMessage represents a routing message containing
-// network interface arrival and depature information.
+// network interface arrival and departure information.
 type InterfaceAnnounceMessage struct {
 	Header IfAnnounceMsghdr
 }
diff --git a/src/pkg/syscall/so_solaris.go b/src/pkg/syscall/so_solaris.go
new file mode 100644
index 0000000..659cd67
--- /dev/null
+++ b/src/pkg/syscall/so_solaris.go
@@ -0,0 +1,260 @@
+// 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.
+
+package syscall
+
+import (
+	"sync"
+	"sync/atomic"
+	"unsafe"
+)
+
+// soError describes reasons for shared library load failures.
+type soError struct {
+	Err     error
+	ObjName string
+	Msg     string
+}
+
+func (e *soError) Error() string { return e.Msg }
+
+// Implemented in ../runtime/syscall_solaris.goc.
+func rawSysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+func dlclose(handle uintptr) (err Errno)
+func dlopen(name *uint8, mode uintptr) (handle uintptr, err Errno)
+func dlsym(handle uintptr, name *uint8) (proc uintptr, err Errno)
+
+// A so implements access to a single shared library object.
+type so struct {
+	Name   string
+	Handle uintptr
+}
+
+// loadSO loads shared library file into memory.
+func loadSO(name string) (*so, error) {
+	namep, err := BytePtrFromString(name)
+	if err != nil {
+		return nil, err
+	}
+	h, e := dlopen(namep, 1) // RTLD_LAZY
+	if e != 0 {
+		return nil, &soError{
+			Err:     e,
+			ObjName: name,
+			Msg:     "Failed to load " + name + ": " + e.Error(),
+		}
+	}
+	d := &so{
+		Name:   name,
+		Handle: uintptr(h),
+	}
+	return d, nil
+}
+
+// mustLoadSO is like loadSO but panics if load operation fails.
+func mustLoadSO(name string) *so {
+	d, e := loadSO(name)
+	if e != nil {
+		panic(e)
+	}
+	return d
+}
+
+// FindProc searches shared library d for procedure named name and returns
+// *proc if found. It returns an error if the search fails.
+func (d *so) FindProc(name string) (*proc, error) {
+	namep, err := BytePtrFromString(name)
+	if err != nil {
+		return nil, err
+	}
+	a, _ := dlsym(uintptr(d.Handle), namep)
+	if a == 0 {
+		return nil, &soError{
+			Err:     ENOSYS,
+			ObjName: name,
+			Msg:     "Failed to find " + name + " procedure in " + d.Name,
+		}
+	}
+	p := &proc{
+		SO:   d,
+		Name: name,
+		addr: a,
+	}
+	return p, nil
+}
+
+// MustFindProc is like FindProc but panics if search fails.
+func (d *so) MustFindProc(name string) *proc {
+	p, e := d.FindProc(name)
+	if e != nil {
+		panic(e)
+	}
+	return p
+}
+
+// Release unloads shared library d from memory.
+func (d *so) Release() (err error) {
+	return dlclose(d.Handle)
+}
+
+// A proc implements access to a procedure inside a shared library.
+type proc struct {
+	SO   *so
+	Name string
+	addr uintptr
+}
+
+// Addr returns the address of the procedure represented by p.
+// The return value can be passed to Syscall to run the procedure.
+func (p *proc) Addr() uintptr {
+	return p.addr
+}
+
+// Call executes procedure p with arguments a. It will panic, if more then
+// 6 arguments are supplied.
+//
+// The returned error is always non-nil, constructed from the result of
+// GetLastError.  Callers must inspect the primary return value to decide
+// whether an error occurred (according to the semantics of the specific
+// function being called) before consulting the error. The error will be
+// guaranteed to contain syscall.Errno.
+func (p *proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
+	switch len(a) {
+	case 0:
+		return sysvicall6(p.Addr(), uintptr(len(a)), 0, 0, 0, 0, 0, 0)
+	case 1:
+		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], 0, 0, 0, 0, 0)
+	case 2:
+		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], 0, 0, 0, 0)
+	case 3:
+		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], 0, 0, 0)
+	case 4:
+		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
+	case 5:
+		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
+	case 6:
+		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
+	default:
+		panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
+	}
+	return
+}
+
+// A lazySO implements access to a single shared library.  It will delay
+// the load of the shared library until the first call to its Handle method
+// or to one of its lazyProc's Addr method.
+type lazySO struct {
+	mu   sync.Mutex
+	so   *so // non nil once SO is loaded
+	Name string
+}
+
+// Load loads single shared file d.Name into memory. It returns an error if
+// fails.  Load will not try to load SO, if it is already loaded into memory.
+func (d *lazySO) Load() error {
+	// Non-racy version of:
+	// if d.so == nil {
+	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.so))) == nil {
+		d.mu.Lock()
+		defer d.mu.Unlock()
+		if d.so == nil {
+			so, e := loadSO(d.Name)
+			if e != nil {
+				return e
+			}
+			// Non-racy version of:
+			// d.so = so
+			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.so)), unsafe.Pointer(so))
+		}
+	}
+	return nil
+}
+
+// mustLoad is like Load but panics if search fails.
+func (d *lazySO) mustLoad() {
+	e := d.Load()
+	if e != nil {
+		panic(e)
+	}
+}
+
+// Handle returns d's module handle.
+func (d *lazySO) Handle() uintptr {
+	d.mustLoad()
+	return uintptr(d.so.Handle)
+}
+
+// NewProc returns a lazyProc for accessing the named procedure in the SO d.
+func (d *lazySO) NewProc(name string) *lazyProc {
+	return &lazyProc{l: d, Name: name}
+}
+
+// newLazySO creates new lazySO associated with SO file.
+func newLazySO(name string) *lazySO {
+	return &lazySO{Name: name}
+}
+
+// A lazyProc implements access to a procedure inside a lazySO.
+// It delays the lookup until the Addr method is called.
+type lazyProc struct {
+	mu   sync.Mutex
+	Name string
+	l    *lazySO
+	proc *proc
+}
+
+// Find searches the shared library for procedure named p.Name. It returns an
+// error if search fails. Find will not search procedure, if it is already
+// found and loaded into memory.
+func (p *lazyProc) Find() error {
+	// Non-racy version of:
+	// if p.proc == nil {
+	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
+		p.mu.Lock()
+		defer p.mu.Unlock()
+		if p.proc == nil {
+			e := p.l.Load()
+			if e != nil {
+				return e
+			}
+			proc, e := p.l.so.FindProc(p.Name)
+			if e != nil {
+				return e
+			}
+			// Non-racy version of:
+			// p.proc = proc
+			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
+		}
+	}
+	return nil
+}
+
+// mustFind is like Find but panics if search fails.
+func (p *lazyProc) mustFind() {
+	e := p.Find()
+	if e != nil {
+		panic(e)
+	}
+}
+
+// Addr returns the address of the procedure represented by p.
+// The return value can be passed to Syscall to run the procedure.
+func (p *lazyProc) Addr() uintptr {
+	p.mustFind()
+	return p.proc.Addr()
+}
+
+// Call executes procedure p with arguments a. It will panic, if more then
+// 6 arguments are supplied.
+//
+// The returned error is always non-nil, constructed from the result of
+// GetLastError.  Callers must inspect the primary return value to decide
+// whether an error occurred (according to the semantics of the specific
+// function being called) before consulting the error. The error will be
+// guaranteed to contain syscall.Errno.
+func (p *lazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
+	p.mustFind()
+	return p.proc.Call(a...)
+}
diff --git a/src/pkg/syscall/sockcmsg_unix.go b/src/pkg/syscall/sockcmsg_unix.go
index a2d234f..045a012 100644
--- a/src/pkg/syscall/sockcmsg_unix.go
+++ b/src/pkg/syscall/sockcmsg_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 netbsd openbsd solaris
 
 // Socket control messages
 
@@ -13,9 +13,9 @@ import "unsafe"
 // Round the length of a raw sockaddr up to align it properly.
 func cmsgAlignOf(salen int) int {
 	salign := sizeofPtr
-	// NOTE: It seems like 64-bit Darwin kernel still requires 32-bit
-	// aligned access to BSD subsystem.
-	if darwin64Bit {
+	// NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels
+	// still require 32-bit aligned access to network subsystem.
+	if darwin64Bit || dragonfly64Bit {
 		salign = 4
 	}
 	return (salen + salign - 1) & ^(salign - 1)
diff --git a/src/pkg/syscall/srpc_nacl.go b/src/pkg/syscall/srpc_nacl.go
new file mode 100644
index 0000000..dd07373
--- /dev/null
+++ b/src/pkg/syscall/srpc_nacl.go
@@ -0,0 +1,822 @@
+// 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.
+
+// Native Client SRPC message passing.
+// This code is needed to invoke SecureRandom, the NaCl equivalent of /dev/random.
+
+package syscall
+
+import (
+	"errors"
+	"sync"
+	"unsafe"
+)
+
+// An srpcClient represents the client side of an SRPC connection.
+type srpcClient struct {
+	fd      int // to server
+	r       msgReceiver
+	s       msgSender
+	service map[string]srpcService // services by name
+
+	outMu sync.Mutex // protects writing to connection
+
+	mu      sync.Mutex // protects following fields
+	muxer   bool       // is someone reading and muxing responses
+	pending map[uint32]*srpc
+	idGen   uint32 // generator for request IDs
+}
+
+// An srpcService is a single method that the server offers.
+type srpcService struct {
+	num uint32 // method number
+	fmt string // argument format; see "parsing of RPC messages" below
+}
+
+// An srpc represents a single srpc issued by a client.
+type srpc struct {
+	Ret  []interface{}
+	Done chan *srpc
+	Err  error
+	c    *srpcClient
+	id   uint32
+}
+
+// newClient allocates a new SRPC client using the file descriptor fd.
+func newClient(fd int) (*srpcClient, error) {
+	c := new(srpcClient)
+	c.fd = fd
+	c.r.fd = fd
+	c.s.fd = fd
+	c.service = make(map[string]srpcService)
+	c.pending = make(map[uint32]*srpc)
+
+	// service discovery request
+	m := &msg{
+		isRequest: 1,
+		template:  []interface{}{[]byte(nil)},
+		size:      []int{4000}, // max size to accept for returned byte slice
+	}
+	if err := m.pack(); err != nil {
+		return nil, errors.New("Native Client SRPC service_discovery: preparing request: " + err.Error())
+	}
+	c.s.send(m)
+	m, err := c.r.recv()
+	if err != nil {
+		return nil, err
+	}
+	m.unpack()
+	if m.status != uint32(srpcOK) {
+		return nil, errors.New("Native Client SRPC service_discovery: " + srpcErrno(m.status).Error())
+	}
+	list := m.value[0].([]byte)
+	var n uint32
+	for len(list) > 0 {
+		var line []byte
+		i := byteIndex(list, '\n')
+		if i < 0 {
+			line, list = list, nil
+		} else {
+			line, list = list[:i], list[i+1:]
+		}
+		i = byteIndex(line, ':')
+		if i >= 0 {
+			c.service[string(line)] = srpcService{n, string(line[i+1:])}
+		}
+		n++
+	}
+
+	return c, nil
+}
+
+func byteIndex(b []byte, c byte) int {
+	for i, bi := range b {
+		if bi == c {
+			return i
+		}
+	}
+	return -1
+}
+
+var yourTurn srpc
+
+func (c *srpcClient) wait(r *srpc) {
+	var rx *srpc
+	for rx = range r.Done {
+		if rx != &yourTurn {
+			break
+		}
+		c.input()
+	}
+	return
+}
+
+func (c *srpcClient) input() {
+	// read message
+	m, err := c.r.recv()
+	if err != nil {
+		println("Native Client SRPC receive error:", err.Error())
+		return
+	}
+	if m.unpack(); m.status != uint32(srpcOK) {
+		println("Native Client SRPC receive error: invalid message: ", srpcErrno(m.status).Error())
+		return
+	}
+
+	// deliver to intended recipient
+	c.mu.Lock()
+	rpc, ok := c.pending[m.id]
+	if ok {
+		delete(c.pending, m.id)
+	}
+
+	// wake a new muxer if there are more RPCs to read
+	c.muxer = false
+	for _, rpc := range c.pending {
+		c.muxer = true
+		rpc.Done <- &yourTurn
+		break
+	}
+	c.mu.Unlock()
+	if !ok {
+		println("Native Client: unexpected response for ID", m.id)
+		return
+	}
+	rpc.Ret = m.value
+	rpc.Done <- rpc
+}
+
+// Wait blocks until the RPC has finished.
+func (r *srpc) Wait() {
+	r.c.wait(r)
+}
+
+// Start issues an RPC request for method name with the given arguments.
+// The RPC r must not be in use for another pending request.
+// To wait for the RPC to finish, receive from r.Done and then
+// inspect r.Ret and r.Errno.
+func (r *srpc) Start(name string, arg []interface{}) {
+	r.Err = nil
+	r.c.mu.Lock()
+	srv, ok := r.c.service[name]
+	if !ok {
+		r.c.mu.Unlock()
+		r.Err = srpcErrBadRPCNumber
+		r.Done <- r
+		return
+	}
+	r.c.pending[r.id] = r
+	if !r.c.muxer {
+		r.c.muxer = true
+		r.Done <- &yourTurn
+	}
+	r.c.mu.Unlock()
+
+	var m msg
+	m.id = r.id
+	m.isRequest = 1
+	m.rpc = srv.num
+	m.value = arg
+
+	// Fill in the return values and sizes to generate
+	// the right type chars.  We'll take most any size.
+
+	// Skip over input arguments.
+	// We could check them against arg, but the server
+	// will do that anyway.
+	i := 0
+	for srv.fmt[i] != ':' {
+		i++
+	}
+	format := srv.fmt[i+1:]
+
+	// Now the return prototypes.
+	m.template = make([]interface{}, len(format))
+	m.size = make([]int, len(format))
+	for i := 0; i < len(format); i++ {
+		switch format[i] {
+		default:
+			println("Native Client SRPC: unexpected service type " + string(format[i]))
+			r.Err = srpcErrBadRPCNumber
+			r.Done <- r
+			return
+		case 'b':
+			m.template[i] = false
+		case 'C':
+			m.template[i] = []byte(nil)
+			m.size[i] = 1 << 30
+		case 'd':
+			m.template[i] = float64(0)
+		case 'D':
+			m.template[i] = []float64(nil)
+			m.size[i] = 1 << 30
+		case 'h':
+			m.template[i] = int(-1)
+		case 'i':
+			m.template[i] = int32(0)
+		case 'I':
+			m.template[i] = []int32(nil)
+			m.size[i] = 1 << 30
+		case 's':
+			m.template[i] = ""
+			m.size[i] = 1 << 30
+		}
+	}
+
+	if err := m.pack(); err != nil {
+		r.Err = errors.New("Native Client RPC Start " + name + ": preparing request: " + err.Error())
+		r.Done <- r
+		return
+	}
+
+	r.c.outMu.Lock()
+	r.c.s.send(&m)
+	r.c.outMu.Unlock()
+}
+
+// Call is a convenience wrapper that starts the RPC request,
+// waits for it to finish, and then returns the results.
+// Its implementation is:
+//
+//	r.Start(name, arg)
+//	r.Wait()
+//	return r.Ret, r.Errno
+//
+func (c *srpcClient) Call(name string, arg ...interface{}) (ret []interface{}, err error) {
+	r := c.NewRPC(nil)
+	r.Start(name, arg)
+	r.Wait()
+	return r.Ret, r.Err
+}
+
+// NewRPC creates a new RPC on the client connection.
+func (c *srpcClient) NewRPC(done chan *srpc) *srpc {
+	if done == nil {
+		done = make(chan *srpc, 1)
+	}
+	c.mu.Lock()
+	id := c.idGen
+	c.idGen++
+	c.mu.Unlock()
+	return &srpc{Done: done, c: c, id: id}
+}
+
+// The current protocol number.
+// Kind of useless, since there have been backwards-incompatible changes
+// to the wire protocol that did not update the protocol number.
+// At this point it's really just a sanity check.
+const protocol = 0xc0da0002
+
+// An srpcErrno is an SRPC status code.
+type srpcErrno uint32
+
+const (
+	srpcOK srpcErrno = 256 + iota
+	srpcErrBreak
+	srpcErrMessageTruncated
+	srpcErrNoMemory
+	srpcErrProtocolMismatch
+	srpcErrBadRPCNumber
+	srpcErrBadArgType
+	srpcErrTooFewArgs
+	srpcErrTooManyArgs
+	srpcErrInArgTypeMismatch
+	srpcErrOutArgTypeMismatch
+	srpcErrInternalError
+	srpcErrAppError
+)
+
+var srpcErrstr = [...]string{
+	srpcOK - srpcOK:                    "ok",
+	srpcErrBreak - srpcOK:              "break",
+	srpcErrMessageTruncated - srpcOK:   "message truncated",
+	srpcErrNoMemory - srpcOK:           "out of memory",
+	srpcErrProtocolMismatch - srpcOK:   "protocol mismatch",
+	srpcErrBadRPCNumber - srpcOK:       "invalid RPC method number",
+	srpcErrBadArgType - srpcOK:         "unexpected argument type",
+	srpcErrTooFewArgs - srpcOK:         "too few arguments",
+	srpcErrTooManyArgs - srpcOK:        "too many arguments",
+	srpcErrInArgTypeMismatch - srpcOK:  "input argument type mismatch",
+	srpcErrOutArgTypeMismatch - srpcOK: "output argument type mismatch",
+	srpcErrInternalError - srpcOK:      "internal error",
+	srpcErrAppError - srpcOK:           "application error",
+}
+
+func (e srpcErrno) Error() string {
+	if e < srpcOK || int(e-srpcOK) >= len(srpcErrstr) {
+		return "srpcErrno(" + itoa(int(e)) + ")"
+	}
+	return srpcErrstr[e-srpcOK]
+}
+
+// A msgHdr is the data argument to the imc_recvmsg
+// and imc_sendmsg system calls.
+type msgHdr struct {
+	iov   *iov
+	niov  int32
+	desc  *int32
+	ndesc int32
+	flags uint32
+}
+
+// A single region for I/O.
+type iov struct {
+	base *byte
+	len  int32
+}
+
+const maxMsgSize = 1<<16 - 4*4
+
+// A msgReceiver receives messages from a file descriptor.
+type msgReceiver struct {
+	fd   int
+	data [maxMsgSize]byte
+	desc [8]int32
+	hdr  msgHdr
+	iov  iov
+}
+
+func (r *msgReceiver) recv() (*msg, error) {
+	// Init pointers to buffers where syscall recvmsg can write.
+	r.iov.base = &r.data[0]
+	r.iov.len = int32(len(r.data))
+	r.hdr.iov = &r.iov
+	r.hdr.niov = 1
+	r.hdr.desc = &r.desc[0]
+	r.hdr.ndesc = int32(len(r.desc))
+	n, _, e := Syscall(sys_imc_recvmsg, uintptr(r.fd), uintptr(unsafe.Pointer(&r.hdr)), 0)
+	if e != 0 {
+		println("Native Client imc_recvmsg: ", e.Error())
+		return nil, e
+	}
+
+	// Make a copy of the data so that the next recvmsg doesn't
+	// smash it.  The system call did not update r.iov.len.  Instead it
+	// returned the total byte count as n.
+	m := new(msg)
+	m.data = make([]byte, n)
+	copy(m.data, r.data[0:])
+
+	// Make a copy of the desc too.
+	// The system call *did* update r.hdr.ndesc.
+	if r.hdr.ndesc > 0 {
+		m.desc = make([]int32, r.hdr.ndesc)
+		copy(m.desc, r.desc[:])
+	}
+
+	return m, nil
+}
+
+// A msgSender sends messages on a file descriptor.
+type msgSender struct {
+	fd  int
+	hdr msgHdr
+	iov iov
+}
+
+func (s *msgSender) send(m *msg) error {
+	if len(m.data) > 0 {
+		s.iov.base = &m.data[0]
+	}
+	s.iov.len = int32(len(m.data))
+	s.hdr.iov = &s.iov
+	s.hdr.niov = 1
+	s.hdr.desc = nil
+	s.hdr.ndesc = 0
+	_, _, e := Syscall(sys_imc_sendmsg, uintptr(s.fd), uintptr(unsafe.Pointer(&s.hdr)), 0)
+	if e != 0 {
+		println("Native Client imc_sendmsg: ", e.Error())
+		return e
+	}
+	return nil
+}
+
+// A msg is the Go representation of an SRPC message.
+type msg struct {
+	data []byte  // message data
+	desc []int32 // message file descriptors
+
+	// parsed version of message
+	id        uint32
+	isRequest uint32
+	rpc       uint32
+	status    uint32
+	value     []interface{}
+	template  []interface{}
+	size      []int
+	format    string
+	broken    bool
+}
+
+// reading from a msg
+
+func (m *msg) uint32() uint32 {
+	if m.broken {
+		return 0
+	}
+	if len(m.data) < 4 {
+		m.broken = true
+		return 0
+	}
+	b := m.data[:4]
+	x := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+	m.data = m.data[4:]
+	return x
+}
+
+func (m *msg) uint64() uint64 {
+	x := uint64(m.uint32()) | uint64(m.uint32())<<32
+	if m.broken {
+		return 0
+	}
+	return x
+}
+
+func (m *msg) bytes(n int) []byte {
+	if m.broken {
+		return nil
+	}
+	if len(m.data) < n {
+		m.broken = true
+		return nil
+	}
+	x := m.data[0:n]
+	m.data = m.data[n:]
+	return x
+}
+
+// writing to a msg
+
+func (m *msg) wuint32(x uint32) {
+	m.data = append(m.data, byte(x), byte(x>>8), byte(x>>16), byte(x>>24))
+}
+
+func (m *msg) wuint64(x uint64) {
+	lo := uint32(x)
+	hi := uint32(x >> 32)
+	m.data = append(m.data, byte(lo), byte(lo>>8), byte(lo>>16), byte(lo>>24), byte(hi), byte(hi>>8), byte(hi>>16), byte(hi>>24))
+}
+
+func (m *msg) wbytes(p []byte) {
+	m.data = append(m.data, p...)
+}
+
+func (m *msg) wstring(s string) {
+	m.data = append(m.data, s...)
+}
+
+// Parsing of RPC messages.
+//
+// Each message begins with
+//	total_size uint32
+//	total_descs uint32
+//	fragment_size uint32
+//	fragment_descs uint32
+//
+// If fragment_size < total_size or fragment_descs < total_descs, the actual
+// message is broken up in multiple messages; follow-up messages omit
+// the "total" fields and begin with the "fragment" fields.
+// We do not support putting fragmented messages back together.
+// To do this we would need to change the message receiver.
+//
+// After that size information, the message header follows:
+//	protocol uint32
+//	requestID uint32
+//	isRequest uint32
+//	rpcNumber uint32
+//	status uint32
+//	numValue uint32
+//	numTemplate uint32
+//
+// After the header come numTemplate fixed-size arguments,
+// numValue fixed-size arguments, and then the variable-sized
+// part of the values. The templates describe the expected results
+// and have no associated variable sized data in the request.
+//
+// Each fixed-size argument has the form:
+//	tag uint32 // really a char, like 'b' or 'C'
+//	pad uint32 // unused
+//	val1 uint32
+//	val2 uint32
+//
+// The tags are:
+//	'b':	bool; val1 == 0 or 1
+//	'C':	[]byte; val1 == len, data in variable-sized section
+//	'd':	float64; (val1, val2) is data
+//	'D':	[]float64; val1 == len, data in variable-sized section
+//	'h':	int; val1 == file descriptor
+//	'i':	int32; descriptor in next entry in m.desc
+//	'I':	[]int; val1 == len, data in variable-sized section
+//	's':	string; val1 == len, data in variable-sized section
+//
+
+func (m *msg) pack() error {
+	m.data = m.data[:0]
+	m.desc = m.desc[:0]
+
+	// sizes, to fill in later
+	m.wuint32(0)
+	m.wuint32(0)
+	m.wuint32(0)
+	m.wuint32(0)
+
+	// message header
+	m.wuint32(protocol)
+	m.wuint32(m.id)
+	m.wuint32(m.isRequest)
+	m.wuint32(m.rpc)
+	m.wuint32(m.status)
+	m.wuint32(uint32(len(m.value)))
+	m.wuint32(uint32(len(m.template)))
+
+	// fixed-size templates
+	for i, x := range m.template {
+		var tag, val1, val2 uint32
+		switch x.(type) {
+		default:
+			return errors.New("unexpected template type")
+		case bool:
+			tag = 'b'
+		case []byte:
+			tag = 'C'
+			val1 = uint32(m.size[i])
+		case float64:
+			tag = 'd'
+		case []float64:
+			tag = 'D'
+			val1 = uint32(m.size[i])
+		case int:
+			tag = 'h'
+		case int32:
+			tag = 'i'
+		case []int32:
+			tag = 'I'
+			val1 = uint32(m.size[i])
+		case string:
+			tag = 's'
+			val1 = uint32(m.size[i])
+		}
+		m.wuint32(tag)
+		m.wuint32(0)
+		m.wuint32(val1)
+		m.wuint32(val2)
+	}
+
+	// fixed-size values
+	for _, x := range m.value {
+		var tag, val1, val2 uint32
+		switch x := x.(type) {
+		default:
+			return errors.New("unexpected value type")
+		case bool:
+			tag = 'b'
+			if x {
+				val1 = 1
+			}
+		case []byte:
+			tag = 'C'
+			val1 = uint32(len(x))
+		case float64:
+			tag = 'd'
+			v := float64bits(x)
+			val1 = uint32(v)
+			val2 = uint32(v >> 32)
+		case []float64:
+			tag = 'D'
+			val1 = uint32(len(x))
+		case int32:
+			tag = 'i'
+			m.desc = append(m.desc, x)
+		case []int32:
+			tag = 'I'
+			val1 = uint32(len(x))
+		case string:
+			tag = 's'
+			val1 = uint32(len(x) + 1)
+		}
+		m.wuint32(tag)
+		m.wuint32(0)
+		m.wuint32(val1)
+		m.wuint32(val2)
+	}
+
+	// variable-length data for values
+	for _, x := range m.value {
+		switch x := x.(type) {
+		case []byte:
+			m.wbytes(x)
+		case []float64:
+			for _, f := range x {
+				m.wuint64(float64bits(f))
+			}
+		case []int32:
+			for _, j := range x {
+				m.wuint32(uint32(j))
+			}
+		case string:
+			m.wstring(x)
+			m.wstring("\x00")
+		}
+	}
+
+	// fill in sizes
+	data := m.data
+	m.data = m.data[:0]
+	m.wuint32(uint32(len(data)))
+	m.wuint32(uint32(len(m.desc)))
+	m.wuint32(uint32(len(data)))
+	m.wuint32(uint32(len(m.desc)))
+	m.data = data
+
+	return nil
+}
+
+func (m *msg) unpack() error {
+	totalSize := m.uint32()
+	totalDesc := m.uint32()
+	fragSize := m.uint32()
+	fragDesc := m.uint32()
+	if totalSize != fragSize || totalDesc != fragDesc {
+		return errors.New("Native Client: fragmented RPC messages not supported")
+	}
+	if m.uint32() != protocol {
+		return errors.New("Native Client: RPC protocol mismatch")
+	}
+
+	// message header
+	m.id = m.uint32()
+	m.isRequest = m.uint32()
+	m.rpc = m.uint32()
+	m.status = m.uint32()
+	m.value = make([]interface{}, m.uint32())
+	m.template = make([]interface{}, m.uint32())
+	m.size = make([]int, len(m.template))
+	if m.broken {
+		return errors.New("Native Client: malformed message")
+	}
+
+	// fixed-size templates
+	for i := range m.template {
+		tag := m.uint32()
+		m.uint32() // padding
+		val1 := m.uint32()
+		m.uint32() // val2
+		switch tag {
+		default:
+			return errors.New("Native Client: unexpected template type " + string(rune(tag)))
+		case 'b':
+			m.template[i] = false
+		case 'C':
+			m.template[i] = []byte(nil)
+			m.size[i] = int(val1)
+		case 'd':
+			m.template[i] = float64(0)
+		case 'D':
+			m.template[i] = []float64(nil)
+			m.size[i] = int(val1)
+		case 'i':
+			m.template[i] = int32(0)
+		case 'I':
+			m.template[i] = []int32(nil)
+			m.size[i] = int(val1)
+		case 'h':
+			m.template[i] = int(0)
+		case 's':
+			m.template[i] = ""
+			m.size[i] = int(val1)
+		}
+	}
+
+	// fixed-size values
+	var (
+		strsize []uint32
+		d       int
+	)
+	for i := range m.value {
+		tag := m.uint32()
+		m.uint32() // padding
+		val1 := m.uint32()
+		val2 := m.uint32()
+		switch tag {
+		default:
+			return errors.New("Native Client: unexpected value type " + string(rune(tag)))
+		case 'b':
+			m.value[i] = val1 > 0
+		case 'C':
+			m.value[i] = []byte(nil)
+			strsize = append(strsize, val1)
+		case 'd':
+			m.value[i] = float64frombits(uint64(val1) | uint64(val2)<<32)
+		case 'D':
+			m.value[i] = make([]float64, val1)
+		case 'i':
+			m.value[i] = int32(val1)
+		case 'I':
+			m.value[i] = make([]int32, val1)
+		case 'h':
+			m.value[i] = int(m.desc[d])
+			d++
+		case 's':
+			m.value[i] = ""
+			strsize = append(strsize, val1)
+		}
+	}
+
+	// variable-sized parts of values
+	for i, x := range m.value {
+		switch x := x.(type) {
+		case []byte:
+			m.value[i] = m.bytes(int(strsize[0]))
+			strsize = strsize[1:]
+		case []float64:
+			for i := range x {
+				x[i] = float64frombits(m.uint64())
+			}
+		case []int32:
+			for i := range x {
+				x[i] = int32(m.uint32())
+			}
+		case string:
+			m.value[i] = string(m.bytes(int(strsize[0])))
+			strsize = strsize[1:]
+		}
+	}
+
+	if len(m.data) > 0 {
+		return errors.New("Native Client: junk at end of message")
+	}
+	return nil
+}
+
+func float64bits(x float64) uint64 {
+	return *(*uint64)(unsafe.Pointer(&x))
+}
+
+func float64frombits(x uint64) float64 {
+	return *(*float64)(unsafe.Pointer(&x))
+}
+
+// At startup, connect to the name service.
+var nsClient = nsConnect()
+
+func nsConnect() *srpcClient {
+	var ns int32 = -1
+	_, _, errno := Syscall(sys_nameservice, uintptr(unsafe.Pointer(&ns)), 0, 0)
+	if errno != 0 {
+		println("Native Client nameservice:", errno.Error())
+		return nil
+	}
+
+	sock, _, errno := Syscall(sys_imc_connect, uintptr(ns), 0, 0)
+	if errno != 0 {
+		println("Native Client nameservice connect:", errno.Error())
+		return nil
+	}
+
+	c, err := newClient(int(sock))
+	if err != nil {
+		println("Native Client nameservice init:", err.Error())
+		return nil
+	}
+
+	return c
+}
+
+const (
+	nsSuccess               = 0
+	nsNameNotFound          = 1
+	nsDuplicateName         = 2
+	nsInsufficientResources = 3
+	nsPermissionDenied      = 4
+	nsInvalidArgument       = 5
+)
+
+func openNamedService(name string, mode int32) (fd int, err error) {
+	if nsClient == nil {
+		return 0, errors.New("no name service")
+	}
+	ret, err := nsClient.Call("lookup:si:ih", name, int32(mode))
+	if err != nil {
+		return 0, err
+	}
+	status := ret[0].(int32)
+	fd = ret[1].(int)
+	switch status {
+	case nsSuccess:
+		// ok
+	case nsNameNotFound:
+		return -1, ENOENT
+	case nsDuplicateName:
+		return -1, EEXIST
+	case nsInsufficientResources:
+		return -1, EWOULDBLOCK
+	case nsPermissionDenied:
+		return -1, EPERM
+	case nsInvalidArgument:
+		return -1, EINVAL
+	default:
+		return -1, EINVAL
+	}
+	return fd, nil
+}
diff --git a/src/pkg/syscall/syscall_bsd.go b/src/pkg/syscall/syscall_bsd.go
index 76b1f41..b042841 100644
--- a/src/pkg/syscall/syscall_bsd.go
+++ b/src/pkg/syscall/syscall_bsd.go
@@ -64,8 +64,11 @@ func Setgroups(gids []int) (err error) {
 
 func ReadDirent(fd int, buf []byte) (n int, err error) {
 	// Final argument is (basep *uintptr) and the syscall doesn't take nil.
+	// 64 bits should be enough. (32 bits isn't even on 386). Since the
+	// actual system call is getdirentries64, 64 is a good guess.
 	// TODO(rsc): Can we use a single global basep for all calls?
-	return Getdirentries(fd, buf, new(uintptr))
+	var base = (*uintptr)(unsafe.Pointer(new(uint64)))
+	return Getdirentries(fd, buf, base)
 }
 
 // Wait status is 7 bits at bottom, either 0 (exited),
@@ -131,18 +134,18 @@ func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int,
 }
 
 //sys	accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
-//sys	bind(s int, addr uintptr, addrlen _Socklen) (err error)
-//sys	connect(s int, addr uintptr, addrlen _Socklen) (err error)
+//sys	bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sys	connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
 //sysnb	socket(domain int, typ int, proto int) (fd int, err error)
-//sys	getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error)
-//sys	setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error)
+//sys	getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
+//sys	setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
 //sysnb	getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
 //sysnb	getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
 //sys	Shutdown(s int, how int) (err error)
 
-func (sa *SockaddrInet4) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
 	if sa.Port < 0 || sa.Port > 0xFFFF {
-		return 0, 0, EINVAL
+		return nil, 0, EINVAL
 	}
 	sa.raw.Len = SizeofSockaddrInet4
 	sa.raw.Family = AF_INET
@@ -152,12 +155,12 @@ func (sa *SockaddrInet4) sockaddr() (uintptr, _Socklen, error) {
 	for i := 0; i < len(sa.Addr); i++ {
 		sa.raw.Addr[i] = sa.Addr[i]
 	}
-	return uintptr(unsafe.Pointer(&sa.raw)), _Socklen(sa.raw.Len), nil
+	return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil
 }
 
-func (sa *SockaddrInet6) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) {
 	if sa.Port < 0 || sa.Port > 0xFFFF {
-		return 0, 0, EINVAL
+		return nil, 0, EINVAL
 	}
 	sa.raw.Len = SizeofSockaddrInet6
 	sa.raw.Family = AF_INET6
@@ -168,26 +171,26 @@ func (sa *SockaddrInet6) sockaddr() (uintptr, _Socklen, error) {
 	for i := 0; i < len(sa.Addr); i++ {
 		sa.raw.Addr[i] = sa.Addr[i]
 	}
-	return uintptr(unsafe.Pointer(&sa.raw)), _Socklen(sa.raw.Len), nil
+	return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil
 }
 
-func (sa *SockaddrUnix) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
 	name := sa.Name
 	n := len(name)
 	if n >= len(sa.raw.Path) || n == 0 {
-		return 0, 0, EINVAL
+		return nil, 0, EINVAL
 	}
 	sa.raw.Len = byte(3 + n) // 2 for Family, Len; 1 for NUL
 	sa.raw.Family = AF_UNIX
 	for i := 0; i < n; i++ {
 		sa.raw.Path[i] = int8(name[i])
 	}
-	return uintptr(unsafe.Pointer(&sa.raw)), _Socklen(sa.raw.Len), nil
+	return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil
 }
 
-func (sa *SockaddrDatalink) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrDatalink) sockaddr() (unsafe.Pointer, _Socklen, error) {
 	if sa.Index == 0 {
-		return 0, 0, EINVAL
+		return nil, 0, EINVAL
 	}
 	sa.raw.Len = sa.Len
 	sa.raw.Family = AF_LINK
@@ -199,7 +202,7 @@ func (sa *SockaddrDatalink) sockaddr() (uintptr, _Socklen, error) {
 	for i := 0; i < len(sa.raw.Data); i++ {
 		sa.raw.Data[i] = sa.Data[i]
 	}
-	return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrDatalink, nil
+	return unsafe.Pointer(&sa.raw), SizeofSockaddrDatalink, nil
 }
 
 func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
@@ -221,14 +224,20 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
 
 	case AF_UNIX:
 		pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
-		if pp.Len < 3 || pp.Len > SizeofSockaddrUnix {
+		if pp.Len < 2 || pp.Len > SizeofSockaddrUnix {
 			return nil, EINVAL
 		}
 		sa := new(SockaddrUnix)
-		n := int(pp.Len) - 3 // subtract leading Family, Len, terminating NUL
+
+		// Some BSDs include the trailing NUL in the length, whereas
+		// others do not. Work around this by subtracting the leading
+		// family and len. The path is then scanned to see if a NUL
+		// terminator still exists within the length.
+		n := int(pp.Len) - 2 // subtract leading Family, Len
 		for i := 0; i < n; i++ {
 			if pp.Path[i] == 0 {
-				// found early NUL; assume Len is overestimating
+				// found early NUL; assume Len included the NUL
+				// or was overestimating.
 				n = i
 				break
 			}
@@ -290,10 +299,9 @@ func Getsockname(fd int) (sa Sockaddr, err error) {
 	if err = getsockname(fd, &rsa, &len); err != nil {
 		return
 	}
-	// TODO(jsing): Remove after OpenBSD 5.4 is released (see issue 3349).
-	// TODO(jsing): Apparently dragonfly has the same "bug", which should
-	// be reported upstream.
-	if (runtime.GOOS == "dragonfly" || runtime.GOOS == "openbsd") && rsa.Addr.Family == AF_UNSPEC && rsa.Addr.Len == 0 {
+	// TODO(jsing): DragonFly has a "bug" (see issue 3349), which should be
+	// reported upstream.
+	if runtime.GOOS == "dragonfly" && rsa.Addr.Family == AF_UNSPEC && rsa.Addr.Len == 0 {
 		rsa.Addr.Family = AF_UNIX
 		rsa.Addr.Len = SizeofSockaddrUnix
 	}
@@ -305,46 +313,46 @@ func Getsockname(fd int) (sa Sockaddr, err error) {
 func GetsockoptByte(fd, level, opt int) (value byte, err error) {
 	var n byte
 	vallen := _Socklen(1)
-	err = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), &vallen)
+	err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
 	return n, err
 }
 
 func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) {
 	vallen := _Socklen(4)
-	err = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value[0])), &vallen)
+	err = getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen)
 	return value, err
 }
 
 func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) {
 	var value IPMreq
 	vallen := _Socklen(SizeofIPMreq)
-	err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+	err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
 	return &value, err
 }
 
 func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) {
 	var value IPv6Mreq
 	vallen := _Socklen(SizeofIPv6Mreq)
-	err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+	err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
 	return &value, err
 }
 
 func GetsockoptIPv6MTUInfo(fd, level, opt int) (*IPv6MTUInfo, error) {
 	var value IPv6MTUInfo
 	vallen := _Socklen(SizeofIPv6MTUInfo)
-	err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+	err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
 	return &value, err
 }
 
 func GetsockoptICMPv6Filter(fd, level, opt int) (*ICMPv6Filter, error) {
 	var value ICMPv6Filter
 	vallen := _Socklen(SizeofICMPv6Filter)
-	err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+	err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
 	return &value, err
 }
 
 //sys   recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
-//sys   sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error)
+//sys   sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
 //sys	recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
 
 func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
@@ -381,15 +389,20 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
 	return
 }
 
-//sys	sendmsg(s int, msg *Msghdr, flags int) (err error)
+//sys	sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
 
 func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
-	var ptr uintptr
+	_, err = SendmsgN(fd, p, oob, to, flags)
+	return
+}
+
+func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
+	var ptr unsafe.Pointer
 	var salen _Socklen
 	if to != nil {
 		ptr, salen, err = to.sockaddr()
 		if err != nil {
-			return
+			return 0, err
 		}
 	}
 	var msg Msghdr
@@ -412,21 +425,24 @@ func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
 	}
 	msg.Iov = &iov
 	msg.Iovlen = 1
-	if err = sendmsg(fd, &msg, flags); err != nil {
-		return
+	if n, err = sendmsg(fd, &msg, flags); err != nil {
+		return 0, err
 	}
-	return
+	if len(oob) > 0 && len(p) == 0 {
+		n = 0
+	}
+	return n, nil
 }
 
-//sys	kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error)
+//sys	kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error)
 
 func Kevent(kq int, changes, events []Kevent_t, timeout *Timespec) (n int, err error) {
-	var change, event uintptr
+	var change, event unsafe.Pointer
 	if len(changes) > 0 {
-		change = uintptr(unsafe.Pointer(&changes[0]))
+		change = unsafe.Pointer(&changes[0])
 	}
 	if len(events) > 0 {
-		event = uintptr(unsafe.Pointer(&events[0]))
+		event = unsafe.Pointer(&events[0])
 	}
 	return kevent(kq, change, len(changes), event, len(events), timeout)
 }
diff --git a/src/pkg/syscall/syscall_bsd_test.go b/src/pkg/syscall/syscall_bsd_test.go
new file mode 100644
index 0000000..c2ea089
--- /dev/null
+++ b/src/pkg/syscall/syscall_bsd_test.go
@@ -0,0 +1,34 @@
+// 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 darwin dragonfly freebsd openbsd
+
+package syscall_test
+
+import (
+	"syscall"
+	"testing"
+)
+
+const MNT_WAIT = 1
+
+func TestGetfsstat(t *testing.T) {
+	n, err := syscall.Getfsstat(nil, MNT_WAIT)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	data := make([]syscall.Statfs_t, n)
+	n, err = syscall.Getfsstat(data, MNT_WAIT)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	empty := syscall.Statfs_t{}
+	for _, stat := range data {
+		if stat == empty {
+			t.Fatal("an empty Statfs_t struct was returned")
+		}
+	}
+}
diff --git a/src/pkg/syscall/syscall_darwin.go b/src/pkg/syscall/syscall_darwin.go
index bd929ff..97414dc 100644
--- a/src/pkg/syscall/syscall_darwin.go
+++ b/src/pkg/syscall/syscall_darwin.go
@@ -187,6 +187,21 @@ func Pipe(p []int) (err error) {
 	return
 }
 
+func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
+	var _p0 unsafe.Pointer
+	var bufsize uintptr
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+		bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
+	}
+	r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), bufsize, uintptr(flags))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
 /*
  * Wrapped
  */
@@ -224,7 +239,6 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1)
 //sys	Getdtablesize() (size int)
 //sysnb	Getegid() (egid int)
 //sysnb	Geteuid() (uid int)
-//sys	Getfsstat(buf []Statfs_t, flags int) (n int, err error) = SYS_GETFSSTAT64
 //sysnb	Getgid() (gid int)
 //sysnb	Getpgid(pid int) (pgid int, err error)
 //sysnb	Getpgrp() (pgrp int)
@@ -244,6 +258,11 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1)
 //sys	Mkdir(path string, mode uint32) (err error)
 //sys	Mkfifo(path string, mode uint32) (err error)
 //sys	Mknod(path string, mode uint32, dev int) (err error)
+//sys	Mlock(b []byte) (err error)
+//sys	Mlockall(flags int) (err error)
+//sys	Mprotect(b []byte, prot int) (err error)
+//sys	Munlock(b []byte) (err error)
+//sys	Munlockall() (err error)
 //sys	Open(path string, mode int, perm uint32) (fd int, err error)
 //sys	Pathconf(path string, name int) (val int, err error)
 //sys	Pread(fd int, p []byte, offset int64) (n int, err error)
diff --git a/src/pkg/syscall/syscall_dragonfly.go b/src/pkg/syscall/syscall_dragonfly.go
index e19a9ce..39c51df 100644
--- a/src/pkg/syscall/syscall_dragonfly.go
+++ b/src/pkg/syscall/syscall_dragonfly.go
@@ -101,6 +101,21 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	return extpwrite(fd, p, 0, offset)
 }
 
+func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
+	var _p0 unsafe.Pointer
+	var bufsize uintptr
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+		bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
+	}
+	r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
 /*
  * Exposed directly
  */
@@ -129,7 +144,6 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 //sys	Getdtablesize() (size int)
 //sysnb	Getegid() (egid int)
 //sysnb	Geteuid() (uid int)
-//sys	Getfsstat(buf []Statfs_t, flags int) (n int, err error)
 //sysnb	Getgid() (gid int)
 //sysnb	Getpgid(pid int) (pgid int, err error)
 //sysnb	Getpgrp() (pgrp int)
diff --git a/src/pkg/syscall/syscall_freebsd.go b/src/pkg/syscall/syscall_freebsd.go
index 9fbcc48..3d834f5 100644
--- a/src/pkg/syscall/syscall_freebsd.go
+++ b/src/pkg/syscall/syscall_freebsd.go
@@ -95,12 +95,45 @@ func Pipe(p []int) (err error) {
 func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) {
 	var value IPMreqn
 	vallen := _Socklen(SizeofIPMreqn)
-	errno := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+	errno := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
 	return &value, errno
 }
 
 func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
-	return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), unsafe.Sizeof(*mreq))
+	return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq))
+}
+
+func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) {
+	var rsa RawSockaddrAny
+	var len _Socklen = SizeofSockaddrAny
+	nfd, err = accept4(fd, &rsa, &len, flags)
+	if err != nil {
+		return
+	}
+	if len > SizeofSockaddrAny {
+		panic("RawSockaddrAny too small")
+	}
+	sa, err = anyToSockaddr(&rsa)
+	if err != nil {
+		Close(nfd)
+		nfd = 0
+	}
+	return
+}
+
+func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
+	var _p0 unsafe.Pointer
+	var bufsize uintptr
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+		bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
+	}
+	r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
 }
 
 /*
@@ -131,7 +164,6 @@ func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
 //sys	Getdtablesize() (size int)
 //sysnb	Getegid() (egid int)
 //sysnb	Geteuid() (uid int)
-//sys	Getfsstat(buf []Statfs_t, flags int) (n int, err error)
 //sysnb	Getgid() (gid int)
 //sysnb	Getpgid(pid int) (pgid int, err error)
 //sysnb	Getpgrp() (pgrp int)
@@ -191,6 +223,7 @@ func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
 //sys   munmap(addr uintptr, length uintptr) (err error)
 //sys	readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_READ
 //sys	writelen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_WRITE
+//sys	accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error)
 
 /*
  * Unimplemented
diff --git a/src/pkg/syscall/syscall_linux.go b/src/pkg/syscall/syscall_linux.go
index 79c1fda..fa0d7ea 100644
--- a/src/pkg/syscall/syscall_linux.go
+++ b/src/pkg/syscall/syscall_linux.go
@@ -230,9 +230,9 @@ func Mkfifo(path string, mode uint32) (err error) {
 	return Mknod(path, mode|S_IFIFO, 0)
 }
 
-func (sa *SockaddrInet4) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
 	if sa.Port < 0 || sa.Port > 0xFFFF {
-		return 0, 0, EINVAL
+		return nil, 0, EINVAL
 	}
 	sa.raw.Family = AF_INET
 	p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
@@ -241,12 +241,12 @@ func (sa *SockaddrInet4) sockaddr() (uintptr, _Socklen, error) {
 	for i := 0; i < len(sa.Addr); i++ {
 		sa.raw.Addr[i] = sa.Addr[i]
 	}
-	return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrInet4, nil
+	return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil
 }
 
-func (sa *SockaddrInet6) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) {
 	if sa.Port < 0 || sa.Port > 0xFFFF {
-		return 0, 0, EINVAL
+		return nil, 0, EINVAL
 	}
 	sa.raw.Family = AF_INET6
 	p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
@@ -256,14 +256,14 @@ func (sa *SockaddrInet6) sockaddr() (uintptr, _Socklen, error) {
 	for i := 0; i < len(sa.Addr); i++ {
 		sa.raw.Addr[i] = sa.Addr[i]
 	}
-	return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrInet6, nil
+	return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil
 }
 
-func (sa *SockaddrUnix) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
 	name := sa.Name
 	n := len(name)
 	if n >= len(sa.raw.Path) {
-		return 0, 0, EINVAL
+		return nil, 0, EINVAL
 	}
 	sa.raw.Family = AF_UNIX
 	for i := 0; i < n; i++ {
@@ -280,7 +280,7 @@ func (sa *SockaddrUnix) sockaddr() (uintptr, _Socklen, error) {
 		sl--
 	}
 
-	return uintptr(unsafe.Pointer(&sa.raw)), sl, nil
+	return unsafe.Pointer(&sa.raw), sl, nil
 }
 
 type SockaddrLinklayer struct {
@@ -293,9 +293,9 @@ type SockaddrLinklayer struct {
 	raw      RawSockaddrLinklayer
 }
 
-func (sa *SockaddrLinklayer) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrLinklayer) sockaddr() (unsafe.Pointer, _Socklen, error) {
 	if sa.Ifindex < 0 || sa.Ifindex > 0x7fffffff {
-		return 0, 0, EINVAL
+		return nil, 0, EINVAL
 	}
 	sa.raw.Family = AF_PACKET
 	sa.raw.Protocol = sa.Protocol
@@ -306,7 +306,7 @@ func (sa *SockaddrLinklayer) sockaddr() (uintptr, _Socklen, error) {
 	for i := 0; i < len(sa.Addr); i++ {
 		sa.raw.Addr[i] = sa.Addr[i]
 	}
-	return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrLinklayer, nil
+	return unsafe.Pointer(&sa.raw), SizeofSockaddrLinklayer, nil
 }
 
 type SockaddrNetlink struct {
@@ -317,12 +317,12 @@ type SockaddrNetlink struct {
 	raw    RawSockaddrNetlink
 }
 
-func (sa *SockaddrNetlink) sockaddr() (uintptr, _Socklen, error) {
+func (sa *SockaddrNetlink) sockaddr() (unsafe.Pointer, _Socklen, error) {
 	sa.raw.Family = AF_NETLINK
 	sa.raw.Pad = sa.Pad
 	sa.raw.Pid = sa.Pid
 	sa.raw.Groups = sa.Groups
-	return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrNetlink, nil
+	return unsafe.Pointer(&sa.raw), SizeofSockaddrNetlink, nil
 }
 
 func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
@@ -420,6 +420,9 @@ func Accept4(fd int, flags int) (nfd int, sa Sockaddr, err error) {
 	if err != nil {
 		return
 	}
+	if len > SizeofSockaddrAny {
+		panic("RawSockaddrAny too small")
+	}
 	sa, err = anyToSockaddr(&rsa)
 	if err != nil {
 		Close(nfd)
@@ -439,54 +442,54 @@ func Getsockname(fd int) (sa Sockaddr, err error) {
 
 func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) {
 	vallen := _Socklen(4)
-	err = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value[0])), &vallen)
+	err = getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen)
 	return value, err
 }
 
 func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) {
 	var value IPMreq
 	vallen := _Socklen(SizeofIPMreq)
-	err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+	err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
 	return &value, err
 }
 
 func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) {
 	var value IPMreqn
 	vallen := _Socklen(SizeofIPMreqn)
-	err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+	err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
 	return &value, err
 }
 
 func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) {
 	var value IPv6Mreq
 	vallen := _Socklen(SizeofIPv6Mreq)
-	err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+	err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
 	return &value, err
 }
 
 func GetsockoptIPv6MTUInfo(fd, level, opt int) (*IPv6MTUInfo, error) {
 	var value IPv6MTUInfo
 	vallen := _Socklen(SizeofIPv6MTUInfo)
-	err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+	err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
 	return &value, err
 }
 
 func GetsockoptICMPv6Filter(fd, level, opt int) (*ICMPv6Filter, error) {
 	var value ICMPv6Filter
 	vallen := _Socklen(SizeofICMPv6Filter)
-	err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+	err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
 	return &value, err
 }
 
 func GetsockoptUcred(fd, level, opt int) (*Ucred, error) {
 	var value Ucred
 	vallen := _Socklen(SizeofUcred)
-	err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+	err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
 	return &value, err
 }
 
 func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
-	return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), unsafe.Sizeof(*mreq))
+	return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq))
 }
 
 func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
@@ -524,13 +527,18 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
 }
 
 func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
-	var ptr uintptr
+	_, err = SendmsgN(fd, p, oob, to, flags)
+	return
+}
+
+func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
+	var ptr unsafe.Pointer
 	var salen _Socklen
 	if to != nil {
 		var err error
 		ptr, salen, err = to.sockaddr()
 		if err != nil {
-			return err
+			return 0, err
 		}
 	}
 	var msg Msghdr
@@ -553,10 +561,13 @@ func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
 	}
 	msg.Iov = &iov
 	msg.Iovlen = 1
-	if err = sendmsg(fd, &msg, flags); err != nil {
-		return
+	if n, err = sendmsg(fd, &msg, flags); err != nil {
+		return 0, err
 	}
-	return
+	if len(oob) > 0 && len(p) == 0 {
+		n = 0
+	}
+	return n, nil
 }
 
 // BindToDevice binds the socket associated with fd to device.
diff --git a/src/pkg/syscall/syscall_linux_386.go b/src/pkg/syscall/syscall_linux_386.go
index a616956..c491a28 100644
--- a/src/pkg/syscall/syscall_linux_386.go
+++ b/src/pkg/syscall/syscall_linux_386.go
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
+// so that go vet can check that they are correct.
+
 package syscall
 
 import "unsafe"
@@ -132,7 +135,15 @@ func Setrlimit(resource int, rlim *Rlimit) (err error) {
 
 // Underlying system call writes to newoffset via pointer.
 // Implemented in assembly to avoid allocation.
-func Seek(fd int, offset int64, whence int) (newoffset int64, err error)
+func seek(fd int, offset int64, whence int) (newoffset int64, err Errno)
+
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
+	newoffset, errno := seek(fd, offset, whence)
+	if errno != 0 {
+		return 0, errno
+	}
+	return newoffset, nil
+}
 
 // Vsyscalls on amd64.
 //sysnb	Gettimeofday(tv *Timeval) (err error)
@@ -212,7 +223,7 @@ func socketpair(domain int, typ int, flags int, fd *[2]int32) (err error) {
 	return
 }
 
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, e := socketcall(_BIND, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
 	if e != 0 {
 		err = e
@@ -220,7 +231,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
 	return
 }
 
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, e := socketcall(_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
 	if e != 0 {
 		err = e
@@ -236,7 +247,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 	return
 }
 
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, e := socketcall(_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e != 0 {
 		err = e
@@ -244,8 +255,8 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
 	return
 }
 
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
-	_, e := socketcall(_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), val, vallen, 0)
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
+	_, e := socketcall(_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), vallen, 0)
 	if e != 0 {
 		err = e
 	}
@@ -264,12 +275,12 @@ func recvfrom(s int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockle
 	return
 }
 
-func sendto(s int, p []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, p []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
 	var base uintptr
 	if len(p) > 0 {
 		base = uintptr(unsafe.Pointer(&p[0]))
 	}
-	_, e := socketcall(_SENDTO, uintptr(s), base, uintptr(len(p)), uintptr(flags), to, uintptr(addrlen))
+	_, e := socketcall(_SENDTO, uintptr(s), base, uintptr(len(p)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e != 0 {
 		err = e
 	}
@@ -284,8 +295,8 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 	return
 }
 
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
-	_, e := socketcall(_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	n, e := socketcall(_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
 	if e != 0 {
 		err = e
 	}
diff --git a/src/pkg/syscall/syscall_linux_amd64.go b/src/pkg/syscall/syscall_linux_amd64.go
index f4b73b2..8915ed8 100644
--- a/src/pkg/syscall/syscall_linux_amd64.go
+++ b/src/pkg/syscall/syscall_linux_amd64.go
@@ -40,26 +40,46 @@ package syscall
 //sys	Truncate(path string, length int64) (err error)
 //sys	accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
 //sys	accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
-//sys	bind(s int, addr uintptr, addrlen _Socklen) (err error)
-//sys	connect(s int, addr uintptr, addrlen _Socklen) (err error)
+//sys	bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sys	connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
 //sysnb	getgroups(n int, list *_Gid_t) (nn int, err error)
 //sysnb	setgroups(n int, list *_Gid_t) (err error)
-//sys	getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error)
-//sys	setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error)
+//sys	getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
+//sys	setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
 //sysnb	socket(domain int, typ int, proto int) (fd int, err error)
 //sysnb	socketpair(domain int, typ int, proto int, fd *[2]int32) (err error)
 //sysnb	getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
 //sysnb	getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
 //sys	recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
-//sys	sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error)
+//sys	sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
 //sys	recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
-//sys	sendmsg(s int, msg *Msghdr, flags int) (err error)
+//sys	sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
 //sys	mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
 
 func Getpagesize() int { return 4096 }
 
-func Gettimeofday(tv *Timeval) (err error)
-func Time(t *Time_t) (tt Time_t, err error)
+//go:noescape
+func gettimeofday(tv *Timeval) (err Errno)
+
+func Gettimeofday(tv *Timeval) (err error) {
+	errno := gettimeofday(tv)
+	if errno != 0 {
+		return errno
+	}
+	return nil
+}
+
+func Time(t *Time_t) (tt Time_t, err error) {
+	var tv Timeval
+	errno := gettimeofday(&tv)
+	if errno != 0 {
+		return 0, errno
+	}
+	if t != nil {
+		*t = Time_t(tv.Sec)
+	}
+	return Time_t(tv.Sec), nil
+}
 
 func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
 
diff --git a/src/pkg/syscall/syscall_linux_arm.go b/src/pkg/syscall/syscall_linux_arm.go
index 4aadf9e..9fe8023 100644
--- a/src/pkg/syscall/syscall_linux_arm.go
+++ b/src/pkg/syscall/syscall_linux_arm.go
@@ -23,26 +23,34 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
 	return
 }
 
-// Seek is defined in assembly.
-
-func Seek(fd int, offset int64, whence int) (newoffset int64, err error)
+// Underlying system call writes to newoffset via pointer.
+// Implemented in assembly to avoid allocation.
+func seek(fd int, offset int64, whence int) (newoffset int64, err Errno)
+
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
+	newoffset, errno := seek(fd, offset, whence)
+	if errno != 0 {
+		return 0, errno
+	}
+	return newoffset, nil
+}
 
 //sys	accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
 //sys	accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
-//sys	bind(s int, addr uintptr, addrlen _Socklen) (err error)
-//sys	connect(s int, addr uintptr, addrlen _Socklen) (err error)
+//sys	bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sys	connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
 //sysnb	getgroups(n int, list *_Gid_t) (nn int, err error) = SYS_GETGROUPS32
 //sysnb	setgroups(n int, list *_Gid_t) (err error) = SYS_SETGROUPS32
-//sys	getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error)
-//sys	setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error)
+//sys	getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
+//sys	setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
 //sysnb	socket(domain int, typ int, proto int) (fd int, err error)
 //sysnb	getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
 //sysnb	getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
 //sys	recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
-//sys	sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error)
+//sys	sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
 //sysnb	socketpair(domain int, typ int, flags int, fd *[2]int32) (err error)
 //sys	recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
-//sys	sendmsg(s int, msg *Msghdr, flags int) (err error)
+//sys	sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
 
 // 64-bit file system and 32-bit uid calls
 // (16-bit uid calls are not always supported in newer kernels)
diff --git a/src/pkg/syscall/syscall_nacl.go b/src/pkg/syscall/syscall_nacl.go
new file mode 100644
index 0000000..c2788b2
--- /dev/null
+++ b/src/pkg/syscall/syscall_nacl.go
@@ -0,0 +1,311 @@
+// 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 syscall
+
+import (
+	"sync"
+	"unsafe"
+)
+
+//sys	naclClose(fd int) (err error) = sys_close
+//sys	Exit(code int) (err error)
+//sys	naclFstat(fd int, stat *Stat_t) (err error) = sys_fstat
+//sys	naclRead(fd int, b []byte) (n int, err error) = sys_read
+//sys	naclSeek(fd int, off *int64, whence int) (err error) = sys_lseek
+
+const direntSize = 8 + 8 + 2 + 256
+
+// native_client/src/trusted/service_runtime/include/sys/dirent.h
+type Dirent struct {
+	Ino    int64
+	Off    int64
+	Reclen uint16
+	Name   [256]byte
+}
+
+func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
+	origlen := len(buf)
+	count = 0
+	for max != 0 && len(buf) > 0 {
+		dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
+		buf = buf[dirent.Reclen:]
+		if dirent.Ino == 0 { // File absent in directory.
+			continue
+		}
+		bytes := (*[512 + PathMax]byte)(unsafe.Pointer(&dirent.Name[0]))
+		var name = string(bytes[0:clen(bytes[:])])
+		if name == "." || name == ".." { // Useless names
+			continue
+		}
+		max--
+		count++
+		names = append(names, name)
+	}
+	return origlen - len(buf), count, names
+}
+
+func clen(n []byte) int {
+	for i := 0; i < len(n); i++ {
+		if n[i] == 0 {
+			return i
+		}
+	}
+	return len(n)
+}
+
+const PathMax = 256
+
+// An Errno is an unsigned number describing an error condition.
+// It implements the error interface.  The zero Errno is by convention
+// a non-error, so code to convert from Errno to error should use:
+//	err = nil
+//	if errno != 0 {
+//		err = errno
+//	}
+type Errno uintptr
+
+func (e Errno) Error() string {
+	if 0 <= int(e) && int(e) < len(errorstr) {
+		s := errorstr[e]
+		if s != "" {
+			return s
+		}
+	}
+	return "errno " + itoa(int(e))
+}
+
+func (e Errno) Temporary() bool {
+	return e == EINTR || e == EMFILE || e.Timeout()
+}
+
+func (e Errno) Timeout() bool {
+	return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
+}
+
+// A Signal is a number describing a process signal.
+// It implements the os.Signal interface.
+type Signal int
+
+const (
+	_ Signal = iota
+	SIGCHLD
+	SIGINT
+	SIGKILL
+	SIGTRAP
+	SIGQUIT
+)
+
+func (s Signal) Signal() {}
+
+func (s Signal) String() string {
+	if 0 <= s && int(s) < len(signals) {
+		str := signals[s]
+		if str != "" {
+			return str
+		}
+	}
+	return "signal " + itoa(int(s))
+}
+
+var signals = [...]string{}
+
+// File system
+
+const (
+	Stdin  = 0
+	Stdout = 1
+	Stderr = 2
+)
+
+// native_client/src/trusted/service_runtime/include/sys/fcntl.h
+const (
+	O_RDONLY  = 0
+	O_WRONLY  = 1
+	O_RDWR    = 2
+	O_ACCMODE = 3
+
+	O_CREAT    = 0100
+	O_CREATE   = O_CREAT // for ken
+	O_TRUNC    = 01000
+	O_APPEND   = 02000
+	O_EXCL     = 0200
+	O_NONBLOCK = 04000
+	O_NDELAY   = O_NONBLOCK
+	O_SYNC     = 010000
+	O_FSYNC    = O_SYNC
+	O_ASYNC    = 020000
+
+	O_CLOEXEC = 0
+
+	FD_CLOEXEC = 1
+)
+
+// native_client/src/trusted/service_runtime/include/sys/fcntl.h
+const (
+	F_DUPFD   = 0
+	F_GETFD   = 1
+	F_SETFD   = 2
+	F_GETFL   = 3
+	F_SETFL   = 4
+	F_GETOWN  = 5
+	F_SETOWN  = 6
+	F_GETLK   = 7
+	F_SETLK   = 8
+	F_SETLKW  = 9
+	F_RGETLK  = 10
+	F_RSETLK  = 11
+	F_CNVT    = 12
+	F_RSETLKW = 13
+
+	F_RDLCK   = 1
+	F_WRLCK   = 2
+	F_UNLCK   = 3
+	F_UNLKSYS = 4
+)
+
+// native_client/src/trusted/service_runtime/include/bits/stat.h
+const (
+	S_IFMT        = 0000370000
+	S_IFSHM_SYSV  = 0000300000
+	S_IFSEMA      = 0000270000
+	S_IFCOND      = 0000260000
+	S_IFMUTEX     = 0000250000
+	S_IFSHM       = 0000240000
+	S_IFBOUNDSOCK = 0000230000
+	S_IFSOCKADDR  = 0000220000
+	S_IFDSOCK     = 0000210000
+
+	S_IFSOCK = 0000140000
+	S_IFLNK  = 0000120000
+	S_IFREG  = 0000100000
+	S_IFBLK  = 0000060000
+	S_IFDIR  = 0000040000
+	S_IFCHR  = 0000020000
+	S_IFIFO  = 0000010000
+
+	S_UNSUP = 0000370000
+
+	S_ISUID = 0004000
+	S_ISGID = 0002000
+	S_ISVTX = 0001000
+
+	S_IREAD  = 0400
+	S_IWRITE = 0200
+	S_IEXEC  = 0100
+
+	S_IRWXU = 0700
+	S_IRUSR = 0400
+	S_IWUSR = 0200
+	S_IXUSR = 0100
+
+	S_IRWXG = 070
+	S_IRGRP = 040
+	S_IWGRP = 020
+	S_IXGRP = 010
+
+	S_IRWXO = 07
+	S_IROTH = 04
+	S_IWOTH = 02
+	S_IXOTH = 01
+)
+
+// native_client/src/trusted/service_runtime/include/sys/stat.h
+// native_client/src/trusted/service_runtime/include/machine/_types.h
+type Stat_t struct {
+	Dev       int64
+	Ino       uint64
+	Mode      uint32
+	Nlink     uint32
+	Uid       uint32
+	Gid       uint32
+	Rdev      int64
+	Size      int64
+	Blksize   int32
+	Blocks    int32
+	Atime     int64
+	AtimeNsec int64
+	Mtime     int64
+	MtimeNsec int64
+	Ctime     int64
+	CtimeNsec int64
+}
+
+// Processes
+// Not supported on NaCl - just enough for package os.
+
+var ForkLock sync.RWMutex
+
+type WaitStatus uint32
+
+func (w WaitStatus) Exited() bool       { return false }
+func (w WaitStatus) ExitStatus() int    { return 0 }
+func (w WaitStatus) Signaled() bool     { return false }
+func (w WaitStatus) Signal() Signal     { return 0 }
+func (w WaitStatus) CoreDump() bool     { return false }
+func (w WaitStatus) Stopped() bool      { return false }
+func (w WaitStatus) Continued() bool    { return false }
+func (w WaitStatus) StopSignal() Signal { return 0 }
+func (w WaitStatus) TrapCause() int     { return 0 }
+
+// XXX made up
+type Rusage struct {
+	Utime Timeval
+	Stime Timeval
+}
+
+// XXX made up
+type ProcAttr struct {
+	Dir   string
+	Env   []string
+	Files []uintptr
+	Sys   *SysProcAttr
+}
+
+type SysProcAttr struct {
+}
+
+// System
+
+func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
+func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { return 0, 0, ENOSYS }
+func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)           { return 0, 0, ENOSYS }
+func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
+	return 0, 0, ENOSYS
+}
+
+func Sysctl(key string) (string, error) {
+	if key == "kern.hostname" {
+		return "naclbox", nil
+	}
+	return "", ENOSYS
+}
+
+// Unimplemented Unix midden heap.
+
+const ImplementsGetwd = false
+
+func Getwd() (wd string, err error)     { return "", ENOSYS }
+func Getegid() int                      { return 1 }
+func Geteuid() int                      { return 1 }
+func Getgid() int                       { return 1 }
+func Getgroups() ([]int, error)         { return []int{1}, nil }
+func Getpagesize() int                  { return 65536 }
+func Getppid() int                      { return 2 }
+func Getpid() int                       { return 3 }
+func Getuid() int                       { return 1 }
+func Kill(pid int, signum Signal) error { return ENOSYS }
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+	return 0, ENOSYS
+}
+func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
+	return 0, 0, ENOSYS
+}
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
+	return 0, ENOSYS
+}
+func RouteRIB(facility, param int) ([]byte, error)                { return nil, ENOSYS }
+func ParseRoutingMessage(b []byte) ([]RoutingMessage, error)      { return nil, ENOSYS }
+func ParseRoutingSockaddr(msg RoutingMessage) ([]Sockaddr, error) { return nil, ENOSYS }
+func SysctlUint32(name string) (value uint32, err error)          { return 0, ENOSYS }
diff --git a/src/pkg/syscall/syscall_nacl_386.go b/src/pkg/syscall/syscall_nacl_386.go
new file mode 100644
index 0000000..d12f8e2
--- /dev/null
+++ b/src/pkg/syscall/syscall_nacl_386.go
@@ -0,0 +1,32 @@
+// 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 syscall
+
+type Timespec struct {
+	Sec  int64
+	Nsec int32
+}
+
+type Timeval struct {
+	Sec  int64
+	Usec int32
+}
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+	ts.Sec = int64(nsec / 1e9)
+	ts.Nsec = int32(nsec % 1e9)
+	return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+	nsec += 999 // round up to microsecond
+	tv.Usec = int32(nsec % 1e9 / 1e3)
+	tv.Sec = int64(nsec / 1e9)
+	return
+}
diff --git a/src/pkg/syscall/syscall_nacl_amd64p32.go b/src/pkg/syscall/syscall_nacl_amd64p32.go
new file mode 100644
index 0000000..d12f8e2
--- /dev/null
+++ b/src/pkg/syscall/syscall_nacl_amd64p32.go
@@ -0,0 +1,32 @@
+// 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 syscall
+
+type Timespec struct {
+	Sec  int64
+	Nsec int32
+}
+
+type Timeval struct {
+	Sec  int64
+	Usec int32
+}
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+	ts.Sec = int64(nsec / 1e9)
+	ts.Nsec = int32(nsec % 1e9)
+	return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+	nsec += 999 // round up to microsecond
+	tv.Usec = int32(nsec % 1e9 / 1e3)
+	tv.Sec = int64(nsec / 1e9)
+	return
+}
diff --git a/src/pkg/syscall/syscall_openbsd.go b/src/pkg/syscall/syscall_openbsd.go
index 89c7321..8d3f825 100644
--- a/src/pkg/syscall/syscall_openbsd.go
+++ b/src/pkg/syscall/syscall_openbsd.go
@@ -90,11 +90,31 @@ func Pipe(p []int) (err error) {
 	return
 }
 
+//sys getdents(fd int, buf []byte) (n int, err error)
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+	return getdents(fd, buf)
+}
+
 // TODO
 func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
 	return -1, ENOSYS
 }
 
+func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
+	var _p0 unsafe.Pointer
+	var bufsize uintptr
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+		bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
+	}
+	r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
 /*
  * Exposed directly
  */
@@ -119,10 +139,8 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
 //sys	Fstatfs(fd int, stat *Statfs_t) (err error)
 //sys	Fsync(fd int) (err error)
 //sys	Ftruncate(fd int, length int64) (err error)
-//sys	Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error)
 //sysnb	Getegid() (egid int)
 //sysnb	Geteuid() (uid int)
-//sys	Getfsstat(buf []Statfs_t, flags int) (n int, err error)
 //sysnb	Getgid() (gid int)
 //sysnb	Getpgid(pid int) (pgid int, err error)
 //sysnb	Getpgrp() (pgrp int)
diff --git a/src/pkg/syscall/syscall_openbsd_386.go b/src/pkg/syscall/syscall_openbsd_386.go
index 3c4c693..ad5ae14 100644
--- a/src/pkg/syscall/syscall_openbsd_386.go
+++ b/src/pkg/syscall/syscall_openbsd_386.go
@@ -9,7 +9,7 @@ func Getpagesize() int { return 4096 }
 func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
 
 func NsecToTimespec(nsec int64) (ts Timespec) {
-	ts.Sec = int32(nsec / 1e9)
+	ts.Sec = int64(nsec / 1e9)
 	ts.Nsec = int32(nsec % 1e9)
 	return
 }
@@ -19,7 +19,7 @@ func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)
 func NsecToTimeval(nsec int64) (tv Timeval) {
 	nsec += 999 // round up to microsecond
 	tv.Usec = int32(nsec % 1e9 / 1e3)
-	tv.Sec = int32(nsec / 1e9)
+	tv.Sec = int64(nsec / 1e9)
 	return
 }
 
diff --git a/src/pkg/syscall/syscall_openbsd_amd64.go b/src/pkg/syscall/syscall_openbsd_amd64.go
index c356ad4..6181344 100644
--- a/src/pkg/syscall/syscall_openbsd_amd64.go
+++ b/src/pkg/syscall/syscall_openbsd_amd64.go
@@ -9,7 +9,7 @@ func Getpagesize() int { return 4096 }
 func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
 
 func NsecToTimespec(nsec int64) (ts Timespec) {
-	ts.Sec = int32(nsec / 1e9)
+	ts.Sec = nsec / 1e9
 	ts.Nsec = nsec % 1e9
 	return
 }
@@ -19,12 +19,12 @@ func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)
 func NsecToTimeval(nsec int64) (tv Timeval) {
 	nsec += 999 // round up to microsecond
 	tv.Usec = nsec % 1e9 / 1e3
-	tv.Sec = int64(nsec / 1e9)
+	tv.Sec = nsec / 1e9
 	return
 }
 
 func SetKevent(k *Kevent_t, fd, mode, flags int) {
-	k.Ident = uint32(fd)
+	k.Ident = uint64(fd)
 	k.Filter = int16(mode)
 	k.Flags = uint16(flags)
 }
diff --git a/src/pkg/syscall/syscall_plan9.go b/src/pkg/syscall/syscall_plan9.go
index 2e1c064..a8c3405 100644
--- a/src/pkg/syscall/syscall_plan9.go
+++ b/src/pkg/syscall/syscall_plan9.go
@@ -83,7 +83,7 @@ func errstr() string {
 }
 
 // Implemented in assembly to import from runtime.
-func exit(int)
+func exit(code int)
 
 func Exit(code int) { exit(code) }
 
diff --git a/src/pkg/syscall/syscall_solaris.go b/src/pkg/syscall/syscall_solaris.go
new file mode 100644
index 0000000..adc52b1
--- /dev/null
+++ b/src/pkg/syscall/syscall_solaris.go
@@ -0,0 +1,523 @@
+// 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.
+
+// Solaris system calls.
+// This file is compiled as ordinary Go code,
+// but it is also input to mksyscall,
+// which parses the //sys lines and generates system call stubs.
+// Note that sometimes we use a lowercase //sys name and wrap
+// it in our own nicer implementation, either here or in
+// syscall_solaris.go or syscall_unix.go.
+
+package syscall
+
+import "unsafe"
+
+type SockaddrDatalink struct {
+	Family uint16
+	Index  uint16
+	Type   uint8
+	Nlen   uint8
+	Alen   uint8
+	Slen   uint8
+	Data   [244]int8
+	raw    RawSockaddrDatalink
+}
+
+func clen(n []byte) int {
+	for i := 0; i < len(n); i++ {
+		if n[i] == 0 {
+			return i
+		}
+	}
+	return len(n)
+}
+
+// ParseDirent parses up to max directory entries in buf,
+// appending the names to names.  It returns the number
+// bytes consumed from buf, the number of entries added
+// to names, and the new names slice.
+func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
+	origlen := len(buf)
+	for max != 0 && len(buf) > 0 {
+		dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
+		if dirent.Reclen == 0 {
+			buf = nil
+			break
+		}
+		buf = buf[dirent.Reclen:]
+		if dirent.Ino == 0 { // File absent in directory.
+			continue
+		}
+		bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
+		var name = string(bytes[0:clen(bytes[:])])
+		if name == "." || name == ".." { // Useless names
+			continue
+		}
+		max--
+		count++
+		names = append(names, name)
+	}
+	return origlen - len(buf), count, names
+}
+
+func pipe() (r uintptr, w uintptr, err uintptr)
+
+func Pipe(p []int) (err error) {
+	if len(p) != 2 {
+		return EINVAL
+	}
+	r0, w0, e1 := pipe()
+	if e1 != 0 {
+		err = Errno(e1)
+	}
+	p[0], p[1] = int(r0), int(w0)
+	return
+}
+
+func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
+	if sa.Port < 0 || sa.Port > 0xFFFF {
+		return nil, 0, EINVAL
+	}
+	sa.raw.Family = AF_INET
+	p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
+	p[0] = byte(sa.Port >> 8)
+	p[1] = byte(sa.Port)
+	for i := 0; i < len(sa.Addr); i++ {
+		sa.raw.Addr[i] = sa.Addr[i]
+	}
+	return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil
+}
+
+func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) {
+	if sa.Port < 0 || sa.Port > 0xFFFF {
+		return nil, 0, EINVAL
+	}
+	sa.raw.Family = AF_INET6
+	p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
+	p[0] = byte(sa.Port >> 8)
+	p[1] = byte(sa.Port)
+	sa.raw.Scope_id = sa.ZoneId
+	for i := 0; i < len(sa.Addr); i++ {
+		sa.raw.Addr[i] = sa.Addr[i]
+	}
+	return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil
+}
+
+func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
+	name := sa.Name
+	n := len(name)
+	if n >= len(sa.raw.Path) {
+		return nil, 0, EINVAL
+	}
+	sa.raw.Family = AF_UNIX
+	for i := 0; i < n; i++ {
+		sa.raw.Path[i] = int8(name[i])
+	}
+	// length is family (uint16), name, NUL.
+	sl := _Socklen(2)
+	if n > 0 {
+		sl += _Socklen(n) + 1
+	}
+	if sa.raw.Path[0] == '@' {
+		sa.raw.Path[0] = 0
+		// Don't count trailing NUL for abstract address.
+		sl--
+	}
+
+	return unsafe.Pointer(&sa.raw), sl, nil
+}
+
+func Getsockname(fd int) (sa Sockaddr, err error) {
+	var rsa RawSockaddrAny
+	var len _Socklen = SizeofSockaddrAny
+	if err = getsockname(fd, &rsa, &len); err != nil {
+		return
+	}
+	return anyToSockaddr(&rsa)
+}
+
+// The const provides a compile-time constant so clients
+// can adjust to whether there is a working Getwd and avoid
+// even linking this function into the binary.  See ../os/getwd.go.
+const ImplementsGetwd = false
+
+func Getwd() (string, error) { return "", ENOTSUP }
+
+/*
+ * Wrapped
+ */
+
+//sysnb	getgroups(ngid int, gid *_Gid_t) (n int, err error)
+//sysnb	setgroups(ngid int, gid *_Gid_t) (err error)
+
+func Getgroups() (gids []int, err error) {
+	n, err := getgroups(0, nil)
+	if err != nil {
+		return nil, err
+	}
+	if n == 0 {
+		return nil, nil
+	}
+
+	// Sanity check group count.  Max is 16 on BSD.
+	if n < 0 || n > 1000 {
+		return nil, EINVAL
+	}
+
+	a := make([]_Gid_t, n)
+	n, err = getgroups(n, &a[0])
+	if err != nil {
+		return nil, err
+	}
+	gids = make([]int, n)
+	for i, v := range a[0:n] {
+		gids[i] = int(v)
+	}
+	return
+}
+
+func Setgroups(gids []int) (err error) {
+	if len(gids) == 0 {
+		return setgroups(0, nil)
+	}
+
+	a := make([]_Gid_t, len(gids))
+	for i, v := range gids {
+		a[i] = _Gid_t(v)
+	}
+	return setgroups(len(a), &a[0])
+}
+
+func ReadDirent(fd int, buf []byte) (n int, err error) {
+	// Final argument is (basep *uintptr) and the syscall doesn't take nil.
+	// TODO(rsc): Can we use a single global basep for all calls?
+	return Getdents(fd, buf, new(uintptr))
+}
+
+// Wait status is 7 bits at bottom, either 0 (exited),
+// 0x7F (stopped), or a signal number that caused an exit.
+// The 0x80 bit is whether there was a core dump.
+// An extra number (exit code, signal causing a stop)
+// is in the high bits.
+
+type WaitStatus uint32
+
+const (
+	mask  = 0x7F
+	core  = 0x80
+	shift = 8
+
+	exited  = 0
+	stopped = 0x7F
+)
+
+func (w WaitStatus) Exited() bool { return w&mask == exited }
+
+func (w WaitStatus) ExitStatus() int {
+	if w&mask != exited {
+		return -1
+	}
+	return int(w >> shift)
+}
+
+func (w WaitStatus) Signaled() bool { return w&mask != stopped && w&mask != 0 }
+
+func (w WaitStatus) Signal() Signal {
+	sig := Signal(w & mask)
+	if sig == stopped || sig == 0 {
+		return -1
+	}
+	return sig
+}
+
+func (w WaitStatus) CoreDump() bool { return w.Signaled() && w&core != 0 }
+
+func (w WaitStatus) Stopped() bool { return w&mask == stopped && Signal(w>>shift) != SIGSTOP }
+
+func (w WaitStatus) Continued() bool { return w&mask == stopped && Signal(w>>shift) == SIGSTOP }
+
+func (w WaitStatus) StopSignal() Signal {
+	if !w.Stopped() {
+		return -1
+	}
+	return Signal(w>>shift) & 0xFF
+}
+
+func (w WaitStatus) TrapCause() int { return -1 }
+
+func wait4(pid uintptr, wstatus *WaitStatus, options uintptr, rusage *Rusage) (wpid uintptr, err uintptr)
+
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
+	r0, e1 := wait4(uintptr(pid), wstatus, uintptr(options), rusage)
+	if e1 != 0 {
+		err = Errno(e1)
+	}
+	return int(r0), err
+}
+
+func gethostname() (name string, err uintptr)
+
+func Gethostname() (name string, err error) {
+	name, e1 := gethostname()
+	if e1 != 0 {
+		err = Errno(e1)
+	}
+	return name, err
+}
+
+func UtimesNano(path string, ts []Timespec) (err error) {
+	if len(ts) != 2 {
+		return EINVAL
+	}
+	var tv [2]Timeval
+	for i := 0; i < 2; i++ {
+		tv[i].Sec = ts[i].Sec
+		tv[i].Usec = ts[i].Nsec / 1000
+	}
+	return Utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
+}
+
+//sys	fcntl(fd int, cmd int, arg int) (val int, err error)
+
+// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
+func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
+	_, _, e1 := sysvicall6(procfcntl.Addr(), 3, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(lk)), 0, 0, 0)
+	if e1 != 0 {
+		return e1
+	}
+	return nil
+}
+
+func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
+	switch rsa.Addr.Family {
+	case AF_UNIX:
+		pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
+		sa := new(SockaddrUnix)
+		// Assume path ends at NUL.
+		// This is not technically the Solaris semantics for
+		// abstract Unix domain sockets -- they are supposed
+		// to be uninterpreted fixed-size binary blobs -- but
+		// everyone uses this convention.
+		n := 0
+		for n < len(pp.Path) && pp.Path[n] != 0 {
+			n++
+		}
+		bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
+		sa.Name = string(bytes)
+		return sa, nil
+
+	case AF_INET:
+		pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
+		sa := new(SockaddrInet4)
+		p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+		sa.Port = int(p[0])<<8 + int(p[1])
+		for i := 0; i < len(sa.Addr); i++ {
+			sa.Addr[i] = pp.Addr[i]
+		}
+		return sa, nil
+
+	case AF_INET6:
+		pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
+		sa := new(SockaddrInet6)
+		p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+		sa.Port = int(p[0])<<8 + int(p[1])
+		sa.ZoneId = pp.Scope_id
+		for i := 0; i < len(sa.Addr); i++ {
+			sa.Addr[i] = pp.Addr[i]
+		}
+		return sa, nil
+	}
+	return nil, EAFNOSUPPORT
+}
+
+//sys	accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) = libsocket.accept
+
+func Accept(fd int) (nfd int, sa Sockaddr, err error) {
+	var rsa RawSockaddrAny
+	var len _Socklen = SizeofSockaddrAny
+	nfd, err = accept(fd, &rsa, &len)
+	if err != nil {
+		return
+	}
+	sa, err = anyToSockaddr(&rsa)
+	if err != nil {
+		Close(nfd)
+		nfd = 0
+	}
+	return
+}
+
+func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
+	var msg Msghdr
+	var rsa RawSockaddrAny
+	msg.Name = (*byte)(unsafe.Pointer(&rsa))
+	msg.Namelen = uint32(SizeofSockaddrAny)
+	var iov Iovec
+	if len(p) > 0 {
+		iov.Base = (*int8)(unsafe.Pointer(&p[0]))
+		iov.SetLen(len(p))
+	}
+	var dummy int8
+	if len(oob) > 0 {
+		// receive at least one normal byte
+		if len(p) == 0 {
+			iov.Base = &dummy
+			iov.SetLen(1)
+		}
+		msg.Accrights = (*int8)(unsafe.Pointer(&oob[0]))
+	}
+	msg.Iov = &iov
+	msg.Iovlen = 1
+	if n, err = recvmsg(fd, &msg, flags); err != nil {
+		return
+	}
+	oobn = int(msg.Accrightslen)
+	// source address is only specified if the socket is unconnected
+	if rsa.Addr.Family != AF_UNSPEC {
+		from, err = anyToSockaddr(&rsa)
+	}
+	return
+}
+
+func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
+	_, err = SendmsgN(fd, p, oob, to, flags)
+	return
+}
+
+//sys	sendmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.sendmsg
+
+func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
+	var ptr unsafe.Pointer
+	var salen _Socklen
+	if to != nil {
+		ptr, salen, err = to.sockaddr()
+		if err != nil {
+			return 0, err
+		}
+	}
+	var msg Msghdr
+	msg.Name = (*byte)(unsafe.Pointer(ptr))
+	msg.Namelen = uint32(salen)
+	var iov Iovec
+	if len(p) > 0 {
+		iov.Base = (*int8)(unsafe.Pointer(&p[0]))
+		iov.SetLen(len(p))
+	}
+	var dummy int8
+	if len(oob) > 0 {
+		// send at least one normal byte
+		if len(p) == 0 {
+			iov.Base = &dummy
+			iov.SetLen(1)
+		}
+		msg.Accrights = (*int8)(unsafe.Pointer(&oob[0]))
+	}
+	msg.Iov = &iov
+	msg.Iovlen = 1
+	if n, err = sendmsg(fd, &msg, flags); err != nil {
+		return 0, err
+	}
+	if len(oob) > 0 && len(p) == 0 {
+		n = 0
+	}
+	return n, nil
+}
+
+/*
+ * Exposed directly
+ */
+//sys	Access(path string, mode uint32) (err error)
+//sys	Adjtime(delta *Timeval, olddelta *Timeval) (err error)
+//sys	Chdir(path string) (err error)
+//sys	Chmod(path string, mode uint32) (err error)
+//sys	Chown(path string, uid int, gid int) (err error)
+//sys	Chroot(path string) (err error)
+//sys	Close(fd int) (err error)
+//sys	Dup(fd int) (nfd int, err error)
+//sys	Exit(code int)
+//sys	Fchdir(fd int) (err error)
+//sys	Fchmod(fd int, mode uint32) (err error)
+//sys	Fchown(fd int, uid int, gid int) (err error)
+//sys	Fpathconf(fd int, name int) (val int, err error)
+//sys	Fstat(fd int, stat *Stat_t) (err error)
+//sys	Getdents(fd int, buf []byte, basep *uintptr) (n int, err error)
+//sysnb	Getgid() (gid int)
+//sysnb	Getpid() (pid int)
+//sys	Geteuid() (euid int)
+//sys	Getegid() (egid int)
+//sys	Getppid() (ppid int)
+//sys	Getpriority(which int, who int) (n int, err error)
+//sysnb	Getrlimit(which int, lim *Rlimit) (err error)
+//sysnb	Gettimeofday(tv *Timeval) (err error)
+//sysnb	Getuid() (uid int)
+//sys	Kill(pid int, signum Signal) (err error)
+//sys	Lchown(path string, uid int, gid int) (err error)
+//sys	Link(path string, link string) (err error)
+//sys	Listen(s int, backlog int) (err error) = libsocket.listen
+//sys	Lstat(path string, stat *Stat_t) (err error)
+//sys	Mkdir(path string, mode uint32) (err error)
+//sys	Mknod(path string, mode uint32, dev int) (err error)
+//sys	Nanosleep(time *Timespec, leftover *Timespec) (err error)
+//sys	Open(path string, mode int, perm uint32) (fd int, err error)
+//sys	Pathconf(path string, name int) (val int, err error)
+//sys	Pread(fd int, p []byte, offset int64) (n int, err error)
+//sys	Pwrite(fd int, p []byte, offset int64) (n int, err error)
+//sys	read(fd int, p []byte) (n int, err error)
+//sys	Readlink(path string, buf []byte) (n int, err error)
+//sys	Rename(from string, to string) (err error)
+//sys	Rmdir(path string) (err error)
+//sys	Seek(fd int, offset int64, whence int) (newoffset int64, err error) = lseek
+//sysnb	Setegid(egid int) (err error)
+//sysnb	Seteuid(euid int) (err error)
+//sysnb	Setgid(gid int) (err error)
+//sysnb	Setpgid(pid int, pgid int) (err error)
+//sys	Setpriority(which int, who int, prio int) (err error)
+//sysnb	Setregid(rgid int, egid int) (err error)
+//sysnb	Setreuid(ruid int, euid int) (err error)
+//sysnb	Setrlimit(which int, lim *Rlimit) (err error)
+//sysnb	Setsid() (pid int, err error)
+//sysnb	Setuid(uid int) (err error)
+//sys	Shutdown(s int, how int) (err error) = libsocket.shutdown
+//sys	Stat(path string, stat *Stat_t) (err error)
+//sys	Symlink(path string, link string) (err error)
+//sys	Sync() (err error)
+//sys	Truncate(path string, length int64) (err error)
+//sys	Fsync(fd int) (err error)
+//sys	Ftruncate(fd int, length int64) (err error)
+//sys	Umask(newmask int) (oldmask int)
+//sys	Unlink(path string) (err error)
+//sys	Utimes(path string, times *[2]Timeval) (err error)
+//sys	bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.bind
+//sys	connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.connect
+//sys	mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
+//sys	munmap(addr uintptr, length uintptr) (err error)
+//sys	sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.sendto
+//sys	socket(domain int, typ int, proto int) (fd int, err error) = libsocket.socket
+//sysnb	socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) = libsocket.socketpair
+//sys	write(fd int, p []byte) (n int, err error)
+//sys	getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) = libsocket.getsockopt
+//sysnb	getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) = libsocket.getpeername
+//sys	getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) = libsocket.getsockname
+//sys	setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) = libsocket.setsockopt
+//sys	recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) = libsocket.recvfrom
+//sys	recvmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.recvmsg
+
+func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
+	r0, _, e1 := sysvicall6(procread.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
+	r0, _, e1 := sysvicall6(procwrite.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
diff --git a/src/pkg/syscall/syscall_solaris_amd64.go b/src/pkg/syscall/syscall_solaris_amd64.go
new file mode 100644
index 0000000..37cf06d
--- /dev/null
+++ b/src/pkg/syscall/syscall_solaris_amd64.go
@@ -0,0 +1,37 @@
+// 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.
+
+package syscall
+
+func Getpagesize() int { return 4096 }
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+	ts.Sec = nsec / 1e9
+	ts.Nsec = nsec % 1e9
+	return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+	nsec += 999 // round up to microsecond
+	tv.Usec = nsec % 1e9 / 1e3
+	tv.Sec = int64(nsec / 1e9)
+	return
+}
+
+func (iov *Iovec) SetLen(length int) {
+	iov.Len = uint64(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+	cmsg.Len = uint32(length)
+}
+
+func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+	// TODO(aram): implement this, see issue 5847.
+	panic("unimplemented")
+}
diff --git a/src/pkg/syscall/syscall_unix.go b/src/pkg/syscall/syscall_unix.go
index 6455dc2..b288915 100644
--- a/src/pkg/syscall/syscall_unix.go
+++ b/src/pkg/syscall/syscall_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 netbsd openbsd solaris
 
 package syscall
 
@@ -19,8 +19,9 @@ var (
 )
 
 const (
-	darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8
-	netbsd32Bit = runtime.GOOS == "netbsd" && sizeofPtr == 4
+	darwin64Bit    = runtime.GOOS == "darwin" && sizeofPtr == 8
+	dragonfly64Bit = runtime.GOOS == "dragonfly" && sizeofPtr == 8
+	netbsd32Bit    = runtime.GOOS == "netbsd" && sizeofPtr == 4
 )
 
 func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
@@ -55,7 +56,7 @@ func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (d
 		cap  int
 	}{addr, length, length}
 
-	// Use unsafe to turn sl into a []byte.
+	// Use unsafeto turn sl into a []byte.
 	b := *(*[]byte)(unsafe.Pointer(&sl))
 
 	// Register mapping in m and return it.
@@ -160,7 +161,7 @@ func Write(fd int, p []byte) (n int, err error) {
 var SocketDisableIPv6 bool
 
 type Sockaddr interface {
-	sockaddr() (ptr uintptr, len _Socklen, err error) // lowercase; only we can define Sockaddrs
+	sockaddr() (ptr unsafe.Pointer, len _Socklen, err error) // lowercase; only we can define Sockaddrs
 }
 
 type SockaddrInet4 struct {
@@ -209,7 +210,7 @@ func Getpeername(fd int) (sa Sockaddr, err error) {
 func GetsockoptInt(fd, level, opt int) (value int, err error) {
 	var n int32
 	vallen := _Socklen(4)
-	err = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), &vallen)
+	err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
 	return int(n), err
 }
 
@@ -234,40 +235,40 @@ func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error) {
 }
 
 func SetsockoptByte(fd, level, opt int, value byte) (err error) {
-	return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), 1)
+	return setsockopt(fd, level, opt, unsafe.Pointer(&value), 1)
 }
 
 func SetsockoptInt(fd, level, opt int, value int) (err error) {
 	var n = int32(value)
-	return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&n)), 4)
+	return setsockopt(fd, level, opt, unsafe.Pointer(&n), 4)
 }
 
 func SetsockoptInet4Addr(fd, level, opt int, value [4]byte) (err error) {
-	return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value[0])), 4)
+	return setsockopt(fd, level, opt, unsafe.Pointer(&value[0]), 4)
 }
 
 func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) (err error) {
-	return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), SizeofIPMreq)
+	return setsockopt(fd, level, opt, unsafe.Pointer(mreq), SizeofIPMreq)
 }
 
 func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) (err error) {
-	return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), SizeofIPv6Mreq)
+	return setsockopt(fd, level, opt, unsafe.Pointer(mreq), SizeofIPv6Mreq)
 }
 
 func SetsockoptICMPv6Filter(fd, level, opt int, filter *ICMPv6Filter) error {
-	return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(filter)), SizeofICMPv6Filter)
+	return setsockopt(fd, level, opt, unsafe.Pointer(filter), SizeofICMPv6Filter)
 }
 
 func SetsockoptLinger(fd, level, opt int, l *Linger) (err error) {
-	return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(l)), SizeofLinger)
+	return setsockopt(fd, level, opt, unsafe.Pointer(l), SizeofLinger)
 }
 
 func SetsockoptString(fd, level, opt int, s string) (err error) {
-	return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&[]byte(s)[0])), uintptr(len(s)))
+	return setsockopt(fd, level, opt, unsafe.Pointer(&[]byte(s)[0]), uintptr(len(s)))
 }
 
 func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (err error) {
-	return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(tv)), unsafe.Sizeof(*tv))
+	return setsockopt(fd, level, opt, unsafe.Pointer(tv), unsafe.Sizeof(*tv))
 }
 
 func Socket(domain, typ, proto int) (fd int, err error) {
diff --git a/src/pkg/syscall/syscall_unix_test.go b/src/pkg/syscall/syscall_unix_test.go
new file mode 100644
index 0000000..a0afb91
--- /dev/null
+++ b/src/pkg/syscall/syscall_unix_test.go
@@ -0,0 +1,314 @@
+// 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 darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package syscall_test
+
+import (
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"net"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"syscall"
+	"testing"
+	"time"
+)
+
+// Tests that below functions, structures and constants are consistent
+// on all Unix-like systems.
+func _() {
+	// program scheduling priority functions and constants
+	var (
+		_ func(int, int, int) error   = syscall.Setpriority
+		_ func(int, int) (int, error) = syscall.Getpriority
+	)
+	const (
+		_ int = syscall.PRIO_USER
+		_ int = syscall.PRIO_PROCESS
+		_ int = syscall.PRIO_PGRP
+	)
+
+	// termios constants
+	const (
+		_ int = syscall.TCIFLUSH
+		_ int = syscall.TCIOFLUSH
+		_ int = syscall.TCOFLUSH
+	)
+
+	// fcntl file locking structure and constants
+	var (
+		_ = syscall.Flock_t{
+			Type:   int16(0),
+			Whence: int16(0),
+			Start:  int64(0),
+			Len:    int64(0),
+			Pid:    int32(0),
+		}
+	)
+	const (
+		_ = syscall.F_GETLK
+		_ = syscall.F_SETLK
+		_ = syscall.F_SETLKW
+	)
+}
+
+// TestFcntlFlock tests whether the file locking structure matches
+// the calling convention of each kernel.
+func TestFcntlFlock(t *testing.T) {
+	name := filepath.Join(os.TempDir(), "TestFcntlFlock")
+	fd, err := syscall.Open(name, syscall.O_CREAT|syscall.O_RDWR|syscall.O_CLOEXEC, 0)
+	if err != nil {
+		t.Fatalf("Open failed: %v", err)
+	}
+	defer syscall.Unlink(name)
+	defer syscall.Close(fd)
+	flock := syscall.Flock_t{
+		Type:  syscall.F_RDLCK,
+		Start: 0, Len: 0, Whence: 1,
+	}
+	if err := syscall.FcntlFlock(uintptr(fd), syscall.F_GETLK, &flock); err != nil {
+		t.Fatalf("FcntlFlock failed: %v", err)
+	}
+}
+
+// TestPassFD tests passing a file descriptor over a Unix socket.
+//
+// This test involved both a parent and child process. The parent
+// process is invoked as a normal test, with "go test", which then
+// runs the child process by running the current test binary with args
+// "-test.run=^TestPassFD$" and an environment variable used to signal
+// that the test should become the child process instead.
+func TestPassFD(t *testing.T) {
+	switch runtime.GOOS {
+	case "dragonfly":
+		// TODO(jsing): Figure out why sendmsg is returning EINVAL.
+		t.Skip("skipping test on dragonfly")
+	case "solaris":
+		// TODO(aram): Figure out why ReadMsgUnix is returning empty message.
+		t.Skip("skipping test on solaris, see issue 7402")
+	}
+	if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
+		passFDChild()
+		return
+	}
+
+	tempDir, err := ioutil.TempDir("", "TestPassFD")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tempDir)
+
+	fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0)
+	if err != nil {
+		t.Fatalf("Socketpair: %v", err)
+	}
+	defer syscall.Close(fds[0])
+	defer syscall.Close(fds[1])
+	writeFile := os.NewFile(uintptr(fds[0]), "child-writes")
+	readFile := os.NewFile(uintptr(fds[1]), "parent-reads")
+	defer writeFile.Close()
+	defer readFile.Close()
+
+	cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir)
+	cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+	cmd.ExtraFiles = []*os.File{writeFile}
+
+	out, err := cmd.CombinedOutput()
+	if len(out) > 0 || err != nil {
+		t.Fatalf("child process: %q, %v", out, err)
+	}
+
+	c, err := net.FileConn(readFile)
+	if err != nil {
+		t.Fatalf("FileConn: %v", err)
+	}
+	defer c.Close()
+
+	uc, ok := c.(*net.UnixConn)
+	if !ok {
+		t.Fatalf("unexpected FileConn type; expected UnixConn, got %T", c)
+	}
+
+	buf := make([]byte, 32) // expect 1 byte
+	oob := make([]byte, 32) // expect 24 bytes
+	closeUnix := time.AfterFunc(5*time.Second, func() {
+		t.Logf("timeout reading from unix socket")
+		uc.Close()
+	})
+	_, oobn, _, _, err := uc.ReadMsgUnix(buf, oob)
+	closeUnix.Stop()
+
+	scms, err := syscall.ParseSocketControlMessage(oob[:oobn])
+	if err != nil {
+		t.Fatalf("ParseSocketControlMessage: %v", err)
+	}
+	if len(scms) != 1 {
+		t.Fatalf("expected 1 SocketControlMessage; got scms = %#v", scms)
+	}
+	scm := scms[0]
+	gotFds, err := syscall.ParseUnixRights(&scm)
+	if err != nil {
+		t.Fatalf("syscall.ParseUnixRights: %v", err)
+	}
+	if len(gotFds) != 1 {
+		t.Fatalf("wanted 1 fd; got %#v", gotFds)
+	}
+
+	f := os.NewFile(uintptr(gotFds[0]), "fd-from-child")
+	defer f.Close()
+
+	got, err := ioutil.ReadAll(f)
+	want := "Hello from child process!\n"
+	if string(got) != want {
+		t.Errorf("child process ReadAll: %q, %v; want %q", got, err, want)
+	}
+}
+
+// passFDChild is the child process used by TestPassFD.
+func passFDChild() {
+	defer os.Exit(0)
+
+	// Look for our fd. It should be fd 3, but we work around an fd leak
+	// bug here (http://golang.org/issue/2603) to let it be elsewhere.
+	var uc *net.UnixConn
+	for fd := uintptr(3); fd <= 10; fd++ {
+		f := os.NewFile(fd, "unix-conn")
+		var ok bool
+		netc, _ := net.FileConn(f)
+		uc, ok = netc.(*net.UnixConn)
+		if ok {
+			break
+		}
+	}
+	if uc == nil {
+		fmt.Println("failed to find unix fd")
+		return
+	}
+
+	// Make a file f to send to our parent process on uc.
+	// We make it in tempDir, which our parent will clean up.
+	flag.Parse()
+	tempDir := flag.Arg(0)
+	f, err := ioutil.TempFile(tempDir, "")
+	if err != nil {
+		fmt.Printf("TempFile: %v", err)
+		return
+	}
+
+	f.Write([]byte("Hello from child process!\n"))
+	f.Seek(0, 0)
+
+	rights := syscall.UnixRights(int(f.Fd()))
+	dummyByte := []byte("x")
+	n, oobn, err := uc.WriteMsgUnix(dummyByte, rights, nil)
+	if err != nil {
+		fmt.Printf("WriteMsgUnix: %v", err)
+		return
+	}
+	if n != 1 || oobn != len(rights) {
+		fmt.Printf("WriteMsgUnix = %d, %d; want 1, %d", n, oobn, len(rights))
+		return
+	}
+}
+
+// TestUnixRightsRoundtrip tests that UnixRights, ParseSocketControlMessage,
+// and ParseUnixRights are able to successfully round-trip lists of file descriptors.
+func TestUnixRightsRoundtrip(t *testing.T) {
+	testCases := [...][][]int{
+		{{42}},
+		{{1, 2}},
+		{{3, 4, 5}},
+		{{}},
+		{{1, 2}, {3, 4, 5}, {}, {7}},
+	}
+	for _, testCase := range testCases {
+		b := []byte{}
+		var n int
+		for _, fds := range testCase {
+			// Last assignment to n wins
+			n = len(b) + syscall.CmsgLen(4*len(fds))
+			b = append(b, syscall.UnixRights(fds...)...)
+		}
+		// Truncate b
+		b = b[:n]
+
+		scms, err := syscall.ParseSocketControlMessage(b)
+		if err != nil {
+			t.Fatalf("ParseSocketControlMessage: %v", err)
+		}
+		if len(scms) != len(testCase) {
+			t.Fatalf("expected %v SocketControlMessage; got scms = %#v", len(testCase), scms)
+		}
+		for i, scm := range scms {
+			gotFds, err := syscall.ParseUnixRights(&scm)
+			if err != nil {
+				t.Fatalf("ParseUnixRights: %v", err)
+			}
+			wantFds := testCase[i]
+			if len(gotFds) != len(wantFds) {
+				t.Fatalf("expected %v fds, got %#v", len(wantFds), gotFds)
+			}
+			for j, fd := range gotFds {
+				if fd != wantFds[j] {
+					t.Fatalf("expected fd %v, got %v", wantFds[j], fd)
+				}
+			}
+		}
+	}
+}
+
+func TestRlimit(t *testing.T) {
+	var rlimit, zero syscall.Rlimit
+	err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit)
+	if err != nil {
+		t.Fatalf("Getrlimit: save failed: %v", err)
+	}
+	if zero == rlimit {
+		t.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit)
+	}
+	set := rlimit
+	set.Cur = set.Max - 1
+	err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &set)
+	if err != nil {
+		t.Fatalf("Setrlimit: set failed: %#v %v", set, err)
+	}
+	var get syscall.Rlimit
+	err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &get)
+	if err != nil {
+		t.Fatalf("Getrlimit: get failed: %v", err)
+	}
+	set = rlimit
+	set.Cur = set.Max - 1
+	if set != get {
+		// Seems like Darwin requires some privilege to
+		// increase the soft limit of rlimit sandbox, though
+		// Setrlimit never reports an error.
+		switch runtime.GOOS {
+		case "darwin":
+		default:
+			t.Fatalf("Rlimit: change failed: wanted %#v got %#v", set, get)
+		}
+	}
+	err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit)
+	if err != nil {
+		t.Fatalf("Setrlimit: restore failed: %#v %v", rlimit, err)
+	}
+}
+
+func TestSeekFailure(t *testing.T) {
+	_, err := syscall.Seek(-1, 0, 0)
+	if err == nil {
+		t.Fatalf("Seek(-1, 0, 0) did not fail")
+	}
+	str := err.Error() // used to crash on Linux
+	t.Logf("Seek: %v", str)
+	if str == "" {
+		t.Fatalf("Seek(-1, 0, 0) return error with empty message")
+	}
+}
diff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go
index 3d78b68..f9733f6 100644
--- a/src/pkg/syscall/syscall_windows.go
+++ b/src/pkg/syscall/syscall_windows.go
@@ -106,10 +106,11 @@ func (e Errno) Timeout() bool {
 }
 
 // Converts a Go function to a function pointer conforming
-// to the stdcall calling convention.  This is useful when
+// to the stdcall or cdecl calling convention.  This is useful when
 // interoperating with Windows code requiring callbacks.
 // Implemented in ../runtime/syscall_windows.goc
 func NewCallback(fn interface{}) uintptr
+func NewCallbackCDecl(fn interface{}) uintptr
 
 // windows api calls
 
@@ -522,8 +523,8 @@ const socket_error = uintptr(^uint32(0))
 //sys	socket(af int32, typ int32, protocol int32) (handle Handle, err error) [failretval==InvalidHandle] = ws2_32.socket
 //sys	Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) [failretval==socket_error] = ws2_32.setsockopt
 //sys	Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockopt
-//sys	bind(s Handle, name uintptr, namelen int32) (err error) [failretval==socket_error] = ws2_32.bind
-//sys	connect(s Handle, name uintptr, namelen int32) (err error) [failretval==socket_error] = ws2_32.connect
+//sys	bind(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.bind
+//sys	connect(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.connect
 //sys	getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockname
 //sys	getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getpeername
 //sys	listen(s Handle, backlog int32) (err error) [failretval==socket_error] = ws2_32.listen
@@ -578,7 +579,7 @@ type RawSockaddrAny struct {
 }
 
 type Sockaddr interface {
-	sockaddr() (ptr uintptr, len int32, err error) // lowercase; only we can define Sockaddrs
+	sockaddr() (ptr unsafe.Pointer, len int32, err error) // lowercase; only we can define Sockaddrs
 }
 
 type SockaddrInet4 struct {
@@ -587,9 +588,9 @@ type SockaddrInet4 struct {
 	raw  RawSockaddrInet4
 }
 
-func (sa *SockaddrInet4) sockaddr() (uintptr, int32, error) {
+func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, int32, error) {
 	if sa.Port < 0 || sa.Port > 0xFFFF {
-		return 0, 0, EINVAL
+		return nil, 0, EINVAL
 	}
 	sa.raw.Family = AF_INET
 	p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
@@ -598,7 +599,7 @@ func (sa *SockaddrInet4) sockaddr() (uintptr, int32, error) {
 	for i := 0; i < len(sa.Addr); i++ {
 		sa.raw.Addr[i] = sa.Addr[i]
 	}
-	return uintptr(unsafe.Pointer(&sa.raw)), int32(unsafe.Sizeof(sa.raw)), nil
+	return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil
 }
 
 type SockaddrInet6 struct {
@@ -608,9 +609,9 @@ type SockaddrInet6 struct {
 	raw    RawSockaddrInet6
 }
 
-func (sa *SockaddrInet6) sockaddr() (uintptr, int32, error) {
+func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, int32, error) {
 	if sa.Port < 0 || sa.Port > 0xFFFF {
-		return 0, 0, EINVAL
+		return nil, 0, EINVAL
 	}
 	sa.raw.Family = AF_INET6
 	p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
@@ -620,16 +621,16 @@ func (sa *SockaddrInet6) sockaddr() (uintptr, int32, error) {
 	for i := 0; i < len(sa.Addr); i++ {
 		sa.raw.Addr[i] = sa.Addr[i]
 	}
-	return uintptr(unsafe.Pointer(&sa.raw)), int32(unsafe.Sizeof(sa.raw)), nil
+	return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil
 }
 
 type SockaddrUnix struct {
 	Name string
 }
 
-func (sa *SockaddrUnix) sockaddr() (uintptr, int32, error) {
+func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, int32, error) {
 	// TODO(brainman): implement SockaddrUnix.sockaddr()
-	return 0, 0, EWINDOWS
+	return nil, 0, EWINDOWS
 }
 
 func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) {
@@ -753,7 +754,7 @@ func LoadConnectEx() error {
 	return connectExFunc.err
 }
 
-func connectEx(s Handle, name uintptr, namelen int32, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) (err error) {
+func connectEx(s Handle, name unsafe.Pointer, namelen int32, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) (err error) {
 	r1, _, e1 := Syscall9(connectExFunc.addr, 7, uintptr(s), uintptr(name), uintptr(namelen), uintptr(unsafe.Pointer(sendBuf)), uintptr(sendDataLen), uintptr(unsafe.Pointer(bytesSent)), uintptr(unsafe.Pointer(overlapped)), 0, 0)
 	if r1 == 0 {
 		if e1 != 0 {
diff --git a/src/pkg/syscall/tables_nacl.go b/src/pkg/syscall/tables_nacl.go
new file mode 100644
index 0000000..08f4ced
--- /dev/null
+++ b/src/pkg/syscall/tables_nacl.go
@@ -0,0 +1,324 @@
+// 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 syscall
+
+// TODO: generate with runtime/mknacl.sh, allow override with IRT.
+const (
+	sys_null                 = 1
+	sys_nameservice          = 2
+	sys_dup                  = 8
+	sys_dup2                 = 9
+	sys_open                 = 10
+	sys_close                = 11
+	sys_read                 = 12
+	sys_write                = 13
+	sys_lseek                = 14
+	sys_ioctl                = 15
+	sys_stat                 = 16
+	sys_fstat                = 17
+	sys_chmod                = 18
+	sys_brk                  = 20
+	sys_mmap                 = 21
+	sys_munmap               = 22
+	sys_getdents             = 23
+	sys_mprotect             = 24
+	sys_list_mappings        = 25
+	sys_exit                 = 30
+	sys_getpid               = 31
+	sys_sched_yield          = 32
+	sys_sysconf              = 33
+	sys_gettimeofday         = 40
+	sys_clock                = 41
+	sys_nanosleep            = 42
+	sys_clock_getres         = 43
+	sys_clock_gettime        = 44
+	sys_mkdir                = 45
+	sys_rmdir                = 46
+	sys_chdir                = 47
+	sys_getcwd               = 48
+	sys_unlink               = 49
+	sys_imc_makeboundsock    = 60
+	sys_imc_accept           = 61
+	sys_imc_connect          = 62
+	sys_imc_sendmsg          = 63
+	sys_imc_recvmsg          = 64
+	sys_imc_mem_obj_create   = 65
+	sys_imc_socketpair       = 66
+	sys_mutex_create         = 70
+	sys_mutex_lock           = 71
+	sys_mutex_trylock        = 72
+	sys_mutex_unlock         = 73
+	sys_cond_create          = 74
+	sys_cond_wait            = 75
+	sys_cond_signal          = 76
+	sys_cond_broadcast       = 77
+	sys_cond_timed_wait_abs  = 79
+	sys_thread_create        = 80
+	sys_thread_exit          = 81
+	sys_tls_init             = 82
+	sys_thread_nice          = 83
+	sys_tls_get              = 84
+	sys_second_tls_set       = 85
+	sys_second_tls_get       = 86
+	sys_exception_handler    = 87
+	sys_exception_stack      = 88
+	sys_exception_clear_flag = 89
+	sys_sem_create           = 100
+	sys_sem_wait             = 101
+	sys_sem_post             = 102
+	sys_sem_get_value        = 103
+	sys_dyncode_create       = 104
+	sys_dyncode_modify       = 105
+	sys_dyncode_delete       = 106
+	sys_test_infoleak        = 109
+	sys_test_crash           = 110
+	sys_test_syscall_1       = 111
+	sys_test_syscall_2       = 112
+)
+
+// TODO: Auto-generate some day. (Hard-coded in binaries so not likely to change.)
+const (
+	// native_client/src/trusted/service_runtime/include/sys/errno.h
+	// The errors are mainly copied from Linux.
+	EPERM           Errno = 1       /* Operation not permitted */
+	ENOENT          Errno = 2       /* No such file or directory */
+	ESRCH           Errno = 3       /* No such process */
+	EINTR           Errno = 4       /* Interrupted system call */
+	EIO             Errno = 5       /* I/O error */
+	ENXIO           Errno = 6       /* No such device or address */
+	E2BIG           Errno = 7       /* Argument list too long */
+	ENOEXEC         Errno = 8       /* Exec format error */
+	EBADF           Errno = 9       /* Bad file number */
+	ECHILD          Errno = 10      /* No child processes */
+	EAGAIN          Errno = 11      /* Try again */
+	ENOMEM          Errno = 12      /* Out of memory */
+	EACCES          Errno = 13      /* Permission denied */
+	EFAULT          Errno = 14      /* Bad address */
+	EBUSY           Errno = 16      /* Device or resource busy */
+	EEXIST          Errno = 17      /* File exists */
+	EXDEV           Errno = 18      /* Cross-device link */
+	ENODEV          Errno = 19      /* No such device */
+	ENOTDIR         Errno = 20      /* Not a directory */
+	EISDIR          Errno = 21      /* Is a directory */
+	EINVAL          Errno = 22      /* Invalid argument */
+	ENFILE          Errno = 23      /* File table overflow */
+	EMFILE          Errno = 24      /* Too many open files */
+	ENOTTY          Errno = 25      /* Not a typewriter */
+	EFBIG           Errno = 27      /* File too large */
+	ENOSPC          Errno = 28      /* No space left on device */
+	ESPIPE          Errno = 29      /* Illegal seek */
+	EROFS           Errno = 30      /* Read-only file system */
+	EMLINK          Errno = 31      /* Too many links */
+	EPIPE           Errno = 32      /* Broken pipe */
+	ENAMETOOLONG    Errno = 36      /* File name too long */
+	ENOSYS          Errno = 38      /* Function not implemented */
+	EDQUOT          Errno = 122     /* Quota exceeded */
+	EDOM            Errno = 33      /* Math arg out of domain of func */
+	ERANGE          Errno = 34      /* Math result not representable */
+	EDEADLK         Errno = 35      /* Deadlock condition */
+	ENOLCK          Errno = 37      /* No record locks available */
+	ENOTEMPTY       Errno = 39      /* Directory not empty */
+	ELOOP           Errno = 40      /* Too many symbolic links */
+	ENOMSG          Errno = 42      /* No message of desired type */
+	EIDRM           Errno = 43      /* Identifier removed */
+	ECHRNG          Errno = 44      /* Channel number out of range */
+	EL2NSYNC        Errno = 45      /* Level 2 not synchronized */
+	EL3HLT          Errno = 46      /* Level 3 halted */
+	EL3RST          Errno = 47      /* Level 3 reset */
+	ELNRNG          Errno = 48      /* Link number out of range */
+	EUNATCH         Errno = 49      /* Protocol driver not attached */
+	ENOCSI          Errno = 50      /* No CSI structure available */
+	EL2HLT          Errno = 51      /* Level 2 halted */
+	EBADE           Errno = 52      /* Invalid exchange */
+	EBADR           Errno = 53      /* Invalid request descriptor */
+	EXFULL          Errno = 54      /* Exchange full */
+	ENOANO          Errno = 55      /* No anode */
+	EBADRQC         Errno = 56      /* Invalid request code */
+	EBADSLT         Errno = 57      /* Invalid slot */
+	EDEADLOCK       Errno = EDEADLK /* File locking deadlock error */
+	EBFONT          Errno = 59      /* Bad font file fmt */
+	ENOSTR          Errno = 60      /* Device not a stream */
+	ENODATA         Errno = 61      /* No data (for no delay io) */
+	ETIME           Errno = 62      /* Timer expired */
+	ENOSR           Errno = 63      /* Out of streams resources */
+	ENONET          Errno = 64      /* Machine is not on the network */
+	ENOPKG          Errno = 65      /* Package not installed */
+	EREMOTE         Errno = 66      /* The object is remote */
+	ENOLINK         Errno = 67      /* The link has been severed */
+	EADV            Errno = 68      /* Advertise error */
+	ESRMNT          Errno = 69      /* Srmount error */
+	ECOMM           Errno = 70      /* Communication error on send */
+	EPROTO          Errno = 71      /* Protocol error */
+	EMULTIHOP       Errno = 72      /* Multihop attempted */
+	EDOTDOT         Errno = 73      /* Cross mount point (not really error) */
+	EBADMSG         Errno = 74      /* Trying to read unreadable message */
+	EOVERFLOW       Errno = 75      /* Value too large for defined data type */
+	ENOTUNIQ        Errno = 76      /* Given log. name not unique */
+	EBADFD          Errno = 77      /* f.d. invalid for this operation */
+	EREMCHG         Errno = 78      /* Remote address changed */
+	ELIBACC         Errno = 79      /* Can't access a needed shared lib */
+	ELIBBAD         Errno = 80      /* Accessing a corrupted shared lib */
+	ELIBSCN         Errno = 81      /* .lib section in a.out corrupted */
+	ELIBMAX         Errno = 82      /* Attempting to link in too many libs */
+	ELIBEXEC        Errno = 83      /* Attempting to exec a shared library */
+	EILSEQ          Errno = 84
+	EUSERS          Errno = 87
+	ENOTSOCK        Errno = 88  /* Socket operation on non-socket */
+	EDESTADDRREQ    Errno = 89  /* Destination address required */
+	EMSGSIZE        Errno = 90  /* Message too long */
+	EPROTOTYPE      Errno = 91  /* Protocol wrong type for socket */
+	ENOPROTOOPT     Errno = 92  /* Protocol not available */
+	EPROTONOSUPPORT Errno = 93  /* Unknown protocol */
+	ESOCKTNOSUPPORT Errno = 94  /* Socket type not supported */
+	EOPNOTSUPP      Errno = 95  /* Operation not supported on transport endpoint */
+	EPFNOSUPPORT    Errno = 96  /* Protocol family not supported */
+	EAFNOSUPPORT    Errno = 97  /* Address family not supported by protocol family */
+	EADDRINUSE      Errno = 98  /* Address already in use */
+	EADDRNOTAVAIL   Errno = 99  /* Address not available */
+	ENETDOWN        Errno = 100 /* Network interface is not configured */
+	ENETUNREACH     Errno = 101 /* Network is unreachable */
+	ENETRESET       Errno = 102
+	ECONNABORTED    Errno = 103 /* Connection aborted */
+	ECONNRESET      Errno = 104 /* Connection reset by peer */
+	ENOBUFS         Errno = 105 /* No buffer space available */
+	EISCONN         Errno = 106 /* Socket is already connected */
+	ENOTCONN        Errno = 107 /* Socket is not connected */
+	ESHUTDOWN       Errno = 108 /* Can't send after socket shutdown */
+	ETOOMANYREFS    Errno = 109
+	ETIMEDOUT       Errno = 110 /* Connection timed out */
+	ECONNREFUSED    Errno = 111 /* Connection refused */
+	EHOSTDOWN       Errno = 112 /* Host is down */
+	EHOSTUNREACH    Errno = 113 /* Host is unreachable */
+	EALREADY        Errno = 114 /* Socket already connected */
+	EINPROGRESS     Errno = 115 /* Connection already in progress */
+	ESTALE          Errno = 116
+	ENOTSUP         Errno = EOPNOTSUPP /* Not supported */
+	ENOMEDIUM       Errno = 123        /* No medium (in tape drive) */
+	ECANCELED       Errno = 125        /* Operation canceled. */
+	ELBIN           Errno = 2048       /* Inode is remote (not really error) */
+	EFTYPE          Errno = 2049       /* Inappropriate file type or format */
+	ENMFILE         Errno = 2050       /* No more files */
+	EPROCLIM        Errno = 2051
+	ENOSHARE        Errno = 2052   /* No such host or network path */
+	ECASECLASH      Errno = 2053   /* Filename exists with different case */
+	EWOULDBLOCK     Errno = EAGAIN /* Operation would block */
+)
+
+// TODO: Auto-generate some day. (Hard-coded in binaries so not likely to change.)
+var errorstr = [...]string{
+	EPERM:           "Operation not permitted",
+	ENOENT:          "No such file or directory",
+	ESRCH:           "No such process",
+	EINTR:           "Interrupted system call",
+	EIO:             "I/O error",
+	ENXIO:           "No such device or address",
+	E2BIG:           "Argument list too long",
+	ENOEXEC:         "Exec format error",
+	EBADF:           "Bad file number",
+	ECHILD:          "No child processes",
+	EAGAIN:          "Try again",
+	ENOMEM:          "Out of memory",
+	EACCES:          "Permission denied",
+	EFAULT:          "Bad address",
+	EBUSY:           "Device or resource busy",
+	EEXIST:          "File exists",
+	EXDEV:           "Cross-device link",
+	ENODEV:          "No such device",
+	ENOTDIR:         "Not a directory",
+	EISDIR:          "Is a directory",
+	EINVAL:          "Invalid argument",
+	ENFILE:          "File table overflow",
+	EMFILE:          "Too many open files",
+	ENOTTY:          "Not a typewriter",
+	EFBIG:           "File too large",
+	ENOSPC:          "No space left on device",
+	ESPIPE:          "Illegal seek",
+	EROFS:           "Read-only file system",
+	EMLINK:          "Too many links",
+	EPIPE:           "Broken pipe",
+	ENAMETOOLONG:    "File name too long",
+	ENOSYS:          "not implemented on Native Client",
+	EDQUOT:          "Quota exceeded",
+	EDOM:            "Math arg out of domain of func",
+	ERANGE:          "Math result not representable",
+	EDEADLK:         "Deadlock condition",
+	ENOLCK:          "No record locks available",
+	ENOTEMPTY:       "Directory not empty",
+	ELOOP:           "Too many symbolic links",
+	ENOMSG:          "No message of desired type",
+	EIDRM:           "Identifier removed",
+	ECHRNG:          "Channel number out of range",
+	EL2NSYNC:        "Level 2 not synchronized",
+	EL3HLT:          "Level 3 halted",
+	EL3RST:          "Level 3 reset",
+	ELNRNG:          "Link number out of range",
+	EUNATCH:         "Protocol driver not attached",
+	ENOCSI:          "No CSI structure available",
+	EL2HLT:          "Level 2 halted",
+	EBADE:           "Invalid exchange",
+	EBADR:           "Invalid request descriptor",
+	EXFULL:          "Exchange full",
+	ENOANO:          "No anode",
+	EBADRQC:         "Invalid request code",
+	EBADSLT:         "Invalid slot",
+	EBFONT:          "Bad font file fmt",
+	ENOSTR:          "Device not a stream",
+	ENODATA:         "No data (for no delay io)",
+	ETIME:           "Timer expired",
+	ENOSR:           "Out of streams resources",
+	ENONET:          "Machine is not on the network",
+	ENOPKG:          "Package not installed",
+	EREMOTE:         "The object is remote",
+	ENOLINK:         "The link has been severed",
+	EADV:            "Advertise error",
+	ESRMNT:          "Srmount error",
+	ECOMM:           "Communication error on send",
+	EPROTO:          "Protocol error",
+	EMULTIHOP:       "Multihop attempted",
+	EDOTDOT:         "Cross mount point (not really error)",
+	EBADMSG:         "Trying to read unreadable message",
+	EOVERFLOW:       "Value too large for defined data type",
+	ENOTUNIQ:        "Given log. name not unique",
+	EBADFD:          "f.d. invalid for this operation",
+	EREMCHG:         "Remote address changed",
+	ELIBACC:         "Can't access a needed shared lib",
+	ELIBBAD:         "Accessing a corrupted shared lib",
+	ELIBSCN:         ".lib section in a.out corrupted",
+	ELIBMAX:         "Attempting to link in too many libs",
+	ELIBEXEC:        "Attempting to exec a shared library",
+	ENOTSOCK:        "Socket operation on non-socket",
+	EDESTADDRREQ:    "Destination address required",
+	EMSGSIZE:        "Message too long",
+	EPROTOTYPE:      "Protocol wrong type for socket",
+	ENOPROTOOPT:     "Protocol not available",
+	EPROTONOSUPPORT: "Unknown protocol",
+	ESOCKTNOSUPPORT: "Socket type not supported",
+	EOPNOTSUPP:      "Operation not supported on transport endpoint",
+	EPFNOSUPPORT:    "Protocol family not supported",
+	EAFNOSUPPORT:    "Address family not supported by protocol family",
+	EADDRINUSE:      "Address already in use",
+	EADDRNOTAVAIL:   "Address not available",
+	ENETDOWN:        "Network interface is not configured",
+	ENETUNREACH:     "Network is unreachable",
+	ECONNABORTED:    "Connection aborted",
+	ECONNRESET:      "Connection reset by peer",
+	ENOBUFS:         "No buffer space available",
+	EISCONN:         "Socket is already connected",
+	ENOTCONN:        "Socket is not connected",
+	ESHUTDOWN:       "Can't send after socket shutdown",
+	ETIMEDOUT:       "Connection timed out",
+	ECONNREFUSED:    "Connection refused",
+	EHOSTDOWN:       "Host is down",
+	EHOSTUNREACH:    "Host is unreachable",
+	EALREADY:        "Socket already connected",
+	EINPROGRESS:     "Connection already in progress",
+	ENOMEDIUM:       "No medium (in tape drive)",
+	ECANCELED:       "Operation canceled.",
+	ELBIN:           "Inode is remote (not really error)",
+	EFTYPE:          "Inappropriate file type or format",
+	ENMFILE:         "No more files",
+	ENOSHARE:        "No such host or network path",
+	ECASECLASH:      "Filename exists with different case",
+}
diff --git a/src/pkg/syscall/time_nacl_386.s b/src/pkg/syscall/time_nacl_386.s
new file mode 100644
index 0000000..b5a22d3
--- /dev/null
+++ b/src/pkg/syscall/time_nacl_386.s
@@ -0,0 +1,11 @@
+// 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 "../../cmd/ld/textflag.h"
+
+TEXT ·startTimer(SB),NOSPLIT,$0
+	JMP time·startTimer(SB)
+
+TEXT ·stopTimer(SB),NOSPLIT,$0
+	JMP time·stopTimer(SB)
diff --git a/src/pkg/syscall/time_nacl_amd64p32.s b/src/pkg/syscall/time_nacl_amd64p32.s
new file mode 100644
index 0000000..b5a22d3
--- /dev/null
+++ b/src/pkg/syscall/time_nacl_amd64p32.s
@@ -0,0 +1,11 @@
+// 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 "../../cmd/ld/textflag.h"
+
+TEXT ·startTimer(SB),NOSPLIT,$0
+	JMP time·startTimer(SB)
+
+TEXT ·stopTimer(SB),NOSPLIT,$0
+	JMP time·stopTimer(SB)
diff --git a/src/pkg/syscall/types_dragonfly.go b/src/pkg/syscall/types_dragonfly.go
index 009b8f0..fb7fd1b 100644
--- a/src/pkg/syscall/types_dragonfly.go
+++ b/src/pkg/syscall/types_dragonfly.go
@@ -18,6 +18,7 @@ package syscall
 #include <dirent.h>
 #include <fcntl.h>
 #include <signal.h>
+#include <termios.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <sys/event.h>
@@ -97,10 +98,6 @@ type _Gid_t C.gid_t
 
 // Files
 
-const (
-	F_DUPFD_CLOEXEC = 0 // not supported
-)
-
 const ( // Directory mode bits
 	S_IFMT   = C.S_IFMT
 	S_IFIFO  = C.S_IFIFO
@@ -239,3 +236,7 @@ type BpfProgram C.struct_bpf_program
 type BpfInsn C.struct_bpf_insn
 
 type BpfHdr C.struct_bpf_hdr
+
+// Terminal handling
+
+type Termios C.struct_termios
diff --git a/src/pkg/syscall/types_freebsd.go b/src/pkg/syscall/types_freebsd.go
index ccf53d0..68a6931 100644
--- a/src/pkg/syscall/types_freebsd.go
+++ b/src/pkg/syscall/types_freebsd.go
@@ -18,6 +18,7 @@ package syscall
 #include <dirent.h>
 #include <fcntl.h>
 #include <signal.h>
+#include <termios.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <sys/event.h>
@@ -59,6 +60,91 @@ struct sockaddr_any {
 	char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
 };
 
+// This structure is a duplicate of stat on FreeBSD 8-STABLE.
+// See /usr/include/sys/stat.h.
+struct stat8 {
+#undef st_atimespec	st_atim
+#undef st_mtimespec	st_mtim
+#undef st_ctimespec	st_ctim
+#undef st_birthtimespec	st_birthtim
+	__dev_t   st_dev;
+	ino_t     st_ino;
+	mode_t    st_mode;
+	nlink_t   st_nlink;
+	uid_t     st_uid;
+	gid_t     st_gid;
+	__dev_t   st_rdev;
+#if __BSD_VISIBLE
+	struct  timespec st_atimespec;
+	struct  timespec st_mtimespec;
+	struct  timespec st_ctimespec;
+#else
+	time_t    st_atime;
+	long      __st_atimensec;
+	time_t    st_mtime;
+	long      __st_mtimensec;
+	time_t    st_ctime;
+	long      __st_ctimensec;
+#endif
+	off_t     st_size;
+	blkcnt_t st_blocks;
+	blksize_t st_blksize;
+	fflags_t  st_flags;
+	__uint32_t st_gen;
+	__int32_t st_lspare;
+#if __BSD_VISIBLE
+	struct timespec st_birthtimespec;
+	unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec));
+	unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec));
+#else
+	time_t    st_birthtime;
+	long      st_birthtimensec;
+	unsigned int :(8 / 2) * (16 - (int)sizeof(struct __timespec));
+	unsigned int :(8 / 2) * (16 - (int)sizeof(struct __timespec));
+#endif
+};
+
+// This structure is a duplicate of if_data on FreeBSD 8-STABLE.
+// See /usr/include/net/if.h.
+struct if_data8 {
+	u_char  ifi_type;
+	u_char  ifi_physical;
+	u_char  ifi_addrlen;
+	u_char  ifi_hdrlen;
+	u_char  ifi_link_state;
+	u_char  ifi_spare_char1;
+	u_char  ifi_spare_char2;
+	u_char  ifi_datalen;
+	u_long  ifi_mtu;
+	u_long  ifi_metric;
+	u_long  ifi_baudrate;
+	u_long  ifi_ipackets;
+	u_long  ifi_ierrors;
+	u_long  ifi_opackets;
+	u_long  ifi_oerrors;
+	u_long  ifi_collisions;
+	u_long  ifi_ibytes;
+	u_long  ifi_obytes;
+	u_long  ifi_imcasts;
+	u_long  ifi_omcasts;
+	u_long  ifi_iqdrops;
+	u_long  ifi_noproto;
+	u_long  ifi_hwassist;
+	time_t  ifi_epoch;
+	struct  timeval ifi_lastchange;
+};
+
+// This structure is a duplicate of if_msghdr on FreeBSD 8-STABLE.
+// See /usr/include/net/if.h.
+struct if_msghdr8 {
+	u_short ifm_msglen;
+	u_char  ifm_version;
+	u_char  ifm_type;
+	int     ifm_addrs;
+	int     ifm_flags;
+	u_short ifm_index;
+	struct  if_data8 ifm_data;
+};
 */
 import "C"
 
@@ -97,10 +183,6 @@ type _Gid_t C.gid_t
 
 // Files
 
-const (
-	O_CLOEXEC = 0 // not supported
-)
-
 const ( // Directory mode bits
 	S_IFMT   = C.S_IFMT
 	S_IFIFO  = C.S_IFIFO
@@ -118,7 +200,7 @@ const ( // Directory mode bits
 	S_IXUSR  = C.S_IXUSR
 )
 
-type Stat_t C.struct_stat
+type Stat_t C.struct_stat8
 
 type Statfs_t C.struct_statfs
 
@@ -200,8 +282,10 @@ type FdSet C.fd_set
 // Routing and interface messages
 
 const (
-	SizeofIfMsghdr         = C.sizeof_struct_if_msghdr
-	SizeofIfData           = C.sizeof_struct_if_data
+	sizeofIfMsghdr         = C.sizeof_struct_if_msghdr
+	SizeofIfMsghdr         = C.sizeof_struct_if_msghdr8
+	sizeofIfData           = C.sizeof_struct_if_data
+	SizeofIfData           = C.sizeof_struct_if_data8
 	SizeofIfaMsghdr        = C.sizeof_struct_ifa_msghdr
 	SizeofIfmaMsghdr       = C.sizeof_struct_ifma_msghdr
 	SizeofIfAnnounceMsghdr = C.sizeof_struct_if_announcemsghdr
@@ -209,9 +293,13 @@ const (
 	SizeofRtMetrics        = C.sizeof_struct_rt_metrics
 )
 
-type IfMsghdr C.struct_if_msghdr
+type ifMsghdr C.struct_if_msghdr
+
+type IfMsghdr C.struct_if_msghdr8
 
-type IfData C.struct_if_data
+type ifData C.struct_if_data
+
+type IfData C.struct_if_data8
 
 type IfaMsghdr C.struct_ifa_msghdr
 
@@ -248,3 +336,7 @@ type BpfInsn C.struct_bpf_insn
 type BpfHdr C.struct_bpf_hdr
 
 type BpfZbufHeader C.struct_bpf_zbuf_header
+
+// Terminal handling
+
+type Termios C.struct_termios
diff --git a/src/pkg/syscall/types_linux.go b/src/pkg/syscall/types_linux.go
index fea09d1..e8396a4 100644
--- a/src/pkg/syscall/types_linux.go
+++ b/src/pkg/syscall/types_linux.go
@@ -158,6 +158,8 @@ type Dirent C.struct_dirent
 
 type Fsid C.fsid_t
 
+type Flock_t C.struct_flock
+
 // Sockets
 
 type RawSockaddrInet4 C.struct_sockaddr_in
diff --git a/src/pkg/syscall/types_netbsd.go b/src/pkg/syscall/types_netbsd.go
index badaa10..04354a3 100644
--- a/src/pkg/syscall/types_netbsd.go
+++ b/src/pkg/syscall/types_netbsd.go
@@ -18,6 +18,7 @@ package syscall
 #include <dirent.h>
 #include <fcntl.h>
 #include <signal.h>
+#include <termios.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <sys/param.h>
@@ -222,6 +223,10 @@ type BpfHdr C.struct_bpf_hdr
 
 type BpfTimeval C.struct_bpf_timeval
 
+// Terminal handling
+
+type Termios C.struct_termios
+
 // Sysctl
 
 type Sysctlnode C.struct_sysctlnode
diff --git a/src/pkg/syscall/types_openbsd.go b/src/pkg/syscall/types_openbsd.go
index 6fe2af6..e6d1ea7 100644
--- a/src/pkg/syscall/types_openbsd.go
+++ b/src/pkg/syscall/types_openbsd.go
@@ -18,6 +18,7 @@ package syscall
 #include <dirent.h>
 #include <fcntl.h>
 #include <signal.h>
+#include <termios.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <sys/param.h>
@@ -237,3 +238,7 @@ type BpfInsn C.struct_bpf_insn
 type BpfHdr C.struct_bpf_hdr
 
 type BpfTimeval C.struct_bpf_timeval
+
+// Terminal handling
+
+type Termios C.struct_termios
diff --git a/src/pkg/syscall/types_solaris.go b/src/pkg/syscall/types_solaris.go
new file mode 100644
index 0000000..53fa350
--- /dev/null
+++ b/src/pkg/syscall/types_solaris.go
@@ -0,0 +1,222 @@
+// 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.
+
+// +build ignore
+
+/*
+Input to cgo -godefs.  See also mkerrors.sh and mkall.sh
+*/
+
+// +godefs map struct_in_addr [4]byte /* in_addr */
+// +godefs map struct_in6_addr [16]byte /* in6_addr */
+
+package syscall
+
+/*
+#define KERNEL
+#include <dirent.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <termios.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/select.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+#include <netinet/tcp.h>
+
+enum {
+	sizeofPtr = sizeof(void*),
+};
+
+union sockaddr_all {
+	struct sockaddr s1;	// this one gets used for fields
+	struct sockaddr_in s2;	// these pad it out
+	struct sockaddr_in6 s3;
+	struct sockaddr_un s4;
+	struct sockaddr_dl s5;
+};
+
+struct sockaddr_any {
+	struct sockaddr addr;
+	char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
+};
+
+*/
+import "C"
+
+// Machine characteristics; for internal use.
+
+const (
+	sizeofPtr      = C.sizeofPtr
+	sizeofShort    = C.sizeof_short
+	sizeofInt      = C.sizeof_int
+	sizeofLong     = C.sizeof_long
+	sizeofLongLong = C.sizeof_longlong
+)
+
+// Basic types
+
+type (
+	_C_short     C.short
+	_C_int       C.int
+	_C_long      C.long
+	_C_long_long C.longlong
+)
+
+// Time
+
+type Timespec C.struct_timespec
+
+type Timeval C.struct_timeval
+
+type Timeval32 C.struct_timeval32
+
+// Processes
+
+type Rusage C.struct_rusage
+
+type Rlimit C.struct_rlimit
+
+type _Gid_t C.gid_t
+
+// Files
+
+const ( // Directory mode bits
+	S_IFMT   = C.S_IFMT
+	S_IFIFO  = C.S_IFIFO
+	S_IFCHR  = C.S_IFCHR
+	S_IFDIR  = C.S_IFDIR
+	S_IFBLK  = C.S_IFBLK
+	S_IFREG  = C.S_IFREG
+	S_IFLNK  = C.S_IFLNK
+	S_IFSOCK = C.S_IFSOCK
+	S_ISUID  = C.S_ISUID
+	S_ISGID  = C.S_ISGID
+	S_ISVTX  = C.S_ISVTX
+	S_IRUSR  = C.S_IRUSR
+	S_IWUSR  = C.S_IWUSR
+	S_IXUSR  = C.S_IXUSR
+)
+
+type Stat_t C.struct_stat
+
+type Flock_t C.struct_flock
+
+type Dirent C.struct_dirent
+
+// Sockets
+
+type RawSockaddrInet4 C.struct_sockaddr_in
+
+type RawSockaddrInet6 C.struct_sockaddr_in6
+
+type RawSockaddrUnix C.struct_sockaddr_un
+
+type RawSockaddrDatalink C.struct_sockaddr_dl
+
+type RawSockaddr C.struct_sockaddr
+
+type RawSockaddrAny C.struct_sockaddr_any
+
+type _Socklen C.socklen_t
+
+type Linger C.struct_linger
+
+type Iovec C.struct_iovec
+
+type IPMreq C.struct_ip_mreq
+
+type IPv6Mreq C.struct_ipv6_mreq
+
+type Msghdr C.struct_msghdr
+
+type Cmsghdr C.struct_cmsghdr
+
+type Inet6Pktinfo C.struct_in6_pktinfo
+
+type IPv6MTUInfo C.struct_ip6_mtuinfo
+
+type ICMPv6Filter C.struct_icmp6_filter
+
+const (
+	SizeofSockaddrInet4    = C.sizeof_struct_sockaddr_in
+	SizeofSockaddrInet6    = C.sizeof_struct_sockaddr_in6
+	SizeofSockaddrAny      = C.sizeof_struct_sockaddr_any
+	SizeofSockaddrUnix     = C.sizeof_struct_sockaddr_un
+	SizeofSockaddrDatalink = C.sizeof_struct_sockaddr_dl
+	SizeofLinger           = C.sizeof_struct_linger
+	SizeofIPMreq           = C.sizeof_struct_ip_mreq
+	SizeofIPv6Mreq         = C.sizeof_struct_ipv6_mreq
+	SizeofMsghdr           = C.sizeof_struct_msghdr
+	SizeofCmsghdr          = C.sizeof_struct_cmsghdr
+	SizeofInet6Pktinfo     = C.sizeof_struct_in6_pktinfo
+	SizeofIPv6MTUInfo      = C.sizeof_struct_ip6_mtuinfo
+	SizeofICMPv6Filter     = C.sizeof_struct_icmp6_filter
+)
+
+// Select
+
+type FdSet C.fd_set
+
+// Routing and interface messages
+
+const (
+	SizeofIfMsghdr  = C.sizeof_struct_if_msghdr
+	SizeofIfData    = C.sizeof_struct_if_data
+	SizeofIfaMsghdr = C.sizeof_struct_ifa_msghdr
+	SizeofRtMsghdr  = C.sizeof_struct_rt_msghdr
+	SizeofRtMetrics = C.sizeof_struct_rt_metrics
+)
+
+type IfMsghdr C.struct_if_msghdr
+
+type IfData C.struct_if_data
+
+type IfaMsghdr C.struct_ifa_msghdr
+
+type RtMsghdr C.struct_rt_msghdr
+
+type RtMetrics C.struct_rt_metrics
+
+// Berkeley packet filter
+
+const (
+	SizeofBpfVersion = C.sizeof_struct_bpf_version
+	SizeofBpfStat    = C.sizeof_struct_bpf_stat
+	SizeofBpfProgram = C.sizeof_struct_bpf_program
+	SizeofBpfInsn    = C.sizeof_struct_bpf_insn
+	SizeofBpfHdr     = C.sizeof_struct_bpf_hdr
+)
+
+type BpfVersion C.struct_bpf_version
+
+type BpfStat C.struct_bpf_stat
+
+type BpfProgram C.struct_bpf_program
+
+type BpfInsn C.struct_bpf_insn
+
+type BpfTimeval C.struct_bpf_timeval
+
+type BpfHdr C.struct_bpf_hdr
+
+// Terminal handling
+
+type Termios C.struct_termios
diff --git a/src/pkg/syscall/unzip_nacl.go b/src/pkg/syscall/unzip_nacl.go
new file mode 100644
index 0000000..5845e44
--- /dev/null
+++ b/src/pkg/syscall/unzip_nacl.go
@@ -0,0 +1,685 @@
+// 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.
+
+// Small in-memory unzip implementation.
+// A simplified copy of the pre-Go 1 compress/flate/inflate.go
+// and a modified copy of the zip reader in package time.
+// (The one in package time does not support decompression; this one does.)
+
+package syscall
+
+const (
+	maxCodeLen = 16    // max length of Huffman code
+	maxHist    = 32768 // max history required
+	maxLit     = 286
+	maxDist    = 32
+	numCodes   = 19 // number of codes in Huffman meta-code
+)
+
+type decompressor struct {
+	in  string // compressed input
+	out []byte // uncompressed output
+	b   uint32 // input bits, at top of b
+	nb  uint
+	err bool // invalid input
+	eof bool // reached EOF
+
+	h1, h2   huffmanDecoder        // decoders for literal/length, distance
+	bits     [maxLit + maxDist]int // lengths defining Huffman codes
+	codebits [numCodes]int
+}
+
+func (f *decompressor) nextBlock() {
+	for f.nb < 1+2 {
+		if f.moreBits(); f.err {
+			return
+		}
+	}
+	f.eof = f.b&1 == 1
+	f.b >>= 1
+	typ := f.b & 3
+	f.b >>= 2
+	f.nb -= 1 + 2
+	switch typ {
+	case 0:
+		f.dataBlock()
+	case 1:
+		// compressed, fixed Huffman tables
+		f.huffmanBlock(&fixedHuffmanDecoder, nil)
+	case 2:
+		// compressed, dynamic Huffman tables
+		if f.readHuffman(); f.err {
+			break
+		}
+		f.huffmanBlock(&f.h1, &f.h2)
+	default:
+		// 3 is reserved.
+		f.err = true
+	}
+}
+
+// RFC 1951 section 3.2.7.
+// Compression with dynamic Huffman codes
+
+var codeOrder = [...]int{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
+
+func (f *decompressor) readHuffman() {
+	// HLIT[5], HDIST[5], HCLEN[4].
+	for f.nb < 5+5+4 {
+		if f.moreBits(); f.err {
+			return
+		}
+	}
+	nlit := int(f.b&0x1F) + 257
+	f.b >>= 5
+	ndist := int(f.b&0x1F) + 1
+	f.b >>= 5
+	nclen := int(f.b&0xF) + 4
+	f.b >>= 4
+	f.nb -= 5 + 5 + 4
+
+	// (HCLEN+4)*3 bits: code lengths in the magic codeOrder order.
+	for i := 0; i < nclen; i++ {
+		for f.nb < 3 {
+			if f.moreBits(); f.err {
+				return
+			}
+		}
+		f.codebits[codeOrder[i]] = int(f.b & 0x7)
+		f.b >>= 3
+		f.nb -= 3
+	}
+	for i := nclen; i < len(codeOrder); i++ {
+		f.codebits[codeOrder[i]] = 0
+	}
+	if !f.h1.init(f.codebits[0:]) {
+		f.err = true
+		return
+	}
+
+	// HLIT + 257 code lengths, HDIST + 1 code lengths,
+	// using the code length Huffman code.
+	for i, n := 0, nlit+ndist; i < n; {
+		x := f.huffSym(&f.h1)
+		if f.err {
+			return
+		}
+		if x < 16 {
+			// Actual length.
+			f.bits[i] = x
+			i++
+			continue
+		}
+		// Repeat previous length or zero.
+		var rep int
+		var nb uint
+		var b int
+		switch x {
+		default:
+			f.err = true
+			return
+		case 16:
+			rep = 3
+			nb = 2
+			if i == 0 {
+				f.err = true
+				return
+			}
+			b = f.bits[i-1]
+		case 17:
+			rep = 3
+			nb = 3
+			b = 0
+		case 18:
+			rep = 11
+			nb = 7
+			b = 0
+		}
+		for f.nb < nb {
+			if f.moreBits(); f.err {
+				return
+			}
+		}
+		rep += int(f.b & uint32(1<<nb-1))
+		f.b >>= nb
+		f.nb -= nb
+		if i+rep > n {
+			f.err = true
+			return
+		}
+		for j := 0; j < rep; j++ {
+			f.bits[i] = b
+			i++
+		}
+	}
+
+	if !f.h1.init(f.bits[0:nlit]) || !f.h2.init(f.bits[nlit:nlit+ndist]) {
+		f.err = true
+		return
+	}
+}
+
+// Decode a single Huffman block from f.
+// hl and hd are the Huffman states for the lit/length values
+// and the distance values, respectively.  If hd == nil, using the
+// fixed distance encoding associated with fixed Huffman blocks.
+func (f *decompressor) huffmanBlock(hl, hd *huffmanDecoder) {
+	for {
+		v := f.huffSym(hl)
+		if f.err {
+			return
+		}
+		var n uint // number of bits extra
+		var length int
+		switch {
+		case v < 256:
+			f.out = append(f.out, byte(v))
+			continue
+		case v == 256:
+			// Done with huffman block; read next block.
+			return
+		// otherwise, reference to older data
+		case v < 265:
+			length = v - (257 - 3)
+			n = 0
+		case v < 269:
+			length = v*2 - (265*2 - 11)
+			n = 1
+		case v < 273:
+			length = v*4 - (269*4 - 19)
+			n = 2
+		case v < 277:
+			length = v*8 - (273*8 - 35)
+			n = 3
+		case v < 281:
+			length = v*16 - (277*16 - 67)
+			n = 4
+		case v < 285:
+			length = v*32 - (281*32 - 131)
+			n = 5
+		default:
+			length = 258
+			n = 0
+		}
+		if n > 0 {
+			for f.nb < n {
+				if f.moreBits(); f.err {
+					return
+				}
+			}
+			length += int(f.b & uint32(1<<n-1))
+			f.b >>= n
+			f.nb -= n
+		}
+
+		var dist int
+		if hd == nil {
+			for f.nb < 5 {
+				if f.moreBits(); f.err {
+					return
+				}
+			}
+			dist = int(reverseByte[(f.b&0x1F)<<3])
+			f.b >>= 5
+			f.nb -= 5
+		} else {
+			if dist = f.huffSym(hd); f.err {
+				return
+			}
+		}
+
+		switch {
+		case dist < 4:
+			dist++
+		case dist >= 30:
+			f.err = true
+			return
+		default:
+			nb := uint(dist-2) >> 1
+			// have 1 bit in bottom of dist, need nb more.
+			extra := (dist & 1) << nb
+			for f.nb < nb {
+				if f.moreBits(); f.err {
+					return
+				}
+			}
+			extra |= int(f.b & uint32(1<<nb-1))
+			f.b >>= nb
+			f.nb -= nb
+			dist = 1<<(nb+1) + 1 + extra
+		}
+
+		// Copy [-dist:-dist+length] into output.
+		// Encoding can be prescient, so no check on length.
+		if dist > len(f.out) {
+			f.err = true
+			return
+		}
+
+		p := len(f.out) - dist
+		for i := 0; i < length; i++ {
+			f.out = append(f.out, f.out[p])
+			p++
+		}
+	}
+}
+
+// Copy a single uncompressed data block from input to output.
+func (f *decompressor) dataBlock() {
+	// Uncompressed.
+	// Discard current half-byte.
+	f.nb = 0
+	f.b = 0
+
+	if len(f.in) < 4 {
+		f.err = true
+		return
+	}
+
+	buf := f.in[:4]
+	f.in = f.in[4:]
+	n := int(buf[0]) | int(buf[1])<<8
+	nn := int(buf[2]) | int(buf[3])<<8
+	if uint16(nn) != uint16(^n) {
+		f.err = true
+		return
+	}
+
+	if len(f.in) < n {
+		f.err = true
+		return
+	}
+	f.out = append(f.out, f.in[:n]...)
+	f.in = f.in[n:]
+}
+
+func (f *decompressor) moreBits() {
+	if len(f.in) == 0 {
+		f.err = true
+		return
+	}
+	c := f.in[0]
+	f.in = f.in[1:]
+	f.b |= uint32(c) << f.nb
+	f.nb += 8
+}
+
+// Read the next Huffman-encoded symbol from f according to h.
+func (f *decompressor) huffSym(h *huffmanDecoder) int {
+	for n := uint(h.min); n <= uint(h.max); n++ {
+		lim := h.limit[n]
+		if lim == -1 {
+			continue
+		}
+		for f.nb < n {
+			if f.moreBits(); f.err {
+				return 0
+			}
+		}
+		v := int(f.b & uint32(1<<n-1))
+		v <<= 16 - n
+		v = int(reverseByte[v>>8]) | int(reverseByte[v&0xFF])<<8 // reverse bits
+		if v <= lim {
+			f.b >>= n
+			f.nb -= n
+			return h.codes[v-h.base[n]]
+		}
+	}
+	f.err = true
+	return 0
+}
+
+var reverseByte = [256]byte{
+	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+}
+
+// Hard-coded Huffman tables for DEFLATE algorithm.
+// See RFC 1951, section 3.2.6.
+var fixedHuffmanDecoder = huffmanDecoder{
+	7, 9,
+	[maxCodeLen + 1]int{7: 23, 199, 511},
+	[maxCodeLen + 1]int{7: 0, 24, 224},
+	[]int{
+		// length 7: 256-279
+		256, 257, 258, 259, 260, 261, 262,
+		263, 264, 265, 266, 267, 268, 269,
+		270, 271, 272, 273, 274, 275, 276,
+		277, 278, 279,
+
+		// length 8: 0-143
+		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+		12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+		22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+		32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+		42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+		52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+		62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
+		72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+		82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+		92, 93, 94, 95, 96, 97, 98, 99, 100,
+		101, 102, 103, 104, 105, 106, 107, 108,
+		109, 110, 111, 112, 113, 114, 115, 116,
+		117, 118, 119, 120, 121, 122, 123, 124,
+		125, 126, 127, 128, 129, 130, 131, 132,
+		133, 134, 135, 136, 137, 138, 139, 140,
+		141, 142, 143,
+
+		// length 8: 280-287
+		280, 281, 282, 283, 284, 285, 286, 287,
+
+		// length 9: 144-255
+		144, 145, 146, 147, 148, 149, 150, 151,
+		152, 153, 154, 155, 156, 157, 158, 159,
+		160, 161, 162, 163, 164, 165, 166, 167,
+		168, 169, 170, 171, 172, 173, 174, 175,
+		176, 177, 178, 179, 180, 181, 182, 183,
+		184, 185, 186, 187, 188, 189, 190, 191,
+		192, 193, 194, 195, 196, 197, 198, 199,
+		200, 201, 202, 203, 204, 205, 206, 207,
+		208, 209, 210, 211, 212, 213, 214, 215,
+		216, 217, 218, 219, 220, 221, 222, 223,
+		224, 225, 226, 227, 228, 229, 230, 231,
+		232, 233, 234, 235, 236, 237, 238, 239,
+		240, 241, 242, 243, 244, 245, 246, 247,
+		248, 249, 250, 251, 252, 253, 254, 255,
+	},
+}
+
+// Huffman decoder is based on
+// J. Brian Connell, ``A Huffman-Shannon-Fano Code,''
+// Proceedings of the IEEE, 61(7) (July 1973), pp 1046-1047.
+type huffmanDecoder struct {
+	// min, max code length
+	min, max int
+
+	// limit[i] = largest code word of length i
+	// Given code v of length n,
+	// need more bits if v > limit[n].
+	limit [maxCodeLen + 1]int
+
+	// base[i] = smallest code word of length i - seq number
+	base [maxCodeLen + 1]int
+
+	// codes[seq number] = output code.
+	// Given code v of length n, value is
+	// codes[v - base[n]].
+	codes []int
+}
+
+// Initialize Huffman decoding tables from array of code lengths.
+func (h *huffmanDecoder) init(bits []int) bool {
+	// Count number of codes of each length,
+	// compute min and max length.
+	var count [maxCodeLen + 1]int
+	var min, max int
+	for _, n := range bits {
+		if n == 0 {
+			continue
+		}
+		if min == 0 || n < min {
+			min = n
+		}
+		if n > max {
+			max = n
+		}
+		count[n]++
+	}
+	if max == 0 {
+		return false
+	}
+
+	h.min = min
+	h.max = max
+
+	// For each code range, compute
+	// nextcode (first code of that length),
+	// limit (last code of that length), and
+	// base (offset from first code to sequence number).
+	code := 0
+	seq := 0
+	var nextcode [maxCodeLen]int
+	for i := min; i <= max; i++ {
+		n := count[i]
+		nextcode[i] = code
+		h.base[i] = code - seq
+		code += n
+		seq += n
+		h.limit[i] = code - 1
+		code <<= 1
+	}
+
+	// Make array mapping sequence numbers to codes.
+	if len(h.codes) < len(bits) {
+		h.codes = make([]int, len(bits))
+	}
+	for i, n := range bits {
+		if n == 0 {
+			continue
+		}
+		code := nextcode[n]
+		nextcode[n]++
+		seq := code - h.base[n]
+		h.codes[seq] = i
+	}
+	return true
+}
+
+func inflate(in string) (out []byte) {
+	var d decompressor
+	d.in = in
+	for !d.err && !d.eof {
+		d.nextBlock()
+	}
+	if len(d.in) != 0 {
+		println("fs unzip: junk at end of compressed data")
+		return nil
+	}
+	return d.out
+}
+
+// get4 returns the little-endian 32-bit value in b.
+func zget4(b string) int {
+	if len(b) < 4 {
+		return 0
+	}
+	return int(b[0]) | int(b[1])<<8 | int(b[2])<<16 | int(b[3])<<24
+}
+
+// get2 returns the little-endian 16-bit value in b.
+func zget2(b string) int {
+	if len(b) < 2 {
+		return 0
+	}
+	return int(b[0]) | int(b[1])<<8
+}
+
+func unzip(data string) {
+	const (
+		zecheader   = 0x06054b50
+		zcheader    = 0x02014b50
+		ztailsize   = 22
+		zheadersize = 30
+		zheader     = 0x04034b50
+	)
+
+	buf := data[len(data)-ztailsize:]
+	n := zget2(buf[10:])
+	size := zget4(buf[12:])
+	off := zget4(buf[16:])
+
+	hdr := data[off : off+size]
+	for i := 0; i < n; i++ {
+		// zip entry layout:
+		//	0	magic[4]
+		//	4	madevers[1]
+		//	5	madeos[1]
+		//	6	extvers[1]
+		//	7	extos[1]
+		//	8	flags[2]
+		//	10	meth[2]
+		//	12	modtime[2]
+		//	14	moddate[2]
+		//	16	crc[4]
+		//	20	csize[4]
+		//	24	uncsize[4]
+		//	28	namelen[2]
+		//	30	xlen[2]
+		//	32	fclen[2]
+		//	34	disknum[2]
+		//	36	iattr[2]
+		//	38	eattr[4]
+		//	42	off[4]
+		//	46	name[namelen]
+		//	46+namelen+xlen+fclen - next header
+		//
+		if zget4(hdr) != zcheader {
+			println("fs unzip: bad magic")
+			break
+		}
+		meth := zget2(hdr[10:])
+		mtime := zget2(hdr[12:])
+		mdate := zget2(hdr[14:])
+		csize := zget4(hdr[20:])
+		size := zget4(hdr[24:])
+		namelen := zget2(hdr[28:])
+		xlen := zget2(hdr[30:])
+		fclen := zget2(hdr[32:])
+		xattr := uint32(zget4(hdr[38:])) >> 16
+		off := zget4(hdr[42:])
+		name := hdr[46 : 46+namelen]
+		hdr = hdr[46+namelen+xlen+fclen:]
+
+		// zip per-file header layout:
+		//	0	magic[4]
+		//	4	extvers[1]
+		//	5	extos[1]
+		//	6	flags[2]
+		//	8	meth[2]
+		//	10	modtime[2]
+		//	12	moddate[2]
+		//	14	crc[4]
+		//	18	csize[4]
+		//	22	uncsize[4]
+		//	26	namelen[2]
+		//	28	xlen[2]
+		//	30	name[namelen]
+		//	30+namelen+xlen - file data
+		//
+		buf := data[off : off+zheadersize+namelen]
+		if zget4(buf) != zheader ||
+			zget2(buf[8:]) != meth ||
+			zget2(buf[26:]) != namelen ||
+			buf[30:30+namelen] != name {
+			println("fs unzip: inconsistent zip file")
+			return
+		}
+		xlen = zget2(buf[28:])
+
+		off += zheadersize + namelen + xlen
+
+		var fdata []byte
+		switch meth {
+		case 0:
+			// buf is uncompressed
+			buf = data[off : off+size]
+			fdata = []byte(buf)
+		case 8:
+			// buf is deflate-compressed
+			buf = data[off : off+csize]
+			fdata = inflate(buf)
+			if len(fdata) != size {
+				println("fs unzip: inconsistent size in zip file")
+				return
+			}
+		}
+
+		if xattr&S_IFMT == 0 {
+			if xattr&0777 == 0 {
+				xattr |= 0666
+			}
+			if len(name) > 0 && name[len(name)-1] == '/' {
+				xattr |= S_IFDIR
+				xattr |= 0111
+			} else {
+				xattr |= S_IFREG
+			}
+		}
+
+		if err := create(name, xattr, zipToTime(mdate, mtime), fdata); err != nil {
+			print("fs unzip: create ", name, ": ", err.Error(), "\n")
+		}
+	}
+
+	chdirEnv()
+}
+
+func zipToTime(date, time int) int64 {
+	dd := date & 0x1f
+	mm := date >> 5 & 0xf
+	yy := date >> 9 // since 1980
+
+	sec := int64(315532800) // jan 1 1980
+	sec += int64(yy) * 365 * 86400
+	sec += int64(yy) / 4 * 86400
+	if yy%4 > 0 || mm >= 3 {
+		sec += 86400
+	}
+	sec += int64(daysBeforeMonth[mm]) * 86400
+	sec += int64(dd-1) * 86400
+
+	h := time >> 11
+	m := time >> 5 & 0x3F
+	s := time & 0x1f * 2
+	sec += int64(h*3600 + m*60 + s)
+
+	return sec
+}
+
+var daysBeforeMonth = [...]int32{
+	0,
+	0,
+	31,
+	31 + 28,
+	31 + 28 + 31,
+	31 + 28 + 31 + 30,
+	31 + 28 + 31 + 30 + 31,
+	31 + 28 + 31 + 30 + 31 + 30,
+	31 + 28 + 31 + 30 + 31 + 30 + 31,
+	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
+	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
+	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
+	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
+	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
+}
diff --git a/src/pkg/syscall/zerrors_dragonfly_386.go b/src/pkg/syscall/zerrors_dragonfly_386.go
index a2eb926..701a1c3 100644
--- a/src/pkg/syscall/zerrors_dragonfly_386.go
+++ b/src/pkg/syscall/zerrors_dragonfly_386.go
@@ -311,7 +311,10 @@ const (
 	FD_CLOEXEC                        = 0x1
 	FD_SETSIZE                        = 0x400
 	FLUSHO                            = 0x800000
+	F_DUP2FD                          = 0xa
+	F_DUP2FD_CLOEXEC                  = 0x12
 	F_DUPFD                           = 0x0
+	F_DUPFD_CLOEXEC                   = 0x11
 	F_GETFD                           = 0x1
 	F_GETFL                           = 0x3
 	F_GETLK                           = 0x7
@@ -1475,7 +1478,7 @@ var errors = [...]string{
 	90: "multihop attempted",
 	91: "link has been severed",
 	92: "protocol error",
-	93: "unknown error: 93",
+	93: "no medium found",
 	94: "unknown error: 94",
 	95: "unknown error: 95",
 	96: "unknown error: 96",
diff --git a/src/pkg/syscall/zerrors_dragonfly_amd64.go b/src/pkg/syscall/zerrors_dragonfly_amd64.go
index d2fe97c..59bff75 100644
--- a/src/pkg/syscall/zerrors_dragonfly_amd64.go
+++ b/src/pkg/syscall/zerrors_dragonfly_amd64.go
@@ -311,7 +311,10 @@ const (
 	FD_CLOEXEC                        = 0x1
 	FD_SETSIZE                        = 0x400
 	FLUSHO                            = 0x800000
+	F_DUP2FD                          = 0xa
+	F_DUP2FD_CLOEXEC                  = 0x12
 	F_DUPFD                           = 0x0
+	F_DUPFD_CLOEXEC                   = 0x11
 	F_GETFD                           = 0x1
 	F_GETFL                           = 0x3
 	F_GETLK                           = 0x7
@@ -1475,7 +1478,7 @@ var errors = [...]string{
 	90: "multihop attempted",
 	91: "link has been severed",
 	92: "protocol error",
-	93: "unknown error: 93",
+	93: "no medium found",
 	94: "unknown error: 94",
 	95: "unknown error: 95",
 	96: "unknown error: 96",
diff --git a/src/pkg/syscall/zerrors_freebsd_386.go b/src/pkg/syscall/zerrors_freebsd_386.go
index 43d7c59..cd3aa80 100644
--- a/src/pkg/syscall/zerrors_freebsd_386.go
+++ b/src/pkg/syscall/zerrors_freebsd_386.go
@@ -25,13 +25,15 @@ const (
 	AF_IMPLINK                        = 0x3
 	AF_INET                           = 0x2
 	AF_INET6                          = 0x1c
+	AF_INET6_SDP                      = 0x2a
+	AF_INET_SDP                       = 0x28
 	AF_IPX                            = 0x17
 	AF_ISDN                           = 0x1a
 	AF_ISO                            = 0x7
 	AF_LAT                            = 0xe
 	AF_LINK                           = 0x12
 	AF_LOCAL                          = 0x1
-	AF_MAX                            = 0x26
+	AF_MAX                            = 0x2a
 	AF_NATM                           = 0x1d
 	AF_NETBIOS                        = 0x6
 	AF_NETGRAPH                       = 0x20
@@ -332,10 +334,11 @@ const (
 	DLT_LINUX_SLL                     = 0x71
 	DLT_LOOP                          = 0x6c
 	DLT_LTALK                         = 0x72
-	DLT_MATCHING_MAX                  = 0xf2
+	DLT_MATCHING_MAX                  = 0xf6
 	DLT_MATCHING_MIN                  = 0x68
 	DLT_MFR                           = 0xb6
 	DLT_MOST                          = 0xd3
+	DLT_MPEG_2_TS                     = 0xf3
 	DLT_MPLS                          = 0xdb
 	DLT_MTP2                          = 0x8c
 	DLT_MTP2_WITH_PHDR                = 0x8b
@@ -343,7 +346,9 @@ const (
 	DLT_MUX27010                      = 0xec
 	DLT_NETANALYZER                   = 0xf0
 	DLT_NETANALYZER_TRANSPARENT       = 0xf1
+	DLT_NFC_LLCP                      = 0xf5
 	DLT_NFLOG                         = 0xef
+	DLT_NG40                          = 0xf4
 	DLT_NULL                          = 0x0
 	DLT_PCI_EXP                       = 0x7d
 	DLT_PFLOG                         = 0x75
@@ -423,6 +428,7 @@ const (
 	EV_DELETE                         = 0x2
 	EV_DISABLE                        = 0x8
 	EV_DISPATCH                       = 0x80
+	EV_DROP                           = 0x1000
 	EV_ENABLE                         = 0x4
 	EV_EOF                            = 0x8000
 	EV_ERROR                          = 0x4000
@@ -789,6 +795,7 @@ const (
 	IPPROTO_MHRP                      = 0x30
 	IPPROTO_MICP                      = 0x5f
 	IPPROTO_MOBILE                    = 0x37
+	IPPROTO_MPLS                      = 0x89
 	IPPROTO_MTP                       = 0x5c
 	IPPROTO_MUX                       = 0x12
 	IPPROTO_ND                        = 0x4d
@@ -996,6 +1003,9 @@ const (
 	MADV_RANDOM                       = 0x1
 	MADV_SEQUENTIAL                   = 0x2
 	MADV_WILLNEED                     = 0x3
+	MAP_ALIGNED_SUPER                 = 0x1000000
+	MAP_ALIGNMENT_MASK                = -0x1000000
+	MAP_ALIGNMENT_SHIFT               = 0x18
 	MAP_ANON                          = 0x1000
 	MAP_ANONYMOUS                     = 0x1000
 	MAP_COPY                          = 0x2
@@ -1014,6 +1024,7 @@ const (
 	MAP_STACK                         = 0x400
 	MCL_CURRENT                       = 0x1
 	MCL_FUTURE                        = 0x2
+	MSG_CMSG_CLOEXEC                  = 0x40000
 	MSG_COMPAT                        = 0x8000
 	MSG_CTRUNC                        = 0x20
 	MSG_DONTROUTE                     = 0x4
@@ -1030,6 +1041,7 @@ const (
 	MS_ASYNC                          = 0x1
 	MS_INVALIDATE                     = 0x2
 	MS_SYNC                           = 0x0
+	NAME_MAX                          = 0xff
 	NET_RT_DUMP                       = 0x1
 	NET_RT_FLAGS                      = 0x2
 	NET_RT_IFLIST                     = 0x3
@@ -1069,6 +1081,7 @@ const (
 	O_ACCMODE                         = 0x3
 	O_APPEND                          = 0x8
 	O_ASYNC                           = 0x40
+	O_CLOEXEC                         = 0x100000
 	O_CREAT                           = 0x200
 	O_DIRECT                          = 0x10000
 	O_DIRECTORY                       = 0x20000
@@ -1129,6 +1142,7 @@ const (
 	RTF_DYNAMIC                       = 0x10
 	RTF_FMASK                         = 0x1004d808
 	RTF_GATEWAY                       = 0x2
+	RTF_GWFLAG_COMPAT                 = 0x80000000
 	RTF_HOST                          = 0x4
 	RTF_LLDATA                        = 0x400
 	RTF_LLINFO                        = 0x400
@@ -1177,6 +1191,7 @@ const (
 	RTV_WEIGHT                        = 0x100
 	RT_CACHING_CONTEXT                = 0x1
 	RT_DEFAULT_FIB                    = 0x0
+	RT_NORTREF                        = 0x2
 	RUSAGE_CHILDREN                   = -0x1
 	RUSAGE_SELF                       = 0x0
 	RUSAGE_THREAD                     = 0x1
@@ -1258,8 +1273,10 @@ const (
 	SIOCSLIFPHYADDR                   = 0x8118694a
 	SIOCSLOWAT                        = 0x80047302
 	SIOCSPGRP                         = 0x80047308
+	SOCK_CLOEXEC                      = 0x10000000
 	SOCK_DGRAM                        = 0x2
 	SOCK_MAXADDRLEN                   = 0xff
+	SOCK_NONBLOCK                     = 0x20000000
 	SOCK_RAW                          = 0x3
 	SOCK_RDM                          = 0x4
 	SOCK_SEQPACKET                    = 0x5
@@ -1299,6 +1316,7 @@ const (
 	SO_TYPE                           = 0x1008
 	SO_USELOOPBACK                    = 0x40
 	SO_USER_COOKIE                    = 0x1015
+	SO_VENDOR                         = 0x80000000
 	TCIFLUSH                          = 0x1
 	TCIOFLUSH                         = 0x3
 	TCOFLUSH                          = 0x2
@@ -1322,6 +1340,7 @@ const (
 	TCP_NODELAY                       = 0x1
 	TCP_NOOPT                         = 0x8
 	TCP_NOPUSH                        = 0x4
+	TCP_VENDOR                        = 0x80000000
 	TCSAFLUSH                         = 0x2
 	TIOCCBRK                          = 0x2000747a
 	TIOCCDTR                          = 0x20007478
@@ -1407,10 +1426,12 @@ const (
 	VWERASE                           = 0x4
 	WCONTINUED                        = 0x4
 	WCOREFLAG                         = 0x80
+	WEXITED                           = 0x10
 	WLINUXCLONE                       = 0x80000000
 	WNOHANG                           = 0x1
 	WNOWAIT                           = 0x8
 	WSTOPPED                          = 0x2
+	WTRAPPED                          = 0x20
 	WUNTRACED                         = 0x2
 )
 
@@ -1453,7 +1474,7 @@ const (
 	EIO             = Errno(0x5)
 	EISCONN         = Errno(0x38)
 	EISDIR          = Errno(0x15)
-	ELAST           = Errno(0x5e)
+	ELAST           = Errno(0x60)
 	ELOOP           = Errno(0x3e)
 	EMFILE          = Errno(0x18)
 	EMLINK          = Errno(0x1f)
@@ -1482,12 +1503,14 @@ const (
 	ENOTCONN        = Errno(0x39)
 	ENOTDIR         = Errno(0x14)
 	ENOTEMPTY       = Errno(0x42)
+	ENOTRECOVERABLE = Errno(0x5f)
 	ENOTSOCK        = Errno(0x26)
 	ENOTSUP         = Errno(0x2d)
 	ENOTTY          = Errno(0x19)
 	ENXIO           = Errno(0x6)
 	EOPNOTSUPP      = Errno(0x2d)
 	EOVERFLOW       = Errno(0x54)
+	EOWNERDEAD      = Errno(0x60)
 	EPERM           = Errno(0x1)
 	EPFNOSUPPORT    = Errno(0x2e)
 	EPIPE           = Errno(0x20)
@@ -1531,6 +1554,7 @@ const (
 	SIGIO     = Signal(0x17)
 	SIGIOT    = Signal(0x6)
 	SIGKILL   = Signal(0x9)
+	SIGLIBRT  = Signal(0x21)
 	SIGLWP    = Signal(0x20)
 	SIGPIPE   = Signal(0xd)
 	SIGPROF   = Signal(0x1b)
@@ -1649,6 +1673,8 @@ var errors = [...]string{
 	92: "protocol error",
 	93: "capabilities insufficient",
 	94: "not permitted in capability mode",
+	95: "state not recoverable",
+	96: "previous owner died",
 }
 
 // Signal table
@@ -1685,4 +1711,5 @@ var signals = [...]string{
 	30: "user defined signal 1",
 	31: "user defined signal 2",
 	32: "unknown signal",
+	33: "unknown signal",
 }
diff --git a/src/pkg/syscall/zerrors_freebsd_amd64.go b/src/pkg/syscall/zerrors_freebsd_amd64.go
index 8e03f45..9edce6e 100644
--- a/src/pkg/syscall/zerrors_freebsd_amd64.go
+++ b/src/pkg/syscall/zerrors_freebsd_amd64.go
@@ -25,13 +25,15 @@ const (
 	AF_IMPLINK                        = 0x3
 	AF_INET                           = 0x2
 	AF_INET6                          = 0x1c
+	AF_INET6_SDP                      = 0x2a
+	AF_INET_SDP                       = 0x28
 	AF_IPX                            = 0x17
 	AF_ISDN                           = 0x1a
 	AF_ISO                            = 0x7
 	AF_LAT                            = 0xe
 	AF_LINK                           = 0x12
 	AF_LOCAL                          = 0x1
-	AF_MAX                            = 0x26
+	AF_MAX                            = 0x2a
 	AF_NATM                           = 0x1d
 	AF_NETBIOS                        = 0x6
 	AF_NETGRAPH                       = 0x20
@@ -332,10 +334,11 @@ const (
 	DLT_LINUX_SLL                     = 0x71
 	DLT_LOOP                          = 0x6c
 	DLT_LTALK                         = 0x72
-	DLT_MATCHING_MAX                  = 0xf2
+	DLT_MATCHING_MAX                  = 0xf6
 	DLT_MATCHING_MIN                  = 0x68
 	DLT_MFR                           = 0xb6
 	DLT_MOST                          = 0xd3
+	DLT_MPEG_2_TS                     = 0xf3
 	DLT_MPLS                          = 0xdb
 	DLT_MTP2                          = 0x8c
 	DLT_MTP2_WITH_PHDR                = 0x8b
@@ -343,7 +346,9 @@ const (
 	DLT_MUX27010                      = 0xec
 	DLT_NETANALYZER                   = 0xf0
 	DLT_NETANALYZER_TRANSPARENT       = 0xf1
+	DLT_NFC_LLCP                      = 0xf5
 	DLT_NFLOG                         = 0xef
+	DLT_NG40                          = 0xf4
 	DLT_NULL                          = 0x0
 	DLT_PCI_EXP                       = 0x7d
 	DLT_PFLOG                         = 0x75
@@ -423,6 +428,7 @@ const (
 	EV_DELETE                         = 0x2
 	EV_DISABLE                        = 0x8
 	EV_DISPATCH                       = 0x80
+	EV_DROP                           = 0x1000
 	EV_ENABLE                         = 0x4
 	EV_EOF                            = 0x8000
 	EV_ERROR                          = 0x4000
@@ -789,6 +795,7 @@ const (
 	IPPROTO_MHRP                      = 0x30
 	IPPROTO_MICP                      = 0x5f
 	IPPROTO_MOBILE                    = 0x37
+	IPPROTO_MPLS                      = 0x89
 	IPPROTO_MTP                       = 0x5c
 	IPPROTO_MUX                       = 0x12
 	IPPROTO_ND                        = 0x4d
@@ -996,6 +1003,10 @@ const (
 	MADV_RANDOM                       = 0x1
 	MADV_SEQUENTIAL                   = 0x2
 	MADV_WILLNEED                     = 0x3
+	MAP_32BIT                         = 0x80000
+	MAP_ALIGNED_SUPER                 = 0x1000000
+	MAP_ALIGNMENT_MASK                = -0x1000000
+	MAP_ALIGNMENT_SHIFT               = 0x18
 	MAP_ANON                          = 0x1000
 	MAP_ANONYMOUS                     = 0x1000
 	MAP_COPY                          = 0x2
@@ -1014,6 +1025,7 @@ const (
 	MAP_STACK                         = 0x400
 	MCL_CURRENT                       = 0x1
 	MCL_FUTURE                        = 0x2
+	MSG_CMSG_CLOEXEC                  = 0x40000
 	MSG_COMPAT                        = 0x8000
 	MSG_CTRUNC                        = 0x20
 	MSG_DONTROUTE                     = 0x4
@@ -1030,6 +1042,7 @@ const (
 	MS_ASYNC                          = 0x1
 	MS_INVALIDATE                     = 0x2
 	MS_SYNC                           = 0x0
+	NAME_MAX                          = 0xff
 	NET_RT_DUMP                       = 0x1
 	NET_RT_FLAGS                      = 0x2
 	NET_RT_IFLIST                     = 0x3
@@ -1069,6 +1082,7 @@ const (
 	O_ACCMODE                         = 0x3
 	O_APPEND                          = 0x8
 	O_ASYNC                           = 0x40
+	O_CLOEXEC                         = 0x100000
 	O_CREAT                           = 0x200
 	O_DIRECT                          = 0x10000
 	O_DIRECTORY                       = 0x20000
@@ -1129,6 +1143,7 @@ const (
 	RTF_DYNAMIC                       = 0x10
 	RTF_FMASK                         = 0x1004d808
 	RTF_GATEWAY                       = 0x2
+	RTF_GWFLAG_COMPAT                 = 0x80000000
 	RTF_HOST                          = 0x4
 	RTF_LLDATA                        = 0x400
 	RTF_LLINFO                        = 0x400
@@ -1177,6 +1192,7 @@ const (
 	RTV_WEIGHT                        = 0x100
 	RT_CACHING_CONTEXT                = 0x1
 	RT_DEFAULT_FIB                    = 0x0
+	RT_NORTREF                        = 0x2
 	RUSAGE_CHILDREN                   = -0x1
 	RUSAGE_SELF                       = 0x0
 	RUSAGE_THREAD                     = 0x1
@@ -1258,8 +1274,10 @@ const (
 	SIOCSLIFPHYADDR                   = 0x8118694a
 	SIOCSLOWAT                        = 0x80047302
 	SIOCSPGRP                         = 0x80047308
+	SOCK_CLOEXEC                      = 0x10000000
 	SOCK_DGRAM                        = 0x2
 	SOCK_MAXADDRLEN                   = 0xff
+	SOCK_NONBLOCK                     = 0x20000000
 	SOCK_RAW                          = 0x3
 	SOCK_RDM                          = 0x4
 	SOCK_SEQPACKET                    = 0x5
@@ -1299,6 +1317,7 @@ const (
 	SO_TYPE                           = 0x1008
 	SO_USELOOPBACK                    = 0x40
 	SO_USER_COOKIE                    = 0x1015
+	SO_VENDOR                         = 0x80000000
 	TCIFLUSH                          = 0x1
 	TCIOFLUSH                         = 0x3
 	TCOFLUSH                          = 0x2
@@ -1322,6 +1341,7 @@ const (
 	TCP_NODELAY                       = 0x1
 	TCP_NOOPT                         = 0x8
 	TCP_NOPUSH                        = 0x4
+	TCP_VENDOR                        = 0x80000000
 	TCSAFLUSH                         = 0x2
 	TIOCCBRK                          = 0x2000747a
 	TIOCCDTR                          = 0x20007478
@@ -1407,10 +1427,12 @@ const (
 	VWERASE                           = 0x4
 	WCONTINUED                        = 0x4
 	WCOREFLAG                         = 0x80
+	WEXITED                           = 0x10
 	WLINUXCLONE                       = 0x80000000
 	WNOHANG                           = 0x1
 	WNOWAIT                           = 0x8
 	WSTOPPED                          = 0x2
+	WTRAPPED                          = 0x20
 	WUNTRACED                         = 0x2
 )
 
@@ -1453,7 +1475,7 @@ const (
 	EIO             = Errno(0x5)
 	EISCONN         = Errno(0x38)
 	EISDIR          = Errno(0x15)
-	ELAST           = Errno(0x5e)
+	ELAST           = Errno(0x60)
 	ELOOP           = Errno(0x3e)
 	EMFILE          = Errno(0x18)
 	EMLINK          = Errno(0x1f)
@@ -1482,12 +1504,14 @@ const (
 	ENOTCONN        = Errno(0x39)
 	ENOTDIR         = Errno(0x14)
 	ENOTEMPTY       = Errno(0x42)
+	ENOTRECOVERABLE = Errno(0x5f)
 	ENOTSOCK        = Errno(0x26)
 	ENOTSUP         = Errno(0x2d)
 	ENOTTY          = Errno(0x19)
 	ENXIO           = Errno(0x6)
 	EOPNOTSUPP      = Errno(0x2d)
 	EOVERFLOW       = Errno(0x54)
+	EOWNERDEAD      = Errno(0x60)
 	EPERM           = Errno(0x1)
 	EPFNOSUPPORT    = Errno(0x2e)
 	EPIPE           = Errno(0x20)
@@ -1531,6 +1555,7 @@ const (
 	SIGIO     = Signal(0x17)
 	SIGIOT    = Signal(0x6)
 	SIGKILL   = Signal(0x9)
+	SIGLIBRT  = Signal(0x21)
 	SIGLWP    = Signal(0x20)
 	SIGPIPE   = Signal(0xd)
 	SIGPROF   = Signal(0x1b)
@@ -1649,6 +1674,8 @@ var errors = [...]string{
 	92: "protocol error",
 	93: "capabilities insufficient",
 	94: "not permitted in capability mode",
+	95: "state not recoverable",
+	96: "previous owner died",
 }
 
 // Signal table
@@ -1685,4 +1712,5 @@ var signals = [...]string{
 	30: "user defined signal 1",
 	31: "user defined signal 2",
 	32: "unknown signal",
+	33: "unknown signal",
 }
diff --git a/src/pkg/syscall/zerrors_freebsd_arm.go b/src/pkg/syscall/zerrors_freebsd_arm.go
index 269f179..f29dd05 100644
--- a/src/pkg/syscall/zerrors_freebsd_arm.go
+++ b/src/pkg/syscall/zerrors_freebsd_arm.go
@@ -25,13 +25,15 @@ const (
 	AF_IMPLINK                        = 0x3
 	AF_INET                           = 0x2
 	AF_INET6                          = 0x1c
+	AF_INET6_SDP                      = 0x2a
+	AF_INET_SDP                       = 0x28
 	AF_IPX                            = 0x17
 	AF_ISDN                           = 0x1a
 	AF_ISO                            = 0x7
 	AF_LAT                            = 0xe
 	AF_LINK                           = 0x12
 	AF_LOCAL                          = 0x1
-	AF_MAX                            = 0x26
+	AF_MAX                            = 0x2a
 	AF_NATM                           = 0x1d
 	AF_NETBIOS                        = 0x6
 	AF_NETGRAPH                       = 0x20
@@ -128,7 +130,7 @@ const (
 	BIOCGETZMAX                       = 0x4004427f
 	BIOCGHDRCMPLT                     = 0x40044274
 	BIOCGRSIG                         = 0x40044272
-	BIOCGRTIMEOUT                     = 0x400c426e
+	BIOCGRTIMEOUT                     = 0x4010426e
 	BIOCGSEESENT                      = 0x40044276
 	BIOCGSTATS                        = 0x4008426f
 	BIOCGTSTAMP                       = 0x40044283
@@ -147,7 +149,7 @@ const (
 	BIOCSETZBUF                       = 0x800c4281
 	BIOCSHDRCMPLT                     = 0x80044275
 	BIOCSRSIG                         = 0x80044273
-	BIOCSRTIMEOUT                     = 0x800c426d
+	BIOCSRTIMEOUT                     = 0x8010426d
 	BIOCSSEESENT                      = 0x80044277
 	BIOCSTSTAMP                       = 0x80044284
 	BIOCVERSION                       = 0x40044271
@@ -426,6 +428,7 @@ const (
 	EV_DELETE                         = 0x2
 	EV_DISABLE                        = 0x8
 	EV_DISPATCH                       = 0x80
+	EV_DROP                           = 0x1000
 	EV_ENABLE                         = 0x4
 	EV_EOF                            = 0x8000
 	EV_ERROR                          = 0x4000
@@ -521,6 +524,7 @@ const (
 	IFT_BGPPOLICYACCOUNTING           = 0xa2
 	IFT_BRIDGE                        = 0xd1
 	IFT_BSC                           = 0x53
+	IFT_CARP                          = 0xf8
 	IFT_CCTEMUL                       = 0x3d
 	IFT_CEPT                          = 0x13
 	IFT_CES                           = 0x85
@@ -999,6 +1003,9 @@ const (
 	MADV_RANDOM                       = 0x1
 	MADV_SEQUENTIAL                   = 0x2
 	MADV_WILLNEED                     = 0x3
+	MAP_ALIGNED_SUPER                 = 0x1000000
+	MAP_ALIGNMENT_MASK                = -0x1000000
+	MAP_ALIGNMENT_SHIFT               = 0x18
 	MAP_ANON                          = 0x1000
 	MAP_ANONYMOUS                     = 0x1000
 	MAP_COPY                          = 0x2
@@ -1017,6 +1024,7 @@ const (
 	MAP_STACK                         = 0x400
 	MCL_CURRENT                       = 0x1
 	MCL_FUTURE                        = 0x2
+	MSG_CMSG_CLOEXEC                  = 0x40000
 	MSG_COMPAT                        = 0x8000
 	MSG_CTRUNC                        = 0x20
 	MSG_DONTROUTE                     = 0x4
@@ -1033,6 +1041,7 @@ const (
 	MS_ASYNC                          = 0x1
 	MS_INVALIDATE                     = 0x2
 	MS_SYNC                           = 0x0
+	NAME_MAX                          = 0xff
 	NET_RT_DUMP                       = 0x1
 	NET_RT_FLAGS                      = 0x2
 	NET_RT_IFLIST                     = 0x3
@@ -1072,6 +1081,7 @@ const (
 	O_ACCMODE                         = 0x3
 	O_APPEND                          = 0x8
 	O_ASYNC                           = 0x40
+	O_CLOEXEC                         = 0x100000
 	O_CREAT                           = 0x200
 	O_DIRECT                          = 0x10000
 	O_DIRECTORY                       = 0x20000
@@ -1132,6 +1142,7 @@ const (
 	RTF_DYNAMIC                       = 0x10
 	RTF_FMASK                         = 0x1004d808
 	RTF_GATEWAY                       = 0x2
+	RTF_GWFLAG_COMPAT                 = 0x80000000
 	RTF_HOST                          = 0x4
 	RTF_LLDATA                        = 0x400
 	RTF_LLINFO                        = 0x400
@@ -1193,7 +1204,7 @@ const (
 	SHUT_WR                           = 0x1
 	SIOCADDMULTI                      = 0x80206931
 	SIOCADDRT                         = 0x8030720a
-	SIOCAIFADDR                       = 0x8044692b
+	SIOCAIFADDR                       = 0x8040691a
 	SIOCAIFGROUP                      = 0x80246987
 	SIOCALIFADDR                      = 0x8118691b
 	SIOCATMARK                        = 0x40047307
@@ -1227,7 +1238,7 @@ const (
 	SIOCGIFPDSTADDR                   = 0xc0206948
 	SIOCGIFPHYS                       = 0xc0206935
 	SIOCGIFPSRCADDR                   = 0xc0206947
-	SIOCGIFSTATUS                     = 0xc334693b
+	SIOCGIFSTATUS                     = 0xc331693b
 	SIOCGLIFADDR                      = 0xc118691c
 	SIOCGLIFPHYADDR                   = 0xc118694b
 	SIOCGLOWAT                        = 0x40047303
@@ -1255,15 +1266,17 @@ const (
 	SIOCSIFMTU                        = 0x80206934
 	SIOCSIFNAME                       = 0x80206928
 	SIOCSIFNETMASK                    = 0x80206916
-	SIOCSIFPHYADDR                    = 0x80446946
+	SIOCSIFPHYADDR                    = 0x80406946
 	SIOCSIFPHYS                       = 0x80206936
 	SIOCSIFRVNET                      = 0xc020695b
 	SIOCSIFVNET                       = 0xc020695a
 	SIOCSLIFPHYADDR                   = 0x8118694a
 	SIOCSLOWAT                        = 0x80047302
 	SIOCSPGRP                         = 0x80047308
+	SOCK_CLOEXEC                      = 0x10000000
 	SOCK_DGRAM                        = 0x2
 	SOCK_MAXADDRLEN                   = 0xff
+	SOCK_NONBLOCK                     = 0x20000000
 	SOCK_RAW                          = 0x3
 	SOCK_RDM                          = 0x4
 	SOCK_SEQPACKET                    = 0x5
@@ -1303,6 +1316,7 @@ const (
 	SO_TYPE                           = 0x1008
 	SO_USELOOPBACK                    = 0x40
 	SO_USER_COOKIE                    = 0x1015
+	SO_VENDOR                         = 0x80000000
 	TCIFLUSH                          = 0x1
 	TCIOFLUSH                         = 0x3
 	TCOFLUSH                          = 0x2
@@ -1326,6 +1340,7 @@ const (
 	TCP_NODELAY                       = 0x1
 	TCP_NOOPT                         = 0x8
 	TCP_NOPUSH                        = 0x4
+	TCP_VENDOR                        = 0x80000000
 	TCSAFLUSH                         = 0x2
 	TIOCCBRK                          = 0x2000747a
 	TIOCCDTR                          = 0x20007478
@@ -1387,7 +1402,7 @@ const (
 	TIOCSTI                           = 0x80017472
 	TIOCSTOP                          = 0x2000746f
 	TIOCSWINSZ                        = 0x80087467
-	TIOCTIMESTAMP                     = 0x400c7459
+	TIOCTIMESTAMP                     = 0x40107459
 	TIOCUCNTL                         = 0x80047466
 	TOSTOP                            = 0x400000
 	VDISCARD                          = 0xf
@@ -1459,7 +1474,7 @@ const (
 	EIO             = Errno(0x5)
 	EISCONN         = Errno(0x38)
 	EISDIR          = Errno(0x15)
-	ELAST           = Errno(0x5e)
+	ELAST           = Errno(0x60)
 	ELOOP           = Errno(0x3e)
 	EMFILE          = Errno(0x18)
 	EMLINK          = Errno(0x1f)
@@ -1488,12 +1503,14 @@ const (
 	ENOTCONN        = Errno(0x39)
 	ENOTDIR         = Errno(0x14)
 	ENOTEMPTY       = Errno(0x42)
+	ENOTRECOVERABLE = Errno(0x5f)
 	ENOTSOCK        = Errno(0x26)
 	ENOTSUP         = Errno(0x2d)
 	ENOTTY          = Errno(0x19)
 	ENXIO           = Errno(0x6)
 	EOPNOTSUPP      = Errno(0x2d)
 	EOVERFLOW       = Errno(0x54)
+	EOWNERDEAD      = Errno(0x60)
 	EPERM           = Errno(0x1)
 	EPFNOSUPPORT    = Errno(0x2e)
 	EPIPE           = Errno(0x20)
@@ -1656,6 +1673,8 @@ var errors = [...]string{
 	92: "protocol error",
 	93: "capabilities insufficient",
 	94: "not permitted in capability mode",
+	95: "state not recoverable",
+	96: "previous owner died",
 }
 
 // Signal table
diff --git a/src/pkg/syscall/zerrors_netbsd_386.go b/src/pkg/syscall/zerrors_netbsd_386.go
index 9b93f5a..1e3dff7 100644
--- a/src/pkg/syscall/zerrors_netbsd_386.go
+++ b/src/pkg/syscall/zerrors_netbsd_386.go
@@ -146,6 +146,14 @@ const (
 	BRKINT                            = 0x2
 	CFLUSH                            = 0xf
 	CLOCAL                            = 0x8000
+	CLONE_CSIGNAL                     = 0xff
+	CLONE_FILES                       = 0x400
+	CLONE_FS                          = 0x200
+	CLONE_PID                         = 0x1000
+	CLONE_PTRACE                      = 0x2000
+	CLONE_SIGHAND                     = 0x800
+	CLONE_VFORK                       = 0x4000
+	CLONE_VM                          = 0x100
 	CREAD                             = 0x800
 	CS5                               = 0x0
 	CS6                               = 0x100
@@ -962,6 +970,40 @@ const (
 	LOCK_NB                           = 0x4
 	LOCK_SH                           = 0x1
 	LOCK_UN                           = 0x8
+	MADV_DONTNEED                     = 0x4
+	MADV_FREE                         = 0x6
+	MADV_NORMAL                       = 0x0
+	MADV_RANDOM                       = 0x1
+	MADV_SEQUENTIAL                   = 0x2
+	MADV_SPACEAVAIL                   = 0x5
+	MADV_WILLNEED                     = 0x3
+	MAP_ALIGNMENT_16MB                = 0x18000000
+	MAP_ALIGNMENT_1TB                 = 0x28000000
+	MAP_ALIGNMENT_256TB               = 0x30000000
+	MAP_ALIGNMENT_4GB                 = 0x20000000
+	MAP_ALIGNMENT_64KB                = 0x10000000
+	MAP_ALIGNMENT_64PB                = 0x38000000
+	MAP_ALIGNMENT_MASK                = -0x1000000
+	MAP_ALIGNMENT_SHIFT               = 0x18
+	MAP_ANON                          = 0x1000
+	MAP_FILE                          = 0x0
+	MAP_FIXED                         = 0x10
+	MAP_HASSEMAPHORE                  = 0x200
+	MAP_INHERIT                       = 0x80
+	MAP_INHERIT_COPY                  = 0x1
+	MAP_INHERIT_DEFAULT               = 0x1
+	MAP_INHERIT_DONATE_COPY           = 0x3
+	MAP_INHERIT_NONE                  = 0x2
+	MAP_INHERIT_SHARE                 = 0x0
+	MAP_NORESERVE                     = 0x40
+	MAP_PRIVATE                       = 0x2
+	MAP_RENAME                        = 0x20
+	MAP_SHARED                        = 0x1
+	MAP_STACK                         = 0x2000
+	MAP_TRYFIXED                      = 0x400
+	MAP_WIRED                         = 0x800
+	MCL_CURRENT                       = 0x1
+	MCL_FUTURE                        = 0x2
 	MSG_BCAST                         = 0x100
 	MSG_CMSG_CLOEXEC                  = 0x800
 	MSG_CONTROLMBUF                   = 0x2000000
@@ -980,6 +1022,9 @@ const (
 	MSG_TRUNC                         = 0x10
 	MSG_USERFLAGS                     = 0xffffff
 	MSG_WAITALL                       = 0x40
+	MS_ASYNC                          = 0x1
+	MS_INVALIDATE                     = 0x2
+	MS_SYNC                           = 0x4
 	NAME_MAX                          = 0x1ff
 	NET_RT_DUMP                       = 0x1
 	NET_RT_FLAGS                      = 0x2
@@ -1039,10 +1084,14 @@ const (
 	PARMRK                            = 0x8
 	PARODD                            = 0x2000
 	PENDIN                            = 0x20000000
-	PRI_IOFLUSH                       = 0x7c
 	PRIO_PGRP                         = 0x1
 	PRIO_PROCESS                      = 0x0
 	PRIO_USER                         = 0x2
+	PRI_IOFLUSH                       = 0x7c
+	PROT_EXEC                         = 0x4
+	PROT_NONE                         = 0x0
+	PROT_READ                         = 0x1
+	PROT_WRITE                        = 0x2
 	RLIMIT_AS                         = 0xa
 	RLIMIT_CORE                       = 0x4
 	RLIMIT_CPU                        = 0x0
diff --git a/src/pkg/syscall/zerrors_netbsd_amd64.go b/src/pkg/syscall/zerrors_netbsd_amd64.go
index 4db30fa..1469d00 100644
--- a/src/pkg/syscall/zerrors_netbsd_amd64.go
+++ b/src/pkg/syscall/zerrors_netbsd_amd64.go
@@ -146,6 +146,14 @@ const (
 	BRKINT                            = 0x2
 	CFLUSH                            = 0xf
 	CLOCAL                            = 0x8000
+	CLONE_CSIGNAL                     = 0xff
+	CLONE_FILES                       = 0x400
+	CLONE_FS                          = 0x200
+	CLONE_PID                         = 0x1000
+	CLONE_PTRACE                      = 0x2000
+	CLONE_SIGHAND                     = 0x800
+	CLONE_VFORK                       = 0x4000
+	CLONE_VM                          = 0x100
 	CREAD                             = 0x800
 	CS5                               = 0x0
 	CS6                               = 0x100
@@ -952,6 +960,40 @@ const (
 	LOCK_NB                           = 0x4
 	LOCK_SH                           = 0x1
 	LOCK_UN                           = 0x8
+	MADV_DONTNEED                     = 0x4
+	MADV_FREE                         = 0x6
+	MADV_NORMAL                       = 0x0
+	MADV_RANDOM                       = 0x1
+	MADV_SEQUENTIAL                   = 0x2
+	MADV_SPACEAVAIL                   = 0x5
+	MADV_WILLNEED                     = 0x3
+	MAP_ALIGNMENT_16MB                = 0x18000000
+	MAP_ALIGNMENT_1TB                 = 0x28000000
+	MAP_ALIGNMENT_256TB               = 0x30000000
+	MAP_ALIGNMENT_4GB                 = 0x20000000
+	MAP_ALIGNMENT_64KB                = 0x10000000
+	MAP_ALIGNMENT_64PB                = 0x38000000
+	MAP_ALIGNMENT_MASK                = -0x1000000
+	MAP_ALIGNMENT_SHIFT               = 0x18
+	MAP_ANON                          = 0x1000
+	MAP_FILE                          = 0x0
+	MAP_FIXED                         = 0x10
+	MAP_HASSEMAPHORE                  = 0x200
+	MAP_INHERIT                       = 0x80
+	MAP_INHERIT_COPY                  = 0x1
+	MAP_INHERIT_DEFAULT               = 0x1
+	MAP_INHERIT_DONATE_COPY           = 0x3
+	MAP_INHERIT_NONE                  = 0x2
+	MAP_INHERIT_SHARE                 = 0x0
+	MAP_NORESERVE                     = 0x40
+	MAP_PRIVATE                       = 0x2
+	MAP_RENAME                        = 0x20
+	MAP_SHARED                        = 0x1
+	MAP_STACK                         = 0x2000
+	MAP_TRYFIXED                      = 0x400
+	MAP_WIRED                         = 0x800
+	MCL_CURRENT                       = 0x1
+	MCL_FUTURE                        = 0x2
 	MSG_BCAST                         = 0x100
 	MSG_CMSG_CLOEXEC                  = 0x800
 	MSG_CONTROLMBUF                   = 0x2000000
@@ -970,6 +1012,9 @@ const (
 	MSG_TRUNC                         = 0x10
 	MSG_USERFLAGS                     = 0xffffff
 	MSG_WAITALL                       = 0x40
+	MS_ASYNC                          = 0x1
+	MS_INVALIDATE                     = 0x2
+	MS_SYNC                           = 0x4
 	NAME_MAX                          = 0x1ff
 	NET_RT_DUMP                       = 0x1
 	NET_RT_FLAGS                      = 0x2
@@ -1029,10 +1074,14 @@ const (
 	PARMRK                            = 0x8
 	PARODD                            = 0x2000
 	PENDIN                            = 0x20000000
-	PRI_IOFLUSH                       = 0x7c
 	PRIO_PGRP                         = 0x1
 	PRIO_PROCESS                      = 0x0
 	PRIO_USER                         = 0x2
+	PRI_IOFLUSH                       = 0x7c
+	PROT_EXEC                         = 0x4
+	PROT_NONE                         = 0x0
+	PROT_READ                         = 0x1
+	PROT_WRITE                        = 0x2
 	RLIMIT_AS                         = 0xa
 	RLIMIT_CORE                       = 0x4
 	RLIMIT_CPU                        = 0x0
diff --git a/src/pkg/syscall/zerrors_netbsd_arm.go b/src/pkg/syscall/zerrors_netbsd_arm.go
index 9262d5a..1a88c0d 100644
--- a/src/pkg/syscall/zerrors_netbsd_arm.go
+++ b/src/pkg/syscall/zerrors_netbsd_arm.go
@@ -952,6 +952,38 @@ const (
 	LOCK_NB                           = 0x4
 	LOCK_SH                           = 0x1
 	LOCK_UN                           = 0x8
+	MADV_DONTNEED                     = 0x4
+	MADV_FREE                         = 0x6
+	MADV_NORMAL                       = 0x0
+	MADV_RANDOM                       = 0x1
+	MADV_SEQUENTIAL                   = 0x2
+	MADV_SPACEAVAIL                   = 0x5
+	MADV_WILLNEED                     = 0x3
+	MAP_ALIGNMENT_16MB                = 0x18000000
+	MAP_ALIGNMENT_1TB                 = 0x28000000
+	MAP_ALIGNMENT_256TB               = 0x30000000
+	MAP_ALIGNMENT_4GB                 = 0x20000000
+	MAP_ALIGNMENT_64KB                = 0x10000000
+	MAP_ALIGNMENT_64PB                = 0x38000000
+	MAP_ALIGNMENT_MASK                = -0x1000000
+	MAP_ALIGNMENT_SHIFT               = 0x18
+	MAP_ANON                          = 0x1000
+	MAP_FILE                          = 0x0
+	MAP_FIXED                         = 0x10
+	MAP_HASSEMAPHORE                  = 0x200
+	MAP_INHERIT                       = 0x80
+	MAP_INHERIT_COPY                  = 0x1
+	MAP_INHERIT_DEFAULT               = 0x1
+	MAP_INHERIT_DONATE_COPY           = 0x3
+	MAP_INHERIT_NONE                  = 0x2
+	MAP_INHERIT_SHARE                 = 0x0
+	MAP_NORESERVE                     = 0x40
+	MAP_PRIVATE                       = 0x2
+	MAP_RENAME                        = 0x20
+	MAP_SHARED                        = 0x1
+	MAP_STACK                         = 0x2000
+	MAP_TRYFIXED                      = 0x400
+	MAP_WIRED                         = 0x800
 	MSG_BCAST                         = 0x100
 	MSG_CMSG_CLOEXEC                  = 0x800
 	MSG_CONTROLMBUF                   = 0x2000000
@@ -1029,6 +1061,10 @@ const (
 	PARMRK                            = 0x8
 	PARODD                            = 0x2000
 	PENDIN                            = 0x20000000
+	PROT_EXEC                         = 0x4
+	PROT_NONE                         = 0x0
+	PROT_READ                         = 0x1
+	PROT_WRITE                        = 0x2
 	PRI_IOFLUSH                       = 0x7c
 	PRIO_PGRP                         = 0x1
 	PRIO_PROCESS                      = 0x0
diff --git a/src/pkg/syscall/zerrors_openbsd_386.go b/src/pkg/syscall/zerrors_openbsd_386.go
index e546243..0829834 100644
--- a/src/pkg/syscall/zerrors_openbsd_386.go
+++ b/src/pkg/syscall/zerrors_openbsd_386.go
@@ -77,7 +77,7 @@ const (
 	BIOCGFILDROP                      = 0x40044278
 	BIOCGHDRCMPLT                     = 0x40044274
 	BIOCGRSIG                         = 0x40044273
-	BIOCGRTIMEOUT                     = 0x4008426e
+	BIOCGRTIMEOUT                     = 0x400c426e
 	BIOCGSTATS                        = 0x4008426f
 	BIOCIMMEDIATE                     = 0x80044270
 	BIOCLOCK                          = 0x20004276
@@ -91,7 +91,7 @@ const (
 	BIOCSFILDROP                      = 0x80044279
 	BIOCSHDRCMPLT                     = 0x80044275
 	BIOCSRSIG                         = 0x80044272
-	BIOCSRTIMEOUT                     = 0x8008426d
+	BIOCSRTIMEOUT                     = 0x800c426d
 	BIOCVERSION                       = 0x40044271
 	BPF_A                             = 0x10
 	BPF_ABS                           = 0x20
@@ -713,6 +713,8 @@ const (
 	IPPROTO_AH                        = 0x33
 	IPPROTO_CARP                      = 0x70
 	IPPROTO_DIVERT                    = 0x102
+	IPPROTO_DIVERT_INIT               = 0x2
+	IPPROTO_DIVERT_RESP               = 0x1
 	IPPROTO_DONE                      = 0x101
 	IPPROTO_DSTOPTS                   = 0x3c
 	IPPROTO_EGP                       = 0x8
@@ -783,6 +785,7 @@ const (
 	IPV6_PORTRANGE_HIGH               = 0x1
 	IPV6_PORTRANGE_LOW                = 0x2
 	IPV6_RECVDSTOPTS                  = 0x28
+	IPV6_RECVDSTPORT                  = 0x40
 	IPV6_RECVHOPLIMIT                 = 0x25
 	IPV6_RECVHOPOPTS                  = 0x27
 	IPV6_RECVPATHMTU                  = 0x2b
@@ -807,6 +810,7 @@ const (
 	IP_DEFAULT_MULTICAST_LOOP         = 0x1
 	IP_DEFAULT_MULTICAST_TTL          = 0x1
 	IP_DF                             = 0x4000
+	IP_DIVERTFL                       = 0x1022
 	IP_DROP_MEMBERSHIP                = 0xd
 	IP_ESP_NETWORK_LEVEL              = 0x16
 	IP_ESP_TRANS_LEVEL                = 0x15
@@ -857,6 +861,32 @@ const (
 	LOCK_NB                           = 0x4
 	LOCK_SH                           = 0x1
 	LOCK_UN                           = 0x8
+	MADV_DONTNEED                     = 0x4
+	MADV_FREE                         = 0x6
+	MADV_NORMAL                       = 0x0
+	MADV_RANDOM                       = 0x1
+	MADV_SEQUENTIAL                   = 0x2
+	MADV_SPACEAVAIL                   = 0x5
+	MADV_WILLNEED                     = 0x3
+	MAP_ANON                          = 0x1000
+	MAP_COPY                          = 0x4
+	MAP_FILE                          = 0x0
+	MAP_FIXED                         = 0x10
+	MAP_FLAGMASK                      = 0x1ff7
+	MAP_HASSEMAPHORE                  = 0x200
+	MAP_INHERIT                       = 0x80
+	MAP_INHERIT_COPY                  = 0x1
+	MAP_INHERIT_DONATE_COPY           = 0x3
+	MAP_INHERIT_NONE                  = 0x2
+	MAP_INHERIT_SHARE                 = 0x0
+	MAP_NOEXTEND                      = 0x100
+	MAP_NORESERVE                     = 0x40
+	MAP_PRIVATE                       = 0x2
+	MAP_RENAME                        = 0x20
+	MAP_SHARED                        = 0x1
+	MAP_TRYFIXED                      = 0x400
+	MCL_CURRENT                       = 0x1
+	MCL_FUTURE                        = 0x2
 	MSG_BCAST                         = 0x100
 	MSG_CTRUNC                        = 0x20
 	MSG_DONTROUTE                     = 0x4
@@ -868,6 +898,9 @@ const (
 	MSG_PEEK                          = 0x2
 	MSG_TRUNC                         = 0x10
 	MSG_WAITALL                       = 0x40
+	MS_ASYNC                          = 0x1
+	MS_INVALIDATE                     = 0x4
+	MS_SYNC                           = 0x2
 	NAME_MAX                          = 0xff
 	NET_RT_DUMP                       = 0x1
 	NET_RT_FLAGS                      = 0x2
@@ -926,10 +959,14 @@ const (
 	PARODD                            = 0x2000
 	PENDIN                            = 0x20000000
 	PF_FLUSH                          = 0x1
-	PT_MASK                           = 0x3ff000
 	PRIO_PGRP                         = 0x1
 	PRIO_PROCESS                      = 0x0
 	PRIO_USER                         = 0x2
+	PROT_EXEC                         = 0x4
+	PROT_NONE                         = 0x0
+	PROT_READ                         = 0x1
+	PROT_WRITE                        = 0x2
+	PT_MASK                           = 0x3ff000
 	RLIMIT_CORE                       = 0x4
 	RLIMIT_CPU                        = 0x0
 	RLIMIT_DATA                       = 0x2
@@ -966,7 +1003,7 @@ const (
 	RTF_CLONING                       = 0x100
 	RTF_DONE                          = 0x40
 	RTF_DYNAMIC                       = 0x10
-	RTF_FMASK                         = 0xf808
+	RTF_FMASK                         = 0x10f808
 	RTF_GATEWAY                       = 0x2
 	RTF_HOST                          = 0x4
 	RTF_LLINFO                        = 0x400
@@ -1001,7 +1038,7 @@ const (
 	RTM_REDIRECT                      = 0x6
 	RTM_RESOLVE                       = 0xb
 	RTM_RTTUNIT                       = 0xf4240
-	RTM_VERSION                       = 0x4
+	RTM_VERSION                       = 0x5
 	RTV_EXPIRE                        = 0x4
 	RTV_HOPCOUNT                      = 0x2
 	RTV_MTU                           = 0x1
@@ -1027,7 +1064,7 @@ const (
 	SIOCBRDGADD                       = 0x8054693c
 	SIOCBRDGADDS                      = 0x80546941
 	SIOCBRDGARL                       = 0x806e694d
-	SIOCBRDGDADDR                     = 0x80286947
+	SIOCBRDGDADDR                     = 0x81286947
 	SIOCBRDGDEL                       = 0x8054693d
 	SIOCBRDGDELS                      = 0x80546942
 	SIOCBRDGFLUSH                     = 0x80546948
@@ -1037,14 +1074,14 @@ const (
 	SIOCBRDGGHT                       = 0xc0146951
 	SIOCBRDGGIFFLGS                   = 0xc054693e
 	SIOCBRDGGMA                       = 0xc0146953
-	SIOCBRDGGPARAM                    = 0xc0386958
+	SIOCBRDGGPARAM                    = 0xc03c6958
 	SIOCBRDGGPRI                      = 0xc0146950
 	SIOCBRDGGRL                       = 0xc028694f
 	SIOCBRDGGSIFS                     = 0xc054693c
 	SIOCBRDGGTO                       = 0xc0146946
 	SIOCBRDGIFS                       = 0xc0546942
 	SIOCBRDGRTS                       = 0xc0186943
-	SIOCBRDGSADDR                     = 0xc0286944
+	SIOCBRDGSADDR                     = 0xc1286944
 	SIOCBRDGSCACHE                    = 0x80146940
 	SIOCBRDGSFD                       = 0x80146952
 	SIOCBRDGSHT                       = 0x80146951
@@ -1067,6 +1104,7 @@ const (
 	SIOCGETPFSYNC                     = 0xc02069f8
 	SIOCGETSGCNT                      = 0xc0147534
 	SIOCGETVIFCNT                     = 0xc0147533
+	SIOCGETVLAN                       = 0xc0206990
 	SIOCGHIWAT                        = 0x40047301
 	SIOCGIFADDR                       = 0xc0206921
 	SIOCGIFASYNCMAP                   = 0xc020697c
@@ -1080,6 +1118,7 @@ const (
 	SIOCGIFGENERIC                    = 0xc020693a
 	SIOCGIFGMEMB                      = 0xc024698a
 	SIOCGIFGROUP                      = 0xc0246988
+	SIOCGIFHARDMTU                    = 0xc02069a5
 	SIOCGIFMEDIA                      = 0xc0286936
 	SIOCGIFMETRIC                     = 0xc0206917
 	SIOCGIFMTU                        = 0xc020697e
@@ -1094,9 +1133,12 @@ const (
 	SIOCGLIFADDR                      = 0xc218691d
 	SIOCGLIFPHYADDR                   = 0xc218694b
 	SIOCGLIFPHYRTABLE                 = 0xc02069a2
+	SIOCGLIFPHYTTL                    = 0xc02069a9
 	SIOCGLOWAT                        = 0x40047303
 	SIOCGPGRP                         = 0x40047309
+	SIOCGSPPPPARAMS                   = 0xc0206994
 	SIOCGVH                           = 0xc02069f6
+	SIOCGVNETID                       = 0xc02069a7
 	SIOCIFCREATE                      = 0x8020697a
 	SIOCIFDESTROY                     = 0x80206979
 	SIOCIFGCLONERS                    = 0xc00c6978
@@ -1104,6 +1146,7 @@ const (
 	SIOCSETLABEL                      = 0x80206999
 	SIOCSETPFLOW                      = 0x802069fd
 	SIOCSETPFSYNC                     = 0x802069f7
+	SIOCSETVLAN                       = 0x8020698f
 	SIOCSHIWAT                        = 0x80047300
 	SIOCSIFADDR                       = 0x8020690c
 	SIOCSIFASYNCMAP                   = 0x8020697d
@@ -1126,9 +1169,12 @@ const (
 	SIOCSIFXFLAGS                     = 0x8020699d
 	SIOCSLIFPHYADDR                   = 0x8218694a
 	SIOCSLIFPHYRTABLE                 = 0x802069a1
+	SIOCSLIFPHYTTL                    = 0x802069a8
 	SIOCSLOWAT                        = 0x80047302
 	SIOCSPGRP                         = 0x80047308
+	SIOCSSPPPPARAMS                   = 0x80206993
 	SIOCSVH                           = 0xc02069f5
+	SIOCSVNETID                       = 0x802069a6
 	SOCK_DGRAM                        = 0x2
 	SOCK_RAW                          = 0x3
 	SOCK_RDM                          = 0x4
@@ -1171,6 +1217,7 @@ const (
 	TCP_MD5SIG                        = 0x4
 	TCP_MSS                           = 0x200
 	TCP_NODELAY                       = 0x1
+	TCP_NOPUSH                        = 0x10
 	TCP_NSTATES                       = 0xb
 	TCP_SACK_ENABLE                   = 0x8
 	TCSAFLUSH                         = 0x2
@@ -1190,7 +1237,8 @@ const (
 	TIOCGETD                          = 0x4004741a
 	TIOCGFLAGS                        = 0x4004745d
 	TIOCGPGRP                         = 0x40047477
-	TIOCGTSTAMP                       = 0x4008745b
+	TIOCGSID                          = 0x40047463
+	TIOCGTSTAMP                       = 0x400c745b
 	TIOCGWINSZ                        = 0x40087468
 	TIOCMBIC                          = 0x8004746b
 	TIOCMBIS                          = 0x8004746c
diff --git a/src/pkg/syscall/zerrors_openbsd_amd64.go b/src/pkg/syscall/zerrors_openbsd_amd64.go
index 411b51a..e9fa37c 100644
--- a/src/pkg/syscall/zerrors_openbsd_amd64.go
+++ b/src/pkg/syscall/zerrors_openbsd_amd64.go
@@ -140,10 +140,8 @@ const (
 	BPF_W                             = 0x0
 	BPF_X                             = 0x8
 	BRKINT                            = 0x2
-	CCR0_FLUSH                        = 0x10
 	CFLUSH                            = 0xf
 	CLOCAL                            = 0x8000
-	CPUID_CFLUSH                      = 0x80000
 	CREAD                             = 0x800
 	CS5                               = 0x0
 	CS6                               = 0x100
@@ -198,10 +196,6 @@ const (
 	ECHOKE                            = 0x1
 	ECHONL                            = 0x10
 	ECHOPRT                           = 0x20
-	EFER_LMA                          = 0x400
-	EFER_LME                          = 0x100
-	EFER_NXE                          = 0x800
-	EFER_SCE                          = 0x1
 	EMT_TAGOVF                        = 0x1
 	EMUL_ENABLED                      = 0x1
 	EMUL_NATIVE                       = 0x2
@@ -719,6 +713,8 @@ const (
 	IPPROTO_AH                        = 0x33
 	IPPROTO_CARP                      = 0x70
 	IPPROTO_DIVERT                    = 0x102
+	IPPROTO_DIVERT_INIT               = 0x2
+	IPPROTO_DIVERT_RESP               = 0x1
 	IPPROTO_DONE                      = 0x101
 	IPPROTO_DSTOPTS                   = 0x3c
 	IPPROTO_EGP                       = 0x8
@@ -789,6 +785,7 @@ const (
 	IPV6_PORTRANGE_HIGH               = 0x1
 	IPV6_PORTRANGE_LOW                = 0x2
 	IPV6_RECVDSTOPTS                  = 0x28
+	IPV6_RECVDSTPORT                  = 0x40
 	IPV6_RECVHOPLIMIT                 = 0x25
 	IPV6_RECVHOPOPTS                  = 0x27
 	IPV6_RECVPATHMTU                  = 0x2b
@@ -813,6 +810,7 @@ const (
 	IP_DEFAULT_MULTICAST_LOOP         = 0x1
 	IP_DEFAULT_MULTICAST_TTL          = 0x1
 	IP_DF                             = 0x4000
+	IP_DIVERTFL                       = 0x1022
 	IP_DROP_MEMBERSHIP                = 0xd
 	IP_ESP_NETWORK_LEVEL              = 0x16
 	IP_ESP_TRANS_LEVEL                = 0x15
@@ -863,6 +861,32 @@ const (
 	LOCK_NB                           = 0x4
 	LOCK_SH                           = 0x1
 	LOCK_UN                           = 0x8
+	MADV_DONTNEED                     = 0x4
+	MADV_FREE                         = 0x6
+	MADV_NORMAL                       = 0x0
+	MADV_RANDOM                       = 0x1
+	MADV_SEQUENTIAL                   = 0x2
+	MADV_SPACEAVAIL                   = 0x5
+	MADV_WILLNEED                     = 0x3
+	MAP_ANON                          = 0x1000
+	MAP_COPY                          = 0x4
+	MAP_FILE                          = 0x0
+	MAP_FIXED                         = 0x10
+	MAP_FLAGMASK                      = 0x1ff7
+	MAP_HASSEMAPHORE                  = 0x200
+	MAP_INHERIT                       = 0x80
+	MAP_INHERIT_COPY                  = 0x1
+	MAP_INHERIT_DONATE_COPY           = 0x3
+	MAP_INHERIT_NONE                  = 0x2
+	MAP_INHERIT_SHARE                 = 0x0
+	MAP_NOEXTEND                      = 0x100
+	MAP_NORESERVE                     = 0x40
+	MAP_PRIVATE                       = 0x2
+	MAP_RENAME                        = 0x20
+	MAP_SHARED                        = 0x1
+	MAP_TRYFIXED                      = 0x400
+	MCL_CURRENT                       = 0x1
+	MCL_FUTURE                        = 0x2
 	MSG_BCAST                         = 0x100
 	MSG_CTRUNC                        = 0x20
 	MSG_DONTROUTE                     = 0x4
@@ -874,6 +898,9 @@ const (
 	MSG_PEEK                          = 0x2
 	MSG_TRUNC                         = 0x10
 	MSG_WAITALL                       = 0x40
+	MS_ASYNC                          = 0x1
+	MS_INVALIDATE                     = 0x4
+	MS_SYNC                           = 0x2
 	NAME_MAX                          = 0xff
 	NET_RT_DUMP                       = 0x1
 	NET_RT_FLAGS                      = 0x2
@@ -932,10 +959,13 @@ const (
 	PARODD                            = 0x2000
 	PENDIN                            = 0x20000000
 	PF_FLUSH                          = 0x1
-	PMC5_PIPELINE_FLUSH               = 0x15
 	PRIO_PGRP                         = 0x1
 	PRIO_PROCESS                      = 0x0
 	PRIO_USER                         = 0x2
+	PROT_EXEC                         = 0x4
+	PROT_NONE                         = 0x0
+	PROT_READ                         = 0x1
+	PROT_WRITE                        = 0x2
 	RLIMIT_CORE                       = 0x4
 	RLIMIT_CPU                        = 0x0
 	RLIMIT_DATA                       = 0x2
@@ -972,7 +1002,7 @@ const (
 	RTF_CLONING                       = 0x100
 	RTF_DONE                          = 0x40
 	RTF_DYNAMIC                       = 0x10
-	RTF_FMASK                         = 0xf808
+	RTF_FMASK                         = 0x10f808
 	RTF_GATEWAY                       = 0x2
 	RTF_HOST                          = 0x4
 	RTF_LLINFO                        = 0x400
@@ -1007,7 +1037,7 @@ const (
 	RTM_REDIRECT                      = 0x6
 	RTM_RESOLVE                       = 0xb
 	RTM_RTTUNIT                       = 0xf4240
-	RTM_VERSION                       = 0x4
+	RTM_VERSION                       = 0x5
 	RTV_EXPIRE                        = 0x4
 	RTV_HOPCOUNT                      = 0x2
 	RTV_MTU                           = 0x1
@@ -1033,7 +1063,7 @@ const (
 	SIOCBRDGADD                       = 0x8058693c
 	SIOCBRDGADDS                      = 0x80586941
 	SIOCBRDGARL                       = 0x806e694d
-	SIOCBRDGDADDR                     = 0x80286947
+	SIOCBRDGDADDR                     = 0x81286947
 	SIOCBRDGDEL                       = 0x8058693d
 	SIOCBRDGDELS                      = 0x80586942
 	SIOCBRDGFLUSH                     = 0x80586948
@@ -1050,7 +1080,7 @@ const (
 	SIOCBRDGGTO                       = 0xc0146946
 	SIOCBRDGIFS                       = 0xc0586942
 	SIOCBRDGRTS                       = 0xc0206943
-	SIOCBRDGSADDR                     = 0xc0286944
+	SIOCBRDGSADDR                     = 0xc1286944
 	SIOCBRDGSCACHE                    = 0x80146940
 	SIOCBRDGSFD                       = 0x80146952
 	SIOCBRDGSHT                       = 0x80146951
@@ -1073,6 +1103,7 @@ const (
 	SIOCGETPFSYNC                     = 0xc02069f8
 	SIOCGETSGCNT                      = 0xc0207534
 	SIOCGETVIFCNT                     = 0xc0287533
+	SIOCGETVLAN                       = 0xc0206990
 	SIOCGHIWAT                        = 0x40047301
 	SIOCGIFADDR                       = 0xc0206921
 	SIOCGIFASYNCMAP                   = 0xc020697c
@@ -1086,6 +1117,7 @@ const (
 	SIOCGIFGENERIC                    = 0xc020693a
 	SIOCGIFGMEMB                      = 0xc028698a
 	SIOCGIFGROUP                      = 0xc0286988
+	SIOCGIFHARDMTU                    = 0xc02069a5
 	SIOCGIFMEDIA                      = 0xc0306936
 	SIOCGIFMETRIC                     = 0xc0206917
 	SIOCGIFMTU                        = 0xc020697e
@@ -1100,9 +1132,12 @@ const (
 	SIOCGLIFADDR                      = 0xc218691d
 	SIOCGLIFPHYADDR                   = 0xc218694b
 	SIOCGLIFPHYRTABLE                 = 0xc02069a2
+	SIOCGLIFPHYTTL                    = 0xc02069a9
 	SIOCGLOWAT                        = 0x40047303
 	SIOCGPGRP                         = 0x40047309
+	SIOCGSPPPPARAMS                   = 0xc0206994
 	SIOCGVH                           = 0xc02069f6
+	SIOCGVNETID                       = 0xc02069a7
 	SIOCIFCREATE                      = 0x8020697a
 	SIOCIFDESTROY                     = 0x80206979
 	SIOCIFGCLONERS                    = 0xc0106978
@@ -1110,6 +1145,7 @@ const (
 	SIOCSETLABEL                      = 0x80206999
 	SIOCSETPFLOW                      = 0x802069fd
 	SIOCSETPFSYNC                     = 0x802069f7
+	SIOCSETVLAN                       = 0x8020698f
 	SIOCSHIWAT                        = 0x80047300
 	SIOCSIFADDR                       = 0x8020690c
 	SIOCSIFASYNCMAP                   = 0x8020697d
@@ -1132,9 +1168,12 @@ const (
 	SIOCSIFXFLAGS                     = 0x8020699d
 	SIOCSLIFPHYADDR                   = 0x8218694a
 	SIOCSLIFPHYRTABLE                 = 0x802069a1
+	SIOCSLIFPHYTTL                    = 0x802069a8
 	SIOCSLOWAT                        = 0x80047302
 	SIOCSPGRP                         = 0x80047308
+	SIOCSSPPPPARAMS                   = 0x80206993
 	SIOCSVH                           = 0xc02069f5
+	SIOCSVNETID                       = 0x802069a6
 	SOCK_DGRAM                        = 0x2
 	SOCK_RAW                          = 0x3
 	SOCK_RDM                          = 0x4
@@ -1177,6 +1216,7 @@ const (
 	TCP_MD5SIG                        = 0x4
 	TCP_MSS                           = 0x200
 	TCP_NODELAY                       = 0x1
+	TCP_NOPUSH                        = 0x10
 	TCP_NSTATES                       = 0xb
 	TCP_SACK_ENABLE                   = 0x8
 	TCSAFLUSH                         = 0x2
@@ -1196,6 +1236,7 @@ const (
 	TIOCGETD                          = 0x4004741a
 	TIOCGFLAGS                        = 0x4004745d
 	TIOCGPGRP                         = 0x40047477
+	TIOCGSID                          = 0x40047463
 	TIOCGTSTAMP                       = 0x4010745b
 	TIOCGWINSZ                        = 0x40087468
 	TIOCMBIC                          = 0x8004746b
diff --git a/src/pkg/syscall/zerrors_solaris_amd64.go b/src/pkg/syscall/zerrors_solaris_amd64.go
new file mode 100644
index 0000000..3f4cbfd
--- /dev/null
+++ b/src/pkg/syscall/zerrors_solaris_amd64.go
@@ -0,0 +1,1414 @@
+// mkerrors.sh -m64
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m64 _const.go
+
+package syscall
+
+const (
+	AF_802                        = 0x12
+	AF_APPLETALK                  = 0x10
+	AF_CCITT                      = 0xa
+	AF_CHAOS                      = 0x5
+	AF_DATAKIT                    = 0x9
+	AF_DECnet                     = 0xc
+	AF_DLI                        = 0xd
+	AF_ECMA                       = 0x8
+	AF_FILE                       = 0x1
+	AF_GOSIP                      = 0x16
+	AF_HYLINK                     = 0xf
+	AF_IMPLINK                    = 0x3
+	AF_INET                       = 0x2
+	AF_INET6                      = 0x1a
+	AF_INET_OFFLOAD               = 0x1e
+	AF_IPX                        = 0x17
+	AF_KEY                        = 0x1b
+	AF_LAT                        = 0xe
+	AF_LINK                       = 0x19
+	AF_LOCAL                      = 0x1
+	AF_MAX                        = 0x20
+	AF_NBS                        = 0x7
+	AF_NCA                        = 0x1c
+	AF_NIT                        = 0x11
+	AF_NS                         = 0x6
+	AF_OSI                        = 0x13
+	AF_OSINET                     = 0x15
+	AF_PACKET                     = 0x20
+	AF_POLICY                     = 0x1d
+	AF_PUP                        = 0x4
+	AF_ROUTE                      = 0x18
+	AF_SNA                        = 0xb
+	AF_TRILL                      = 0x1f
+	AF_UNIX                       = 0x1
+	AF_UNSPEC                     = 0x0
+	AF_X25                        = 0x14
+	ARPHRD_ARCNET                 = 0x7
+	ARPHRD_ATM                    = 0x10
+	ARPHRD_AX25                   = 0x3
+	ARPHRD_CHAOS                  = 0x5
+	ARPHRD_EETHER                 = 0x2
+	ARPHRD_ETHER                  = 0x1
+	ARPHRD_FC                     = 0x12
+	ARPHRD_FRAME                  = 0xf
+	ARPHRD_HDLC                   = 0x11
+	ARPHRD_IB                     = 0x20
+	ARPHRD_IEEE802                = 0x6
+	ARPHRD_IPATM                  = 0x13
+	ARPHRD_METRICOM               = 0x17
+	ARPHRD_TUNNEL                 = 0x1f
+	B0                            = 0x0
+	B110                          = 0x3
+	B115200                       = 0x12
+	B1200                         = 0x9
+	B134                          = 0x4
+	B150                          = 0x5
+	B153600                       = 0x13
+	B1800                         = 0xa
+	B19200                        = 0xe
+	B200                          = 0x6
+	B230400                       = 0x14
+	B2400                         = 0xb
+	B300                          = 0x7
+	B307200                       = 0x15
+	B38400                        = 0xf
+	B460800                       = 0x16
+	B4800                         = 0xc
+	B50                           = 0x1
+	B57600                        = 0x10
+	B600                          = 0x8
+	B75                           = 0x2
+	B76800                        = 0x11
+	B921600                       = 0x17
+	B9600                         = 0xd
+	BIOCFLUSH                     = 0x20004268
+	BIOCGBLEN                     = 0x40044266
+	BIOCGDLT                      = 0x4004426a
+	BIOCGDLTLIST                  = -0x3fefbd89
+	BIOCGDLTLIST32                = -0x3ff7bd89
+	BIOCGETIF                     = 0x4020426b
+	BIOCGETLIF                    = 0x4078426b
+	BIOCGHDRCMPLT                 = 0x40044274
+	BIOCGRTIMEOUT                 = 0x4010427b
+	BIOCGRTIMEOUT32               = 0x4008427b
+	BIOCGSEESENT                  = 0x40044278
+	BIOCGSTATS                    = 0x4080426f
+	BIOCGSTATSOLD                 = 0x4008426f
+	BIOCIMMEDIATE                 = -0x7ffbbd90
+	BIOCPROMISC                   = 0x20004269
+	BIOCSBLEN                     = -0x3ffbbd9a
+	BIOCSDLT                      = -0x7ffbbd8a
+	BIOCSETF                      = -0x7fefbd99
+	BIOCSETF32                    = -0x7ff7bd99
+	BIOCSETIF                     = -0x7fdfbd94
+	BIOCSETLIF                    = -0x7f87bd94
+	BIOCSHDRCMPLT                 = -0x7ffbbd8b
+	BIOCSRTIMEOUT                 = -0x7fefbd86
+	BIOCSRTIMEOUT32               = -0x7ff7bd86
+	BIOCSSEESENT                  = -0x7ffbbd87
+	BIOCSTCPF                     = -0x7fefbd8e
+	BIOCSUDPF                     = -0x7fefbd8d
+	BIOCVERSION                   = 0x40044271
+	BPF_A                         = 0x10
+	BPF_ABS                       = 0x20
+	BPF_ADD                       = 0x0
+	BPF_ALIGNMENT                 = 0x4
+	BPF_ALU                       = 0x4
+	BPF_AND                       = 0x50
+	BPF_B                         = 0x10
+	BPF_DFLTBUFSIZE               = 0x100000
+	BPF_DIV                       = 0x30
+	BPF_H                         = 0x8
+	BPF_IMM                       = 0x0
+	BPF_IND                       = 0x40
+	BPF_JA                        = 0x0
+	BPF_JEQ                       = 0x10
+	BPF_JGE                       = 0x30
+	BPF_JGT                       = 0x20
+	BPF_JMP                       = 0x5
+	BPF_JSET                      = 0x40
+	BPF_K                         = 0x0
+	BPF_LD                        = 0x0
+	BPF_LDX                       = 0x1
+	BPF_LEN                       = 0x80
+	BPF_LSH                       = 0x60
+	BPF_MAJOR_VERSION             = 0x1
+	BPF_MAXBUFSIZE                = 0x1000000
+	BPF_MAXINSNS                  = 0x200
+	BPF_MEM                       = 0x60
+	BPF_MEMWORDS                  = 0x10
+	BPF_MINBUFSIZE                = 0x20
+	BPF_MINOR_VERSION             = 0x1
+	BPF_MISC                      = 0x7
+	BPF_MSH                       = 0xa0
+	BPF_MUL                       = 0x20
+	BPF_NEG                       = 0x80
+	BPF_OR                        = 0x40
+	BPF_RELEASE                   = 0x30bb6
+	BPF_RET                       = 0x6
+	BPF_RSH                       = 0x70
+	BPF_ST                        = 0x2
+	BPF_STX                       = 0x3
+	BPF_SUB                       = 0x10
+	BPF_TAX                       = 0x0
+	BPF_TXA                       = 0x80
+	BPF_W                         = 0x0
+	BPF_X                         = 0x8
+	BRKINT                        = 0x2
+	CFLUSH                        = 0xf
+	CLOCAL                        = 0x800
+	CREAD                         = 0x80
+	CS5                           = 0x0
+	CS6                           = 0x10
+	CS7                           = 0x20
+	CS8                           = 0x30
+	CSIZE                         = 0x30
+	CSTART                        = 0x11
+	CSTOP                         = 0x13
+	CSTOPB                        = 0x40
+	CSUSP                         = 0x1a
+	CSWTCH                        = 0x1a
+	DLT_AIRONET_HEADER            = 0x78
+	DLT_APPLE_IP_OVER_IEEE1394    = 0x8a
+	DLT_ARCNET                    = 0x7
+	DLT_ARCNET_LINUX              = 0x81
+	DLT_ATM_CLIP                  = 0x13
+	DLT_ATM_RFC1483               = 0xb
+	DLT_AURORA                    = 0x7e
+	DLT_AX25                      = 0x3
+	DLT_BACNET_MS_TP              = 0xa5
+	DLT_CHAOS                     = 0x5
+	DLT_CISCO_IOS                 = 0x76
+	DLT_C_HDLC                    = 0x68
+	DLT_DOCSIS                    = 0x8f
+	DLT_ECONET                    = 0x73
+	DLT_EN10MB                    = 0x1
+	DLT_EN3MB                     = 0x2
+	DLT_ENC                       = 0x6d
+	DLT_ERF_ETH                   = 0xaf
+	DLT_ERF_POS                   = 0xb0
+	DLT_FDDI                      = 0xa
+	DLT_FRELAY                    = 0x6b
+	DLT_GCOM_SERIAL               = 0xad
+	DLT_GCOM_T1E1                 = 0xac
+	DLT_GPF_F                     = 0xab
+	DLT_GPF_T                     = 0xaa
+	DLT_GPRS_LLC                  = 0xa9
+	DLT_HDLC                      = 0x10
+	DLT_HHDLC                     = 0x79
+	DLT_HIPPI                     = 0xf
+	DLT_IBM_SN                    = 0x92
+	DLT_IBM_SP                    = 0x91
+	DLT_IEEE802                   = 0x6
+	DLT_IEEE802_11                = 0x69
+	DLT_IEEE802_11_RADIO          = 0x7f
+	DLT_IEEE802_11_RADIO_AVS      = 0xa3
+	DLT_IPNET                     = 0xe2
+	DLT_IPOIB                     = 0xa2
+	DLT_IP_OVER_FC                = 0x7a
+	DLT_JUNIPER_ATM1              = 0x89
+	DLT_JUNIPER_ATM2              = 0x87
+	DLT_JUNIPER_CHDLC             = 0xb5
+	DLT_JUNIPER_ES                = 0x84
+	DLT_JUNIPER_ETHER             = 0xb2
+	DLT_JUNIPER_FRELAY            = 0xb4
+	DLT_JUNIPER_GGSN              = 0x85
+	DLT_JUNIPER_MFR               = 0x86
+	DLT_JUNIPER_MLFR              = 0x83
+	DLT_JUNIPER_MLPPP             = 0x82
+	DLT_JUNIPER_MONITOR           = 0xa4
+	DLT_JUNIPER_PIC_PEER          = 0xae
+	DLT_JUNIPER_PPP               = 0xb3
+	DLT_JUNIPER_PPPOE             = 0xa7
+	DLT_JUNIPER_PPPOE_ATM         = 0xa8
+	DLT_JUNIPER_SERVICES          = 0x88
+	DLT_LINUX_IRDA                = 0x90
+	DLT_LINUX_LAPD                = 0xb1
+	DLT_LINUX_SLL                 = 0x71
+	DLT_LOOP                      = 0x6c
+	DLT_LTALK                     = 0x72
+	DLT_MTP2                      = 0x8c
+	DLT_MTP2_WITH_PHDR            = 0x8b
+	DLT_MTP3                      = 0x8d
+	DLT_NULL                      = 0x0
+	DLT_PCI_EXP                   = 0x7d
+	DLT_PFLOG                     = 0x75
+	DLT_PFSYNC                    = 0x12
+	DLT_PPP                       = 0x9
+	DLT_PPP_BSDOS                 = 0xe
+	DLT_PPP_PPPD                  = 0xa6
+	DLT_PRISM_HEADER              = 0x77
+	DLT_PRONET                    = 0x4
+	DLT_RAW                       = 0xc
+	DLT_RAWAF_MASK                = 0x2240000
+	DLT_RIO                       = 0x7c
+	DLT_SCCP                      = 0x8e
+	DLT_SLIP                      = 0x8
+	DLT_SLIP_BSDOS                = 0xd
+	DLT_SUNATM                    = 0x7b
+	DLT_SYMANTEC_FIREWALL         = 0x63
+	DLT_TZSP                      = 0x80
+	ECHO                          = 0x8
+	ECHOCTL                       = 0x200
+	ECHOE                         = 0x10
+	ECHOK                         = 0x20
+	ECHOKE                        = 0x800
+	ECHONL                        = 0x40
+	ECHOPRT                       = 0x400
+	EMPTY_SET                     = 0x0
+	EMT_CPCOVF                    = 0x1
+	EQUALITY_CHECK                = 0x0
+	EXTA                          = 0xe
+	EXTB                          = 0xf
+	FD_CLOEXEC                    = 0x1
+	FD_NFDBITS                    = 0x40
+	FD_SETSIZE                    = 0x10000
+	FLUSHALL                      = 0x1
+	FLUSHDATA                     = 0x0
+	FLUSHO                        = 0x2000
+	F_ALLOCSP                     = 0xa
+	F_ALLOCSP64                   = 0xa
+	F_BADFD                       = 0x2e
+	F_BLKSIZE                     = 0x13
+	F_BLOCKS                      = 0x12
+	F_CHKFL                       = 0x8
+	F_COMPAT                      = 0x8
+	F_DUP2FD                      = 0x9
+	F_DUP2FD_CLOEXEC              = 0x24
+	F_DUPFD                       = 0x0
+	F_DUPFD_CLOEXEC               = 0x25
+	F_FREESP                      = 0xb
+	F_FREESP64                    = 0xb
+	F_GETFD                       = 0x1
+	F_GETFL                       = 0x3
+	F_GETLK                       = 0xe
+	F_GETLK64                     = 0xe
+	F_GETOWN                      = 0x17
+	F_GETXFL                      = 0x2d
+	F_HASREMOTELOCKS              = 0x1a
+	F_ISSTREAM                    = 0xd
+	F_MANDDNY                     = 0x10
+	F_MDACC                       = 0x20
+	F_NODNY                       = 0x0
+	F_NPRIV                       = 0x10
+	F_PRIV                        = 0xf
+	F_QUOTACTL                    = 0x11
+	F_RDACC                       = 0x1
+	F_RDDNY                       = 0x1
+	F_RDLCK                       = 0x1
+	F_REVOKE                      = 0x19
+	F_RMACC                       = 0x4
+	F_RMDNY                       = 0x4
+	F_RWACC                       = 0x3
+	F_RWDNY                       = 0x3
+	F_SETFD                       = 0x2
+	F_SETFL                       = 0x4
+	F_SETLK                       = 0x6
+	F_SETLK64                     = 0x6
+	F_SETLK64_NBMAND              = 0x2a
+	F_SETLKW                      = 0x7
+	F_SETLKW64                    = 0x7
+	F_SETLK_NBMAND                = 0x2a
+	F_SETOWN                      = 0x18
+	F_SHARE                       = 0x28
+	F_SHARE_NBMAND                = 0x2b
+	F_UNLCK                       = 0x3
+	F_UNLKSYS                     = 0x4
+	F_UNSHARE                     = 0x29
+	F_WRACC                       = 0x2
+	F_WRDNY                       = 0x2
+	F_WRLCK                       = 0x2
+	HUPCL                         = 0x400
+	ICANON                        = 0x2
+	ICRNL                         = 0x100
+	IEXTEN                        = 0x8000
+	IFF_ADDRCONF                  = 0x80000
+	IFF_ALLMULTI                  = 0x200
+	IFF_ANYCAST                   = 0x400000
+	IFF_BROADCAST                 = 0x2
+	IFF_CANTCHANGE                = 0x7f203003b5a
+	IFF_COS_ENABLED               = 0x200000000
+	IFF_DEBUG                     = 0x4
+	IFF_DEPRECATED                = 0x40000
+	IFF_DHCPRUNNING               = 0x4000
+	IFF_DUPLICATE                 = 0x4000000000
+	IFF_FAILED                    = 0x10000000
+	IFF_FIXEDMTU                  = 0x1000000000
+	IFF_INACTIVE                  = 0x40000000
+	IFF_INTELLIGENT               = 0x400
+	IFF_IPMP                      = 0x8000000000
+	IFF_IPMP_CANTCHANGE           = 0x10000000
+	IFF_IPMP_INVALID              = 0x1ec200080
+	IFF_IPV4                      = 0x1000000
+	IFF_IPV6                      = 0x2000000
+	IFF_L3PROTECT                 = 0x40000000000
+	IFF_LOOPBACK                  = 0x8
+	IFF_MULTICAST                 = 0x800
+	IFF_MULTI_BCAST               = 0x1000
+	IFF_NOACCEPT                  = 0x4000000
+	IFF_NOARP                     = 0x80
+	IFF_NOFAILOVER                = 0x8000000
+	IFF_NOLINKLOCAL               = 0x20000000000
+	IFF_NOLOCAL                   = 0x20000
+	IFF_NONUD                     = 0x200000
+	IFF_NORTEXCH                  = 0x800000
+	IFF_NOTRAILERS                = 0x20
+	IFF_NOXMIT                    = 0x10000
+	IFF_OFFLINE                   = 0x80000000
+	IFF_POINTOPOINT               = 0x10
+	IFF_PREFERRED                 = 0x400000000
+	IFF_PRIVATE                   = 0x8000
+	IFF_PROMISC                   = 0x100
+	IFF_ROUTER                    = 0x100000
+	IFF_RUNNING                   = 0x40
+	IFF_STANDBY                   = 0x20000000
+	IFF_TEMPORARY                 = 0x800000000
+	IFF_UNNUMBERED                = 0x2000
+	IFF_UP                        = 0x1
+	IFF_VIRTUAL                   = 0x2000000000
+	IFF_VRRP                      = 0x10000000000
+	IFF_XRESOLV                   = 0x100000000
+	IFNAMSIZ                      = 0x10
+	IFT_1822                      = 0x2
+	IFT_6TO4                      = 0xca
+	IFT_AAL5                      = 0x31
+	IFT_ARCNET                    = 0x23
+	IFT_ARCNETPLUS                = 0x24
+	IFT_ATM                       = 0x25
+	IFT_CEPT                      = 0x13
+	IFT_DS3                       = 0x1e
+	IFT_EON                       = 0x19
+	IFT_ETHER                     = 0x6
+	IFT_FDDI                      = 0xf
+	IFT_FRELAY                    = 0x20
+	IFT_FRELAYDCE                 = 0x2c
+	IFT_HDH1822                   = 0x3
+	IFT_HIPPI                     = 0x2f
+	IFT_HSSI                      = 0x2e
+	IFT_HY                        = 0xe
+	IFT_IB                        = 0xc7
+	IFT_IPV4                      = 0xc8
+	IFT_IPV6                      = 0xc9
+	IFT_ISDNBASIC                 = 0x14
+	IFT_ISDNPRIMARY               = 0x15
+	IFT_ISO88022LLC               = 0x29
+	IFT_ISO88023                  = 0x7
+	IFT_ISO88024                  = 0x8
+	IFT_ISO88025                  = 0x9
+	IFT_ISO88026                  = 0xa
+	IFT_LAPB                      = 0x10
+	IFT_LOCALTALK                 = 0x2a
+	IFT_LOOP                      = 0x18
+	IFT_MIOX25                    = 0x26
+	IFT_MODEM                     = 0x30
+	IFT_NSIP                      = 0x1b
+	IFT_OTHER                     = 0x1
+	IFT_P10                       = 0xc
+	IFT_P80                       = 0xd
+	IFT_PARA                      = 0x22
+	IFT_PPP                       = 0x17
+	IFT_PROPMUX                   = 0x36
+	IFT_PROPVIRTUAL               = 0x35
+	IFT_PTPSERIAL                 = 0x16
+	IFT_RS232                     = 0x21
+	IFT_SDLC                      = 0x11
+	IFT_SIP                       = 0x1f
+	IFT_SLIP                      = 0x1c
+	IFT_SMDSDXI                   = 0x2b
+	IFT_SMDSICIP                  = 0x34
+	IFT_SONET                     = 0x27
+	IFT_SONETPATH                 = 0x32
+	IFT_SONETVT                   = 0x33
+	IFT_STARLAN                   = 0xb
+	IFT_T1                        = 0x12
+	IFT_ULTRA                     = 0x1d
+	IFT_V35                       = 0x2d
+	IFT_X25                       = 0x5
+	IFT_X25DDN                    = 0x4
+	IFT_X25PLE                    = 0x28
+	IFT_XETHER                    = 0x1a
+	IGNBRK                        = 0x1
+	IGNCR                         = 0x80
+	IGNPAR                        = 0x4
+	IMAXBEL                       = 0x2000
+	INLCR                         = 0x40
+	INPCK                         = 0x10
+	IN_AUTOCONF_MASK              = 0xffff0000
+	IN_AUTOCONF_NET               = 0xa9fe0000
+	IN_CLASSA_HOST                = 0xffffff
+	IN_CLASSA_MAX                 = 0x80
+	IN_CLASSA_NET                 = 0xff000000
+	IN_CLASSA_NSHIFT              = 0x18
+	IN_CLASSB_HOST                = 0xffff
+	IN_CLASSB_MAX                 = 0x10000
+	IN_CLASSB_NET                 = 0xffff0000
+	IN_CLASSB_NSHIFT              = 0x10
+	IN_CLASSC_HOST                = 0xff
+	IN_CLASSC_NET                 = 0xffffff00
+	IN_CLASSC_NSHIFT              = 0x8
+	IN_CLASSD_HOST                = 0xfffffff
+	IN_CLASSD_NET                 = 0xf0000000
+	IN_CLASSD_NSHIFT              = 0x1c
+	IN_CLASSE_NET                 = 0xffffffff
+	IN_LOOPBACKNET                = 0x7f
+	IN_PRIVATE12_MASK             = 0xfff00000
+	IN_PRIVATE12_NET              = 0xac100000
+	IN_PRIVATE16_MASK             = 0xffff0000
+	IN_PRIVATE16_NET              = 0xc0a80000
+	IN_PRIVATE8_MASK              = 0xff000000
+	IN_PRIVATE8_NET               = 0xa000000
+	IPPROTO_AH                    = 0x33
+	IPPROTO_DSTOPTS               = 0x3c
+	IPPROTO_EGP                   = 0x8
+	IPPROTO_ENCAP                 = 0x4
+	IPPROTO_EON                   = 0x50
+	IPPROTO_ESP                   = 0x32
+	IPPROTO_FRAGMENT              = 0x2c
+	IPPROTO_GGP                   = 0x3
+	IPPROTO_HELLO                 = 0x3f
+	IPPROTO_HOPOPTS               = 0x0
+	IPPROTO_ICMP                  = 0x1
+	IPPROTO_ICMPV6                = 0x3a
+	IPPROTO_IDP                   = 0x16
+	IPPROTO_IGMP                  = 0x2
+	IPPROTO_IP                    = 0x0
+	IPPROTO_IPV6                  = 0x29
+	IPPROTO_MAX                   = 0x100
+	IPPROTO_ND                    = 0x4d
+	IPPROTO_NONE                  = 0x3b
+	IPPROTO_OSPF                  = 0x59
+	IPPROTO_PIM                   = 0x67
+	IPPROTO_PUP                   = 0xc
+	IPPROTO_RAW                   = 0xff
+	IPPROTO_ROUTING               = 0x2b
+	IPPROTO_RSVP                  = 0x2e
+	IPPROTO_SCTP                  = 0x84
+	IPPROTO_TCP                   = 0x6
+	IPPROTO_UDP                   = 0x11
+	IPV6_ADD_MEMBERSHIP           = 0x9
+	IPV6_BOUND_IF                 = 0x41
+	IPV6_CHECKSUM                 = 0x18
+	IPV6_DONTFRAG                 = 0x21
+	IPV6_DROP_MEMBERSHIP          = 0xa
+	IPV6_DSTOPTS                  = 0xf
+	IPV6_FLOWINFO_FLOWLABEL       = 0xffff0f00
+	IPV6_FLOWINFO_TCLASS          = 0xf00f
+	IPV6_HOPLIMIT                 = 0xc
+	IPV6_HOPOPTS                  = 0xe
+	IPV6_JOIN_GROUP               = 0x9
+	IPV6_LEAVE_GROUP              = 0xa
+	IPV6_MULTICAST_HOPS           = 0x7
+	IPV6_MULTICAST_IF             = 0x6
+	IPV6_MULTICAST_LOOP           = 0x8
+	IPV6_NEXTHOP                  = 0xd
+	IPV6_PAD1_OPT                 = 0x0
+	IPV6_PATHMTU                  = 0x25
+	IPV6_PKTINFO                  = 0xb
+	IPV6_PREFER_SRC_CGA           = 0x20
+	IPV6_PREFER_SRC_CGADEFAULT    = 0x10
+	IPV6_PREFER_SRC_CGAMASK       = 0x30
+	IPV6_PREFER_SRC_COA           = 0x2
+	IPV6_PREFER_SRC_DEFAULT       = 0x15
+	IPV6_PREFER_SRC_HOME          = 0x1
+	IPV6_PREFER_SRC_MASK          = 0x3f
+	IPV6_PREFER_SRC_MIPDEFAULT    = 0x1
+	IPV6_PREFER_SRC_MIPMASK       = 0x3
+	IPV6_PREFER_SRC_NONCGA        = 0x10
+	IPV6_PREFER_SRC_PUBLIC        = 0x4
+	IPV6_PREFER_SRC_TMP           = 0x8
+	IPV6_PREFER_SRC_TMPDEFAULT    = 0x4
+	IPV6_PREFER_SRC_TMPMASK       = 0xc
+	IPV6_RECVDSTOPTS              = 0x28
+	IPV6_RECVHOPLIMIT             = 0x13
+	IPV6_RECVHOPOPTS              = 0x14
+	IPV6_RECVPATHMTU              = 0x24
+	IPV6_RECVPKTINFO              = 0x12
+	IPV6_RECVRTHDR                = 0x16
+	IPV6_RECVRTHDRDSTOPTS         = 0x17
+	IPV6_RECVTCLASS               = 0x19
+	IPV6_RTHDR                    = 0x10
+	IPV6_RTHDRDSTOPTS             = 0x11
+	IPV6_RTHDR_TYPE_0             = 0x0
+	IPV6_SEC_OPT                  = 0x22
+	IPV6_SRC_PREFERENCES          = 0x23
+	IPV6_TCLASS                   = 0x26
+	IPV6_UNICAST_HOPS             = 0x5
+	IPV6_UNSPEC_SRC               = 0x42
+	IPV6_USE_MIN_MTU              = 0x20
+	IPV6_V6ONLY                   = 0x27
+	IP_ADD_MEMBERSHIP             = 0x13
+	IP_ADD_SOURCE_MEMBERSHIP      = 0x17
+	IP_BLOCK_SOURCE               = 0x15
+	IP_BOUND_IF                   = 0x41
+	IP_BROADCAST                  = 0x106
+	IP_BROADCAST_TTL              = 0x43
+	IP_DEFAULT_MULTICAST_LOOP     = 0x1
+	IP_DEFAULT_MULTICAST_TTL      = 0x1
+	IP_DF                         = 0x4000
+	IP_DHCPINIT_IF                = 0x45
+	IP_DONTFRAG                   = 0x1b
+	IP_DONTROUTE                  = 0x105
+	IP_DROP_MEMBERSHIP            = 0x14
+	IP_DROP_SOURCE_MEMBERSHIP     = 0x18
+	IP_HDRINCL                    = 0x2
+	IP_MAXPACKET                  = 0xffff
+	IP_MF                         = 0x2000
+	IP_MSS                        = 0x240
+	IP_MULTICAST_IF               = 0x10
+	IP_MULTICAST_LOOP             = 0x12
+	IP_MULTICAST_TTL              = 0x11
+	IP_NEXTHOP                    = 0x19
+	IP_OPTIONS                    = 0x1
+	IP_PKTINFO                    = 0x1a
+	IP_RECVDSTADDR                = 0x7
+	IP_RECVIF                     = 0x9
+	IP_RECVOPTS                   = 0x5
+	IP_RECVPKTINFO                = 0x1a
+	IP_RECVRETOPTS                = 0x6
+	IP_RECVSLLA                   = 0xa
+	IP_RECVTTL                    = 0xb
+	IP_RETOPTS                    = 0x8
+	IP_REUSEADDR                  = 0x104
+	IP_SEC_OPT                    = 0x22
+	IP_TOS                        = 0x3
+	IP_TTL                        = 0x4
+	IP_UNBLOCK_SOURCE             = 0x16
+	IP_UNSPEC_SRC                 = 0x42
+	ISIG                          = 0x1
+	ISTRIP                        = 0x20
+	IXANY                         = 0x800
+	IXOFF                         = 0x1000
+	IXON                          = 0x400
+	MADV_ACCESS_DEFAULT           = 0x6
+	MADV_ACCESS_LWP               = 0x7
+	MADV_ACCESS_MANY              = 0x8
+	MADV_DONTNEED                 = 0x4
+	MADV_FREE                     = 0x5
+	MADV_NORMAL                   = 0x0
+	MADV_RANDOM                   = 0x1
+	MADV_SEQUENTIAL               = 0x2
+	MADV_WILLNEED                 = 0x3
+	MAP_32BIT                     = 0x80
+	MAP_ALIGN                     = 0x200
+	MAP_ANON                      = 0x100
+	MAP_ANONYMOUS                 = 0x100
+	MAP_FIXED                     = 0x10
+	MAP_INITDATA                  = 0x800
+	MAP_NORESERVE                 = 0x40
+	MAP_PRIVATE                   = 0x2
+	MAP_RENAME                    = 0x20
+	MAP_SHARED                    = 0x1
+	MAP_TEXT                      = 0x400
+	MAP_TYPE                      = 0xf
+	MCL_CURRENT                   = 0x1
+	MCL_FUTURE                    = 0x2
+	MSG_CTRUNC                    = 0x10
+	MSG_DONTROUTE                 = 0x4
+	MSG_DONTWAIT                  = 0x80
+	MSG_DUPCTRL                   = 0x800
+	MSG_EOR                       = 0x8
+	MSG_MAXIOVLEN                 = 0x10
+	MSG_NOTIFICATION              = 0x100
+	MSG_OOB                       = 0x1
+	MSG_PEEK                      = 0x2
+	MSG_TRUNC                     = 0x20
+	MSG_WAITALL                   = 0x40
+	MSG_XPG4_2                    = 0x8000
+	MS_ASYNC                      = 0x1
+	MS_INVALIDATE                 = 0x2
+	MS_OLDSYNC                    = 0x0
+	MS_SYNC                       = 0x4
+	M_FLUSH                       = 0x86
+	NOFLSH                        = 0x80
+	OCRNL                         = 0x8
+	OFDEL                         = 0x80
+	OFILL                         = 0x40
+	ONLCR                         = 0x4
+	ONLRET                        = 0x20
+	ONOCR                         = 0x10
+	OPENFAIL                      = -0x1
+	OPOST                         = 0x1
+	O_ACCMODE                     = 0x600003
+	O_APPEND                      = 0x8
+	O_CLOEXEC                     = 0x800000
+	O_CREAT                       = 0x100
+	O_DSYNC                       = 0x40
+	O_EXCL                        = 0x400
+	O_EXEC                        = 0x400000
+	O_LARGEFILE                   = 0x2000
+	O_NDELAY                      = 0x4
+	O_NOCTTY                      = 0x800
+	O_NOFOLLOW                    = 0x20000
+	O_NOLINKS                     = 0x40000
+	O_NONBLOCK                    = 0x80
+	O_RDONLY                      = 0x0
+	O_RDWR                        = 0x2
+	O_RSYNC                       = 0x8000
+	O_SEARCH                      = 0x200000
+	O_SIOCGIFCONF                 = -0x3ff796ec
+	O_SIOCGLIFCONF                = -0x3fef9688
+	O_SYNC                        = 0x10
+	O_TRUNC                       = 0x200
+	O_WRONLY                      = 0x1
+	O_XATTR                       = 0x4000
+	PARENB                        = 0x100
+	PAREXT                        = 0x100000
+	PARMRK                        = 0x8
+	PARODD                        = 0x200
+	PENDIN                        = 0x4000
+	PRIO_PGRP                     = 0x1
+	PRIO_PROCESS                  = 0x0
+	PRIO_USER                     = 0x2
+	PROT_EXEC                     = 0x4
+	PROT_NONE                     = 0x0
+	PROT_READ                     = 0x1
+	PROT_WRITE                    = 0x2
+	RLIMIT_AS                     = 0x6
+	RLIMIT_CORE                   = 0x4
+	RLIMIT_CPU                    = 0x0
+	RLIMIT_DATA                   = 0x2
+	RLIMIT_FSIZE                  = 0x1
+	RLIMIT_NOFILE                 = 0x5
+	RLIMIT_STACK                  = 0x3
+	RLIM_INFINITY                 = -0x3
+	RTAX_AUTHOR                   = 0x6
+	RTAX_BRD                      = 0x7
+	RTAX_DST                      = 0x0
+	RTAX_GATEWAY                  = 0x1
+	RTAX_GENMASK                  = 0x3
+	RTAX_IFA                      = 0x5
+	RTAX_IFP                      = 0x4
+	RTAX_MAX                      = 0x9
+	RTAX_NETMASK                  = 0x2
+	RTAX_SRC                      = 0x8
+	RTA_AUTHOR                    = 0x40
+	RTA_BRD                       = 0x80
+	RTA_DST                       = 0x1
+	RTA_GATEWAY                   = 0x2
+	RTA_GENMASK                   = 0x8
+	RTA_IFA                       = 0x20
+	RTA_IFP                       = 0x10
+	RTA_NETMASK                   = 0x4
+	RTA_NUMBITS                   = 0x9
+	RTA_SRC                       = 0x100
+	RTF_BLACKHOLE                 = 0x1000
+	RTF_CLONING                   = 0x100
+	RTF_DONE                      = 0x40
+	RTF_DYNAMIC                   = 0x10
+	RTF_GATEWAY                   = 0x2
+	RTF_HOST                      = 0x4
+	RTF_INDIRECT                  = 0x40000
+	RTF_KERNEL                    = 0x80000
+	RTF_LLINFO                    = 0x400
+	RTF_MASK                      = 0x80
+	RTF_MODIFIED                  = 0x20
+	RTF_MULTIRT                   = 0x10000
+	RTF_PRIVATE                   = 0x2000
+	RTF_PROTO1                    = 0x8000
+	RTF_PROTO2                    = 0x4000
+	RTF_REJECT                    = 0x8
+	RTF_SETSRC                    = 0x20000
+	RTF_STATIC                    = 0x800
+	RTF_UP                        = 0x1
+	RTF_XRESOLVE                  = 0x200
+	RTF_ZONE                      = 0x100000
+	RTM_ADD                       = 0x1
+	RTM_CHANGE                    = 0x3
+	RTM_CHGADDR                   = 0xf
+	RTM_DELADDR                   = 0xd
+	RTM_DELETE                    = 0x2
+	RTM_FREEADDR                  = 0x10
+	RTM_GET                       = 0x4
+	RTM_IFINFO                    = 0xe
+	RTM_LOCK                      = 0x8
+	RTM_LOSING                    = 0x5
+	RTM_MISS                      = 0x7
+	RTM_NEWADDR                   = 0xc
+	RTM_OLDADD                    = 0x9
+	RTM_OLDDEL                    = 0xa
+	RTM_REDIRECT                  = 0x6
+	RTM_RESOLVE                   = 0xb
+	RTM_VERSION                   = 0x3
+	RTV_EXPIRE                    = 0x4
+	RTV_HOPCOUNT                  = 0x2
+	RTV_MTU                       = 0x1
+	RTV_RPIPE                     = 0x8
+	RTV_RTT                       = 0x40
+	RTV_RTTVAR                    = 0x80
+	RTV_SPIPE                     = 0x10
+	RTV_SSTHRESH                  = 0x20
+	RT_AWARE                      = 0x1
+	RUSAGE_CHILDREN               = -0x1
+	RUSAGE_SELF                   = 0x0
+	SCM_RIGHTS                    = 0x1010
+	SCM_TIMESTAMP                 = 0x1013
+	SCM_UCRED                     = 0x1012
+	SHUT_RD                       = 0x0
+	SHUT_RDWR                     = 0x2
+	SHUT_WR                       = 0x1
+	SIG2STR_MAX                   = 0x20
+	SIOCADDMULTI                  = -0x7fdf96cf
+	SIOCADDRT                     = -0x7fcf8df6
+	SIOCATMARK                    = 0x40047307
+	SIOCDARP                      = -0x7fdb96e0
+	SIOCDELMULTI                  = -0x7fdf96ce
+	SIOCDELRT                     = -0x7fcf8df5
+	SIOCDIPSECONFIG               = -0x7ffb9669
+	SIOCDXARP                     = -0x7fff9658
+	SIOCFIPSECONFIG               = -0x7ffb966b
+	SIOCGARP                      = -0x3fdb96e1
+	SIOCGDSTINFO                  = -0x3fff965c
+	SIOCGENADDR                   = -0x3fdf96ab
+	SIOCGENPSTATS                 = -0x3fdf96c7
+	SIOCGETLSGCNT                 = -0x3fef8deb
+	SIOCGETNAME                   = 0x40107334
+	SIOCGETPEER                   = 0x40107335
+	SIOCGETPROP                   = -0x3fff8f44
+	SIOCGETSGCNT                  = -0x3feb8deb
+	SIOCGETSYNC                   = -0x3fdf96d3
+	SIOCGETVIFCNT                 = -0x3feb8dec
+	SIOCGHIWAT                    = 0x40047301
+	SIOCGIFADDR                   = -0x3fdf96f3
+	SIOCGIFBRDADDR                = -0x3fdf96e9
+	SIOCGIFCONF                   = -0x3ff796a4
+	SIOCGIFDSTADDR                = -0x3fdf96f1
+	SIOCGIFFLAGS                  = -0x3fdf96ef
+	SIOCGIFHWADDR                 = -0x3fdf9647
+	SIOCGIFINDEX                  = -0x3fdf96a6
+	SIOCGIFMEM                    = -0x3fdf96ed
+	SIOCGIFMETRIC                 = -0x3fdf96e5
+	SIOCGIFMTU                    = -0x3fdf96ea
+	SIOCGIFMUXID                  = -0x3fdf96a8
+	SIOCGIFNETMASK                = -0x3fdf96e7
+	SIOCGIFNUM                    = 0x40046957
+	SIOCGIP6ADDRPOLICY            = -0x3fff965e
+	SIOCGIPMSFILTER               = -0x3ffb964c
+	SIOCGLIFADDR                  = -0x3f87968f
+	SIOCGLIFBINDING               = -0x3f879666
+	SIOCGLIFBRDADDR               = -0x3f879685
+	SIOCGLIFCONF                  = -0x3fef965b
+	SIOCGLIFDADSTATE              = -0x3f879642
+	SIOCGLIFDSTADDR               = -0x3f87968d
+	SIOCGLIFFLAGS                 = -0x3f87968b
+	SIOCGLIFGROUPINFO             = -0x3f4b9663
+	SIOCGLIFGROUPNAME             = -0x3f879664
+	SIOCGLIFHWADDR                = -0x3f879640
+	SIOCGLIFINDEX                 = -0x3f87967b
+	SIOCGLIFLNKINFO               = -0x3f879674
+	SIOCGLIFMETRIC                = -0x3f879681
+	SIOCGLIFMTU                   = -0x3f879686
+	SIOCGLIFMUXID                 = -0x3f87967d
+	SIOCGLIFNETMASK               = -0x3f879683
+	SIOCGLIFNUM                   = -0x3ff3967e
+	SIOCGLIFSRCOF                 = -0x3fef964f
+	SIOCGLIFSUBNET                = -0x3f879676
+	SIOCGLIFTOKEN                 = -0x3f879678
+	SIOCGLIFUSESRC                = -0x3f879651
+	SIOCGLIFZONE                  = -0x3f879656
+	SIOCGLOWAT                    = 0x40047303
+	SIOCGMSFILTER                 = -0x3ffb964e
+	SIOCGPGRP                     = 0x40047309
+	SIOCGSTAMP                    = -0x3fef9646
+	SIOCGXARP                     = -0x3fff9659
+	SIOCIFDETACH                  = -0x7fdf96c8
+	SIOCILB                       = -0x3ffb9645
+	SIOCLIFADDIF                  = -0x3f879691
+	SIOCLIFDELND                  = -0x7f879673
+	SIOCLIFGETND                  = -0x3f879672
+	SIOCLIFREMOVEIF               = -0x7f879692
+	SIOCLIFSETND                  = -0x7f879671
+	SIOCLIPSECONFIG               = -0x7ffb9668
+	SIOCLOWER                     = -0x7fdf96d7
+	SIOCSARP                      = -0x7fdb96e2
+	SIOCSCTPGOPT                  = -0x3fef9653
+	SIOCSCTPPEELOFF               = -0x3ffb9652
+	SIOCSCTPSOPT                  = -0x7fef9654
+	SIOCSENABLESDP                = -0x3ffb9649
+	SIOCSETPROP                   = -0x7ffb8f43
+	SIOCSETSYNC                   = -0x7fdf96d4
+	SIOCSHIWAT                    = -0x7ffb8d00
+	SIOCSIFADDR                   = -0x7fdf96f4
+	SIOCSIFBRDADDR                = -0x7fdf96e8
+	SIOCSIFDSTADDR                = -0x7fdf96f2
+	SIOCSIFFLAGS                  = -0x7fdf96f0
+	SIOCSIFINDEX                  = -0x7fdf96a5
+	SIOCSIFMEM                    = -0x7fdf96ee
+	SIOCSIFMETRIC                 = -0x7fdf96e4
+	SIOCSIFMTU                    = -0x7fdf96eb
+	SIOCSIFMUXID                  = -0x7fdf96a7
+	SIOCSIFNAME                   = -0x7fdf96b7
+	SIOCSIFNETMASK                = -0x7fdf96e6
+	SIOCSIP6ADDRPOLICY            = -0x7fff965d
+	SIOCSIPMSFILTER               = -0x7ffb964b
+	SIOCSIPSECONFIG               = -0x7ffb966a
+	SIOCSLGETREQ                  = -0x3fdf96b9
+	SIOCSLIFADDR                  = -0x7f879690
+	SIOCSLIFBRDADDR               = -0x7f879684
+	SIOCSLIFDSTADDR               = -0x7f87968e
+	SIOCSLIFFLAGS                 = -0x7f87968c
+	SIOCSLIFGROUPNAME             = -0x7f879665
+	SIOCSLIFINDEX                 = -0x7f87967a
+	SIOCSLIFLNKINFO               = -0x7f879675
+	SIOCSLIFMETRIC                = -0x7f879680
+	SIOCSLIFMTU                   = -0x7f879687
+	SIOCSLIFMUXID                 = -0x7f87967c
+	SIOCSLIFNAME                  = -0x3f87967f
+	SIOCSLIFNETMASK               = -0x7f879682
+	SIOCSLIFPREFIX                = -0x3f879641
+	SIOCSLIFSUBNET                = -0x7f879677
+	SIOCSLIFTOKEN                 = -0x7f879679
+	SIOCSLIFUSESRC                = -0x7f879650
+	SIOCSLIFZONE                  = -0x7f879655
+	SIOCSLOWAT                    = -0x7ffb8cfe
+	SIOCSLSTAT                    = -0x7fdf96b8
+	SIOCSMSFILTER                 = -0x7ffb964d
+	SIOCSPGRP                     = -0x7ffb8cf8
+	SIOCSPROMISC                  = -0x7ffb96d0
+	SIOCSQPTR                     = -0x3ffb9648
+	SIOCSSDSTATS                  = -0x3fdf96d2
+	SIOCSSESTATS                  = -0x3fdf96d1
+	SIOCSXARP                     = -0x7fff965a
+	SIOCTMYADDR                   = -0x3ff79670
+	SIOCTMYSITE                   = -0x3ff7966e
+	SIOCTONLINK                   = -0x3ff7966f
+	SIOCUPPER                     = -0x7fdf96d8
+	SIOCX25RCV                    = -0x3fdf96c4
+	SIOCX25TBL                    = -0x3fdf96c3
+	SIOCX25XMT                    = -0x3fdf96c5
+	SIOCXPROTO                    = 0x20007337
+	SOCK_CLOEXEC                  = 0x80000
+	SOCK_DGRAM                    = 0x1
+	SOCK_NDELAY                   = 0x200000
+	SOCK_NONBLOCK                 = 0x100000
+	SOCK_RAW                      = 0x4
+	SOCK_RDM                      = 0x5
+	SOCK_SEQPACKET                = 0x6
+	SOCK_STREAM                   = 0x2
+	SOCK_TYPE_MASK                = 0xffff
+	SOL_FILTER                    = 0xfffc
+	SOL_PACKET                    = 0xfffd
+	SOL_ROUTE                     = 0xfffe
+	SOL_SOCKET                    = 0xffff
+	SOMAXCONN                     = 0x80
+	SO_ACCEPTCONN                 = 0x2
+	SO_ALL                        = 0x3f
+	SO_ALLZONES                   = 0x1014
+	SO_ANON_MLP                   = 0x100a
+	SO_ATTACH_FILTER              = 0x40000001
+	SO_BAND                       = 0x4000
+	SO_BROADCAST                  = 0x20
+	SO_COPYOPT                    = 0x80000
+	SO_DEBUG                      = 0x1
+	SO_DELIM                      = 0x8000
+	SO_DETACH_FILTER              = 0x40000002
+	SO_DGRAM_ERRIND               = 0x200
+	SO_DOMAIN                     = 0x100c
+	SO_DONTLINGER                 = -0x81
+	SO_DONTROUTE                  = 0x10
+	SO_ERROPT                     = 0x40000
+	SO_ERROR                      = 0x1007
+	SO_EXCLBIND                   = 0x1015
+	SO_HIWAT                      = 0x10
+	SO_ISNTTY                     = 0x800
+	SO_ISTTY                      = 0x400
+	SO_KEEPALIVE                  = 0x8
+	SO_LINGER                     = 0x80
+	SO_LOWAT                      = 0x20
+	SO_MAC_EXEMPT                 = 0x100b
+	SO_MAC_IMPLICIT               = 0x1016
+	SO_MAXBLK                     = 0x100000
+	SO_MAXPSZ                     = 0x8
+	SO_MINPSZ                     = 0x4
+	SO_MREADOFF                   = 0x80
+	SO_MREADON                    = 0x40
+	SO_NDELOFF                    = 0x200
+	SO_NDELON                     = 0x100
+	SO_NODELIM                    = 0x10000
+	SO_OOBINLINE                  = 0x100
+	SO_PROTOTYPE                  = 0x1009
+	SO_RCVBUF                     = 0x1002
+	SO_RCVLOWAT                   = 0x1004
+	SO_RCVPSH                     = 0x100d
+	SO_RCVTIMEO                   = 0x1006
+	SO_READOPT                    = 0x1
+	SO_RECVUCRED                  = 0x400
+	SO_REUSEADDR                  = 0x4
+	SO_SECATTR                    = 0x1011
+	SO_SNDBUF                     = 0x1001
+	SO_SNDLOWAT                   = 0x1003
+	SO_SNDTIMEO                   = 0x1005
+	SO_STRHOLD                    = 0x20000
+	SO_TAIL                       = 0x200000
+	SO_TIMESTAMP                  = 0x1013
+	SO_TONSTOP                    = 0x2000
+	SO_TOSTOP                     = 0x1000
+	SO_TYPE                       = 0x1008
+	SO_USELOOPBACK                = 0x40
+	SO_VRRP                       = 0x1017
+	SO_WROFF                      = 0x2
+	TCFLSH                        = 0x5407
+	TCIFLUSH                      = 0x0
+	TCIOFLUSH                     = 0x2
+	TCOFLUSH                      = 0x1
+	TCP_ABORT_THRESHOLD           = 0x11
+	TCP_ANONPRIVBIND              = 0x20
+	TCP_CONN_ABORT_THRESHOLD      = 0x13
+	TCP_CONN_NOTIFY_THRESHOLD     = 0x12
+	TCP_CORK                      = 0x18
+	TCP_EXCLBIND                  = 0x21
+	TCP_INIT_CWND                 = 0x15
+	TCP_KEEPALIVE                 = 0x8
+	TCP_KEEPALIVE_ABORT_THRESHOLD = 0x17
+	TCP_KEEPALIVE_THRESHOLD       = 0x16
+	TCP_KEEPCNT                   = 0x23
+	TCP_KEEPIDLE                  = 0x22
+	TCP_KEEPINTVL                 = 0x24
+	TCP_LINGER2                   = 0x1c
+	TCP_MAXSEG                    = 0x2
+	TCP_MSS                       = 0x218
+	TCP_NODELAY                   = 0x1
+	TCP_NOTIFY_THRESHOLD          = 0x10
+	TCP_RECVDSTADDR               = 0x14
+	TCP_RTO_INITIAL               = 0x19
+	TCP_RTO_MAX                   = 0x1b
+	TCP_RTO_MIN                   = 0x1a
+	TCSAFLUSH                     = 0x5410
+	TIOC                          = 0x5400
+	TIOCCBRK                      = 0x747a
+	TIOCCDTR                      = 0x7478
+	TIOCCILOOP                    = 0x746c
+	TIOCEXCL                      = 0x740d
+	TIOCFLUSH                     = 0x7410
+	TIOCGETC                      = 0x7412
+	TIOCGETD                      = 0x7400
+	TIOCGETP                      = 0x7408
+	TIOCGLTC                      = 0x7474
+	TIOCGPGRP                     = 0x7414
+	TIOCGPPS                      = 0x547d
+	TIOCGPPSEV                    = 0x547f
+	TIOCGSID                      = 0x7416
+	TIOCGSOFTCAR                  = 0x5469
+	TIOCGWINSZ                    = 0x5468
+	TIOCHPCL                      = 0x7402
+	TIOCKBOF                      = 0x5409
+	TIOCKBON                      = 0x5408
+	TIOCLBIC                      = 0x747e
+	TIOCLBIS                      = 0x747f
+	TIOCLGET                      = 0x747c
+	TIOCLSET                      = 0x747d
+	TIOCMBIC                      = 0x741c
+	TIOCMBIS                      = 0x741b
+	TIOCMGET                      = 0x741d
+	TIOCMSET                      = 0x741a
+	TIOCM_CAR                     = 0x40
+	TIOCM_CD                      = 0x40
+	TIOCM_CTS                     = 0x20
+	TIOCM_DSR                     = 0x100
+	TIOCM_DTR                     = 0x2
+	TIOCM_LE                      = 0x1
+	TIOCM_RI                      = 0x80
+	TIOCM_RNG                     = 0x80
+	TIOCM_RTS                     = 0x4
+	TIOCM_SR                      = 0x10
+	TIOCM_ST                      = 0x8
+	TIOCNOTTY                     = 0x7471
+	TIOCNXCL                      = 0x740e
+	TIOCOUTQ                      = 0x7473
+	TIOCREMOTE                    = 0x741e
+	TIOCSBRK                      = 0x747b
+	TIOCSCTTY                     = 0x7484
+	TIOCSDTR                      = 0x7479
+	TIOCSETC                      = 0x7411
+	TIOCSETD                      = 0x7401
+	TIOCSETN                      = 0x740a
+	TIOCSETP                      = 0x7409
+	TIOCSIGNAL                    = 0x741f
+	TIOCSILOOP                    = 0x746d
+	TIOCSLTC                      = 0x7475
+	TIOCSPGRP                     = 0x7415
+	TIOCSPPS                      = 0x547e
+	TIOCSSOFTCAR                  = 0x546a
+	TIOCSTART                     = 0x746e
+	TIOCSTI                       = 0x7417
+	TIOCSTOP                      = 0x746f
+	TIOCSWINSZ                    = 0x5467
+	TOSTOP                        = 0x100
+	VCEOF                         = 0x8
+	VCEOL                         = 0x9
+	VDISCARD                      = 0xd
+	VDSUSP                        = 0xb
+	VEOF                          = 0x4
+	VEOL                          = 0x5
+	VEOL2                         = 0x6
+	VERASE                        = 0x2
+	VINTR                         = 0x0
+	VKILL                         = 0x3
+	VLNEXT                        = 0xf
+	VMIN                          = 0x4
+	VQUIT                         = 0x1
+	VREPRINT                      = 0xc
+	VSTART                        = 0x8
+	VSTOP                         = 0x9
+	VSUSP                         = 0xa
+	VSWTCH                        = 0x7
+	VT0                           = 0x0
+	VT1                           = 0x4000
+	VTDLY                         = 0x4000
+	VTIME                         = 0x5
+	VWERASE                       = 0xe
+	WCONTFLG                      = 0xffff
+	WCONTINUED                    = 0x8
+	WCOREFLG                      = 0x80
+	WEXITED                       = 0x1
+	WNOHANG                       = 0x40
+	WNOWAIT                       = 0x80
+	WOPTMASK                      = 0xcf
+	WRAP                          = 0x20000
+	WSIGMASK                      = 0x7f
+	WSTOPFLG                      = 0x7f
+	WSTOPPED                      = 0x4
+	WTRAPPED                      = 0x2
+	WUNTRACED                     = 0x4
+)
+
+// Errors
+const (
+	E2BIG           = Errno(0x7)
+	EACCES          = Errno(0xd)
+	EADDRINUSE      = Errno(0x7d)
+	EADDRNOTAVAIL   = Errno(0x7e)
+	EADV            = Errno(0x44)
+	EAFNOSUPPORT    = Errno(0x7c)
+	EAGAIN          = Errno(0xb)
+	EALREADY        = Errno(0x95)
+	EBADE           = Errno(0x32)
+	EBADF           = Errno(0x9)
+	EBADFD          = Errno(0x51)
+	EBADMSG         = Errno(0x4d)
+	EBADR           = Errno(0x33)
+	EBADRQC         = Errno(0x36)
+	EBADSLT         = Errno(0x37)
+	EBFONT          = Errno(0x39)
+	EBUSY           = Errno(0x10)
+	ECANCELED       = Errno(0x2f)
+	ECHILD          = Errno(0xa)
+	ECHRNG          = Errno(0x25)
+	ECOMM           = Errno(0x46)
+	ECONNABORTED    = Errno(0x82)
+	ECONNREFUSED    = Errno(0x92)
+	ECONNRESET      = Errno(0x83)
+	EDEADLK         = Errno(0x2d)
+	EDEADLOCK       = Errno(0x38)
+	EDESTADDRREQ    = Errno(0x60)
+	EDOM            = Errno(0x21)
+	EDQUOT          = Errno(0x31)
+	EEXIST          = Errno(0x11)
+	EFAULT          = Errno(0xe)
+	EFBIG           = Errno(0x1b)
+	EHOSTDOWN       = Errno(0x93)
+	EHOSTUNREACH    = Errno(0x94)
+	EIDRM           = Errno(0x24)
+	EILSEQ          = Errno(0x58)
+	EINPROGRESS     = Errno(0x96)
+	EINTR           = Errno(0x4)
+	EINVAL          = Errno(0x16)
+	EIO             = Errno(0x5)
+	EISCONN         = Errno(0x85)
+	EISDIR          = Errno(0x15)
+	EL2HLT          = Errno(0x2c)
+	EL2NSYNC        = Errno(0x26)
+	EL3HLT          = Errno(0x27)
+	EL3RST          = Errno(0x28)
+	ELIBACC         = Errno(0x53)
+	ELIBBAD         = Errno(0x54)
+	ELIBEXEC        = Errno(0x57)
+	ELIBMAX         = Errno(0x56)
+	ELIBSCN         = Errno(0x55)
+	ELNRNG          = Errno(0x29)
+	ELOCKUNMAPPED   = Errno(0x48)
+	ELOOP           = Errno(0x5a)
+	EMFILE          = Errno(0x18)
+	EMLINK          = Errno(0x1f)
+	EMSGSIZE        = Errno(0x61)
+	EMULTIHOP       = Errno(0x4a)
+	ENAMETOOLONG    = Errno(0x4e)
+	ENETDOWN        = Errno(0x7f)
+	ENETRESET       = Errno(0x81)
+	ENETUNREACH     = Errno(0x80)
+	ENFILE          = Errno(0x17)
+	ENOANO          = Errno(0x35)
+	ENOBUFS         = Errno(0x84)
+	ENOCSI          = Errno(0x2b)
+	ENODATA         = Errno(0x3d)
+	ENODEV          = Errno(0x13)
+	ENOENT          = Errno(0x2)
+	ENOEXEC         = Errno(0x8)
+	ENOLCK          = Errno(0x2e)
+	ENOLINK         = Errno(0x43)
+	ENOMEM          = Errno(0xc)
+	ENOMSG          = Errno(0x23)
+	ENONET          = Errno(0x40)
+	ENOPKG          = Errno(0x41)
+	ENOPROTOOPT     = Errno(0x63)
+	ENOSPC          = Errno(0x1c)
+	ENOSR           = Errno(0x3f)
+	ENOSTR          = Errno(0x3c)
+	ENOSYS          = Errno(0x59)
+	ENOTACTIVE      = Errno(0x49)
+	ENOTBLK         = Errno(0xf)
+	ENOTCONN        = Errno(0x86)
+	ENOTDIR         = Errno(0x14)
+	ENOTEMPTY       = Errno(0x5d)
+	ENOTRECOVERABLE = Errno(0x3b)
+	ENOTSOCK        = Errno(0x5f)
+	ENOTSUP         = Errno(0x30)
+	ENOTTY          = Errno(0x19)
+	ENOTUNIQ        = Errno(0x50)
+	ENXIO           = Errno(0x6)
+	EOPNOTSUPP      = Errno(0x7a)
+	EOVERFLOW       = Errno(0x4f)
+	EOWNERDEAD      = Errno(0x3a)
+	EPERM           = Errno(0x1)
+	EPFNOSUPPORT    = Errno(0x7b)
+	EPIPE           = Errno(0x20)
+	EPROTO          = Errno(0x47)
+	EPROTONOSUPPORT = Errno(0x78)
+	EPROTOTYPE      = Errno(0x62)
+	ERANGE          = Errno(0x22)
+	EREMCHG         = Errno(0x52)
+	EREMOTE         = Errno(0x42)
+	ERESTART        = Errno(0x5b)
+	EROFS           = Errno(0x1e)
+	ESHUTDOWN       = Errno(0x8f)
+	ESOCKTNOSUPPORT = Errno(0x79)
+	ESPIPE          = Errno(0x1d)
+	ESRCH           = Errno(0x3)
+	ESRMNT          = Errno(0x45)
+	ESTALE          = Errno(0x97)
+	ESTRPIPE        = Errno(0x5c)
+	ETIME           = Errno(0x3e)
+	ETIMEDOUT       = Errno(0x91)
+	ETOOMANYREFS    = Errno(0x90)
+	ETXTBSY         = Errno(0x1a)
+	EUNATCH         = Errno(0x2a)
+	EUSERS          = Errno(0x5e)
+	EWOULDBLOCK     = Errno(0xb)
+	EXDEV           = Errno(0x12)
+	EXFULL          = Errno(0x34)
+)
+
+// Signals
+const (
+	SIGABRT    = Signal(0x6)
+	SIGALRM    = Signal(0xe)
+	SIGBUS     = Signal(0xa)
+	SIGCANCEL  = Signal(0x24)
+	SIGCHLD    = Signal(0x12)
+	SIGCLD     = Signal(0x12)
+	SIGCONT    = Signal(0x19)
+	SIGEMT     = Signal(0x7)
+	SIGFPE     = Signal(0x8)
+	SIGFREEZE  = Signal(0x22)
+	SIGHUP     = Signal(0x1)
+	SIGILL     = Signal(0x4)
+	SIGINT     = Signal(0x2)
+	SIGIO      = Signal(0x16)
+	SIGIOT     = Signal(0x6)
+	SIGJVM1    = Signal(0x27)
+	SIGJVM2    = Signal(0x28)
+	SIGKILL    = Signal(0x9)
+	SIGLOST    = Signal(0x25)
+	SIGLWP     = Signal(0x21)
+	SIGPIPE    = Signal(0xd)
+	SIGPOLL    = Signal(0x16)
+	SIGPROF    = Signal(0x1d)
+	SIGPWR     = Signal(0x13)
+	SIGQUIT    = Signal(0x3)
+	SIGSEGV    = Signal(0xb)
+	SIGSTOP    = Signal(0x17)
+	SIGSYS     = Signal(0xc)
+	SIGTERM    = Signal(0xf)
+	SIGTHAW    = Signal(0x23)
+	SIGTRAP    = Signal(0x5)
+	SIGTSTP    = Signal(0x18)
+	SIGTTIN    = Signal(0x1a)
+	SIGTTOU    = Signal(0x1b)
+	SIGURG     = Signal(0x15)
+	SIGUSR1    = Signal(0x10)
+	SIGUSR2    = Signal(0x11)
+	SIGVTALRM  = Signal(0x1c)
+	SIGWAITING = Signal(0x20)
+	SIGWINCH   = Signal(0x14)
+	SIGXCPU    = Signal(0x1e)
+	SIGXFSZ    = Signal(0x1f)
+	SIGXRES    = Signal(0x26)
+)
+
+// Error table
+var errors = [...]string{
+	1:   "not owner",
+	2:   "no such file or directory",
+	3:   "no such process",
+	4:   "interrupted system call",
+	5:   "I/O error",
+	6:   "no such device or address",
+	7:   "arg list too long",
+	8:   "exec format error",
+	9:   "bad file number",
+	10:  "no child processes",
+	11:  "resource temporarily unavailable",
+	12:  "not enough space",
+	13:  "permission denied",
+	14:  "bad address",
+	15:  "block device required",
+	16:  "device busy",
+	17:  "file exists",
+	18:  "cross-device link",
+	19:  "no such device",
+	20:  "not a directory",
+	21:  "is a directory",
+	22:  "invalid argument",
+	23:  "file table overflow",
+	24:  "too many open files",
+	25:  "inappropriate ioctl for device",
+	26:  "text file busy",
+	27:  "file too large",
+	28:  "no space left on device",
+	29:  "illegal seek",
+	30:  "read-only file system",
+	31:  "too many links",
+	32:  "broken pipe",
+	33:  "argument out of domain",
+	34:  "result too large",
+	35:  "no message of desired type",
+	36:  "identifier removed",
+	37:  "channel number out of range",
+	38:  "level 2 not synchronized",
+	39:  "level 3 halted",
+	40:  "level 3 reset",
+	41:  "link number out of range",
+	42:  "protocol driver not attached",
+	43:  "no CSI structure available",
+	44:  "level 2 halted",
+	45:  "deadlock situation detected/avoided",
+	46:  "no record locks available",
+	47:  "operation canceled",
+	48:  "operation not supported",
+	49:  "disc quota exceeded",
+	50:  "bad exchange descriptor",
+	51:  "bad request descriptor",
+	52:  "message tables full",
+	53:  "anode table overflow",
+	54:  "bad request code",
+	55:  "invalid slot",
+	56:  "file locking deadlock",
+	57:  "bad font file format",
+	58:  "owner of the lock died",
+	59:  "lock is not recoverable",
+	60:  "not a stream device",
+	61:  "no data available",
+	62:  "timer expired",
+	63:  "out of stream resources",
+	64:  "machine is not on the network",
+	65:  "package not installed",
+	66:  "object is remote",
+	67:  "link has been severed",
+	68:  "advertise error",
+	69:  "srmount error",
+	70:  "communication error on send",
+	71:  "protocol error",
+	72:  "locked lock was unmapped ",
+	73:  "facility is not active",
+	74:  "multihop attempted",
+	77:  "not a data message",
+	78:  "file name too long",
+	79:  "value too large for defined data type",
+	80:  "name not unique on network",
+	81:  "file descriptor in bad state",
+	82:  "remote address changed",
+	83:  "can not access a needed shared library",
+	84:  "accessing a corrupted shared library",
+	85:  ".lib section in a.out corrupted",
+	86:  "attempting to link in more shared libraries than system limit",
+	87:  "can not exec a shared library directly",
+	88:  "illegal byte sequence",
+	89:  "operation not applicable",
+	90:  "number of symbolic links encountered during path name traversal exceeds MAXSYMLINKS",
+	91:  "error 91",
+	92:  "error 92",
+	93:  "directory not empty",
+	94:  "too many users",
+	95:  "socket operation on non-socket",
+	96:  "destination address required",
+	97:  "message too long",
+	98:  "protocol wrong type for socket",
+	99:  "option not supported by protocol",
+	120: "protocol not supported",
+	121: "socket type not supported",
+	122: "operation not supported on transport endpoint",
+	123: "protocol family not supported",
+	124: "address family not supported by protocol family",
+	125: "address already in use",
+	126: "cannot assign requested address",
+	127: "network is down",
+	128: "network is unreachable",
+	129: "network dropped connection because of reset",
+	130: "software caused connection abort",
+	131: "connection reset by peer",
+	132: "no buffer space available",
+	133: "transport endpoint is already connected",
+	134: "transport endpoint is not connected",
+	143: "cannot send after socket shutdown",
+	144: "too many references: cannot splice",
+	145: "connection timed out",
+	146: "connection refused",
+	147: "host is down",
+	148: "no route to host",
+	149: "operation already in progress",
+	150: "operation now in progress",
+	151: "stale NFS file handle",
+}
+
+// Signal table
+var signals = [...]string{
+	1:  "hangup",
+	2:  "interrupt",
+	3:  "quit",
+	4:  "illegal Instruction",
+	5:  "trace/Breakpoint Trap",
+	6:  "abort",
+	7:  "emulation Trap",
+	8:  "arithmetic Exception",
+	9:  "killed",
+	10: "bus Error",
+	11: "segmentation Fault",
+	12: "bad System Call",
+	13: "broken Pipe",
+	14: "alarm Clock",
+	15: "terminated",
+	16: "user Signal 1",
+	17: "user Signal 2",
+	18: "child Status Changed",
+	19: "power-Fail/Restart",
+	20: "window Size Change",
+	21: "urgent Socket Condition",
+	22: "pollable Event",
+	23: "stopped (signal)",
+	24: "stopped (user)",
+	25: "continued",
+	26: "stopped (tty input)",
+	27: "stopped (tty output)",
+	28: "virtual Timer Expired",
+	29: "profiling Timer Expired",
+	30: "cpu Limit Exceeded",
+	31: "file Size Limit Exceeded",
+	32: "no runnable lwp",
+	33: "inter-lwp signal",
+	34: "checkpoint Freeze",
+	35: "checkpoint Thaw",
+	36: "thread Cancellation",
+	37: "resource Lost",
+	38: "resource Control Exceeded",
+	39: "reserved for JVM 1",
+	40: "reserved for JVM 2",
+}
diff --git a/src/pkg/syscall/zsyscall_darwin_386.go b/src/pkg/syscall/zsyscall_darwin_386.go
index 9850079..a6a176b 100644
--- a/src/pkg/syscall/zsyscall_darwin_386.go
+++ b/src/pkg/syscall/zsyscall_darwin_386.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
 		err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
 		err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
-	_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+	n = int(r0)
 	if e1 != 0 {
 		err = e1
 	}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
@@ -590,23 +591,6 @@ func Geteuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
-	var _p0 unsafe.Pointer
-	if len(buf) > 0 {
-		_p0 = unsafe.Pointer(&buf[0])
-	} else {
-		_p0 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
-	n = int(r0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Getgid() (gid int) {
 	r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
 	gid = int(r0)
@@ -824,6 +808,74 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Mlock(b []byte) (err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlockall(flags int) (err error) {
+	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mprotect(b []byte, prot int) (err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlock(b []byte) (err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlockall() (err error) {
+	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Open(path string, mode int, perm uint32) (fd int, err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
diff --git a/src/pkg/syscall/zsyscall_darwin_amd64.go b/src/pkg/syscall/zsyscall_darwin_amd64.go
index ee810e0..f5867c4 100644
--- a/src/pkg/syscall/zsyscall_darwin_amd64.go
+++ b/src/pkg/syscall/zsyscall_darwin_amd64.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
 		err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
 		err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
-	_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+	n = int(r0)
 	if e1 != 0 {
 		err = e1
 	}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
@@ -590,23 +591,6 @@ func Geteuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
-	var _p0 unsafe.Pointer
-	if len(buf) > 0 {
-		_p0 = unsafe.Pointer(&buf[0])
-	} else {
-		_p0 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
-	n = int(r0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Getgid() (gid int) {
 	r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
 	gid = int(r0)
@@ -824,6 +808,74 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Mlock(b []byte) (err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlockall(flags int) (err error) {
+	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mprotect(b []byte, prot int) (err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlock(b []byte) (err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlockall() (err error) {
+	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Open(path string, mode int, perm uint32) (fd int, err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
diff --git a/src/pkg/syscall/zsyscall_dragonfly_386.go b/src/pkg/syscall/zsyscall_dragonfly_386.go
index 5c3fe07..0ec8132 100644
--- a/src/pkg/syscall/zsyscall_dragonfly_386.go
+++ b/src/pkg/syscall/zsyscall_dragonfly_386.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
 		err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
 		err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
-	_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+	n = int(r0)
 	if e1 != 0 {
 		err = e1
 	}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
@@ -584,23 +585,6 @@ func Geteuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
-	var _p0 unsafe.Pointer
-	if len(buf) > 0 {
-		_p0 = unsafe.Pointer(&buf[0])
-	} else {
-		_p0 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
-	n = int(r0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Getgid() (gid int) {
 	r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
 	gid = int(r0)
diff --git a/src/pkg/syscall/zsyscall_dragonfly_amd64.go b/src/pkg/syscall/zsyscall_dragonfly_amd64.go
index c7766a8..8c7cce5 100644
--- a/src/pkg/syscall/zsyscall_dragonfly_amd64.go
+++ b/src/pkg/syscall/zsyscall_dragonfly_amd64.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
 		err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
 		err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
-	_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+	n = int(r0)
 	if e1 != 0 {
 		err = e1
 	}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
@@ -584,23 +585,6 @@ func Geteuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
-	var _p0 unsafe.Pointer
-	if len(buf) > 0 {
-		_p0 = unsafe.Pointer(&buf[0])
-	} else {
-		_p0 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
-	n = int(r0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Getgid() (gid int) {
 	r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
 	gid = int(r0)
diff --git a/src/pkg/syscall/zsyscall_freebsd_386.go b/src/pkg/syscall/zsyscall_freebsd_386.go
index 631994f..5befe83 100644
--- a/src/pkg/syscall/zsyscall_freebsd_386.go
+++ b/src/pkg/syscall/zsyscall_freebsd_386.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
 		err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
 		err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
-	_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+	n = int(r0)
 	if e1 != 0 {
 		err = e1
 	}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
@@ -550,23 +551,6 @@ func Geteuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
-	var _p0 unsafe.Pointer
-	if len(buf) > 0 {
-		_p0 = unsafe.Pointer(&buf[0])
-	} else {
-		_p0 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
-	n = int(r0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Getgid() (gid int) {
 	r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
 	gid = int(r0)
@@ -1301,3 +1285,14 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
 	}
 	return
 }
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error) {
+	r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
+	nfd = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
diff --git a/src/pkg/syscall/zsyscall_freebsd_amd64.go b/src/pkg/syscall/zsyscall_freebsd_amd64.go
index 1d51808..ab2eb80 100644
--- a/src/pkg/syscall/zsyscall_freebsd_amd64.go
+++ b/src/pkg/syscall/zsyscall_freebsd_amd64.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
 		err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
 		err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
-	_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+	n = int(r0)
 	if e1 != 0 {
 		err = e1
 	}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
@@ -550,23 +551,6 @@ func Geteuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
-	var _p0 unsafe.Pointer
-	if len(buf) > 0 {
-		_p0 = unsafe.Pointer(&buf[0])
-	} else {
-		_p0 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
-	n = int(r0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Getgid() (gid int) {
 	r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
 	gid = int(r0)
@@ -1301,3 +1285,14 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
 	}
 	return
 }
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error) {
+	r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
+	nfd = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
diff --git a/src/pkg/syscall/zsyscall_freebsd_arm.go b/src/pkg/syscall/zsyscall_freebsd_arm.go
index 925b83f..c1f0f90 100644
--- a/src/pkg/syscall/zsyscall_freebsd_arm.go
+++ b/src/pkg/syscall/zsyscall_freebsd_arm.go
@@ -1,4 +1,4 @@
-// mksyscall.pl -l32 syscall_bsd.go syscall_freebsd.go syscall_freebsd_386.go
+// mksyscall.pl -l32 -arm syscall_bsd.go syscall_freebsd.go syscall_freebsd_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
 package syscall
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
 		err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
 		err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
-	_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+	n = int(r0)
 	if e1 != 0 {
 		err = e1
 	}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
@@ -418,13 +419,8 @@ func Fchdir(fd int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Fchflags(path string, flags int) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+func Fchflags(fd int, flags int) (err error) {
+	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
 		err = e1
 	}
@@ -505,7 +501,7 @@ func Fsync(fd int) (err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Ftruncate(fd int, length int64) (err error) {
-	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length>>32))
+	_, _, e1 := Syscall6(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	if e1 != 0 {
 		err = e1
 	}
@@ -555,23 +551,6 @@ func Geteuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
-	var _p0 unsafe.Pointer
-	if len(buf) > 0 {
-		_p0 = unsafe.Pointer(&buf[0])
-	} else {
-		_p0 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
-	n = int(r0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Getgid() (gid int) {
 	r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
 	gid = int(r0)
@@ -858,7 +837,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	} else {
 		_p0 = unsafe.Pointer(&_zero)
 	}
-	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
 	n = int(r0)
 	if e1 != 0 {
 		err = e1
@@ -875,7 +854,24 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	} else {
 		_p0 = unsafe.Pointer(&_zero)
 	}
-	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func read(fd int, p []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
 		err = e1
@@ -958,7 +954,7 @@ func Rmdir(path string) (err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
-	r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(whence), 0, 0)
+	r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(whence), 0)
 	newoffset = int64(int64(r1)<<32 | int64(r0))
 	if e1 != 0 {
 		err = e1
@@ -1170,7 +1166,7 @@ func Truncate(path string, length int64) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32))
+	_, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	if e1 != 0 {
 		err = e1
 	}
@@ -1232,9 +1228,15 @@ func Unmount(path string, flags int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
-	r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos), uintptr(pos>>32), 0, 0)
-	ret = uintptr(r0)
+func write(fd int, p []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+	n = int(r0)
 	if e1 != 0 {
 		err = e1
 	}
@@ -1243,8 +1245,9 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func munmap(addr uintptr, length uintptr) (err error) {
-	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
+	r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), uintptr(pos>>32), 0)
+	ret = uintptr(r0)
 	if e1 != 0 {
 		err = e1
 	}
@@ -1253,15 +1256,8 @@ func munmap(addr uintptr, length uintptr) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func read(fd int, p []byte) (n int, err error) {
-	var _p0 unsafe.Pointer
-	if len(p) > 0 {
-		_p0 = unsafe.Pointer(&p[0])
-	} else {
-		_p0 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
-	n = int(r0)
+func munmap(addr uintptr, length uintptr) (err error) {
+	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
 		err = e1
 	}
@@ -1270,14 +1266,8 @@ func read(fd int, p []byte) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func write(fd int, p []byte) (n int, err error) {
-	var _p0 unsafe.Pointer
-	if len(p) > 0 {
-		_p0 = unsafe.Pointer(&p[0])
-	} else {
-		_p0 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
 		err = e1
@@ -1287,8 +1277,8 @@ func write(fd int, p []byte) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
-	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
 		err = e1
@@ -1298,9 +1288,9 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
-	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
-	n = int(r0)
+func accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error) {
+	r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
+	nfd = int(r0)
 	if e1 != 0 {
 		err = e1
 	}
diff --git a/src/pkg/syscall/zsyscall_linux_amd64.go b/src/pkg/syscall/zsyscall_linux_amd64.go
index c1c3d45..c65448e 100644
--- a/src/pkg/syscall/zsyscall_linux_amd64.go
+++ b/src/pkg/syscall/zsyscall_linux_amd64.go
@@ -1763,7 +1763,7 @@ func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int,
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -1773,7 +1773,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -1804,7 +1804,7 @@ func setgroups(n int, list *_Gid_t) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
 		err = e1
@@ -1814,7 +1814,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
 		err = e1
@@ -1882,7 +1882,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
@@ -1909,8 +1909,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
-	_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+	n = int(r0)
 	if e1 != 0 {
 		err = e1
 	}
diff --git a/src/pkg/syscall/zsyscall_linux_arm.go b/src/pkg/syscall/zsyscall_linux_arm.go
index 3380714..a970ce6 100644
--- a/src/pkg/syscall/zsyscall_linux_arm.go
+++ b/src/pkg/syscall/zsyscall_linux_arm.go
@@ -1383,7 +1383,7 @@ func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int,
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -1393,7 +1393,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -1424,7 +1424,7 @@ func setgroups(n int, list *_Gid_t) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
 		err = e1
@@ -1434,7 +1434,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
 		err = e1
@@ -1492,7 +1492,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
@@ -1529,8 +1529,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
-	_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+	n = int(r0)
 	if e1 != 0 {
 		err = e1
 	}
diff --git a/src/pkg/syscall/zsyscall_nacl_386.go b/src/pkg/syscall/zsyscall_nacl_386.go
new file mode 100644
index 0000000..32eed33
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_nacl_386.go
@@ -0,0 +1,63 @@
+// mksyscall.pl -l32 -nacl syscall_nacl.go syscall_nacl_386.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclClose(fd int) (err error) {
+	_, _, e1 := Syscall(sys_close, uintptr(fd), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) (err error) {
+	_, _, e1 := Syscall(sys_exit, uintptr(code), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclFstat(fd int, stat *Stat_t) (err error) {
+	_, _, e1 := Syscall(sys_fstat, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclRead(fd int, b []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(sys_read, uintptr(fd), uintptr(_p0), uintptr(len(b)))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclSeek(fd int, off *int64, whence int) (err error) {
+	_, _, e1 := Syscall(sys_lseek, uintptr(fd), uintptr(unsafe.Pointer(off)), uintptr(whence))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
diff --git a/src/pkg/syscall/zsyscall_nacl_amd64p32.go b/src/pkg/syscall/zsyscall_nacl_amd64p32.go
new file mode 100644
index 0000000..8bc81fa
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_nacl_amd64p32.go
@@ -0,0 +1,63 @@
+// mksyscall.pl -nacl syscall_nacl.go syscall_nacl_amd64p32.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclClose(fd int) (err error) {
+	_, _, e1 := Syscall(sys_close, uintptr(fd), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) (err error) {
+	_, _, e1 := Syscall(sys_exit, uintptr(code), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclFstat(fd int, stat *Stat_t) (err error) {
+	_, _, e1 := Syscall(sys_fstat, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclRead(fd int, b []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(sys_read, uintptr(fd), uintptr(_p0), uintptr(len(b)))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclSeek(fd int, off *int64, whence int) (err error) {
+	_, _, e1 := Syscall(sys_lseek, uintptr(fd), uintptr(unsafe.Pointer(off)), uintptr(whence))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
diff --git a/src/pkg/syscall/zsyscall_netbsd_386.go b/src/pkg/syscall/zsyscall_netbsd_386.go
index 0ee19be..281208f 100644
--- a/src/pkg/syscall/zsyscall_netbsd_386.go
+++ b/src/pkg/syscall/zsyscall_netbsd_386.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
 		err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
 		err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
-	_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+	n = int(r0)
 	if e1 != 0 {
 		err = e1
 	}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
diff --git a/src/pkg/syscall/zsyscall_netbsd_amd64.go b/src/pkg/syscall/zsyscall_netbsd_amd64.go
index b9d2721..ed9a87d 100644
--- a/src/pkg/syscall/zsyscall_netbsd_amd64.go
+++ b/src/pkg/syscall/zsyscall_netbsd_amd64.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
 		err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
 		err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
-	_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+	n = int(r0)
 	if e1 != 0 {
 		err = e1
 	}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
diff --git a/src/pkg/syscall/zsyscall_netbsd_arm.go b/src/pkg/syscall/zsyscall_netbsd_arm.go
index 763a906..c5c9a9f 100644
--- a/src/pkg/syscall/zsyscall_netbsd_arm.go
+++ b/src/pkg/syscall/zsyscall_netbsd_arm.go
@@ -1,4 +1,4 @@
-// mksyscall.pl -l32 -netbsd syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm.go
+// mksyscall.pl -l32 -arm syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
 package syscall
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
 		err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
 		err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
-	_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+	n = int(r0)
 	if e1 != 0 {
 		err = e1
 	}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
@@ -435,13 +436,8 @@ func Fchdir(fd int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Fchflags(path string, flags int) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+func Fchflags(fd int, flags int) (err error) {
+	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
 		err = e1
 	}
diff --git a/src/pkg/syscall/zsyscall_openbsd_386.go b/src/pkg/syscall/zsyscall_openbsd_386.go
index 2c2a567..785e7c3 100644
--- a/src/pkg/syscall/zsyscall_openbsd_386.go
+++ b/src/pkg/syscall/zsyscall_openbsd_386.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
 		err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
 		err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
-	_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+	n = int(r0)
 	if e1 != 0 {
 		err = e1
 	}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
@@ -268,6 +269,23 @@ func pipe(p *[2]_C_int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func getdents(fd int, buf []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Access(path string, mode uint32) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
@@ -507,23 +525,6 @@ func Ftruncate(fd int, length int64) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
-	var _p0 unsafe.Pointer
-	if len(buf) > 0 {
-		_p0 = unsafe.Pointer(&buf[0])
-	} else {
-		_p0 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
-	n = int(r0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Getegid() (egid int) {
 	r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
 	egid = int(r0)
@@ -540,23 +541,6 @@ func Geteuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
-	var _p0 unsafe.Pointer
-	if len(buf) > 0 {
-		_p0 = unsafe.Pointer(&buf[0])
-	} else {
-		_p0 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
-	n = int(r0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Getgid() (gid int) {
 	r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
 	gid = int(r0)
diff --git a/src/pkg/syscall/zsyscall_openbsd_amd64.go b/src/pkg/syscall/zsyscall_openbsd_amd64.go
index 4e14706..7a8d9b6 100644
--- a/src/pkg/syscall/zsyscall_openbsd_amd64.go
+++ b/src/pkg/syscall/zsyscall_openbsd_amd64.go
@@ -50,7 +50,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -60,7 +60,7 @@ func bind(s int, addr uintptr, addrlen _Socklen) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func connect(s int, addr uintptr, addrlen _Socklen) (err error) {
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
 		err = e1
@@ -81,7 +81,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) {
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
 		err = e1
@@ -91,7 +91,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (err error) {
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
 		err = e1
@@ -158,7 +158,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (err error) {
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
 	var _p0 unsafe.Pointer
 	if len(buf) > 0 {
 		_p0 = unsafe.Pointer(&buf[0])
@@ -185,8 +185,9 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func sendmsg(s int, msg *Msghdr, flags int) (err error) {
-	_, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+	n = int(r0)
 	if e1 != 0 {
 		err = e1
 	}
@@ -195,7 +196,7 @@ func sendmsg(s int, msg *Msghdr, flags int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, err error) {
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
@@ -268,6 +269,23 @@ func pipe(p *[2]_C_int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func getdents(fd int, buf []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Access(path string, mode uint32) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
@@ -507,23 +525,6 @@ func Ftruncate(fd int, length int64) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
-	var _p0 unsafe.Pointer
-	if len(buf) > 0 {
-		_p0 = unsafe.Pointer(&buf[0])
-	} else {
-		_p0 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
-	n = int(r0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Getegid() (egid int) {
 	r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
 	egid = int(r0)
@@ -540,23 +541,6 @@ func Geteuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
-	var _p0 unsafe.Pointer
-	if len(buf) > 0 {
-		_p0 = unsafe.Pointer(&buf[0])
-	} else {
-		_p0 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
-	n = int(r0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Getgid() (gid int) {
 	r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
 	gid = int(r0)
diff --git a/src/pkg/syscall/zsyscall_solaris_amd64.go b/src/pkg/syscall/zsyscall_solaris_amd64.go
new file mode 100644
index 0000000..8847cad
--- /dev/null
+++ b/src/pkg/syscall/zsyscall_solaris_amd64.go
@@ -0,0 +1,883 @@
+// mksyscall_solaris.pl syscall_solaris.go syscall_solaris_amd64.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+var (
+	modlibc      = newLazySO("libc.so")
+	modlibsocket = newLazySO("libsocket.so")
+
+	procgetgroups    = modlibc.NewProc("getgroups")
+	procsetgroups    = modlibc.NewProc("setgroups")
+	procfcntl        = modlibc.NewProc("fcntl")
+	procaccept       = modlibsocket.NewProc("accept")
+	procsendmsg      = modlibsocket.NewProc("sendmsg")
+	procAccess       = modlibc.NewProc("access")
+	procAdjtime      = modlibc.NewProc("adjtime")
+	procChdir        = modlibc.NewProc("chdir")
+	procChmod        = modlibc.NewProc("chmod")
+	procChown        = modlibc.NewProc("chown")
+	procChroot       = modlibc.NewProc("chroot")
+	procClose        = modlibc.NewProc("close")
+	procDup          = modlibc.NewProc("dup")
+	procExit         = modlibc.NewProc("exit")
+	procFchdir       = modlibc.NewProc("fchdir")
+	procFchmod       = modlibc.NewProc("fchmod")
+	procFchown       = modlibc.NewProc("fchown")
+	procFpathconf    = modlibc.NewProc("fpathconf")
+	procFstat        = modlibc.NewProc("fstat")
+	procGetdents     = modlibc.NewProc("getdents")
+	procGetgid       = modlibc.NewProc("getgid")
+	procGetpid       = modlibc.NewProc("getpid")
+	procGeteuid      = modlibc.NewProc("geteuid")
+	procGetegid      = modlibc.NewProc("getegid")
+	procGetppid      = modlibc.NewProc("getppid")
+	procGetpriority  = modlibc.NewProc("getpriority")
+	procGetrlimit    = modlibc.NewProc("getrlimit")
+	procGettimeofday = modlibc.NewProc("gettimeofday")
+	procGetuid       = modlibc.NewProc("getuid")
+	procKill         = modlibc.NewProc("kill")
+	procLchown       = modlibc.NewProc("lchown")
+	procLink         = modlibc.NewProc("link")
+	proclisten       = modlibsocket.NewProc("listen")
+	procLstat        = modlibc.NewProc("lstat")
+	procMkdir        = modlibc.NewProc("mkdir")
+	procMknod        = modlibc.NewProc("mknod")
+	procNanosleep    = modlibc.NewProc("nanosleep")
+	procOpen         = modlibc.NewProc("open")
+	procPathconf     = modlibc.NewProc("pathconf")
+	procPread        = modlibc.NewProc("pread")
+	procPwrite       = modlibc.NewProc("pwrite")
+	procread         = modlibc.NewProc("read")
+	procReadlink     = modlibc.NewProc("readlink")
+	procRename       = modlibc.NewProc("rename")
+	procRmdir        = modlibc.NewProc("rmdir")
+	proclseek        = modlibc.NewProc("lseek")
+	procSetegid      = modlibc.NewProc("setegid")
+	procSeteuid      = modlibc.NewProc("seteuid")
+	procSetgid       = modlibc.NewProc("setgid")
+	procSetpgid      = modlibc.NewProc("setpgid")
+	procSetpriority  = modlibc.NewProc("setpriority")
+	procSetregid     = modlibc.NewProc("setregid")
+	procSetreuid     = modlibc.NewProc("setreuid")
+	procSetrlimit    = modlibc.NewProc("setrlimit")
+	procSetsid       = modlibc.NewProc("setsid")
+	procSetuid       = modlibc.NewProc("setuid")
+	procshutdown     = modlibsocket.NewProc("shutdown")
+	procStat         = modlibc.NewProc("stat")
+	procSymlink      = modlibc.NewProc("symlink")
+	procSync         = modlibc.NewProc("sync")
+	procTruncate     = modlibc.NewProc("truncate")
+	procFsync        = modlibc.NewProc("fsync")
+	procFtruncate    = modlibc.NewProc("ftruncate")
+	procUmask        = modlibc.NewProc("umask")
+	procUnlink       = modlibc.NewProc("unlink")
+	procUtimes       = modlibc.NewProc("utimes")
+	procbind         = modlibsocket.NewProc("bind")
+	procconnect      = modlibsocket.NewProc("connect")
+	procmmap         = modlibc.NewProc("mmap")
+	procmunmap       = modlibc.NewProc("munmap")
+	procsendto       = modlibsocket.NewProc("sendto")
+	procsocket       = modlibsocket.NewProc("socket")
+	procsocketpair   = modlibsocket.NewProc("socketpair")
+	procwrite        = modlibc.NewProc("write")
+	procgetsockopt   = modlibsocket.NewProc("getsockopt")
+	procgetpeername  = modlibsocket.NewProc("getpeername")
+	procgetsockname  = modlibsocket.NewProc("getsockname")
+	procsetsockopt   = modlibsocket.NewProc("setsockopt")
+	procrecvfrom     = modlibsocket.NewProc("recvfrom")
+	procrecvmsg      = modlibsocket.NewProc("recvmsg")
+)
+
+func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
+	r0, _, e1 := rawSysvicall6(procgetgroups.Addr(), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func setgroups(ngid int, gid *_Gid_t) (err error) {
+	_, _, e1 := rawSysvicall6(procsetgroups.Addr(), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
+	r0, _, e1 := sysvicall6(procfcntl.Addr(), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0)
+	val = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
+	r0, _, e1 := sysvicall6(procaccept.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := sysvicall6(procsendmsg.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Access(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := sysvicall6(procAccess.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
+	_, _, e1 := sysvicall6(procAdjtime.Addr(), 2, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Chdir(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := sysvicall6(procChdir.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Chmod(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := sysvicall6(procChmod.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Chown(path string, uid int, gid int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := sysvicall6(procChown.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Chroot(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := sysvicall6(procChroot.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Close(fd int) (err error) {
+	_, _, e1 := sysvicall6(procClose.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Dup(fd int) (nfd int, err error) {
+	r0, _, e1 := sysvicall6(procDup.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
+	nfd = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Exit(code int) {
+	sysvicall6(procExit.Addr(), 1, uintptr(code), 0, 0, 0, 0, 0)
+	return
+}
+
+func Fchdir(fd int) (err error) {
+	_, _, e1 := sysvicall6(procFchdir.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Fchmod(fd int, mode uint32) (err error) {
+	_, _, e1 := sysvicall6(procFchmod.Addr(), 2, uintptr(fd), uintptr(mode), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Fchown(fd int, uid int, gid int) (err error) {
+	_, _, e1 := sysvicall6(procFchown.Addr(), 3, uintptr(fd), uintptr(uid), uintptr(gid), 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Fpathconf(fd int, name int) (val int, err error) {
+	r0, _, e1 := sysvicall6(procFpathconf.Addr(), 2, uintptr(fd), uintptr(name), 0, 0, 0, 0)
+	val = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Fstat(fd int, stat *Stat_t) (err error) {
+	_, _, e1 := sysvicall6(procFstat.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Getdents(fd int, buf []byte, basep *uintptr) (n int, err error) {
+	var _p0 *byte
+	if len(buf) > 0 {
+		_p0 = &buf[0]
+	}
+	r0, _, e1 := sysvicall6(procGetdents.Addr(), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Getgid() (gid int) {
+	r0, _, _ := rawSysvicall6(procGetgid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	gid = int(r0)
+	return
+}
+
+func Getpid() (pid int) {
+	r0, _, _ := rawSysvicall6(procGetpid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	pid = int(r0)
+	return
+}
+
+func Geteuid() (euid int) {
+	r0, _, _ := sysvicall6(procGeteuid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	euid = int(r0)
+	return
+}
+
+func Getegid() (egid int) {
+	r0, _, _ := sysvicall6(procGetegid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	egid = int(r0)
+	return
+}
+
+func Getppid() (ppid int) {
+	r0, _, _ := sysvicall6(procGetppid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	ppid = int(r0)
+	return
+}
+
+func Getpriority(which int, who int) (n int, err error) {
+	r0, _, e1 := sysvicall6(procGetpriority.Addr(), 2, uintptr(which), uintptr(who), 0, 0, 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Getrlimit(which int, lim *Rlimit) (err error) {
+	_, _, e1 := rawSysvicall6(procGetrlimit.Addr(), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Gettimeofday(tv *Timeval) (err error) {
+	_, _, e1 := rawSysvicall6(procGettimeofday.Addr(), 1, uintptr(unsafe.Pointer(tv)), 0, 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Getuid() (uid int) {
+	r0, _, _ := rawSysvicall6(procGetuid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	uid = int(r0)
+	return
+}
+
+func Kill(pid int, signum Signal) (err error) {
+	_, _, e1 := sysvicall6(procKill.Addr(), 2, uintptr(pid), uintptr(signum), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Lchown(path string, uid int, gid int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := sysvicall6(procLchown.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Link(path string, link string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(link)
+	if err != nil {
+		return
+	}
+	_, _, e1 := sysvicall6(procLink.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Listen(s int, backlog int) (err error) {
+	_, _, e1 := sysvicall6(proclisten.Addr(), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Lstat(path string, stat *Stat_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := sysvicall6(procLstat.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Mkdir(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := sysvicall6(procMkdir.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Mknod(path string, mode uint32, dev int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := sysvicall6(procMknod.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
+	_, _, e1 := sysvicall6(procNanosleep.Addr(), 2, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Open(path string, mode int, perm uint32) (fd int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	r0, _, e1 := sysvicall6(procOpen.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Pathconf(path string, name int) (val int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	r0, _, e1 := sysvicall6(procPathconf.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0, 0, 0, 0)
+	val = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+	var _p0 *byte
+	if len(p) > 0 {
+		_p0 = &p[0]
+	}
+	r0, _, e1 := sysvicall6(procPread.Addr(), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+	var _p0 *byte
+	if len(p) > 0 {
+		_p0 = &p[0]
+	}
+	r0, _, e1 := sysvicall6(procPwrite.Addr(), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func read(fd int, p []byte) (n int, err error) {
+	var _p0 *byte
+	if len(p) > 0 {
+		_p0 = &p[0]
+	}
+	r0, _, e1 := sysvicall6(procread.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0, 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Readlink(path string, buf []byte) (n int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	if len(buf) > 0 {
+		_p1 = &buf[0]
+	}
+	r0, _, e1 := sysvicall6(procReadlink.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(len(buf)), 0, 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Rename(from string, to string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(from)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(to)
+	if err != nil {
+		return
+	}
+	_, _, e1 := sysvicall6(procRename.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Rmdir(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := sysvicall6(procRmdir.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
+	r0, _, e1 := sysvicall6(proclseek.Addr(), 3, uintptr(fd), uintptr(offset), uintptr(whence), 0, 0, 0)
+	newoffset = int64(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Setegid(egid int) (err error) {
+	_, _, e1 := rawSysvicall6(procSetegid.Addr(), 1, uintptr(egid), 0, 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Seteuid(euid int) (err error) {
+	_, _, e1 := rawSysvicall6(procSeteuid.Addr(), 1, uintptr(euid), 0, 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Setgid(gid int) (err error) {
+	_, _, e1 := rawSysvicall6(procSetgid.Addr(), 1, uintptr(gid), 0, 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Setpgid(pid int, pgid int) (err error) {
+	_, _, e1 := rawSysvicall6(procSetpgid.Addr(), 2, uintptr(pid), uintptr(pgid), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Setpriority(which int, who int, prio int) (err error) {
+	_, _, e1 := sysvicall6(procSetpriority.Addr(), 3, uintptr(which), uintptr(who), uintptr(prio), 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Setregid(rgid int, egid int) (err error) {
+	_, _, e1 := rawSysvicall6(procSetregid.Addr(), 2, uintptr(rgid), uintptr(egid), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Setreuid(ruid int, euid int) (err error) {
+	_, _, e1 := rawSysvicall6(procSetreuid.Addr(), 2, uintptr(ruid), uintptr(euid), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Setrlimit(which int, lim *Rlimit) (err error) {
+	_, _, e1 := rawSysvicall6(procSetrlimit.Addr(), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Setsid() (pid int, err error) {
+	r0, _, e1 := rawSysvicall6(procSetsid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	pid = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Setuid(uid int) (err error) {
+	_, _, e1 := rawSysvicall6(procSetuid.Addr(), 1, uintptr(uid), 0, 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Shutdown(s int, how int) (err error) {
+	_, _, e1 := sysvicall6(procshutdown.Addr(), 2, uintptr(s), uintptr(how), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Stat(path string, stat *Stat_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := sysvicall6(procStat.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Symlink(path string, link string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(link)
+	if err != nil {
+		return
+	}
+	_, _, e1 := sysvicall6(procSymlink.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Sync() (err error) {
+	_, _, e1 := sysvicall6(procSync.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Truncate(path string, length int64) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := sysvicall6(procTruncate.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Fsync(fd int) (err error) {
+	_, _, e1 := sysvicall6(procFsync.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Ftruncate(fd int, length int64) (err error) {
+	_, _, e1 := sysvicall6(procFtruncate.Addr(), 2, uintptr(fd), uintptr(length), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Umask(newmask int) (oldmask int) {
+	r0, _, _ := sysvicall6(procUmask.Addr(), 1, uintptr(newmask), 0, 0, 0, 0, 0)
+	oldmask = int(r0)
+	return
+}
+
+func Unlink(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := sysvicall6(procUnlink.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Utimes(path string, times *[2]Timeval) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := sysvicall6(procUtimes.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+	_, _, e1 := sysvicall6(procbind.Addr(), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+	_, _, e1 := sysvicall6(procconnect.Addr(), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
+	r0, _, e1 := sysvicall6(procmmap.Addr(), 6, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
+	ret = uintptr(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func munmap(addr uintptr, length uintptr) (err error) {
+	_, _, e1 := sysvicall6(procmunmap.Addr(), 2, uintptr(addr), uintptr(length), 0, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
+	var _p0 *byte
+	if len(buf) > 0 {
+		_p0 = &buf[0]
+	}
+	_, _, e1 := sysvicall6(procsendto.Addr(), 6, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func socket(domain int, typ int, proto int) (fd int, err error) {
+	r0, _, e1 := sysvicall6(procsocket.Addr(), 3, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
+	_, _, e1 := rawSysvicall6(procsocketpair.Addr(), 4, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func write(fd int, p []byte) (n int, err error) {
+	var _p0 *byte
+	if len(p) > 0 {
+		_p0 = &p[0]
+	}
+	r0, _, e1 := sysvicall6(procwrite.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0, 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
+	_, _, e1 := sysvicall6(procgetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+	_, _, e1 := rawSysvicall6(procgetpeername.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+	_, _, e1 := sysvicall6(procgetsockname.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
+	_, _, e1 := sysvicall6(procsetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
+	var _p0 *byte
+	if len(p) > 0 {
+		_p0 = &p[0]
+	}
+	r0, _, e1 := sysvicall6(procrecvfrom.Addr(), 6, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := sysvicall6(procrecvmsg.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
diff --git a/src/pkg/syscall/zsyscall_windows_386.go b/src/pkg/syscall/zsyscall_windows_386.go
index 3cd12dd..132adaf 100644
--- a/src/pkg/syscall/zsyscall_windows_386.go
+++ b/src/pkg/syscall/zsyscall_windows_386.go
@@ -1,4 +1,4 @@
-// mksyscall_windows.pl -l32 syscall_windows.go security_windows.go syscall_windows_386.go
+// go build mksyscall_windows.go && ./mksyscall_windows syscall_windows.go security_windows.go syscall_windows_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
 package syscall
@@ -1323,7 +1323,7 @@ func Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int3
 	return
 }
 
-func bind(s Handle, name uintptr, namelen int32) (err error) {
+func bind(s Handle, name unsafe.Pointer, namelen int32) (err error) {
 	r1, _, e1 := Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
 	if r1 == socket_error {
 		if e1 != 0 {
@@ -1335,7 +1335,7 @@ func bind(s Handle, name uintptr, namelen int32) (err error) {
 	return
 }
 
-func connect(s Handle, name uintptr, namelen int32) (err error) {
+func connect(s Handle, name unsafe.Pointer, namelen int32) (err error) {
 	r1, _, e1 := Syscall(procconnect.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
 	if r1 == socket_error {
 		if e1 != 0 {
diff --git a/src/pkg/syscall/zsyscall_windows_amd64.go b/src/pkg/syscall/zsyscall_windows_amd64.go
index d23c231..353a6fd 100644
--- a/src/pkg/syscall/zsyscall_windows_amd64.go
+++ b/src/pkg/syscall/zsyscall_windows_amd64.go
@@ -1,4 +1,4 @@
-// mksyscall_windows.pl syscall_windows.go security_windows.go syscall_windows_amd64.go
+// go build mksyscall_windows.go && ./mksyscall_windows syscall_windows.go security_windows.go syscall_windows_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
 package syscall
@@ -1323,7 +1323,7 @@ func Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int3
 	return
 }
 
-func bind(s Handle, name uintptr, namelen int32) (err error) {
+func bind(s Handle, name unsafe.Pointer, namelen int32) (err error) {
 	r1, _, e1 := Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
 	if r1 == socket_error {
 		if e1 != 0 {
@@ -1335,7 +1335,7 @@ func bind(s Handle, name uintptr, namelen int32) (err error) {
 	return
 }
 
-func connect(s Handle, name uintptr, namelen int32) (err error) {
+func connect(s Handle, name unsafe.Pointer, namelen int32) (err error) {
 	r1, _, e1 := Syscall(procconnect.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
 	if r1 == socket_error {
 		if e1 != 0 {
diff --git a/src/pkg/syscall/zsysctl_openbsd.go b/src/pkg/syscall/zsysctl_openbsd.go
index a5914f3..923b2c2 100644
--- a/src/pkg/syscall/zsysctl_openbsd.go
+++ b/src/pkg/syscall/zsysctl_openbsd.go
@@ -48,8 +48,7 @@ var sysctlMib = []mibentry{
 	{"kern.cp_time2", []_C_int{1, 71}},
 	{"kern.cryptodevallowsoft", []_C_int{1, 53}},
 	{"kern.domainname", []_C_int{1, 22}},
-	{"kern.file", []_C_int{1, 15}},
-	{"kern.file2", []_C_int{1, 73}},
+	{"kern.file", []_C_int{1, 73}},
 	{"kern.forkstat", []_C_int{1, 42}},
 	{"kern.fscale", []_C_int{1, 46}},
 	{"kern.fsync", []_C_int{1, 33}},
@@ -87,7 +86,6 @@ var sysctlMib = []mibentry{
 	{"kern.proc", []_C_int{1, 66}},
 	{"kern.random", []_C_int{1, 31}},
 	{"kern.rawpartition", []_C_int{1, 24}},
-	{"kern.rthreads", []_C_int{1, 74}},
 	{"kern.saved_ids", []_C_int{1, 20}},
 	{"kern.securelevel", []_C_int{1, 9}},
 	{"kern.seminfo", []_C_int{1, 61}},
@@ -226,8 +224,6 @@ var sysctlMib = []mibentry{
 	{"net.inet6.ip6.forwsrcrt", []_C_int{4, 24, 17, 5}},
 	{"net.inet6.ip6.hdrnestlimit", []_C_int{4, 24, 17, 15}},
 	{"net.inet6.ip6.hlim", []_C_int{4, 24, 17, 3}},
-	{"net.inet6.ip6.kame_version", []_C_int{4, 24, 17, 20}},
-	{"net.inet6.ip6.keepfaith", []_C_int{4, 24, 17, 13}},
 	{"net.inet6.ip6.log_interval", []_C_int{4, 24, 17, 14}},
 	{"net.inet6.ip6.maxdynroutes", []_C_int{4, 24, 17, 48}},
 	{"net.inet6.ip6.maxfragpackets", []_C_int{4, 24, 17, 9}},
@@ -236,7 +232,7 @@ var sysctlMib = []mibentry{
 	{"net.inet6.ip6.maxifprefixes", []_C_int{4, 24, 17, 46}},
 	{"net.inet6.ip6.mforwarding", []_C_int{4, 24, 17, 42}},
 	{"net.inet6.ip6.mrtproto", []_C_int{4, 24, 17, 8}},
-	{"net.inet6.ip6.mtu", []_C_int{4, 24, 17, 4}},
+	{"net.inet6.ip6.mtudisctimeout", []_C_int{4, 24, 17, 50}},
 	{"net.inet6.ip6.multicast_mtudisc", []_C_int{4, 24, 17, 44}},
 	{"net.inet6.ip6.multipath", []_C_int{4, 24, 17, 43}},
 	{"net.inet6.ip6.neighborgcthresh", []_C_int{4, 24, 17, 45}},
@@ -258,26 +254,6 @@ var sysctlMib = []mibentry{
 	{"net.mpls.ttl", []_C_int{4, 33, 2}},
 	{"net.pflow.stats", []_C_int{4, 34, 1}},
 	{"net.pipex.enable", []_C_int{4, 35, 1}},
-	{"user.bc_base_max", []_C_int{8, 2}},
-	{"user.bc_dim_max", []_C_int{8, 3}},
-	{"user.bc_scale_max", []_C_int{8, 4}},
-	{"user.bc_string_max", []_C_int{8, 5}},
-	{"user.coll_weights_max", []_C_int{8, 6}},
-	{"user.cs_path", []_C_int{8, 1}},
-	{"user.expr_nest_max", []_C_int{8, 7}},
-	{"user.line_max", []_C_int{8, 8}},
-	{"user.posix2_c_bind", []_C_int{8, 11}},
-	{"user.posix2_c_dev", []_C_int{8, 12}},
-	{"user.posix2_char_term", []_C_int{8, 13}},
-	{"user.posix2_fort_dev", []_C_int{8, 14}},
-	{"user.posix2_fort_run", []_C_int{8, 15}},
-	{"user.posix2_localedef", []_C_int{8, 16}},
-	{"user.posix2_sw_dev", []_C_int{8, 17}},
-	{"user.posix2_upe", []_C_int{8, 18}},
-	{"user.posix2_version", []_C_int{8, 10}},
-	{"user.re_dup_max", []_C_int{8, 9}},
-	{"user.stream_max", []_C_int{8, 19}},
-	{"user.tzname_max", []_C_int{8, 20}},
 	{"vm.anonmin", []_C_int{2, 7}},
 	{"vm.loadavg", []_C_int{2, 2}},
 	{"vm.maxslp", []_C_int{2, 10}},
diff --git a/src/pkg/syscall/zsysnum_dragonfly_386.go b/src/pkg/syscall/zsysnum_dragonfly_386.go
index 68eeb32..4b086b9 100644
--- a/src/pkg/syscall/zsysnum_dragonfly_386.go
+++ b/src/pkg/syscall/zsysnum_dragonfly_386.go
@@ -115,9 +115,6 @@ const (
 	SYS_UNAME         = 164 // { int uname(struct utsname *name); }
 	SYS_SYSARCH       = 165 // { int sysarch(int op, char *parms); }
 	SYS_RTPRIO        = 166 // { int rtprio(int function, pid_t pid, \
-	SYS_SEMSYS        = 169 // { int semsys(int which, int a2, int a3, int a4, \
-	SYS_MSGSYS        = 170 // { int msgsys(int which, int a2, int a3, int a4, \
-	SYS_SHMSYS        = 171 // { int shmsys(int which, int a2, int a3, int a4); }
 	SYS_EXTPREAD      = 173 // { ssize_t extpread(int fd, void *buf, \
 	SYS_EXTPWRITE     = 174 // { ssize_t extpwrite(int fd, const void *buf, \
 	SYS_NTP_ADJTIME   = 176 // { int ntp_adjtime(struct timex *tp); }
@@ -300,4 +297,6 @@ const (
 	SYS_LINKAT                 = 531 // { int linkat(int fd1, char *path1, int fd2, \
 	SYS_EACCESS                = 532 // { int eaccess(char *path, int flags); }
 	SYS_LPATHCONF              = 533 // { int lpathconf(char *path, int name); }
+	SYS_VMM_GUEST_CTL          = 534 // { int vmm_guest_ctl(int op, struct vmm_guest_options *options); }
+	SYS_VMM_GUEST_SYNC_ADDR    = 535 // { int vmm_guest_sync_addr(long *dstaddr, long *srcaddr); }
 )
diff --git a/src/pkg/syscall/zsysnum_dragonfly_amd64.go b/src/pkg/syscall/zsysnum_dragonfly_amd64.go
index 68eeb32..4b086b9 100644
--- a/src/pkg/syscall/zsysnum_dragonfly_amd64.go
+++ b/src/pkg/syscall/zsysnum_dragonfly_amd64.go
@@ -115,9 +115,6 @@ const (
 	SYS_UNAME         = 164 // { int uname(struct utsname *name); }
 	SYS_SYSARCH       = 165 // { int sysarch(int op, char *parms); }
 	SYS_RTPRIO        = 166 // { int rtprio(int function, pid_t pid, \
-	SYS_SEMSYS        = 169 // { int semsys(int which, int a2, int a3, int a4, \
-	SYS_MSGSYS        = 170 // { int msgsys(int which, int a2, int a3, int a4, \
-	SYS_SHMSYS        = 171 // { int shmsys(int which, int a2, int a3, int a4); }
 	SYS_EXTPREAD      = 173 // { ssize_t extpread(int fd, void *buf, \
 	SYS_EXTPWRITE     = 174 // { ssize_t extpwrite(int fd, const void *buf, \
 	SYS_NTP_ADJTIME   = 176 // { int ntp_adjtime(struct timex *tp); }
@@ -300,4 +297,6 @@ const (
 	SYS_LINKAT                 = 531 // { int linkat(int fd1, char *path1, int fd2, \
 	SYS_EACCESS                = 532 // { int eaccess(char *path, int flags); }
 	SYS_LPATHCONF              = 533 // { int lpathconf(char *path, int name); }
+	SYS_VMM_GUEST_CTL          = 534 // { int vmm_guest_ctl(int op, struct vmm_guest_options *options); }
+	SYS_VMM_GUEST_SYNC_ADDR    = 535 // { int vmm_guest_sync_addr(long *dstaddr, long *srcaddr); }
 )
diff --git a/src/pkg/syscall/zsysnum_freebsd_386.go b/src/pkg/syscall/zsysnum_freebsd_386.go
index 74400b6..dfca558 100644
--- a/src/pkg/syscall/zsysnum_freebsd_386.go
+++ b/src/pkg/syscall/zsysnum_freebsd_386.go
@@ -34,8 +34,8 @@ const (
 	SYS_GETPEERNAME              = 31  // { int getpeername(int fdes, \
 	SYS_GETSOCKNAME              = 32  // { int getsockname(int fdes, \
 	SYS_ACCESS                   = 33  // { int access(char *path, int amode); }
-	SYS_CHFLAGS                  = 34  // { int chflags(char *path, int flags); }
-	SYS_FCHFLAGS                 = 35  // { int fchflags(int fd, int flags); }
+	SYS_CHFLAGS                  = 34  // { int chflags(const char *path, u_long flags); }
+	SYS_FCHFLAGS                 = 35  // { int fchflags(int fd, u_long flags); }
 	SYS_SYNC                     = 36  // { int sync(void); }
 	SYS_KILL                     = 37  // { int kill(int pid, int signum); }
 	SYS_GETPPID                  = 39  // { pid_t getppid(void); }
@@ -208,14 +208,14 @@ const (
 	SYS___ACL_ACLCHECK_FILE      = 353 // { int __acl_aclcheck_file(const char *path, \
 	SYS___ACL_ACLCHECK_FD        = 354 // { int __acl_aclcheck_fd(int filedes, \
 	SYS_EXTATTRCTL               = 355 // { int extattrctl(const char *path, int cmd, \
-	SYS_EXTATTR_SET_FILE         = 356 // { int extattr_set_file( \
+	SYS_EXTATTR_SET_FILE         = 356 // { ssize_t extattr_set_file( \
 	SYS_EXTATTR_GET_FILE         = 357 // { ssize_t extattr_get_file( \
 	SYS_EXTATTR_DELETE_FILE      = 358 // { int extattr_delete_file(const char *path, \
 	SYS_GETRESUID                = 360 // { int getresuid(uid_t *ruid, uid_t *euid, \
 	SYS_GETRESGID                = 361 // { int getresgid(gid_t *rgid, gid_t *egid, \
 	SYS_KQUEUE                   = 362 // { int kqueue(void); }
 	SYS_KEVENT                   = 363 // { int kevent(int fd, \
-	SYS_EXTATTR_SET_FD           = 371 // { int extattr_set_fd(int fd, \
+	SYS_EXTATTR_SET_FD           = 371 // { ssize_t extattr_set_fd(int fd, \
 	SYS_EXTATTR_GET_FD           = 372 // { ssize_t extattr_get_fd(int fd, \
 	SYS_EXTATTR_DELETE_FD        = 373 // { int extattr_delete_fd(int fd, \
 	SYS___SETUGID                = 374 // { int __setugid(int flag); }
@@ -228,7 +228,7 @@ const (
 	SYS___MAC_SET_FD             = 388 // { int __mac_set_fd(int fd, \
 	SYS___MAC_SET_FILE           = 389 // { int __mac_set_file(const char *path_p, \
 	SYS_KENV                     = 390 // { int kenv(int what, const char *name, \
-	SYS_LCHFLAGS                 = 391 // { int lchflags(const char *path, int flags); }
+	SYS_LCHFLAGS                 = 391 // { int lchflags(const char *path, \
 	SYS_UUIDGEN                  = 392 // { int uuidgen(struct uuid *store, \
 	SYS_SENDFILE                 = 393 // { int sendfile(int fd, int s, off_t offset, \
 	SYS_MAC_SYSCALL              = 394 // { int mac_syscall(const char *policy, \
@@ -239,7 +239,7 @@ const (
 	SYS___MAC_GET_PID            = 409 // { int __mac_get_pid(pid_t pid, \
 	SYS___MAC_GET_LINK           = 410 // { int __mac_get_link(const char *path_p, \
 	SYS___MAC_SET_LINK           = 411 // { int __mac_set_link(const char *path_p, \
-	SYS_EXTATTR_SET_LINK         = 412 // { int extattr_set_link( \
+	SYS_EXTATTR_SET_LINK         = 412 // { ssize_t extattr_set_link( \
 	SYS_EXTATTR_GET_LINK         = 413 // { ssize_t extattr_get_link( \
 	SYS_EXTATTR_DELETE_LINK      = 414 // { int extattr_delete_link( \
 	SYS___MAC_EXECVE             = 415 // { int __mac_execve(char *fname, char **argv, \
@@ -338,5 +338,11 @@ const (
 	SYS_RCTL_REMOVE_RULE         = 529 // { int rctl_remove_rule(const void *inbufp, \
 	SYS_POSIX_FALLOCATE          = 530 // { int posix_fallocate(int fd, \
 	SYS_POSIX_FADVISE            = 531 // { int posix_fadvise(int fd, off_t offset, \
-	SYS_WAIT6                    = 532 // { int wait6(int idtype, int id, \
+	SYS_WAIT6                    = 532 // { int wait6(idtype_t idtype, id_t id, \
+	SYS_BINDAT                   = 538 // { int bindat(int fd, int s, caddr_t name, \
+	SYS_CONNECTAT                = 539 // { int connectat(int fd, int s, caddr_t name, \
+	SYS_CHFLAGSAT                = 540 // { int chflagsat(int fd, const char *path, \
+	SYS_ACCEPT4                  = 541 // { int accept4(int s, \
+	SYS_PIPE2                    = 542 // { int pipe2(int *fildes, int flags); }
+	SYS_PROCCTL                  = 544 // { int procctl(idtype_t idtype, id_t id, \
 )
diff --git a/src/pkg/syscall/zsysnum_freebsd_amd64.go b/src/pkg/syscall/zsysnum_freebsd_amd64.go
index 74400b6..dfca558 100644
--- a/src/pkg/syscall/zsysnum_freebsd_amd64.go
+++ b/src/pkg/syscall/zsysnum_freebsd_amd64.go
@@ -34,8 +34,8 @@ const (
 	SYS_GETPEERNAME              = 31  // { int getpeername(int fdes, \
 	SYS_GETSOCKNAME              = 32  // { int getsockname(int fdes, \
 	SYS_ACCESS                   = 33  // { int access(char *path, int amode); }
-	SYS_CHFLAGS                  = 34  // { int chflags(char *path, int flags); }
-	SYS_FCHFLAGS                 = 35  // { int fchflags(int fd, int flags); }
+	SYS_CHFLAGS                  = 34  // { int chflags(const char *path, u_long flags); }
+	SYS_FCHFLAGS                 = 35  // { int fchflags(int fd, u_long flags); }
 	SYS_SYNC                     = 36  // { int sync(void); }
 	SYS_KILL                     = 37  // { int kill(int pid, int signum); }
 	SYS_GETPPID                  = 39  // { pid_t getppid(void); }
@@ -208,14 +208,14 @@ const (
 	SYS___ACL_ACLCHECK_FILE      = 353 // { int __acl_aclcheck_file(const char *path, \
 	SYS___ACL_ACLCHECK_FD        = 354 // { int __acl_aclcheck_fd(int filedes, \
 	SYS_EXTATTRCTL               = 355 // { int extattrctl(const char *path, int cmd, \
-	SYS_EXTATTR_SET_FILE         = 356 // { int extattr_set_file( \
+	SYS_EXTATTR_SET_FILE         = 356 // { ssize_t extattr_set_file( \
 	SYS_EXTATTR_GET_FILE         = 357 // { ssize_t extattr_get_file( \
 	SYS_EXTATTR_DELETE_FILE      = 358 // { int extattr_delete_file(const char *path, \
 	SYS_GETRESUID                = 360 // { int getresuid(uid_t *ruid, uid_t *euid, \
 	SYS_GETRESGID                = 361 // { int getresgid(gid_t *rgid, gid_t *egid, \
 	SYS_KQUEUE                   = 362 // { int kqueue(void); }
 	SYS_KEVENT                   = 363 // { int kevent(int fd, \
-	SYS_EXTATTR_SET_FD           = 371 // { int extattr_set_fd(int fd, \
+	SYS_EXTATTR_SET_FD           = 371 // { ssize_t extattr_set_fd(int fd, \
 	SYS_EXTATTR_GET_FD           = 372 // { ssize_t extattr_get_fd(int fd, \
 	SYS_EXTATTR_DELETE_FD        = 373 // { int extattr_delete_fd(int fd, \
 	SYS___SETUGID                = 374 // { int __setugid(int flag); }
@@ -228,7 +228,7 @@ const (
 	SYS___MAC_SET_FD             = 388 // { int __mac_set_fd(int fd, \
 	SYS___MAC_SET_FILE           = 389 // { int __mac_set_file(const char *path_p, \
 	SYS_KENV                     = 390 // { int kenv(int what, const char *name, \
-	SYS_LCHFLAGS                 = 391 // { int lchflags(const char *path, int flags); }
+	SYS_LCHFLAGS                 = 391 // { int lchflags(const char *path, \
 	SYS_UUIDGEN                  = 392 // { int uuidgen(struct uuid *store, \
 	SYS_SENDFILE                 = 393 // { int sendfile(int fd, int s, off_t offset, \
 	SYS_MAC_SYSCALL              = 394 // { int mac_syscall(const char *policy, \
@@ -239,7 +239,7 @@ const (
 	SYS___MAC_GET_PID            = 409 // { int __mac_get_pid(pid_t pid, \
 	SYS___MAC_GET_LINK           = 410 // { int __mac_get_link(const char *path_p, \
 	SYS___MAC_SET_LINK           = 411 // { int __mac_set_link(const char *path_p, \
-	SYS_EXTATTR_SET_LINK         = 412 // { int extattr_set_link( \
+	SYS_EXTATTR_SET_LINK         = 412 // { ssize_t extattr_set_link( \
 	SYS_EXTATTR_GET_LINK         = 413 // { ssize_t extattr_get_link( \
 	SYS_EXTATTR_DELETE_LINK      = 414 // { int extattr_delete_link( \
 	SYS___MAC_EXECVE             = 415 // { int __mac_execve(char *fname, char **argv, \
@@ -338,5 +338,11 @@ const (
 	SYS_RCTL_REMOVE_RULE         = 529 // { int rctl_remove_rule(const void *inbufp, \
 	SYS_POSIX_FALLOCATE          = 530 // { int posix_fallocate(int fd, \
 	SYS_POSIX_FADVISE            = 531 // { int posix_fadvise(int fd, off_t offset, \
-	SYS_WAIT6                    = 532 // { int wait6(int idtype, int id, \
+	SYS_WAIT6                    = 532 // { int wait6(idtype_t idtype, id_t id, \
+	SYS_BINDAT                   = 538 // { int bindat(int fd, int s, caddr_t name, \
+	SYS_CONNECTAT                = 539 // { int connectat(int fd, int s, caddr_t name, \
+	SYS_CHFLAGSAT                = 540 // { int chflagsat(int fd, const char *path, \
+	SYS_ACCEPT4                  = 541 // { int accept4(int s, \
+	SYS_PIPE2                    = 542 // { int pipe2(int *fildes, int flags); }
+	SYS_PROCCTL                  = 544 // { int procctl(idtype_t idtype, id_t id, \
 )
diff --git a/src/pkg/syscall/zsysnum_freebsd_arm.go b/src/pkg/syscall/zsysnum_freebsd_arm.go
index 61a6a32..dfca558 100644
--- a/src/pkg/syscall/zsysnum_freebsd_arm.go
+++ b/src/pkg/syscall/zsysnum_freebsd_arm.go
@@ -34,8 +34,8 @@ const (
 	SYS_GETPEERNAME              = 31  // { int getpeername(int fdes, \
 	SYS_GETSOCKNAME              = 32  // { int getsockname(int fdes, \
 	SYS_ACCESS                   = 33  // { int access(char *path, int amode); }
-	SYS_CHFLAGS                  = 34  // { int chflags(char *path, int flags); }
-	SYS_FCHFLAGS                 = 35  // { int fchflags(int fd, int flags); }
+	SYS_CHFLAGS                  = 34  // { int chflags(const char *path, u_long flags); }
+	SYS_FCHFLAGS                 = 35  // { int fchflags(int fd, u_long flags); }
 	SYS_SYNC                     = 36  // { int sync(void); }
 	SYS_KILL                     = 37  // { int kill(int pid, int signum); }
 	SYS_GETPPID                  = 39  // { pid_t getppid(void); }
@@ -208,14 +208,14 @@ const (
 	SYS___ACL_ACLCHECK_FILE      = 353 // { int __acl_aclcheck_file(const char *path, \
 	SYS___ACL_ACLCHECK_FD        = 354 // { int __acl_aclcheck_fd(int filedes, \
 	SYS_EXTATTRCTL               = 355 // { int extattrctl(const char *path, int cmd, \
-	SYS_EXTATTR_SET_FILE         = 356 // { int extattr_set_file( \
+	SYS_EXTATTR_SET_FILE         = 356 // { ssize_t extattr_set_file( \
 	SYS_EXTATTR_GET_FILE         = 357 // { ssize_t extattr_get_file( \
 	SYS_EXTATTR_DELETE_FILE      = 358 // { int extattr_delete_file(const char *path, \
 	SYS_GETRESUID                = 360 // { int getresuid(uid_t *ruid, uid_t *euid, \
 	SYS_GETRESGID                = 361 // { int getresgid(gid_t *rgid, gid_t *egid, \
 	SYS_KQUEUE                   = 362 // { int kqueue(void); }
 	SYS_KEVENT                   = 363 // { int kevent(int fd, \
-	SYS_EXTATTR_SET_FD           = 371 // { int extattr_set_fd(int fd, \
+	SYS_EXTATTR_SET_FD           = 371 // { ssize_t extattr_set_fd(int fd, \
 	SYS_EXTATTR_GET_FD           = 372 // { ssize_t extattr_get_fd(int fd, \
 	SYS_EXTATTR_DELETE_FD        = 373 // { int extattr_delete_fd(int fd, \
 	SYS___SETUGID                = 374 // { int __setugid(int flag); }
@@ -228,7 +228,7 @@ const (
 	SYS___MAC_SET_FD             = 388 // { int __mac_set_fd(int fd, \
 	SYS___MAC_SET_FILE           = 389 // { int __mac_set_file(const char *path_p, \
 	SYS_KENV                     = 390 // { int kenv(int what, const char *name, \
-	SYS_LCHFLAGS                 = 391 // { int lchflags(const char *path, int flags); }
+	SYS_LCHFLAGS                 = 391 // { int lchflags(const char *path, \
 	SYS_UUIDGEN                  = 392 // { int uuidgen(struct uuid *store, \
 	SYS_SENDFILE                 = 393 // { int sendfile(int fd, int s, off_t offset, \
 	SYS_MAC_SYSCALL              = 394 // { int mac_syscall(const char *policy, \
@@ -239,7 +239,7 @@ const (
 	SYS___MAC_GET_PID            = 409 // { int __mac_get_pid(pid_t pid, \
 	SYS___MAC_GET_LINK           = 410 // { int __mac_get_link(const char *path_p, \
 	SYS___MAC_SET_LINK           = 411 // { int __mac_set_link(const char *path_p, \
-	SYS_EXTATTR_SET_LINK         = 412 // { int extattr_set_link( \
+	SYS_EXTATTR_SET_LINK         = 412 // { ssize_t extattr_set_link( \
 	SYS_EXTATTR_GET_LINK         = 413 // { ssize_t extattr_get_link( \
 	SYS_EXTATTR_DELETE_LINK      = 414 // { int extattr_delete_link( \
 	SYS___MAC_EXECVE             = 415 // { int __mac_execve(char *fname, char **argv, \
@@ -322,7 +322,7 @@ const (
 	SYS_CLOSEFROM                = 509 // { int closefrom(int lowfd); }
 	SYS_LPATHCONF                = 513 // { int lpathconf(char *path, int name); }
 	SYS_CAP_NEW                  = 514 // { int cap_new(int fd, uint64_t rights); }
-	SYS_CAP_RIGHTS_GET           = 515 // { int cap_rights_get(int fd, \
+	SYS_CAP_GETRIGHTS            = 515 // { int cap_getrights(int fd, \
 	SYS_CAP_ENTER                = 516 // { int cap_enter(void); }
 	SYS_CAP_GETMODE              = 517 // { int cap_getmode(u_int *modep); }
 	SYS_PDFORK                   = 518 // { int pdfork(int *fdp, int flags); }
@@ -338,10 +338,11 @@ const (
 	SYS_RCTL_REMOVE_RULE         = 529 // { int rctl_remove_rule(const void *inbufp, \
 	SYS_POSIX_FALLOCATE          = 530 // { int posix_fallocate(int fd, \
 	SYS_POSIX_FADVISE            = 531 // { int posix_fadvise(int fd, off_t offset, \
-	SYS_WAIT6                    = 532 // { int wait6(int idtype, int id, \
-	SYS_CAP_RIGHTS_LIMIT         = 533 // { int cap_rights_limit(int fd, \
-	SYS_CAP_IOCTLS_LIMIT         = 534 // { int cap_ioctls_limit(int fd, \
-	SYS_CAP_IOCTLS_GET           = 535 // { ssize_t cap_ioctls_get(int fd, \
-	SYS_CAP_FCNTLS_LIMIT         = 536 // { int cap_fcntls_limit(int fd, \
-	SYS_CAP_FCNTLS_GET           = 537 // { int cap_fcntls_get(int fd, \
+	SYS_WAIT6                    = 532 // { int wait6(idtype_t idtype, id_t id, \
+	SYS_BINDAT                   = 538 // { int bindat(int fd, int s, caddr_t name, \
+	SYS_CONNECTAT                = 539 // { int connectat(int fd, int s, caddr_t name, \
+	SYS_CHFLAGSAT                = 540 // { int chflagsat(int fd, const char *path, \
+	SYS_ACCEPT4                  = 541 // { int accept4(int s, \
+	SYS_PIPE2                    = 542 // { int pipe2(int *fildes, int flags); }
+	SYS_PROCCTL                  = 544 // { int procctl(idtype_t idtype, id_t id, \
 )
diff --git a/src/pkg/syscall/zsysnum_openbsd_386.go b/src/pkg/syscall/zsysnum_openbsd_386.go
index 82c98b9..3b9ac4c 100644
--- a/src/pkg/syscall/zsysnum_openbsd_386.go
+++ b/src/pkg/syscall/zsysnum_openbsd_386.go
@@ -10,10 +10,10 @@ const (
 	SYS_WRITE          = 4   // { ssize_t sys_write(int fd, const void *buf, \
 	SYS_OPEN           = 5   // { int sys_open(const char *path, \
 	SYS_CLOSE          = 6   // { int sys_close(int fd); }
-	SYS_WAIT4          = 7   // { pid_t sys_wait4(pid_t pid, int *status, int options, \
 	SYS___TFORK        = 8   // { int sys___tfork(const struct __tfork *param, \
 	SYS_LINK           = 9   // { int sys_link(const char *path, const char *link); }
 	SYS_UNLINK         = 10  // { int sys_unlink(const char *path); }
+	SYS_WAIT4          = 11  // { pid_t sys_wait4(pid_t pid, int *status, \
 	SYS_CHDIR          = 12  // { int sys_chdir(const char *path); }
 	SYS_FCHDIR         = 13  // { int sys_fchdir(int fd); }
 	SYS_MKNOD          = 14  // { int sys_mknod(const char *path, mode_t mode, \
@@ -21,6 +21,7 @@ const (
 	SYS_CHOWN          = 16  // { int sys_chown(const char *path, uid_t uid, \
 	SYS_OBREAK         = 17  // { int sys_obreak(char *nsize); } break
 	SYS_GETDTABLECOUNT = 18  // { int sys_getdtablecount(void); }
+	SYS_GETRUSAGE      = 19  // { int sys_getrusage(int who, \
 	SYS_GETPID         = 20  // { pid_t sys_getpid(void); }
 	SYS_MOUNT          = 21  // { int sys_mount(const char *type, const char *path, \
 	SYS_UNMOUNT        = 22  // { int sys_unmount(const char *path, int flags); }
@@ -39,8 +40,11 @@ const (
 	SYS_FCHFLAGS       = 35  // { int sys_fchflags(int fd, u_int flags); }
 	SYS_SYNC           = 36  // { void sys_sync(void); }
 	SYS_KILL           = 37  // { int sys_kill(int pid, int signum); }
+	SYS_STAT           = 38  // { int sys_stat(const char *path, struct stat *ub); }
 	SYS_GETPPID        = 39  // { pid_t sys_getppid(void); }
+	SYS_LSTAT          = 40  // { int sys_lstat(const char *path, struct stat *ub); }
 	SYS_DUP            = 41  // { int sys_dup(int fd); }
+	SYS_FSTATAT        = 42  // { int sys_fstatat(int fd, const char *path, \
 	SYS_GETEGID        = 43  // { gid_t sys_getegid(void); }
 	SYS_PROFIL         = 44  // { int sys_profil(caddr_t samples, size_t size, \
 	SYS_KTRACE         = 45  // { int sys_ktrace(const char *fname, int ops, \
@@ -51,6 +55,7 @@ const (
 	SYS_SETLOGIN       = 50  // { int sys_setlogin(const char *namebuf); }
 	SYS_ACCT           = 51  // { int sys_acct(const char *path); }
 	SYS_SIGPENDING     = 52  // { int sys_sigpending(void); }
+	SYS_FSTAT          = 53  // { int sys_fstat(int fd, struct stat *sb); }
 	SYS_IOCTL          = 54  // { int sys_ioctl(int fd, \
 	SYS_REBOOT         = 55  // { int sys_reboot(int opt); }
 	SYS_REVOKE         = 56  // { int sys_revoke(const char *path); }
@@ -59,36 +64,52 @@ const (
 	SYS_EXECVE         = 59  // { int sys_execve(const char *path, \
 	SYS_UMASK          = 60  // { mode_t sys_umask(mode_t newmask); }
 	SYS_CHROOT         = 61  // { int sys_chroot(const char *path); }
+	SYS_GETFSSTAT      = 62  // { int sys_getfsstat(struct statfs *buf, size_t bufsize, \
+	SYS_STATFS         = 63  // { int sys_statfs(const char *path, \
+	SYS_FSTATFS        = 64  // { int sys_fstatfs(int fd, struct statfs *buf); }
+	SYS_FHSTATFS       = 65  // { int sys_fhstatfs(const fhandle_t *fhp, \
 	SYS_VFORK          = 66  // { int sys_vfork(void); }
+	SYS_GETTIMEOFDAY   = 67  // { int sys_gettimeofday(struct timeval *tp, \
+	SYS_SETTIMEOFDAY   = 68  // { int sys_settimeofday(const struct timeval *tv, \
+	SYS_SETITIMER      = 69  // { int sys_setitimer(int which, \
+	SYS_GETITIMER      = 70  // { int sys_getitimer(int which, \
+	SYS_SELECT         = 71  // { int sys_select(int nd, fd_set *in, fd_set *ou, \
+	SYS_KEVENT         = 72  // { int sys_kevent(int fd, \
 	SYS_MUNMAP         = 73  // { int sys_munmap(void *addr, size_t len); }
 	SYS_MPROTECT       = 74  // { int sys_mprotect(void *addr, size_t len, \
 	SYS_MADVISE        = 75  // { int sys_madvise(void *addr, size_t len, \
+	SYS_UTIMES         = 76  // { int sys_utimes(const char *path, \
+	SYS_FUTIMES        = 77  // { int sys_futimes(int fd, \
 	SYS_MINCORE        = 78  // { int sys_mincore(void *addr, size_t len, \
 	SYS_GETGROUPS      = 79  // { int sys_getgroups(int gidsetsize, \
 	SYS_SETGROUPS      = 80  // { int sys_setgroups(int gidsetsize, \
 	SYS_GETPGRP        = 81  // { int sys_getpgrp(void); }
 	SYS_SETPGID        = 82  // { int sys_setpgid(pid_t pid, int pgid); }
-	SYS_SETITIMER      = 83  // { int sys_setitimer(int which, \
-	SYS_GETITIMER      = 86  // { int sys_getitimer(int which, \
+	SYS_UTIMENSAT      = 84  // { int sys_utimensat(int fd, const char *path, \
+	SYS_FUTIMENS       = 85  // { int sys_futimens(int fd, \
+	SYS_CLOCK_GETTIME  = 87  // { int sys_clock_gettime(clockid_t clock_id, \
+	SYS_CLOCK_SETTIME  = 88  // { int sys_clock_settime(clockid_t clock_id, \
+	SYS_CLOCK_GETRES   = 89  // { int sys_clock_getres(clockid_t clock_id, \
 	SYS_DUP2           = 90  // { int sys_dup2(int from, int to); }
+	SYS_NANOSLEEP      = 91  // { int sys_nanosleep(const struct timespec *rqtp, \
 	SYS_FCNTL          = 92  // { int sys_fcntl(int fd, int cmd, ... void *arg); }
-	SYS_SELECT         = 93  // { int sys_select(int nd, fd_set *in, fd_set *ou, \
+	SYS___THRSLEEP     = 94  // { int sys___thrsleep(const volatile void *ident, \
 	SYS_FSYNC          = 95  // { int sys_fsync(int fd); }
 	SYS_SETPRIORITY    = 96  // { int sys_setpriority(int which, id_t who, int prio); }
 	SYS_SOCKET         = 97  // { int sys_socket(int domain, int type, int protocol); }
 	SYS_CONNECT        = 98  // { int sys_connect(int s, const struct sockaddr *name, \
+	SYS_GETDENTS       = 99  // { int sys_getdents(int fd, void *buf, size_t buflen); }
 	SYS_GETPRIORITY    = 100 // { int sys_getpriority(int which, id_t who); }
 	SYS_SIGRETURN      = 103 // { int sys_sigreturn(struct sigcontext *sigcntxp); }
 	SYS_BIND           = 104 // { int sys_bind(int s, const struct sockaddr *name, \
 	SYS_SETSOCKOPT     = 105 // { int sys_setsockopt(int s, int level, int name, \
 	SYS_LISTEN         = 106 // { int sys_listen(int s, int backlog); }
+	SYS_PPOLL          = 109 // { int sys_ppoll(struct pollfd *fds, \
+	SYS_PSELECT        = 110 // { int sys_pselect(int nd, fd_set *in, fd_set *ou, \
 	SYS_SIGSUSPEND     = 111 // { int sys_sigsuspend(int mask); }
-	SYS_GETTIMEOFDAY   = 116 // { int sys_gettimeofday(struct timeval *tp, \
-	SYS_GETRUSAGE      = 117 // { int sys_getrusage(int who, struct rusage *rusage); }
 	SYS_GETSOCKOPT     = 118 // { int sys_getsockopt(int s, int level, int name, \
 	SYS_READV          = 120 // { ssize_t sys_readv(int fd, \
 	SYS_WRITEV         = 121 // { ssize_t sys_writev(int fd, \
-	SYS_SETTIMEOFDAY   = 122 // { int sys_settimeofday(const struct timeval *tv, \
 	SYS_FCHOWN         = 123 // { int sys_fchown(int fd, uid_t uid, gid_t gid); }
 	SYS_FCHMOD         = 124 // { int sys_fchmod(int fd, mode_t mode); }
 	SYS_SETREUID       = 126 // { int sys_setreuid(uid_t ruid, uid_t euid); }
@@ -101,7 +122,6 @@ const (
 	SYS_SOCKETPAIR     = 135 // { int sys_socketpair(int domain, int type, \
 	SYS_MKDIR          = 136 // { int sys_mkdir(const char *path, mode_t mode); }
 	SYS_RMDIR          = 137 // { int sys_rmdir(const char *path); }
-	SYS_UTIMES         = 138 // { int sys_utimes(const char *path, \
 	SYS_ADJTIME        = 140 // { int sys_adjtime(const struct timeval *delta, \
 	SYS_SETSID         = 147 // { int sys_setsid(void); }
 	SYS_QUOTACTL       = 148 // { int sys_quotactl(const char *path, int cmd, \
@@ -122,21 +142,17 @@ const (
 	SYS_LSEEK          = 199 // { off_t sys_lseek(int fd, int pad, off_t offset, \
 	SYS_TRUNCATE       = 200 // { int sys_truncate(const char *path, int pad, \
 	SYS_FTRUNCATE      = 201 // { int sys_ftruncate(int fd, int pad, off_t length); }
-	SYS___SYSCTL       = 202 // { int sys___sysctl(int *name, u_int namelen, \
+	SYS___SYSCTL       = 202 // { int sys___sysctl(const int *name, u_int namelen, \
 	SYS_MLOCK          = 203 // { int sys_mlock(const void *addr, size_t len); }
 	SYS_MUNLOCK        = 204 // { int sys_munlock(const void *addr, size_t len); }
-	SYS_FUTIMES        = 206 // { int sys_futimes(int fd, \
 	SYS_GETPGID        = 207 // { pid_t sys_getpgid(pid_t pid); }
+	SYS_UTRACE         = 209 // { int sys_utrace(const char *label, const void *addr, \
 	SYS_SEMGET         = 221 // { int sys_semget(key_t key, int nsems, int semflg); }
 	SYS_MSGGET         = 225 // { int sys_msgget(key_t key, int msgflg); }
 	SYS_MSGSND         = 226 // { int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, \
 	SYS_MSGRCV         = 227 // { int sys_msgrcv(int msqid, void *msgp, size_t msgsz, \
 	SYS_SHMAT          = 228 // { void *sys_shmat(int shmid, const void *shmaddr, \
 	SYS_SHMDT          = 230 // { int sys_shmdt(const void *shmaddr); }
-	SYS_CLOCK_GETTIME  = 232 // { int sys_clock_gettime(clockid_t clock_id, \
-	SYS_CLOCK_SETTIME  = 233 // { int sys_clock_settime(clockid_t clock_id, \
-	SYS_CLOCK_GETRES   = 234 // { int sys_clock_getres(clockid_t clock_id, \
-	SYS_NANOSLEEP      = 240 // { int sys_nanosleep(const struct timespec *rqtp, \
 	SYS_MINHERIT       = 250 // { int sys_minherit(void *addr, size_t len, \
 	SYS_POLL           = 252 // { int sys_poll(struct pollfd *fds, \
 	SYS_ISSETUGID      = 253 // { int sys_issetugid(void); }
@@ -148,7 +164,6 @@ const (
 	SYS_PREADV         = 267 // { ssize_t sys_preadv(int fd, \
 	SYS_PWRITEV        = 268 // { ssize_t sys_pwritev(int fd, \
 	SYS_KQUEUE         = 269 // { int sys_kqueue(void); }
-	SYS_KEVENT         = 270 // { int sys_kevent(int fd, \
 	SYS_MLOCKALL       = 271 // { int sys_mlockall(int flags); }
 	SYS_MUNLOCKALL     = 272 // { int sys_munlockall(void); }
 	SYS_GETRESUID      = 281 // { int sys_getresuid(uid_t *ruid, uid_t *euid, \
@@ -160,32 +175,22 @@ const (
 	SYS_SIGALTSTACK    = 288 // { int sys_sigaltstack(const struct sigaltstack *nss, \
 	SYS_SHMGET         = 289 // { int sys_shmget(key_t key, size_t size, int shmflg); }
 	SYS_SEMOP          = 290 // { int sys_semop(int semid, struct sembuf *sops, \
-	SYS_STAT           = 291 // { int sys_stat(const char *path, struct stat *ub); }
-	SYS_FSTAT          = 292 // { int sys_fstat(int fd, struct stat *sb); }
-	SYS_LSTAT          = 293 // { int sys_lstat(const char *path, struct stat *ub); }
 	SYS_FHSTAT         = 294 // { int sys_fhstat(const fhandle_t *fhp, \
 	SYS___SEMCTL       = 295 // { int sys___semctl(int semid, int semnum, int cmd, \
 	SYS_SHMCTL         = 296 // { int sys_shmctl(int shmid, int cmd, \
 	SYS_MSGCTL         = 297 // { int sys_msgctl(int msqid, int cmd, \
 	SYS_SCHED_YIELD    = 298 // { int sys_sched_yield(void); }
 	SYS_GETTHRID       = 299 // { pid_t sys_getthrid(void); }
-	SYS___THRSLEEP     = 300 // { int sys___thrsleep(const volatile void *ident, \
 	SYS___THRWAKEUP    = 301 // { int sys___thrwakeup(const volatile void *ident, \
 	SYS___THREXIT      = 302 // { void sys___threxit(pid_t *notdead); }
 	SYS___THRSIGDIVERT = 303 // { int sys___thrsigdivert(sigset_t sigmask, \
 	SYS___GETCWD       = 304 // { int sys___getcwd(char *buf, size_t len); }
 	SYS_ADJFREQ        = 305 // { int sys_adjfreq(const int64_t *freq, \
-	SYS_GETFSSTAT      = 306 // { int sys_getfsstat(struct statfs *buf, size_t bufsize, \
-	SYS_STATFS         = 307 // { int sys_statfs(const char *path, \
-	SYS_FSTATFS        = 308 // { int sys_fstatfs(int fd, struct statfs *buf); }
-	SYS_FHSTATFS       = 309 // { int sys_fhstatfs(const fhandle_t *fhp, \
 	SYS_SETRTABLE      = 310 // { int sys_setrtable(int rtableid); }
 	SYS_GETRTABLE      = 311 // { int sys_getrtable(void); }
-	SYS_GETDIRENTRIES  = 312 // { int sys_getdirentries(int fd, char *buf, \
 	SYS_FACCESSAT      = 313 // { int sys_faccessat(int fd, const char *path, \
 	SYS_FCHMODAT       = 314 // { int sys_fchmodat(int fd, const char *path, \
 	SYS_FCHOWNAT       = 315 // { int sys_fchownat(int fd, const char *path, \
-	SYS_FSTATAT        = 316 // { int sys_fstatat(int fd, const char *path, \
 	SYS_LINKAT         = 317 // { int sys_linkat(int fd1, const char *path1, int fd2, \
 	SYS_MKDIRAT        = 318 // { int sys_mkdirat(int fd, const char *path, \
 	SYS_MKFIFOAT       = 319 // { int sys_mkfifoat(int fd, const char *path, \
@@ -195,8 +200,6 @@ const (
 	SYS_RENAMEAT       = 323 // { int sys_renameat(int fromfd, const char *from, \
 	SYS_SYMLINKAT      = 324 // { int sys_symlinkat(const char *path, int fd, \
 	SYS_UNLINKAT       = 325 // { int sys_unlinkat(int fd, const char *path, \
-	SYS_UTIMENSAT      = 326 // { int sys_utimensat(int fd, const char *path, \
-	SYS_FUTIMENS       = 327 // { int sys_futimens(int fd, \
 	SYS___SET_TCB      = 329 // { void sys___set_tcb(void *tcb); }
 	SYS___GET_TCB      = 330 // { void *sys___get_tcb(void); }
 )
diff --git a/src/pkg/syscall/zsysnum_openbsd_amd64.go b/src/pkg/syscall/zsysnum_openbsd_amd64.go
index 82c98b9..3b9ac4c 100644
--- a/src/pkg/syscall/zsysnum_openbsd_amd64.go
+++ b/src/pkg/syscall/zsysnum_openbsd_amd64.go
@@ -10,10 +10,10 @@ const (
 	SYS_WRITE          = 4   // { ssize_t sys_write(int fd, const void *buf, \
 	SYS_OPEN           = 5   // { int sys_open(const char *path, \
 	SYS_CLOSE          = 6   // { int sys_close(int fd); }
-	SYS_WAIT4          = 7   // { pid_t sys_wait4(pid_t pid, int *status, int options, \
 	SYS___TFORK        = 8   // { int sys___tfork(const struct __tfork *param, \
 	SYS_LINK           = 9   // { int sys_link(const char *path, const char *link); }
 	SYS_UNLINK         = 10  // { int sys_unlink(const char *path); }
+	SYS_WAIT4          = 11  // { pid_t sys_wait4(pid_t pid, int *status, \
 	SYS_CHDIR          = 12  // { int sys_chdir(const char *path); }
 	SYS_FCHDIR         = 13  // { int sys_fchdir(int fd); }
 	SYS_MKNOD          = 14  // { int sys_mknod(const char *path, mode_t mode, \
@@ -21,6 +21,7 @@ const (
 	SYS_CHOWN          = 16  // { int sys_chown(const char *path, uid_t uid, \
 	SYS_OBREAK         = 17  // { int sys_obreak(char *nsize); } break
 	SYS_GETDTABLECOUNT = 18  // { int sys_getdtablecount(void); }
+	SYS_GETRUSAGE      = 19  // { int sys_getrusage(int who, \
 	SYS_GETPID         = 20  // { pid_t sys_getpid(void); }
 	SYS_MOUNT          = 21  // { int sys_mount(const char *type, const char *path, \
 	SYS_UNMOUNT        = 22  // { int sys_unmount(const char *path, int flags); }
@@ -39,8 +40,11 @@ const (
 	SYS_FCHFLAGS       = 35  // { int sys_fchflags(int fd, u_int flags); }
 	SYS_SYNC           = 36  // { void sys_sync(void); }
 	SYS_KILL           = 37  // { int sys_kill(int pid, int signum); }
+	SYS_STAT           = 38  // { int sys_stat(const char *path, struct stat *ub); }
 	SYS_GETPPID        = 39  // { pid_t sys_getppid(void); }
+	SYS_LSTAT          = 40  // { int sys_lstat(const char *path, struct stat *ub); }
 	SYS_DUP            = 41  // { int sys_dup(int fd); }
+	SYS_FSTATAT        = 42  // { int sys_fstatat(int fd, const char *path, \
 	SYS_GETEGID        = 43  // { gid_t sys_getegid(void); }
 	SYS_PROFIL         = 44  // { int sys_profil(caddr_t samples, size_t size, \
 	SYS_KTRACE         = 45  // { int sys_ktrace(const char *fname, int ops, \
@@ -51,6 +55,7 @@ const (
 	SYS_SETLOGIN       = 50  // { int sys_setlogin(const char *namebuf); }
 	SYS_ACCT           = 51  // { int sys_acct(const char *path); }
 	SYS_SIGPENDING     = 52  // { int sys_sigpending(void); }
+	SYS_FSTAT          = 53  // { int sys_fstat(int fd, struct stat *sb); }
 	SYS_IOCTL          = 54  // { int sys_ioctl(int fd, \
 	SYS_REBOOT         = 55  // { int sys_reboot(int opt); }
 	SYS_REVOKE         = 56  // { int sys_revoke(const char *path); }
@@ -59,36 +64,52 @@ const (
 	SYS_EXECVE         = 59  // { int sys_execve(const char *path, \
 	SYS_UMASK          = 60  // { mode_t sys_umask(mode_t newmask); }
 	SYS_CHROOT         = 61  // { int sys_chroot(const char *path); }
+	SYS_GETFSSTAT      = 62  // { int sys_getfsstat(struct statfs *buf, size_t bufsize, \
+	SYS_STATFS         = 63  // { int sys_statfs(const char *path, \
+	SYS_FSTATFS        = 64  // { int sys_fstatfs(int fd, struct statfs *buf); }
+	SYS_FHSTATFS       = 65  // { int sys_fhstatfs(const fhandle_t *fhp, \
 	SYS_VFORK          = 66  // { int sys_vfork(void); }
+	SYS_GETTIMEOFDAY   = 67  // { int sys_gettimeofday(struct timeval *tp, \
+	SYS_SETTIMEOFDAY   = 68  // { int sys_settimeofday(const struct timeval *tv, \
+	SYS_SETITIMER      = 69  // { int sys_setitimer(int which, \
+	SYS_GETITIMER      = 70  // { int sys_getitimer(int which, \
+	SYS_SELECT         = 71  // { int sys_select(int nd, fd_set *in, fd_set *ou, \
+	SYS_KEVENT         = 72  // { int sys_kevent(int fd, \
 	SYS_MUNMAP         = 73  // { int sys_munmap(void *addr, size_t len); }
 	SYS_MPROTECT       = 74  // { int sys_mprotect(void *addr, size_t len, \
 	SYS_MADVISE        = 75  // { int sys_madvise(void *addr, size_t len, \
+	SYS_UTIMES         = 76  // { int sys_utimes(const char *path, \
+	SYS_FUTIMES        = 77  // { int sys_futimes(int fd, \
 	SYS_MINCORE        = 78  // { int sys_mincore(void *addr, size_t len, \
 	SYS_GETGROUPS      = 79  // { int sys_getgroups(int gidsetsize, \
 	SYS_SETGROUPS      = 80  // { int sys_setgroups(int gidsetsize, \
 	SYS_GETPGRP        = 81  // { int sys_getpgrp(void); }
 	SYS_SETPGID        = 82  // { int sys_setpgid(pid_t pid, int pgid); }
-	SYS_SETITIMER      = 83  // { int sys_setitimer(int which, \
-	SYS_GETITIMER      = 86  // { int sys_getitimer(int which, \
+	SYS_UTIMENSAT      = 84  // { int sys_utimensat(int fd, const char *path, \
+	SYS_FUTIMENS       = 85  // { int sys_futimens(int fd, \
+	SYS_CLOCK_GETTIME  = 87  // { int sys_clock_gettime(clockid_t clock_id, \
+	SYS_CLOCK_SETTIME  = 88  // { int sys_clock_settime(clockid_t clock_id, \
+	SYS_CLOCK_GETRES   = 89  // { int sys_clock_getres(clockid_t clock_id, \
 	SYS_DUP2           = 90  // { int sys_dup2(int from, int to); }
+	SYS_NANOSLEEP      = 91  // { int sys_nanosleep(const struct timespec *rqtp, \
 	SYS_FCNTL          = 92  // { int sys_fcntl(int fd, int cmd, ... void *arg); }
-	SYS_SELECT         = 93  // { int sys_select(int nd, fd_set *in, fd_set *ou, \
+	SYS___THRSLEEP     = 94  // { int sys___thrsleep(const volatile void *ident, \
 	SYS_FSYNC          = 95  // { int sys_fsync(int fd); }
 	SYS_SETPRIORITY    = 96  // { int sys_setpriority(int which, id_t who, int prio); }
 	SYS_SOCKET         = 97  // { int sys_socket(int domain, int type, int protocol); }
 	SYS_CONNECT        = 98  // { int sys_connect(int s, const struct sockaddr *name, \
+	SYS_GETDENTS       = 99  // { int sys_getdents(int fd, void *buf, size_t buflen); }
 	SYS_GETPRIORITY    = 100 // { int sys_getpriority(int which, id_t who); }
 	SYS_SIGRETURN      = 103 // { int sys_sigreturn(struct sigcontext *sigcntxp); }
 	SYS_BIND           = 104 // { int sys_bind(int s, const struct sockaddr *name, \
 	SYS_SETSOCKOPT     = 105 // { int sys_setsockopt(int s, int level, int name, \
 	SYS_LISTEN         = 106 // { int sys_listen(int s, int backlog); }
+	SYS_PPOLL          = 109 // { int sys_ppoll(struct pollfd *fds, \
+	SYS_PSELECT        = 110 // { int sys_pselect(int nd, fd_set *in, fd_set *ou, \
 	SYS_SIGSUSPEND     = 111 // { int sys_sigsuspend(int mask); }
-	SYS_GETTIMEOFDAY   = 116 // { int sys_gettimeofday(struct timeval *tp, \
-	SYS_GETRUSAGE      = 117 // { int sys_getrusage(int who, struct rusage *rusage); }
 	SYS_GETSOCKOPT     = 118 // { int sys_getsockopt(int s, int level, int name, \
 	SYS_READV          = 120 // { ssize_t sys_readv(int fd, \
 	SYS_WRITEV         = 121 // { ssize_t sys_writev(int fd, \
-	SYS_SETTIMEOFDAY   = 122 // { int sys_settimeofday(const struct timeval *tv, \
 	SYS_FCHOWN         = 123 // { int sys_fchown(int fd, uid_t uid, gid_t gid); }
 	SYS_FCHMOD         = 124 // { int sys_fchmod(int fd, mode_t mode); }
 	SYS_SETREUID       = 126 // { int sys_setreuid(uid_t ruid, uid_t euid); }
@@ -101,7 +122,6 @@ const (
 	SYS_SOCKETPAIR     = 135 // { int sys_socketpair(int domain, int type, \
 	SYS_MKDIR          = 136 // { int sys_mkdir(const char *path, mode_t mode); }
 	SYS_RMDIR          = 137 // { int sys_rmdir(const char *path); }
-	SYS_UTIMES         = 138 // { int sys_utimes(const char *path, \
 	SYS_ADJTIME        = 140 // { int sys_adjtime(const struct timeval *delta, \
 	SYS_SETSID         = 147 // { int sys_setsid(void); }
 	SYS_QUOTACTL       = 148 // { int sys_quotactl(const char *path, int cmd, \
@@ -122,21 +142,17 @@ const (
 	SYS_LSEEK          = 199 // { off_t sys_lseek(int fd, int pad, off_t offset, \
 	SYS_TRUNCATE       = 200 // { int sys_truncate(const char *path, int pad, \
 	SYS_FTRUNCATE      = 201 // { int sys_ftruncate(int fd, int pad, off_t length); }
-	SYS___SYSCTL       = 202 // { int sys___sysctl(int *name, u_int namelen, \
+	SYS___SYSCTL       = 202 // { int sys___sysctl(const int *name, u_int namelen, \
 	SYS_MLOCK          = 203 // { int sys_mlock(const void *addr, size_t len); }
 	SYS_MUNLOCK        = 204 // { int sys_munlock(const void *addr, size_t len); }
-	SYS_FUTIMES        = 206 // { int sys_futimes(int fd, \
 	SYS_GETPGID        = 207 // { pid_t sys_getpgid(pid_t pid); }
+	SYS_UTRACE         = 209 // { int sys_utrace(const char *label, const void *addr, \
 	SYS_SEMGET         = 221 // { int sys_semget(key_t key, int nsems, int semflg); }
 	SYS_MSGGET         = 225 // { int sys_msgget(key_t key, int msgflg); }
 	SYS_MSGSND         = 226 // { int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, \
 	SYS_MSGRCV         = 227 // { int sys_msgrcv(int msqid, void *msgp, size_t msgsz, \
 	SYS_SHMAT          = 228 // { void *sys_shmat(int shmid, const void *shmaddr, \
 	SYS_SHMDT          = 230 // { int sys_shmdt(const void *shmaddr); }
-	SYS_CLOCK_GETTIME  = 232 // { int sys_clock_gettime(clockid_t clock_id, \
-	SYS_CLOCK_SETTIME  = 233 // { int sys_clock_settime(clockid_t clock_id, \
-	SYS_CLOCK_GETRES   = 234 // { int sys_clock_getres(clockid_t clock_id, \
-	SYS_NANOSLEEP      = 240 // { int sys_nanosleep(const struct timespec *rqtp, \
 	SYS_MINHERIT       = 250 // { int sys_minherit(void *addr, size_t len, \
 	SYS_POLL           = 252 // { int sys_poll(struct pollfd *fds, \
 	SYS_ISSETUGID      = 253 // { int sys_issetugid(void); }
@@ -148,7 +164,6 @@ const (
 	SYS_PREADV         = 267 // { ssize_t sys_preadv(int fd, \
 	SYS_PWRITEV        = 268 // { ssize_t sys_pwritev(int fd, \
 	SYS_KQUEUE         = 269 // { int sys_kqueue(void); }
-	SYS_KEVENT         = 270 // { int sys_kevent(int fd, \
 	SYS_MLOCKALL       = 271 // { int sys_mlockall(int flags); }
 	SYS_MUNLOCKALL     = 272 // { int sys_munlockall(void); }
 	SYS_GETRESUID      = 281 // { int sys_getresuid(uid_t *ruid, uid_t *euid, \
@@ -160,32 +175,22 @@ const (
 	SYS_SIGALTSTACK    = 288 // { int sys_sigaltstack(const struct sigaltstack *nss, \
 	SYS_SHMGET         = 289 // { int sys_shmget(key_t key, size_t size, int shmflg); }
 	SYS_SEMOP          = 290 // { int sys_semop(int semid, struct sembuf *sops, \
-	SYS_STAT           = 291 // { int sys_stat(const char *path, struct stat *ub); }
-	SYS_FSTAT          = 292 // { int sys_fstat(int fd, struct stat *sb); }
-	SYS_LSTAT          = 293 // { int sys_lstat(const char *path, struct stat *ub); }
 	SYS_FHSTAT         = 294 // { int sys_fhstat(const fhandle_t *fhp, \
 	SYS___SEMCTL       = 295 // { int sys___semctl(int semid, int semnum, int cmd, \
 	SYS_SHMCTL         = 296 // { int sys_shmctl(int shmid, int cmd, \
 	SYS_MSGCTL         = 297 // { int sys_msgctl(int msqid, int cmd, \
 	SYS_SCHED_YIELD    = 298 // { int sys_sched_yield(void); }
 	SYS_GETTHRID       = 299 // { pid_t sys_getthrid(void); }
-	SYS___THRSLEEP     = 300 // { int sys___thrsleep(const volatile void *ident, \
 	SYS___THRWAKEUP    = 301 // { int sys___thrwakeup(const volatile void *ident, \
 	SYS___THREXIT      = 302 // { void sys___threxit(pid_t *notdead); }
 	SYS___THRSIGDIVERT = 303 // { int sys___thrsigdivert(sigset_t sigmask, \
 	SYS___GETCWD       = 304 // { int sys___getcwd(char *buf, size_t len); }
 	SYS_ADJFREQ        = 305 // { int sys_adjfreq(const int64_t *freq, \
-	SYS_GETFSSTAT      = 306 // { int sys_getfsstat(struct statfs *buf, size_t bufsize, \
-	SYS_STATFS         = 307 // { int sys_statfs(const char *path, \
-	SYS_FSTATFS        = 308 // { int sys_fstatfs(int fd, struct statfs *buf); }
-	SYS_FHSTATFS       = 309 // { int sys_fhstatfs(const fhandle_t *fhp, \
 	SYS_SETRTABLE      = 310 // { int sys_setrtable(int rtableid); }
 	SYS_GETRTABLE      = 311 // { int sys_getrtable(void); }
-	SYS_GETDIRENTRIES  = 312 // { int sys_getdirentries(int fd, char *buf, \
 	SYS_FACCESSAT      = 313 // { int sys_faccessat(int fd, const char *path, \
 	SYS_FCHMODAT       = 314 // { int sys_fchmodat(int fd, const char *path, \
 	SYS_FCHOWNAT       = 315 // { int sys_fchownat(int fd, const char *path, \
-	SYS_FSTATAT        = 316 // { int sys_fstatat(int fd, const char *path, \
 	SYS_LINKAT         = 317 // { int sys_linkat(int fd1, const char *path1, int fd2, \
 	SYS_MKDIRAT        = 318 // { int sys_mkdirat(int fd, const char *path, \
 	SYS_MKFIFOAT       = 319 // { int sys_mkfifoat(int fd, const char *path, \
@@ -195,8 +200,6 @@ const (
 	SYS_RENAMEAT       = 323 // { int sys_renameat(int fromfd, const char *from, \
 	SYS_SYMLINKAT      = 324 // { int sys_symlinkat(const char *path, int fd, \
 	SYS_UNLINKAT       = 325 // { int sys_unlinkat(int fd, const char *path, \
-	SYS_UTIMENSAT      = 326 // { int sys_utimensat(int fd, const char *path, \
-	SYS_FUTIMENS       = 327 // { int sys_futimens(int fd, \
 	SYS___SET_TCB      = 329 // { void sys___set_tcb(void *tcb); }
 	SYS___GET_TCB      = 330 // { void *sys___get_tcb(void); }
 )
diff --git a/src/pkg/syscall/zsysnum_solaris_amd64.go b/src/pkg/syscall/zsysnum_solaris_amd64.go
new file mode 100644
index 0000000..43b3d8b
--- /dev/null
+++ b/src/pkg/syscall/zsysnum_solaris_amd64.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.
+
+package syscall
+
+// TODO(aram): remove these before Go 1.3.
+const (
+	SYS_EXECVE = 59
+	SYS_FCNTL  = 62
+)
diff --git a/src/pkg/syscall/ztypes_dragonfly_386.go b/src/pkg/syscall/ztypes_dragonfly_386.go
index c467d85..6b6ec15 100644
--- a/src/pkg/syscall/ztypes_dragonfly_386.go
+++ b/src/pkg/syscall/ztypes_dragonfly_386.go
@@ -55,10 +55,6 @@ type Rlimit struct {
 type _Gid_t uint32
 
 const (
-	F_DUPFD_CLOEXEC = 0
-)
-
-const (
 	S_IFMT   = 0xf000
 	S_IFIFO  = 0x1000
 	S_IFCHR  = 0x2000
@@ -427,3 +423,13 @@ type BpfHdr struct {
 	Hdrlen    uint16
 	Pad_cgo_0 [2]byte
 }
+
+type Termios struct {
+	Iflag  uint32
+	Oflag  uint32
+	Cflag  uint32
+	Lflag  uint32
+	Cc     [20]uint8
+	Ispeed uint32
+	Ospeed uint32
+}
diff --git a/src/pkg/syscall/ztypes_dragonfly_amd64.go b/src/pkg/syscall/ztypes_dragonfly_amd64.go
index b71bf29..954ffd7 100644
--- a/src/pkg/syscall/ztypes_dragonfly_amd64.go
+++ b/src/pkg/syscall/ztypes_dragonfly_amd64.go
@@ -55,10 +55,6 @@ type Rlimit struct {
 type _Gid_t uint32
 
 const (
-	F_DUPFD_CLOEXEC = 0
-)
-
-const (
 	S_IFMT   = 0xf000
 	S_IFIFO  = 0x1000
 	S_IFCHR  = 0x2000
@@ -433,3 +429,13 @@ type BpfHdr struct {
 	Hdrlen    uint16
 	Pad_cgo_0 [6]byte
 }
+
+type Termios struct {
+	Iflag  uint32
+	Oflag  uint32
+	Cflag  uint32
+	Lflag  uint32
+	Cc     [20]uint8
+	Ispeed uint32
+	Ospeed uint32
+}
diff --git a/src/pkg/syscall/ztypes_freebsd_386.go b/src/pkg/syscall/ztypes_freebsd_386.go
index e77bd4b..b809eea 100644
--- a/src/pkg/syscall/ztypes_freebsd_386.go
+++ b/src/pkg/syscall/ztypes_freebsd_386.go
@@ -55,10 +55,6 @@ type Rlimit struct {
 type _Gid_t uint32
 
 const (
-	O_CLOEXEC = 0
-)
-
-const (
 	S_IFMT   = 0xf000
 	S_IFIFO  = 0x1000
 	S_IFCHR  = 0x2000
@@ -282,7 +278,9 @@ type FdSet struct {
 }
 
 const (
+	sizeofIfMsghdr         = 0x64
 	SizeofIfMsghdr         = 0x60
+	sizeofIfData           = 0x54
 	SizeofIfData           = 0x50
 	SizeofIfaMsghdr        = 0x14
 	SizeofIfmaMsghdr       = 0x10
@@ -291,6 +289,17 @@ const (
 	SizeofRtMetrics        = 0x38
 )
 
+type ifMsghdr struct {
+	Msglen    uint16
+	Version   uint8
+	Type      uint8
+	Addrs     int32
+	Flags     int32
+	Index     uint16
+	Pad_cgo_0 [2]byte
+	Data      ifData
+}
+
 type IfMsghdr struct {
 	Msglen    uint16
 	Version   uint8
@@ -302,6 +311,34 @@ type IfMsghdr struct {
 	Data      IfData
 }
 
+type ifData struct {
+	Type        uint8
+	Physical    uint8
+	Addrlen     uint8
+	Hdrlen      uint8
+	Link_state  uint8
+	Vhid        uint8
+	Baudrate_pf uint8
+	Datalen     uint8
+	Mtu         uint32
+	Metric      uint32
+	Baudrate    uint32
+	Ipackets    uint32
+	Ierrors     uint32
+	Opackets    uint32
+	Oerrors     uint32
+	Collisions  uint32
+	Ibytes      uint32
+	Obytes      uint32
+	Imcasts     uint32
+	Omcasts     uint32
+	Iqdrops     uint32
+	Noproto     uint32
+	Hwassist    uint64
+	Epoch       int32
+	Lastchange  Timeval
+}
+
 type IfData struct {
 	Type        uint8
 	Physical    uint8
@@ -443,3 +480,13 @@ type BpfZbufHeader struct {
 	User_gen   uint32
 	X_bzh_pad  [5]uint32
 }
+
+type Termios struct {
+	Iflag  uint32
+	Oflag  uint32
+	Cflag  uint32
+	Lflag  uint32
+	Cc     [20]uint8
+	Ispeed uint32
+	Ospeed uint32
+}
diff --git a/src/pkg/syscall/ztypes_freebsd_amd64.go b/src/pkg/syscall/ztypes_freebsd_amd64.go
index 922de2c..a05908a 100644
--- a/src/pkg/syscall/ztypes_freebsd_amd64.go
+++ b/src/pkg/syscall/ztypes_freebsd_amd64.go
@@ -55,10 +55,6 @@ type Rlimit struct {
 type _Gid_t uint32
 
 const (
-	O_CLOEXEC = 0
-)
-
-const (
 	S_IFMT   = 0xf000
 	S_IFIFO  = 0x1000
 	S_IFCHR  = 0x2000
@@ -284,7 +280,9 @@ type FdSet struct {
 }
 
 const (
+	sizeofIfMsghdr         = 0xa8
 	SizeofIfMsghdr         = 0xa8
+	sizeofIfData           = 0x98
 	SizeofIfData           = 0x98
 	SizeofIfaMsghdr        = 0x14
 	SizeofIfmaMsghdr       = 0x10
@@ -293,6 +291,17 @@ const (
 	SizeofRtMetrics        = 0x70
 )
 
+type ifMsghdr struct {
+	Msglen    uint16
+	Version   uint8
+	Type      uint8
+	Addrs     int32
+	Flags     int32
+	Index     uint16
+	Pad_cgo_0 [2]byte
+	Data      ifData
+}
+
 type IfMsghdr struct {
 	Msglen    uint16
 	Version   uint8
@@ -304,6 +313,34 @@ type IfMsghdr struct {
 	Data      IfData
 }
 
+type ifData struct {
+	Type        uint8
+	Physical    uint8
+	Addrlen     uint8
+	Hdrlen      uint8
+	Link_state  uint8
+	Vhid        uint8
+	Baudrate_pf uint8
+	Datalen     uint8
+	Mtu         uint64
+	Metric      uint64
+	Baudrate    uint64
+	Ipackets    uint64
+	Ierrors     uint64
+	Opackets    uint64
+	Oerrors     uint64
+	Collisions  uint64
+	Ibytes      uint64
+	Obytes      uint64
+	Imcasts     uint64
+	Omcasts     uint64
+	Iqdrops     uint64
+	Noproto     uint64
+	Hwassist    uint64
+	Epoch       int64
+	Lastchange  Timeval
+}
+
 type IfData struct {
 	Type        uint8
 	Physical    uint8
@@ -446,3 +483,13 @@ type BpfZbufHeader struct {
 	User_gen   uint32
 	X_bzh_pad  [5]uint32
 }
+
+type Termios struct {
+	Iflag  uint32
+	Oflag  uint32
+	Cflag  uint32
+	Lflag  uint32
+	Cc     [20]uint8
+	Ispeed uint32
+	Ospeed uint32
+}
diff --git a/src/pkg/syscall/ztypes_freebsd_arm.go b/src/pkg/syscall/ztypes_freebsd_arm.go
index b1bf83b..9303816 100644
--- a/src/pkg/syscall/ztypes_freebsd_arm.go
+++ b/src/pkg/syscall/ztypes_freebsd_arm.go
@@ -1,5 +1,5 @@
 // Created by cgo -godefs - DO NOT EDIT
-// cgo -godefs types_freebsd.go
+// cgo -godefs -- -fsigned-char types_freebsd.go
 
 package syscall
 
@@ -19,13 +19,15 @@ type (
 )
 
 type Timespec struct {
-	Sec  int64
-	Nsec int32
+	Sec       int64
+	Nsec      int32
+	Pad_cgo_0 [4]byte
 }
 
 type Timeval struct {
-	Sec  int64
-	Usec int32
+	Sec       int64
+	Usec      int32
+	Pad_cgo_0 [4]byte
 }
 
 type Rusage struct {
@@ -55,10 +57,6 @@ type Rlimit struct {
 type _Gid_t uint32
 
 const (
-	O_CLOEXEC = 0 // not supported
-)
-
-const (
 	S_IFMT   = 0xf000
 	S_IFIFO  = 0x1000
 	S_IFCHR  = 0x2000
@@ -93,7 +91,6 @@ type Stat_t struct {
 	Gen           uint32
 	Lspare        int32
 	Birthtimespec Timespec
-	Pad_cgo_0     [4]byte
 }
 
 type Statfs_t struct {
@@ -122,12 +119,13 @@ type Statfs_t struct {
 }
 
 type Flock_t struct {
-	Start  int64
-	Len    int64
-	Pid    int32
-	Type   int16
-	Whence int16
-	Sysid  int32
+	Start     int64
+	Len       int64
+	Pid       int32
+	Type      int16
+	Whence    int16
+	Sysid     int32
+	Pad_cgo_0 [4]byte
 }
 
 type Dirent struct {
@@ -160,22 +158,20 @@ type RawSockaddrInet6 struct {
 }
 
 type RawSockaddrUnix struct {
-	Len       uint8
-	Family    uint8
-	Path      [104]int8
-	Pad_cgo_0 [2]byte
+	Len    uint8
+	Family uint8
+	Path   [104]int8
 }
 
 type RawSockaddrDatalink struct {
-	Len       uint8
-	Family    uint8
-	Index     uint16
-	Type      uint8
-	Nlen      uint8
-	Alen      uint8
-	Slen      uint8
-	Data      [46]int8
-	Pad_cgo_0 [2]byte
+	Len    uint8
+	Family uint8
+	Index  uint16
+	Type   uint8
+	Nlen   uint8
+	Alen   uint8
+	Slen   uint8
+	Data   [46]int8
 }
 
 type RawSockaddr struct {
@@ -251,8 +247,8 @@ const (
 	SizeofSockaddrInet4    = 0x10
 	SizeofSockaddrInet6    = 0x1c
 	SizeofSockaddrAny      = 0x6c
-	SizeofSockaddrUnix     = 0x6c
-	SizeofSockaddrDatalink = 0x38
+	SizeofSockaddrUnix     = 0x6a
+	SizeofSockaddrDatalink = 0x36
 	SizeofLinger           = 0x8
 	SizeofIPMreq           = 0x8
 	SizeofIPMreqn          = 0xc
@@ -284,8 +280,10 @@ type FdSet struct {
 }
 
 const (
-	SizeofIfMsghdr         = 0x68
-	SizeofIfData           = 0x58
+	sizeofIfMsghdr         = 0x70
+	SizeofIfMsghdr         = 0x70
+	sizeofIfData           = 0x60
+	SizeofIfData           = 0x60
 	SizeofIfaMsghdr        = 0x14
 	SizeofIfmaMsghdr       = 0x10
 	SizeofIfAnnounceMsghdr = 0x18
@@ -293,6 +291,17 @@ const (
 	SizeofRtMetrics        = 0x38
 )
 
+type ifMsghdr struct {
+	Msglen    uint16
+	Version   uint8
+	Type      uint8
+	Addrs     int32
+	Flags     int32
+	Index     uint16
+	Pad_cgo_0 [2]byte
+	Data      ifData
+}
+
 type IfMsghdr struct {
 	Msglen    uint16
 	Version   uint8
@@ -304,13 +313,41 @@ type IfMsghdr struct {
 	Data      IfData
 }
 
+type ifData struct {
+	Type        uint8
+	Physical    uint8
+	Addrlen     uint8
+	Hdrlen      uint8
+	Link_state  uint8
+	Vhid        uint8
+	Baudrate_pf uint8
+	Datalen     uint8
+	Mtu         uint32
+	Metric      uint32
+	Baudrate    uint32
+	Ipackets    uint32
+	Ierrors     uint32
+	Opackets    uint32
+	Oerrors     uint32
+	Collisions  uint32
+	Ibytes      uint32
+	Obytes      uint32
+	Imcasts     uint32
+	Omcasts     uint32
+	Iqdrops     uint32
+	Noproto     uint32
+	Hwassist    uint64
+	Epoch       int64
+	Lastchange  Timeval
+}
+
 type IfData struct {
 	Type        uint8
 	Physical    uint8
 	Addrlen     uint8
 	Hdrlen      uint8
 	Link_state  uint8
-	Spare_char1 uint8 //Vhid        uint8
+	Spare_char1 uint8
 	Spare_char2 uint8
 	Datalen     uint8
 	Mtu         uint32
@@ -328,6 +365,7 @@ type IfData struct {
 	Iqdrops     uint32
 	Noproto     uint32
 	Hwassist    uint32
+	Pad_cgo_0   [4]byte
 	Epoch       int64
 	Lastchange  Timeval
 }
@@ -399,7 +437,7 @@ const (
 	SizeofBpfZbuf       = 0xc
 	SizeofBpfProgram    = 0x8
 	SizeofBpfInsn       = 0x8
-	SizeofBpfHdr        = 0x18
+	SizeofBpfHdr        = 0x20
 	SizeofBpfZbufHeader = 0x20
 )
 
@@ -436,7 +474,7 @@ type BpfHdr struct {
 	Caplen    uint32
 	Datalen   uint32
 	Hdrlen    uint16
-	Pad_cgo_0 [2]byte
+	Pad_cgo_0 [6]byte
 }
 
 type BpfZbufHeader struct {
@@ -445,3 +483,13 @@ type BpfZbufHeader struct {
 	User_gen   uint32
 	X_bzh_pad  [5]uint32
 }
+
+type Termios struct {
+	Iflag  uint32
+	Oflag  uint32
+	Cflag  uint32
+	Lflag  uint32
+	Cc     [20]uint8
+	Ispeed uint32
+	Ospeed uint32
+}
diff --git a/src/pkg/syscall/ztypes_linux_386.go b/src/pkg/syscall/ztypes_linux_386.go
index 9abd647..daecb1d 100644
--- a/src/pkg/syscall/ztypes_linux_386.go
+++ b/src/pkg/syscall/ztypes_linux_386.go
@@ -142,6 +142,14 @@ type Fsid struct {
 	X__val [2]int32
 }
 
+type Flock_t struct {
+	Type   int16
+	Whence int16
+	Start  int64
+	Len    int64
+	Pid    int32
+}
+
 type RawSockaddrInet4 struct {
 	Family uint16
 	Port   uint16
diff --git a/src/pkg/syscall/ztypes_linux_amd64.go b/src/pkg/syscall/ztypes_linux_amd64.go
index 32da4e4..694fe1e 100644
--- a/src/pkg/syscall/ztypes_linux_amd64.go
+++ b/src/pkg/syscall/ztypes_linux_amd64.go
@@ -142,6 +142,16 @@ type Fsid struct {
 	X__val [2]int32
 }
 
+type Flock_t struct {
+	Type      int16
+	Whence    int16
+	Pad_cgo_0 [4]byte
+	Start     int64
+	Len       int64
+	Pid       int32
+	Pad_cgo_1 [4]byte
+}
+
 type RawSockaddrInet4 struct {
 	Family uint16
 	Port   uint16
diff --git a/src/pkg/syscall/ztypes_linux_arm.go b/src/pkg/syscall/ztypes_linux_arm.go
index 4a918a8..5f21a94 100644
--- a/src/pkg/syscall/ztypes_linux_arm.go
+++ b/src/pkg/syscall/ztypes_linux_arm.go
@@ -144,6 +144,16 @@ type Fsid struct {
 	X__val [2]int32
 }
 
+type Flock_t struct {
+	Type      int16
+	Whence    int16
+	Pad_cgo_0 [4]byte
+	Start     int64
+	Len       int64
+	Pid       int32
+	Pad_cgo_1 [4]byte
+}
+
 type RawSockaddrInet4 struct {
 	Family uint16
 	Port   uint16
diff --git a/src/pkg/syscall/ztypes_netbsd_386.go b/src/pkg/syscall/ztypes_netbsd_386.go
index 59314ba..6add325 100644
--- a/src/pkg/syscall/ztypes_netbsd_386.go
+++ b/src/pkg/syscall/ztypes_netbsd_386.go
@@ -370,6 +370,16 @@ type BpfTimeval struct {
 	Usec int32
 }
 
+type Termios struct {
+	Iflag  uint32
+	Oflag  uint32
+	Cflag  uint32
+	Lflag  uint32
+	Cc     [20]uint8
+	Ispeed int32
+	Ospeed int32
+}
+
 type Sysctlnode struct {
 	Flags           uint32
 	Num             int32
diff --git a/src/pkg/syscall/ztypes_netbsd_amd64.go b/src/pkg/syscall/ztypes_netbsd_amd64.go
index a021a57..4451fc1 100644
--- a/src/pkg/syscall/ztypes_netbsd_amd64.go
+++ b/src/pkg/syscall/ztypes_netbsd_amd64.go
@@ -377,6 +377,16 @@ type BpfTimeval struct {
 	Usec int64
 }
 
+type Termios struct {
+	Iflag  uint32
+	Oflag  uint32
+	Cflag  uint32
+	Lflag  uint32
+	Cc     [20]uint8
+	Ispeed int32
+	Ospeed int32
+}
+
 type Sysctlnode struct {
 	Flags           uint32
 	Num             int32
diff --git a/src/pkg/syscall/ztypes_netbsd_arm.go b/src/pkg/syscall/ztypes_netbsd_arm.go
index 59314ba..4e853ea 100644
--- a/src/pkg/syscall/ztypes_netbsd_arm.go
+++ b/src/pkg/syscall/ztypes_netbsd_arm.go
@@ -19,13 +19,15 @@ type (
 )
 
 type Timespec struct {
-	Sec  int64
-	Nsec int32
+	Sec       int64
+	Nsec      int32
+	Pad_cgo_0 [4]byte
 }
 
 type Timeval struct {
-	Sec  int64
-	Usec int32
+	Sec       int64
+	Usec      int32
+	Pad_cgo_0 [4]byte
 }
 
 type Rusage struct {
@@ -57,10 +59,12 @@ type _Gid_t uint32
 type Stat_t struct {
 	Dev           uint64
 	Mode          uint32
+	Pad_cgo_0     [4]byte
 	Ino           uint64
 	Nlink         uint32
 	Uid           uint32
 	Gid           uint32
+	Pad_cgo_1     [4]byte
 	Rdev          uint64
 	Atimespec     Timespec
 	Mtimespec     Timespec
@@ -72,6 +76,7 @@ type Stat_t struct {
 	Flags         uint32
 	Gen           uint32
 	Spare         [2]uint32
+	Pad_cgo_2     [4]byte
 }
 
 type Statfs_t [0]byte
@@ -217,12 +222,13 @@ const (
 )
 
 type Kevent_t struct {
-	Ident  uint32
-	Filter uint32
-	Flags  uint32
-	Fflags uint32
-	Data   int64
-	Udata  int32
+	Ident     uint32
+	Filter    uint32
+	Flags     uint32
+	Fflags    uint32
+	Data      int64
+	Udata     int32
+	Pad_cgo_0 [4]byte
 }
 
 type FdSet struct {
@@ -231,7 +237,7 @@ type FdSet struct {
 
 const (
 	SizeofIfMsghdr         = 0x98
-	SizeofIfData           = 0x84
+	SizeofIfData           = 0x88
 	SizeofIfaMsghdr        = 0x18
 	SizeofIfAnnounceMsghdr = 0x18
 	SizeofRtMsghdr         = 0x78
@@ -247,7 +253,6 @@ type IfMsghdr struct {
 	Index     uint16
 	Pad_cgo_0 [2]byte
 	Data      IfData
-	Pad_cgo_1 [4]byte
 }
 
 type IfData struct {
@@ -370,6 +375,16 @@ type BpfTimeval struct {
 	Usec int32
 }
 
+type Termios struct {
+	Iflag  uint32
+	Oflag  uint32
+	Cflag  uint32
+	Lflag  uint32
+	Cc     [20]uint8
+	Ispeed int32
+	Ospeed int32
+}
+
 type Sysctlnode struct {
 	Flags           uint32
 	Num             int32
diff --git a/src/pkg/syscall/ztypes_openbsd_386.go b/src/pkg/syscall/ztypes_openbsd_386.go
index 3c9cdf2..2e4d9dd 100644
--- a/src/pkg/syscall/ztypes_openbsd_386.go
+++ b/src/pkg/syscall/ztypes_openbsd_386.go
@@ -19,12 +19,12 @@ type (
 )
 
 type Timespec struct {
-	Sec  int32
+	Sec  int64
 	Nsec int32
 }
 
 type Timeval struct {
-	Sec  int32
+	Sec  int64
 	Usec int32
 }
 
@@ -72,14 +72,13 @@ const (
 )
 
 type Stat_t struct {
-	Dev            int32
-	Ino            uint32
 	Mode           uint32
+	Dev            int32
+	Ino            uint64
 	Nlink          uint32
 	Uid            uint32
 	Gid            uint32
 	Rdev           int32
-	Lspare0        int32
 	Atim           Timespec
 	Mtim           Timespec
 	Ctim           Timespec
@@ -88,9 +87,7 @@ type Stat_t struct {
 	Blksize        uint32
 	Flags          uint32
 	Gen            uint32
-	Lspare1        int32
 	X__st_birthtim Timespec
-	Qspare         [2]int64
 }
 
 type Statfs_t struct {
@@ -110,11 +107,12 @@ type Statfs_t struct {
 	F_fsid        Fsid
 	F_namemax     uint32
 	F_owner       uint32
-	F_ctime       uint32
-	F_spare       [3]uint32
+	F_ctime       uint64
 	F_fstypename  [16]int8
 	F_mntonname   [90]int8
 	F_mntfromname [90]int8
+	F_mntfromspec [90]int8
+	Pad_cgo_0     [2]byte
 	Mount_info    [160]byte
 }
 
@@ -127,11 +125,13 @@ type Flock_t struct {
 }
 
 type Dirent struct {
-	Fileno uint32
-	Reclen uint16
-	Type   uint8
-	Namlen uint8
-	Name   [256]int8
+	Fileno       uint64
+	Off          int64
+	Reclen       uint16
+	Type         uint8
+	Namlen       uint8
+	X__d_padding [4]uint8
+	Name         [256]int8
 }
 
 type Fsid struct {
@@ -262,21 +262,21 @@ type Kevent_t struct {
 	Filter int16
 	Flags  uint16
 	Fflags uint32
-	Data   int32
+	Data   int64
 	Udata  *byte
 }
 
 type FdSet struct {
-	Bits [32]int32
+	Bits [32]uint32
 }
 
 const (
-	SizeofIfMsghdr         = 0xe8
-	SizeofIfData           = 0xd0
+	SizeofIfMsghdr         = 0xec
+	SizeofIfData           = 0xd4
 	SizeofIfaMsghdr        = 0x18
 	SizeofIfAnnounceMsghdr = 0x1a
-	SizeofRtMsghdr         = 0x58
-	SizeofRtMetrics        = 0x30
+	SizeofRtMsghdr         = 0x60
+	SizeofRtMetrics        = 0x38
 )
 
 type IfMsghdr struct {
@@ -364,9 +364,9 @@ type RtMsghdr struct {
 
 type RtMetrics struct {
 	Pksent   uint64
+	Expire   int64
 	Locks    uint32
 	Mtu      uint32
-	Expire   uint32
 	Refcnt   uint32
 	Hopcount uint32
 	Recvpipe uint32
@@ -374,10 +374,11 @@ type RtMetrics struct {
 	Ssthresh uint32
 	Rtt      uint32
 	Rttvar   uint32
+	Pad      uint32
 }
 
 type Mclpool struct {
-	Grown uint32
+	Grown int32
 	Alive uint16
 	Hwm   uint16
 	Cwm   uint16
@@ -426,3 +427,13 @@ type BpfTimeval struct {
 	Sec  uint32
 	Usec uint32
 }
+
+type Termios struct {
+	Iflag  uint32
+	Oflag  uint32
+	Cflag  uint32
+	Lflag  uint32
+	Cc     [20]uint8
+	Ispeed int32
+	Ospeed int32
+}
diff --git a/src/pkg/syscall/ztypes_openbsd_amd64.go b/src/pkg/syscall/ztypes_openbsd_amd64.go
index 3a0ac96..f07bc71 100644
--- a/src/pkg/syscall/ztypes_openbsd_amd64.go
+++ b/src/pkg/syscall/ztypes_openbsd_amd64.go
@@ -19,9 +19,8 @@ type (
 )
 
 type Timespec struct {
-	Sec       int32
-	Pad_cgo_0 [4]byte
-	Nsec      int64
+	Sec  int64
+	Nsec int64
 }
 
 type Timeval struct {
@@ -73,14 +72,13 @@ const (
 )
 
 type Stat_t struct {
-	Dev            int32
-	Ino            uint32
 	Mode           uint32
+	Dev            int32
+	Ino            uint64
 	Nlink          uint32
 	Uid            uint32
 	Gid            uint32
 	Rdev           int32
-	Lspare0        int32
 	Atim           Timespec
 	Mtim           Timespec
 	Ctim           Timespec
@@ -89,9 +87,8 @@ type Stat_t struct {
 	Blksize        uint32
 	Flags          uint32
 	Gen            uint32
-	Lspare1        int32
+	Pad_cgo_0      [4]byte
 	X__st_birthtim Timespec
-	Qspare         [2]int64
 }
 
 type Statfs_t struct {
@@ -112,12 +109,12 @@ type Statfs_t struct {
 	F_fsid        Fsid
 	F_namemax     uint32
 	F_owner       uint32
-	F_ctime       uint32
-	F_spare       [3]uint32
+	F_ctime       uint64
 	F_fstypename  [16]int8
 	F_mntonname   [90]int8
 	F_mntfromname [90]int8
-	Pad_cgo_1     [4]byte
+	F_mntfromspec [90]int8
+	Pad_cgo_1     [2]byte
 	Mount_info    [160]byte
 }
 
@@ -130,11 +127,13 @@ type Flock_t struct {
 }
 
 type Dirent struct {
-	Fileno uint32
-	Reclen uint16
-	Type   uint8
-	Namlen uint8
-	Name   [256]int8
+	Fileno       uint64
+	Off          int64
+	Reclen       uint16
+	Type         uint8
+	Namlen       uint8
+	X__d_padding [4]uint8
+	Name         [256]int8
 }
 
 type Fsid struct {
@@ -263,16 +262,16 @@ const (
 )
 
 type Kevent_t struct {
-	Ident  uint32
+	Ident  uint64
 	Filter int16
 	Flags  uint16
 	Fflags uint32
-	Data   int32
+	Data   int64
 	Udata  *byte
 }
 
 type FdSet struct {
-	Bits [32]int32
+	Bits [32]uint32
 }
 
 const (
@@ -280,8 +279,8 @@ const (
 	SizeofIfData           = 0xe0
 	SizeofIfaMsghdr        = 0x18
 	SizeofIfAnnounceMsghdr = 0x1a
-	SizeofRtMsghdr         = 0x58
-	SizeofRtMetrics        = 0x30
+	SizeofRtMsghdr         = 0x60
+	SizeofRtMetrics        = 0x38
 )
 
 type IfMsghdr struct {
@@ -371,9 +370,9 @@ type RtMsghdr struct {
 
 type RtMetrics struct {
 	Pksent   uint64
+	Expire   int64
 	Locks    uint32
 	Mtu      uint32
-	Expire   uint32
 	Refcnt   uint32
 	Hopcount uint32
 	Recvpipe uint32
@@ -381,10 +380,11 @@ type RtMetrics struct {
 	Ssthresh uint32
 	Rtt      uint32
 	Rttvar   uint32
+	Pad      uint32
 }
 
 type Mclpool struct {
-	Grown uint32
+	Grown int32
 	Alive uint16
 	Hwm   uint16
 	Cwm   uint16
@@ -434,3 +434,13 @@ type BpfTimeval struct {
 	Sec  uint32
 	Usec uint32
 }
+
+type Termios struct {
+	Iflag  uint32
+	Oflag  uint32
+	Cflag  uint32
+	Lflag  uint32
+	Cc     [20]uint8
+	Ispeed int32
+	Ospeed int32
+}
diff --git a/src/pkg/syscall/ztypes_solaris_amd64.go b/src/pkg/syscall/ztypes_solaris_amd64.go
new file mode 100644
index 0000000..77275a5
--- /dev/null
+++ b/src/pkg/syscall/ztypes_solaris_amd64.go
@@ -0,0 +1,365 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_solaris.go
+
+package syscall
+
+const (
+	sizeofPtr      = 0x8
+	sizeofShort    = 0x2
+	sizeofInt      = 0x4
+	sizeofLong     = 0x8
+	sizeofLongLong = 0x8
+)
+
+type (
+	_C_short     int16
+	_C_int       int32
+	_C_long      int64
+	_C_long_long int64
+)
+
+type Timespec struct {
+	Sec  int64
+	Nsec int64
+}
+
+type Timeval struct {
+	Sec  int64
+	Usec int64
+}
+
+type Timeval32 struct {
+	Sec  int32
+	Usec int32
+}
+
+type Rusage struct {
+	Utime    Timeval
+	Stime    Timeval
+	Maxrss   int64
+	Ixrss    int64
+	Idrss    int64
+	Isrss    int64
+	Minflt   int64
+	Majflt   int64
+	Nswap    int64
+	Inblock  int64
+	Oublock  int64
+	Msgsnd   int64
+	Msgrcv   int64
+	Nsignals int64
+	Nvcsw    int64
+	Nivcsw   int64
+}
+
+type Rlimit struct {
+	Cur uint64
+	Max uint64
+}
+
+type _Gid_t uint32
+
+const (
+	S_IFMT   = 0xf000
+	S_IFIFO  = 0x1000
+	S_IFCHR  = 0x2000
+	S_IFDIR  = 0x4000
+	S_IFBLK  = 0x6000
+	S_IFREG  = 0x8000
+	S_IFLNK  = 0xa000
+	S_IFSOCK = 0xc000
+	S_ISUID  = 0x800
+	S_ISGID  = 0x400
+	S_ISVTX  = 0x200
+	S_IRUSR  = 0x100
+	S_IWUSR  = 0x80
+	S_IXUSR  = 0x40
+)
+
+type Stat_t struct {
+	Dev       uint64
+	Ino       uint64
+	Mode      uint32
+	Nlink     uint32
+	Uid       uint32
+	Gid       uint32
+	Rdev      uint64
+	Size      int64
+	Atim      Timespec
+	Mtim      Timespec
+	Ctim      Timespec
+	Blksize   int32
+	Pad_cgo_0 [4]byte
+	Blocks    int64
+	Fstype    [16]int8
+}
+
+type Flock_t struct {
+	Type      int16
+	Whence    int16
+	Pad_cgo_0 [4]byte
+	Start     int64
+	Len       int64
+	Sysid     int32
+	Pid       int32
+	Pad       [4]int64
+}
+
+type Dirent struct {
+	Ino       uint64
+	Off       int64
+	Reclen    uint16
+	Name      [1]int8
+	Pad_cgo_0 [5]byte
+}
+
+type RawSockaddrInet4 struct {
+	Family uint16
+	Port   uint16
+	Addr   [4]byte /* in_addr */
+	Zero   [8]int8
+}
+
+type RawSockaddrInet6 struct {
+	Family         uint16
+	Port           uint16
+	Flowinfo       uint32
+	Addr           [16]byte /* in6_addr */
+	Scope_id       uint32
+	X__sin6_src_id uint32
+}
+
+type RawSockaddrUnix struct {
+	Family uint16
+	Path   [108]int8
+}
+
+type RawSockaddrDatalink struct {
+	Family uint16
+	Index  uint16
+	Type   uint8
+	Nlen   uint8
+	Alen   uint8
+	Slen   uint8
+	Data   [244]int8
+}
+
+type RawSockaddr struct {
+	Family uint16
+	Data   [14]int8
+}
+
+type RawSockaddrAny struct {
+	Addr RawSockaddr
+	Pad  [236]int8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+	Onoff  int32
+	Linger int32
+}
+
+type Iovec struct {
+	Base *int8
+	Len  uint64
+}
+
+type IPMreq struct {
+	Multiaddr [4]byte /* in_addr */
+	Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+	Multiaddr [16]byte /* in6_addr */
+	Interface uint32
+}
+
+type Msghdr struct {
+	Name         *byte
+	Namelen      uint32
+	Pad_cgo_0    [4]byte
+	Iov          *Iovec
+	Iovlen       int32
+	Pad_cgo_1    [4]byte
+	Accrights    *int8
+	Accrightslen int32
+	Pad_cgo_2    [4]byte
+}
+
+type Cmsghdr struct {
+	Len   uint32
+	Level int32
+	Type  int32
+}
+
+type Inet6Pktinfo struct {
+	Addr    [16]byte /* in6_addr */
+	Ifindex uint32
+}
+
+type IPv6MTUInfo struct {
+	Addr RawSockaddrInet6
+	Mtu  uint32
+}
+
+type ICMPv6Filter struct {
+	X__icmp6_filt [8]uint32
+}
+
+const (
+	SizeofSockaddrInet4    = 0x10
+	SizeofSockaddrInet6    = 0x20
+	SizeofSockaddrAny      = 0xfc
+	SizeofSockaddrUnix     = 0x6e
+	SizeofSockaddrDatalink = 0xfc
+	SizeofLinger           = 0x8
+	SizeofIPMreq           = 0x8
+	SizeofIPv6Mreq         = 0x14
+	SizeofMsghdr           = 0x30
+	SizeofCmsghdr          = 0xc
+	SizeofInet6Pktinfo     = 0x14
+	SizeofIPv6MTUInfo      = 0x24
+	SizeofICMPv6Filter     = 0x20
+)
+
+type FdSet struct {
+	Bits [1024]int64
+}
+
+const (
+	SizeofIfMsghdr  = 0x54
+	SizeofIfData    = 0x44
+	SizeofIfaMsghdr = 0x14
+	SizeofRtMsghdr  = 0x4c
+	SizeofRtMetrics = 0x28
+)
+
+type IfMsghdr struct {
+	Msglen    uint16
+	Version   uint8
+	Type      uint8
+	Addrs     int32
+	Flags     int32
+	Index     uint16
+	Pad_cgo_0 [2]byte
+	Data      IfData
+}
+
+type IfData struct {
+	Type       uint8
+	Addrlen    uint8
+	Hdrlen     uint8
+	Pad_cgo_0  [1]byte
+	Mtu        uint32
+	Metric     uint32
+	Baudrate   uint32
+	Ipackets   uint32
+	Ierrors    uint32
+	Opackets   uint32
+	Oerrors    uint32
+	Collisions uint32
+	Ibytes     uint32
+	Obytes     uint32
+	Imcasts    uint32
+	Omcasts    uint32
+	Iqdrops    uint32
+	Noproto    uint32
+	Lastchange Timeval32
+}
+
+type IfaMsghdr struct {
+	Msglen    uint16
+	Version   uint8
+	Type      uint8
+	Addrs     int32
+	Flags     int32
+	Index     uint16
+	Pad_cgo_0 [2]byte
+	Metric    int32
+}
+
+type RtMsghdr struct {
+	Msglen    uint16
+	Version   uint8
+	Type      uint8
+	Index     uint16
+	Pad_cgo_0 [2]byte
+	Flags     int32
+	Addrs     int32
+	Pid       int32
+	Seq       int32
+	Errno     int32
+	Use       int32
+	Inits     uint32
+	Rmx       RtMetrics
+}
+
+type RtMetrics struct {
+	Locks    uint32
+	Mtu      uint32
+	Hopcount uint32
+	Expire   uint32
+	Recvpipe uint32
+	Sendpipe uint32
+	Ssthresh uint32
+	Rtt      uint32
+	Rttvar   uint32
+	Pksent   uint32
+}
+
+const (
+	SizeofBpfVersion = 0x4
+	SizeofBpfStat    = 0x80
+	SizeofBpfProgram = 0x10
+	SizeofBpfInsn    = 0x8
+	SizeofBpfHdr     = 0x14
+)
+
+type BpfVersion struct {
+	Major uint16
+	Minor uint16
+}
+
+type BpfStat struct {
+	Recv    uint64
+	Drop    uint64
+	Capt    uint64
+	Padding [13]uint64
+}
+
+type BpfProgram struct {
+	Len       uint32
+	Pad_cgo_0 [4]byte
+	Insns     *BpfInsn
+}
+
+type BpfInsn struct {
+	Code uint16
+	Jt   uint8
+	Jf   uint8
+	K    uint32
+}
+
+type BpfTimeval struct {
+	Sec  int32
+	Usec int32
+}
+
+type BpfHdr struct {
+	Tstamp    BpfTimeval
+	Caplen    uint32
+	Datalen   uint32
+	Hdrlen    uint16
+	Pad_cgo_0 [2]byte
+}
+
+type Termios struct {
+	Iflag     uint32
+	Oflag     uint32
+	Cflag     uint32
+	Lflag     uint32
+	Cc        [19]uint8
+	Pad_cgo_0 [1]byte
+}
diff --git a/src/pkg/syscall/ztypes_windows.go b/src/pkg/syscall/ztypes_windows.go
index a5681d7..a1d77e0 100644
--- a/src/pkg/syscall/ztypes_windows.go
+++ b/src/pkg/syscall/ztypes_windows.go
@@ -20,6 +20,7 @@ const (
 	ERROR_PROC_NOT_FOUND      Errno = 127
 	ERROR_ALREADY_EXISTS      Errno = 183
 	ERROR_ENVVAR_NOT_FOUND    Errno = 203
+	ERROR_MORE_DATA           Errno = 234
 	ERROR_OPERATION_ABORTED   Errno = 995
 	ERROR_IO_PENDING          Errno = 997
 	ERROR_NOT_FOUND           Errno = 1168
@@ -514,9 +515,11 @@ const (
 
 	IOC_OUT                            = 0x40000000
 	IOC_IN                             = 0x80000000
+	IOC_VENDOR                         = 0x18000000
 	IOC_INOUT                          = IOC_IN | IOC_OUT
 	IOC_WS2                            = 0x08000000
 	SIO_GET_EXTENSION_FUNCTION_POINTER = IOC_INOUT | IOC_WS2 | 6
+	SIO_KEEPALIVE_VALS                 = IOC_IN | IOC_VENDOR | 4
 
 	// cf. http://support.microsoft.com/default.aspx?scid=kb;en-us;257460
 
@@ -1033,3 +1036,9 @@ type WSAProtocolChain struct {
 	ChainLen     int32
 	ChainEntries [MAX_PROTOCOL_CHAIN]uint32
 }
+
+type TCPKeepalive struct {
+	OnOff    uint32
+	Time     uint32
+	Interval uint32
+}
diff --git a/src/pkg/testing/benchmark.go b/src/pkg/testing/benchmark.go
index 3473c5b..1fbf5c8 100644
--- a/src/pkg/testing/benchmark.go
+++ b/src/pkg/testing/benchmark.go
@@ -10,6 +10,7 @@ import (
 	"os"
 	"runtime"
 	"sync"
+	"sync/atomic"
 	"time"
 )
 
@@ -34,12 +35,15 @@ type InternalBenchmark struct {
 // timing and to specify the number of iterations to run.
 type B struct {
 	common
-	N               int
-	benchmark       InternalBenchmark
-	bytes           int64
-	timerOn         bool
-	showAllocResult bool
-	result          BenchmarkResult
+	N                int
+	previousN        int           // number of iterations in the previous run
+	previousDuration time.Duration // total duration of the previous run
+	benchmark        InternalBenchmark
+	bytes            int64
+	timerOn          bool
+	showAllocResult  bool
+	result           BenchmarkResult
+	parallelism      int // RunParallel creates parallelism*GOMAXPROCS goroutines
 	// The initial states of memStats.Mallocs and memStats.TotalAlloc.
 	startAllocs uint64
 	startBytes  uint64
@@ -74,7 +78,7 @@ func (b *B) StopTimer() {
 	}
 }
 
-// ResetTimer sets the elapsed benchmark time to zero.
+// ResetTimer zeros the elapsed benchmark time and memory allocation counters.
 // It does not affect whether the timer is running.
 func (b *B) ResetTimer() {
 	if b.timerOn {
@@ -114,10 +118,13 @@ func (b *B) runN(n int) {
 	// by clearing garbage from previous runs.
 	runtime.GC()
 	b.N = n
+	b.parallelism = 1
 	b.ResetTimer()
 	b.StartTimer()
 	b.benchmark.F(b)
 	b.StopTimer()
+	b.previousN = n
+	b.previousDuration = b.duration
 }
 
 func min(x, y int) int {
@@ -343,6 +350,87 @@ func (b *B) trimOutput() {
 	}
 }
 
+// A PB is used by RunParallel for running parallel benchmarks.
+type PB struct {
+	globalN *uint64 // shared between all worker goroutines iteration counter
+	grain   uint64  // acquire that many iterations from globalN at once
+	cache   uint64  // local cache of acquired iterations
+	bN      uint64  // total number of iterations to execute (b.N)
+}
+
+// Next reports whether there are more iterations to execute.
+func (pb *PB) Next() bool {
+	if pb.cache == 0 {
+		n := atomic.AddUint64(pb.globalN, pb.grain)
+		if n <= pb.bN {
+			pb.cache = pb.grain
+		} else if n < pb.bN+pb.grain {
+			pb.cache = pb.bN + pb.grain - n
+		} else {
+			return false
+		}
+	}
+	pb.cache--
+	return true
+}
+
+// RunParallel runs a benchmark in parallel.
+// It creates multiple goroutines and distributes b.N iterations among them.
+// The number of goroutines defaults to GOMAXPROCS. To increase parallelism for
+// non-CPU-bound benchmarks, call SetParallelism before RunParallel.
+// RunParallel is usually used with the go test -cpu flag.
+//
+// The body function will be run in each goroutine. It should set up any
+// goroutine-local state and then iterate until pb.Next returns false.
+// It should not use the StartTimer, StopTimer, or ResetTimer functions,
+// because they have global effect.
+func (b *B) RunParallel(body func(*PB)) {
+	// Calculate grain size as number of iterations that take ~100µs.
+	// 100µs is enough to amortize the overhead and provide sufficient
+	// dynamic load balancing.
+	grain := uint64(0)
+	if b.previousN > 0 && b.previousDuration > 0 {
+		grain = 1e5 * uint64(b.previousN) / uint64(b.previousDuration)
+	}
+	if grain < 1 {
+		grain = 1
+	}
+	// We expect the inner loop and function call to take at least 10ns,
+	// so do not do more than 100µs/10ns=1e4 iterations.
+	if grain > 1e4 {
+		grain = 1e4
+	}
+
+	n := uint64(0)
+	numProcs := b.parallelism * runtime.GOMAXPROCS(0)
+	var wg sync.WaitGroup
+	wg.Add(numProcs)
+	for p := 0; p < numProcs; p++ {
+		go func() {
+			defer wg.Done()
+			pb := &PB{
+				globalN: &n,
+				grain:   grain,
+				bN:      uint64(b.N),
+			}
+			body(pb)
+		}()
+	}
+	wg.Wait()
+	if n <= uint64(b.N) && !b.Failed() {
+		b.Fatal("RunParallel: body exited without pb.Next() == false")
+	}
+}
+
+// SetParallelism sets the number of goroutines used by RunParallel to p*GOMAXPROCS.
+// There is usually no need to call SetParallelism for CPU-bound benchmarks.
+// If p is less than 1, this call will have no effect.
+func (b *B) SetParallelism(p int) {
+	if p >= 1 {
+		b.parallelism = p
+	}
+}
+
 // Benchmark benchmarks a single function. Useful for creating
 // custom benchmarks that do not use the "go test" command.
 func Benchmark(f func(b *B)) BenchmarkResult {
diff --git a/src/pkg/testing/benchmark_test.go b/src/pkg/testing/benchmark_test.go
index 94e994d..f7ea64e 100644
--- a/src/pkg/testing/benchmark_test.go
+++ b/src/pkg/testing/benchmark_test.go
@@ -5,7 +5,11 @@
 package testing_test
 
 import (
+	"bytes"
+	"runtime"
+	"sync/atomic"
 	"testing"
+	"text/template"
 )
 
 var roundDownTests = []struct {
@@ -56,3 +60,52 @@ func TestRoundUp(t *testing.T) {
 		}
 	}
 }
+
+func TestRunParallel(t *testing.T) {
+	testing.Benchmark(func(b *testing.B) {
+		procs := uint32(0)
+		iters := uint64(0)
+		b.SetParallelism(3)
+		b.RunParallel(func(pb *testing.PB) {
+			atomic.AddUint32(&procs, 1)
+			for pb.Next() {
+				atomic.AddUint64(&iters, 1)
+			}
+		})
+		if want := uint32(3 * runtime.GOMAXPROCS(0)); procs != want {
+			t.Errorf("got %v procs, want %v", procs, want)
+		}
+		if iters != uint64(b.N) {
+			t.Errorf("got %v iters, want %v", iters, b.N)
+		}
+	})
+}
+
+func TestRunParallelFail(t *testing.T) {
+	testing.Benchmark(func(b *testing.B) {
+		b.RunParallel(func(pb *testing.PB) {
+			// The function must be able to log/abort
+			// w/o crashing/deadlocking the whole benchmark.
+			b.Log("log")
+			b.Error("error")
+		})
+	})
+}
+
+func ExampleB_RunParallel() {
+	// Parallel benchmark for text/template.Template.Execute on a single object.
+	testing.Benchmark(func(b *testing.B) {
+		templ := template.Must(template.New("test").Parse("Hello, {{.}}!"))
+		// RunParallel will create GOMAXPROCS goroutines
+		// and distribute work among them.
+		b.RunParallel(func(pb *testing.PB) {
+			// Each goroutine has its own bytes.Buffer.
+			var buf bytes.Buffer
+			for pb.Next() {
+				// The loop body is executed b.N times total across all goroutines.
+				buf.Reset()
+				templ.Execute(&buf, "World")
+			}
+		})
+	})
+}
diff --git a/src/pkg/testing/testing.go b/src/pkg/testing/testing.go
index 52dc166..8078ba7 100644
--- a/src/pkg/testing/testing.go
+++ b/src/pkg/testing/testing.go
@@ -8,9 +8,17 @@
 //     func TestXxx(*testing.T)
 // where Xxx can be any alphanumeric string (but the first letter must not be in
 // [a-z]) and serves to identify the test routine.
-// These TestXxx routines should be declared within the package they are testing.
 //
-// Tests and benchmarks may be skipped if not applicable like this:
+// Within these functions, use the Error, Fail or related methods to signal failure.
+//
+// To write a new test suite, create a file whose name ends _test.go that
+// contains the TestXxx functions as described here. Put the file in the same
+// package as the one being tested. The file will be excluded from regular
+// package builds but will be included when the ``go test'' command is run.
+// For more detail, run ``go help test'' and ``go help testflag''.
+//
+// Tests and benchmarks may be skipped if not applicable with a call to
+// the Skip method of *T and *B:
 //     func TestTimeConsuming(t *testing.T) {
 //         if testing.Short() {
 //             t.Skip("skipping test in short mode.")
@@ -43,6 +51,7 @@
 //
 // If a benchmark needs some expensive setup before running, the timer
 // may be reset:
+//
 //     func BenchmarkBigLen(b *testing.B) {
 //         big := NewBig()
 //         b.ResetTimer()
@@ -51,6 +60,21 @@
 //         }
 //     }
 //
+// If a benchmark needs to test performance in a parallel setting, it may use
+// the RunParallel helper function; such benchmarks are intended to be used with
+// the go test -cpu flag:
+//
+//     func BenchmarkTemplateParallel(b *testing.B) {
+//         templ := template.Must(template.New("test").Parse("Hello, {{.}}!"))
+//         b.RunParallel(func(pb *testing.PB) {
+//             var buf bytes.Buffer
+//             for pb.Next() {
+//                 buf.Reset()
+//                 templ.Execute(&buf, "World")
+//             }
+//         })
+//     }
+//
 // Examples
 //
 // The package also runs and verifies example code. Example functions may
@@ -143,10 +167,11 @@ var (
 // common holds the elements common between T and B and
 // captures common methods such as Errorf.
 type common struct {
-	mu      sync.RWMutex // guards output and failed
-	output  []byte       // Output generated by test or benchmark.
-	failed  bool         // Test or benchmark has failed.
-	skipped bool         // Test of benchmark has been skipped.
+	mu       sync.RWMutex // guards output and failed
+	output   []byte       // Output generated by test or benchmark.
+	failed   bool         // Test or benchmark has failed.
+	skipped  bool         // Test of benchmark has been skipped.
+	finished bool
 
 	start    time.Time // Time test or benchmark started
 	duration time.Duration
@@ -275,6 +300,7 @@ func (c *common) FailNow() {
 	// it would run on a test failure.  Because we send on c.signal during
 	// a top-of-stack deferred function now, we know that the send
 	// only happens after any other stacked defers have completed.
+	c.finished = true
 	runtime.Goexit()
 }
 
@@ -338,6 +364,7 @@ func (c *common) Skipf(format string, args ...interface{}) {
 // those other goroutines.
 func (c *common) SkipNow() {
 	c.skip()
+	c.finished = true
 	runtime.Goexit()
 }
 
@@ -379,7 +406,11 @@ func tRunner(t *T, test *InternalTest) {
 	defer func() {
 		t.duration = time.Now().Sub(t.start)
 		// If the test panicked, print any test output before dying.
-		if err := recover(); err != nil {
+		err := recover()
+		if !t.finished && err == nil {
+			err = fmt.Errorf("test executed panic(nil) or runtime.Goexit")
+		}
+		if err != nil {
 			t.Fail()
 			t.report()
 			panic(err)
@@ -389,6 +420,7 @@ func tRunner(t *T, test *InternalTest) {
 
 	t.start = time.Now()
 	test.F(t)
+	t.finished = true
 }
 
 // An internal function but exported because it is cross-package; part of the implementation
@@ -405,6 +437,7 @@ func Main(matchString func(pat, str string) (bool, error), tests []InternalTest,
 	stopAlarm()
 	if !testOk || !exampleOk {
 		fmt.Println("FAIL")
+		after()
 		os.Exit(1)
 	}
 	fmt.Println("PASS")
diff --git a/src/pkg/text/scanner/scanner.go b/src/pkg/text/scanner/scanner.go
index e0d86e3..db7ca73 100644
--- a/src/pkg/text/scanner/scanner.go
+++ b/src/pkg/text/scanner/scanner.go
@@ -240,6 +240,9 @@ func (s *Scanner) next() rune {
 			s.srcEnd = i + n
 			s.srcBuf[s.srcEnd] = utf8.RuneSelf // sentinel
 			if err != nil {
+				if err != io.EOF {
+					s.error(err.Error())
+				}
 				if s.srcEnd == 0 {
 					if s.lastCharLen > 0 {
 						// previous character was not EOF
@@ -248,9 +251,6 @@ func (s *Scanner) next() rune {
 					s.lastCharLen = 0
 					return EOF
 				}
-				if err != io.EOF {
-					s.error(err.Error())
-				}
 				// If err == EOF, we won't be getting more
 				// bytes; break to avoid infinite loop. If
 				// err is something else, we don't know if
diff --git a/src/pkg/text/scanner/scanner_test.go b/src/pkg/text/scanner/scanner_test.go
index 496eed4..7d3f597 100644
--- a/src/pkg/text/scanner/scanner_test.go
+++ b/src/pkg/text/scanner/scanner_test.go
@@ -360,7 +360,7 @@ func TestScanSelectedMask(t *testing.T) {
 func TestScanNext(t *testing.T) {
 	const BOM = '\uFEFF'
 	BOMs := string(BOM)
-	s := new(Scanner).Init(bytes.NewBufferString(BOMs + "if a == bcd /* com" + BOMs + "ment */ {\n\ta += c\n}" + BOMs + "// line comment ending in eof"))
+	s := new(Scanner).Init(strings.NewReader(BOMs + "if a == bcd /* com" + BOMs + "ment */ {\n\ta += c\n}" + BOMs + "// line comment ending in eof"))
 	checkTok(t, s, 1, s.Scan(), Ident, "if") // the first BOM is ignored
 	checkTok(t, s, 1, s.Scan(), Ident, "a")
 	checkTok(t, s, 1, s.Scan(), '=', "=")
@@ -402,7 +402,7 @@ func TestScanWhitespace(t *testing.T) {
 }
 
 func testError(t *testing.T, src, pos, msg string, tok rune) {
-	s := new(Scanner).Init(bytes.NewBufferString(src))
+	s := new(Scanner).Init(strings.NewReader(src))
 	errorCalled := false
 	s.Error = func(s *Scanner, m string) {
 		if !errorCalled {
@@ -462,6 +462,33 @@ func TestError(t *testing.T) {
 	testError(t, `/*/`, "1:4", "comment not terminated", EOF)
 }
 
+// An errReader returns (0, err) where err is not io.EOF.
+type errReader struct{}
+
+func (errReader) Read(b []byte) (int, error) {
+	return 0, io.ErrNoProgress // some error that is not io.EOF
+}
+
+func TestIOError(t *testing.T) {
+	s := new(Scanner).Init(errReader{})
+	errorCalled := false
+	s.Error = func(s *Scanner, msg string) {
+		if !errorCalled {
+			if want := io.ErrNoProgress.Error(); msg != want {
+				t.Errorf("msg = %q, want %q", msg, want)
+			}
+			errorCalled = true
+		}
+	}
+	tok := s.Scan()
+	if tok != EOF {
+		t.Errorf("tok = %s, want EOF", TokenString(tok))
+	}
+	if !errorCalled {
+		t.Errorf("error handler not called")
+	}
+}
+
 func checkPos(t *testing.T, got, want Position) {
 	if got.Offset != want.Offset || got.Line != want.Line || got.Column != want.Column {
 		t.Errorf("got offset, line, column = %d, %d, %d; want %d, %d, %d",
@@ -491,13 +518,13 @@ func checkScanPos(t *testing.T, s *Scanner, offset, line, column int, char rune)
 
 func TestPos(t *testing.T) {
 	// corner case: empty source
-	s := new(Scanner).Init(bytes.NewBufferString(""))
+	s := new(Scanner).Init(strings.NewReader(""))
 	checkPos(t, s.Pos(), Position{Offset: 0, Line: 1, Column: 1})
 	s.Peek() // peek doesn't affect the position
 	checkPos(t, s.Pos(), Position{Offset: 0, Line: 1, Column: 1})
 
 	// corner case: source with only a newline
-	s = new(Scanner).Init(bytes.NewBufferString("\n"))
+	s = new(Scanner).Init(strings.NewReader("\n"))
 	checkPos(t, s.Pos(), Position{Offset: 0, Line: 1, Column: 1})
 	checkNextPos(t, s, 1, 2, 1, '\n')
 	// after EOF position doesn't change
@@ -509,7 +536,7 @@ func TestPos(t *testing.T) {
 	}
 
 	// corner case: source with only a single character
-	s = new(Scanner).Init(bytes.NewBufferString("本"))
+	s = new(Scanner).Init(strings.NewReader("本"))
 	checkPos(t, s.Pos(), Position{Offset: 0, Line: 1, Column: 1})
 	checkNextPos(t, s, 3, 1, 2, '本')
 	// after EOF position doesn't change
@@ -521,7 +548,7 @@ func TestPos(t *testing.T) {
 	}
 
 	// positions after calling Next
-	s = new(Scanner).Init(bytes.NewBufferString("  foo६४  \n\n本語\n"))
+	s = new(Scanner).Init(strings.NewReader("  foo६४  \n\n本語\n"))
 	checkNextPos(t, s, 1, 1, 2, ' ')
 	s.Peek() // peek doesn't affect the position
 	checkNextPos(t, s, 2, 1, 3, ' ')
@@ -546,7 +573,7 @@ func TestPos(t *testing.T) {
 	}
 
 	// positions after calling Scan
-	s = new(Scanner).Init(bytes.NewBufferString("abc\n本語\n\nx"))
+	s = new(Scanner).Init(strings.NewReader("abc\n本語\n\nx"))
 	s.Mode = 0
 	s.Whitespace = 0
 	checkScanPos(t, s, 0, 1, 1, 'a')
diff --git a/src/pkg/text/tabwriter/tabwriter.go b/src/pkg/text/tabwriter/tabwriter.go
index 722ac8d..c0c32d5 100644
--- a/src/pkg/text/tabwriter/tabwriter.go
+++ b/src/pkg/text/tabwriter/tabwriter.go
@@ -434,9 +434,13 @@ func (b *Writer) terminateCell(htab bool) int {
 	return len(*line)
 }
 
-func handlePanic(err *error) {
+func handlePanic(err *error, op string) {
 	if e := recover(); e != nil {
-		*err = e.(osError).err // re-panics if it's not a local osError
+		if nerr, ok := e.(osError); ok {
+			*err = nerr.err
+			return
+		}
+		panic("tabwriter: panic during " + op)
 	}
 }
 
@@ -447,7 +451,7 @@ func handlePanic(err *error) {
 //
 func (b *Writer) Flush() (err error) {
 	defer b.reset() // even in the presence of errors
-	defer handlePanic(&err)
+	defer handlePanic(&err, "Flush")
 
 	// add current cell if not empty
 	if b.cell.size > 0 {
@@ -471,7 +475,7 @@ var hbar = []byte("---\n")
 // while writing to the underlying output stream.
 //
 func (b *Writer) Write(buf []byte) (n int, err error) {
-	defer handlePanic(&err)
+	defer handlePanic(&err, "Write")
 
 	// split text into cells
 	n = 0
diff --git a/src/pkg/text/tabwriter/tabwriter_test.go b/src/pkg/text/tabwriter/tabwriter_test.go
index ace5356..9d3111e 100644
--- a/src/pkg/text/tabwriter/tabwriter_test.go
+++ b/src/pkg/text/tabwriter/tabwriter_test.go
@@ -14,7 +14,7 @@ type buffer struct {
 	a []byte
 }
 
-func (b *buffer) init(n int) { b.a = make([]byte, n)[0:0] }
+func (b *buffer) init(n int) { b.a = make([]byte, 0, n) }
 
 func (b *buffer) clear() { b.a = b.a[0:0] }
 
@@ -613,3 +613,40 @@ func Test(t *testing.T) {
 		check(t, e.testname, e.minwidth, e.tabwidth, e.padding, e.padchar, e.flags, e.src, e.expected)
 	}
 }
+
+type panicWriter struct{}
+
+func (panicWriter) Write([]byte) (int, error) {
+	panic("cannot write")
+}
+
+func wantPanicString(t *testing.T, want string) {
+	if e := recover(); e != nil {
+		got, ok := e.(string)
+		switch {
+		case !ok:
+			t.Errorf("got %v (%T), want panic string", e, e)
+		case got != want:
+			t.Errorf("wrong panic message: got %q, want %q", got, want)
+		}
+	}
+}
+
+func TestPanicDuringFlush(t *testing.T) {
+	defer wantPanicString(t, "tabwriter: panic during Flush")
+	var p panicWriter
+	w := new(Writer)
+	w.Init(p, 0, 0, 5, ' ', 0)
+	io.WriteString(w, "a")
+	w.Flush()
+	t.Errorf("failed to panic during Flush")
+}
+
+func TestPanicDuringWrite(t *testing.T) {
+	defer wantPanicString(t, "tabwriter: panic during Write")
+	var p panicWriter
+	w := new(Writer)
+	w.Init(p, 0, 0, 5, ' ', 0)
+	io.WriteString(w, "a\n\n") // the second \n triggers a call to w.Write and thus a panic
+	t.Errorf("failed to panic during Write")
+}
diff --git a/src/pkg/text/template/doc.go b/src/pkg/text/template/doc.go
index f622ac7..7c6efd5 100644
--- a/src/pkg/text/template/doc.go
+++ b/src/pkg/text/template/doc.go
@@ -20,7 +20,7 @@ The input text for a template is UTF-8-encoded text in any format.
 "{{" and "}}"; all text outside actions is copied to the output unchanged.
 Actions may not span newlines, although comments can.
 
-Once constructed, a template may be executed safely in parallel.
+Once parsed, a template may be executed safely in parallel.
 
 Here is a trivial example that prints "17 items are made of wool".
 
diff --git a/src/pkg/text/template/exec.go b/src/pkg/text/template/exec.go
index 43b0b26..2f32312 100644
--- a/src/pkg/text/template/exec.go
+++ b/src/pkg/text/template/exec.go
@@ -108,6 +108,10 @@ func errRecover(errp *error) {
 
 // ExecuteTemplate applies the template associated with t that has the given name
 // to the specified data object and writes the output to wr.
+// If an error occurs executing the template or writing its output,
+// execution stops, but partial results may already have been written to
+// the output writer.
+// A template may be executed safely in parallel.
 func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
 	tmpl := t.tmpl[name]
 	if tmpl == nil {
@@ -118,6 +122,10 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{})
 
 // Execute applies a parsed template to the specified data object,
 // and writes the output to wr.
+// If an error occurs executing the template or writing its output,
+// execution stops, but partial results may already have been written to
+// the output writer.
+// A template may be executed safely in parallel.
 func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
 	defer errRecover(&err)
 	value := reflect.ValueOf(data)
@@ -594,6 +602,9 @@ func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Valu
 		switch {
 		case value.Kind() == reflect.Ptr && value.Type().Elem().AssignableTo(typ):
 			value = value.Elem()
+			if !value.IsValid() {
+				s.errorf("dereference of nil pointer of type %s", typ)
+			}
 		case reflect.PtrTo(value.Type()).AssignableTo(typ) && value.CanAddr():
 			value = value.Addr()
 		default:
diff --git a/src/pkg/text/template/exec_test.go b/src/pkg/text/template/exec_test.go
index f60702d..868f2cb 100644
--- a/src/pkg/text/template/exec_test.go
+++ b/src/pkg/text/template/exec_test.go
@@ -512,6 +512,8 @@ var execTests = []execTest{
 	{"bug9", "{{.cause}}", "neglect", map[string]string{"cause": "neglect"}, true},
 	// Field chain starting with function did not work.
 	{"bug10", "{{mapOfThree.three}}-{{(mapOfThree).three}}", "3-3", 0, true},
+	// Dereferencing nil pointer while evaluating function arguments should not panic. Issue 7333.
+	{"bug11", "{{valueString .PS}}", "", T{}, false},
 }
 
 func zeroArgs() string {
@@ -546,6 +548,11 @@ func vfunc(V, *V) string {
 	return "vfunc"
 }
 
+// valueString takes a string, not a pointer.
+func valueString(v string) string {
+	return "value is ignored"
+}
+
 func add(args ...int) int {
 	sum := 0
 	for _, x := range args {
@@ -580,17 +587,18 @@ func mapOfThree() interface{} {
 func testExecute(execTests []execTest, template *Template, t *testing.T) {
 	b := new(bytes.Buffer)
 	funcs := FuncMap{
-		"add":        add,
-		"count":      count,
-		"dddArg":     dddArg,
-		"echo":       echo,
-		"makemap":    makemap,
-		"mapOfThree": mapOfThree,
-		"oneArg":     oneArg,
-		"stringer":   stringer,
-		"typeOf":     typeOf,
-		"vfunc":      vfunc,
-		"zeroArgs":   zeroArgs,
+		"add":         add,
+		"count":       count,
+		"dddArg":      dddArg,
+		"echo":        echo,
+		"makemap":     makemap,
+		"mapOfThree":  mapOfThree,
+		"oneArg":      oneArg,
+		"stringer":    stringer,
+		"typeOf":      typeOf,
+		"valueString": valueString,
+		"vfunc":       vfunc,
+		"zeroArgs":    zeroArgs,
 	}
 	for _, test := range execTests {
 		var tmpl *Template
diff --git a/src/pkg/text/template/multi_test.go b/src/pkg/text/template/multi_test.go
index 1f6ed5d..e4e8048 100644
--- a/src/pkg/text/template/multi_test.go
+++ b/src/pkg/text/template/multi_test.go
@@ -259,6 +259,18 @@ func TestAddParseTree(t *testing.T) {
 	}
 }
 
+// Issue 7032
+func TestAddParseTreeToUnparsedTemplate(t *testing.T) {
+	master := "{{define \"master\"}}{{end}}"
+	tmpl := New("master")
+	tree, err := parse.Parse("master", master, "", "", nil)
+	if err != nil {
+		t.Fatalf("unexpected parse err: %v", err)
+	}
+	masterTree := tree["master"]
+	tmpl.AddParseTree("master", masterTree) // used to panic
+}
+
 func TestRedefinition(t *testing.T) {
 	var tmpl *Template
 	var err error
diff --git a/src/pkg/text/template/template.go b/src/pkg/text/template/template.go
index a2b9062..249d0cb 100644
--- a/src/pkg/text/template/template.go
+++ b/src/pkg/text/template/template.go
@@ -105,7 +105,7 @@ func (t *Template) copy(c *common) *Template {
 // AddParseTree creates a new template with the name and parse tree
 // and associates it with t.
 func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
-	if t.tmpl[name] != nil {
+	if t.common != nil && t.tmpl[name] != nil {
 		return nil, fmt.Errorf("template: redefinition of template %q", name)
 	}
 	nt := t.New(name)
diff --git a/src/pkg/time/format.go b/src/pkg/time/format.go
index 6f92c12..9f210ea 100644
--- a/src/pkg/time/format.go
+++ b/src/pkg/time/format.go
@@ -102,7 +102,7 @@ const (
 // std0x records the std values for "01", "02", ..., "06".
 var std0x = [...]int{stdZeroMonth, stdZeroDay, stdZeroHour12, stdZeroMinute, stdZeroSecond, stdYear}
 
-// startsWithLowerCase reports whether the the string has a lower-case letter at the beginning.
+// startsWithLowerCase reports whether the string has a lower-case letter at the beginning.
 // Its purpose is to prevent matching strings like "Month" when looking for "Mon".
 func startsWithLowerCase(str string) bool {
 	if len(str) == 0 {
@@ -1037,8 +1037,8 @@ func parseTimeZone(value string) (length int, ok bool) {
 	if len(value) < 3 {
 		return 0, false
 	}
-	// Special case 1: This is the only zone with a lower-case letter.
-	if len(value) >= 4 && value[:4] == "ChST" {
+	// Special case 1: ChST and MeST are the only zones with a lower-case letter.
+	if len(value) >= 4 && (value[:4] == "ChST" || value[:4] == "MeST") {
 		return 4, true
 	}
 	// Special case 2: GMT may have an hour offset; treat it specially.
@@ -1240,5 +1240,8 @@ func ParseDuration(s string) (Duration, error) {
 	if neg {
 		f = -f
 	}
+	if f < float64(-1<<63) || f > float64(1<<63-1) {
+		return 0, errors.New("time: overflow parsing duration")
+	}
 	return Duration(f), nil
 }
diff --git a/src/pkg/time/format_test.go b/src/pkg/time/format_test.go
new file mode 100644
index 0000000..3bc8f42
--- /dev/null
+++ b/src/pkg/time/format_test.go
@@ -0,0 +1,511 @@
+// 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.
+
+package time_test
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+	"testing"
+	"testing/quick"
+	. "time"
+)
+
+type TimeFormatTest struct {
+	time           Time
+	formattedValue string
+}
+
+var rfc3339Formats = []TimeFormatTest{
+	{Date(2008, 9, 17, 20, 4, 26, 0, UTC), "2008-09-17T20:04:26Z"},
+	{Date(1994, 9, 17, 20, 4, 26, 0, FixedZone("EST", -18000)), "1994-09-17T20:04:26-05:00"},
+	{Date(2000, 12, 26, 1, 15, 6, 0, FixedZone("OTO", 15600)), "2000-12-26T01:15:06+04:20"},
+}
+
+func TestRFC3339Conversion(t *testing.T) {
+	for _, f := range rfc3339Formats {
+		if f.time.Format(RFC3339) != f.formattedValue {
+			t.Error("RFC3339:")
+			t.Errorf("  want=%+v", f.formattedValue)
+			t.Errorf("  have=%+v", f.time.Format(RFC3339))
+		}
+	}
+}
+
+type FormatTest struct {
+	name   string
+	format string
+	result string
+}
+
+var formatTests = []FormatTest{
+	{"ANSIC", ANSIC, "Wed Feb  4 21:00:57 2009"},
+	{"UnixDate", UnixDate, "Wed Feb  4 21:00:57 PST 2009"},
+	{"RubyDate", RubyDate, "Wed Feb 04 21:00:57 -0800 2009"},
+	{"RFC822", RFC822, "04 Feb 09 21:00 PST"},
+	{"RFC850", RFC850, "Wednesday, 04-Feb-09 21:00:57 PST"},
+	{"RFC1123", RFC1123, "Wed, 04 Feb 2009 21:00:57 PST"},
+	{"RFC1123Z", RFC1123Z, "Wed, 04 Feb 2009 21:00:57 -0800"},
+	{"RFC3339", RFC3339, "2009-02-04T21:00:57-08:00"},
+	{"RFC3339Nano", RFC3339Nano, "2009-02-04T21:00:57.0123456-08:00"},
+	{"Kitchen", Kitchen, "9:00PM"},
+	{"am/pm", "3pm", "9pm"},
+	{"AM/PM", "3PM", "9PM"},
+	{"two-digit year", "06 01 02", "09 02 04"},
+	// Three-letter months and days must not be followed by lower-case letter.
+	{"Janet", "Hi Janet, the Month is January", "Hi Janet, the Month is February"},
+	// Time stamps, Fractional seconds.
+	{"Stamp", Stamp, "Feb  4 21:00:57"},
+	{"StampMilli", StampMilli, "Feb  4 21:00:57.012"},
+	{"StampMicro", StampMicro, "Feb  4 21:00:57.012345"},
+	{"StampNano", StampNano, "Feb  4 21:00:57.012345600"},
+}
+
+func TestFormat(t *testing.T) {
+	// The numeric time represents Thu Feb  4 21:00:57.012345600 PST 2010
+	time := Unix(0, 1233810057012345600)
+	for _, test := range formatTests {
+		result := time.Format(test.format)
+		if result != test.result {
+			t.Errorf("%s expected %q got %q", test.name, test.result, result)
+		}
+	}
+}
+
+func TestFormatShortYear(t *testing.T) {
+	years := []int{
+		-100001, -100000, -99999,
+		-10001, -10000, -9999,
+		-1001, -1000, -999,
+		-101, -100, -99,
+		-11, -10, -9,
+		-1, 0, 1,
+		9, 10, 11,
+		99, 100, 101,
+		999, 1000, 1001,
+		9999, 10000, 10001,
+		99999, 100000, 100001,
+	}
+
+	for _, y := range years {
+		time := Date(y, January, 1, 0, 0, 0, 0, UTC)
+		result := time.Format("2006.01.02")
+		var want string
+		if y < 0 {
+			// The 4 in %04d counts the - sign, so print -y instead
+			// and introduce our own - sign.
+			want = fmt.Sprintf("-%04d.%02d.%02d", -y, 1, 1)
+		} else {
+			want = fmt.Sprintf("%04d.%02d.%02d", y, 1, 1)
+		}
+		if result != want {
+			t.Errorf("(jan 1 %d).Format(\"2006.01.02\") = %q, want %q", y, result, want)
+		}
+	}
+}
+
+type ParseTest struct {
+	name       string
+	format     string
+	value      string
+	hasTZ      bool // contains a time zone
+	hasWD      bool // contains a weekday
+	yearSign   int  // sign of year, -1 indicates the year is not present in the format
+	fracDigits int  // number of digits of fractional second
+}
+
+var parseTests = []ParseTest{
+	{"ANSIC", ANSIC, "Thu Feb  4 21:00:57 2010", false, true, 1, 0},
+	{"UnixDate", UnixDate, "Thu Feb  4 21:00:57 PST 2010", true, true, 1, 0},
+	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
+	{"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true, 1, 0},
+	{"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true, 1, 0},
+	{"RFC1123", RFC1123, "Thu, 04 Feb 2010 22:00:57 PDT", true, true, 1, 0},
+	{"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57 -0800", true, true, 1, 0},
+	{"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00", true, false, 1, 0},
+	{"custom: \"2006-01-02 15:04:05-07\"", "2006-01-02 15:04:05-07", "2010-02-04 21:00:57-08", true, false, 1, 0},
+	// Optional fractional seconds.
+	{"ANSIC", ANSIC, "Thu Feb  4 21:00:57.0 2010", false, true, 1, 1},
+	{"UnixDate", UnixDate, "Thu Feb  4 21:00:57.01 PST 2010", true, true, 1, 2},
+	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57.012 -0800 2010", true, true, 1, 3},
+	{"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57.0123 PST", true, true, 1, 4},
+	{"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57.01234 PST", true, true, 1, 5},
+	{"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57.01234 -0800", true, true, 1, 5},
+	{"RFC3339", RFC3339, "2010-02-04T21:00:57.012345678-08:00", true, false, 1, 9},
+	{"custom: \"2006-01-02 15:04:05\"", "2006-01-02 15:04:05", "2010-02-04 21:00:57.0", false, false, 1, 0},
+	// Amount of white space should not matter.
+	{"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
+	{"ANSIC", ANSIC, "Thu      Feb     4     21:00:57     2010", false, true, 1, 0},
+	// Case should not matter
+	{"ANSIC", ANSIC, "THU FEB 4 21:00:57 2010", false, true, 1, 0},
+	{"ANSIC", ANSIC, "thu feb 4 21:00:57 2010", false, true, 1, 0},
+	// Fractional seconds.
+	{"millisecond", "Mon Jan _2 15:04:05.000 2006", "Thu Feb  4 21:00:57.012 2010", false, true, 1, 3},
+	{"microsecond", "Mon Jan _2 15:04:05.000000 2006", "Thu Feb  4 21:00:57.012345 2010", false, true, 1, 6},
+	{"nanosecond", "Mon Jan _2 15:04:05.000000000 2006", "Thu Feb  4 21:00:57.012345678 2010", false, true, 1, 9},
+	// Leading zeros in other places should not be taken as fractional seconds.
+	{"zero1", "2006.01.02.15.04.05.0", "2010.02.04.21.00.57.0", false, false, 1, 1},
+	{"zero2", "2006.01.02.15.04.05.00", "2010.02.04.21.00.57.01", false, false, 1, 2},
+	// Month and day names only match when not followed by a lower-case letter.
+	{"Janet", "Hi Janet, the Month is January: Jan _2 15:04:05 2006", "Hi Janet, the Month is February: Feb  4 21:00:57 2010", false, true, 1, 0},
+
+	// GMT with offset.
+	{"GMT-8", UnixDate, "Fri Feb  5 05:00:57 GMT-8 2010", true, true, 1, 0},
+
+	// Accept any number of fractional second digits (including none) for .999...
+	// In Go 1, .999... was completely ignored in the format, meaning the first two
+	// cases would succeed, but the next four would not. Go 1.1 accepts all six.
+	{"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
+	{"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
+	{"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
+	{"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
+	{"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
+	{"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
+
+	// issue 4502.
+	{"", StampNano, "Feb  4 21:00:57.012345678", false, false, -1, 9},
+	{"", "Jan _2 15:04:05.999", "Feb  4 21:00:57.012300000", false, false, -1, 4},
+	{"", "Jan _2 15:04:05.999", "Feb  4 21:00:57.012345678", false, false, -1, 9},
+	{"", "Jan _2 15:04:05.999999999", "Feb  4 21:00:57.0123", false, false, -1, 4},
+	{"", "Jan _2 15:04:05.999999999", "Feb  4 21:00:57.012345678", false, false, -1, 9},
+}
+
+func TestParse(t *testing.T) {
+	for _, test := range parseTests {
+		time, err := Parse(test.format, test.value)
+		if err != nil {
+			t.Errorf("%s error: %v", test.name, err)
+		} else {
+			checkTime(time, &test, t)
+		}
+	}
+}
+
+func TestParseInSydney(t *testing.T) {
+	loc, err := LoadLocation("Australia/Sydney")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Check that Parse (and ParseInLocation) understand
+	// that Feb EST and Aug EST are different time zones in Sydney
+	// even though both are called EST.
+	t1, err := ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 EST", loc)
+	if err != nil {
+		t.Fatal(err)
+	}
+	t2 := Date(2013, February, 1, 00, 00, 00, 0, loc)
+	if t1 != t2 {
+		t.Fatalf("ParseInLocation(Feb 01 2013 EST, Sydney) = %v, want %v", t1, t2)
+	}
+	_, offset := t1.Zone()
+	if offset != 11*60*60 {
+		t.Fatalf("ParseInLocation(Feb 01 2013 EST, Sydney).Zone = _, %d, want _, %d", offset, 11*60*60)
+	}
+
+	t1, err = ParseInLocation("Jan 02 2006 MST", "Aug 01 2013 EST", loc)
+	if err != nil {
+		t.Fatal(err)
+	}
+	t2 = Date(2013, August, 1, 00, 00, 00, 0, loc)
+	if t1 != t2 {
+		t.Fatalf("ParseInLocation(Aug 01 2013 EST, Sydney) = %v, want %v", t1, t2)
+	}
+	_, offset = t1.Zone()
+	if offset != 10*60*60 {
+		t.Fatalf("ParseInLocation(Aug 01 2013 EST, Sydney).Zone = _, %d, want _, %d", offset, 10*60*60)
+	}
+}
+
+func TestLoadLocationZipFile(t *testing.T) {
+	ForceZipFileForTesting(true)
+	defer ForceZipFileForTesting(false)
+
+	_, err := LoadLocation("Australia/Sydney")
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+var rubyTests = []ParseTest{
+	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
+	// Ignore the time zone in the test. If it parses, it'll be OK.
+	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0000 2010", false, true, 1, 0},
+	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +0000 2010", false, true, 1, 0},
+	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +1130 2010", false, true, 1, 0},
+}
+
+// Problematic time zone format needs special tests.
+func TestRubyParse(t *testing.T) {
+	for _, test := range rubyTests {
+		time, err := Parse(test.format, test.value)
+		if err != nil {
+			t.Errorf("%s error: %v", test.name, err)
+		} else {
+			checkTime(time, &test, t)
+		}
+	}
+}
+
+func checkTime(time Time, test *ParseTest, t *testing.T) {
+	// The time should be Thu Feb  4 21:00:57 PST 2010
+	if test.yearSign >= 0 && test.yearSign*time.Year() != 2010 {
+		t.Errorf("%s: bad year: %d not %d", test.name, time.Year(), 2010)
+	}
+	if time.Month() != February {
+		t.Errorf("%s: bad month: %s not %s", test.name, time.Month(), February)
+	}
+	if time.Day() != 4 {
+		t.Errorf("%s: bad day: %d not %d", test.name, time.Day(), 4)
+	}
+	if time.Hour() != 21 {
+		t.Errorf("%s: bad hour: %d not %d", test.name, time.Hour(), 21)
+	}
+	if time.Minute() != 0 {
+		t.Errorf("%s: bad minute: %d not %d", test.name, time.Minute(), 0)
+	}
+	if time.Second() != 57 {
+		t.Errorf("%s: bad second: %d not %d", test.name, time.Second(), 57)
+	}
+	// Nanoseconds must be checked against the precision of the input.
+	nanosec, err := strconv.ParseUint("012345678"[:test.fracDigits]+"000000000"[:9-test.fracDigits], 10, 0)
+	if err != nil {
+		panic(err)
+	}
+	if time.Nanosecond() != int(nanosec) {
+		t.Errorf("%s: bad nanosecond: %d not %d", test.name, time.Nanosecond(), nanosec)
+	}
+	name, offset := time.Zone()
+	if test.hasTZ && offset != -28800 {
+		t.Errorf("%s: bad tz offset: %s %d not %d", test.name, name, offset, -28800)
+	}
+	if test.hasWD && time.Weekday() != Thursday {
+		t.Errorf("%s: bad weekday: %s not %s", test.name, time.Weekday(), Thursday)
+	}
+}
+
+func TestFormatAndParse(t *testing.T) {
+	const fmt = "Mon MST " + RFC3339 // all fields
+	f := func(sec int64) bool {
+		t1 := Unix(sec, 0)
+		if t1.Year() < 1000 || t1.Year() > 9999 {
+			// not required to work
+			return true
+		}
+		t2, err := Parse(fmt, t1.Format(fmt))
+		if err != nil {
+			t.Errorf("error: %s", err)
+			return false
+		}
+		if t1.Unix() != t2.Unix() || t1.Nanosecond() != t2.Nanosecond() {
+			t.Errorf("FormatAndParse %d: %q(%d) %q(%d)", sec, t1, t1.Unix(), t2, t2.Unix())
+			return false
+		}
+		return true
+	}
+	f32 := func(sec int32) bool { return f(int64(sec)) }
+	cfg := &quick.Config{MaxCount: 10000}
+
+	// Try a reasonable date first, then the huge ones.
+	if err := quick.Check(f32, cfg); err != nil {
+		t.Fatal(err)
+	}
+	if err := quick.Check(f, cfg); err != nil {
+		t.Fatal(err)
+	}
+}
+
+type ParseTimeZoneTest struct {
+	value  string
+	length int
+	ok     bool
+}
+
+var parseTimeZoneTests = []ParseTimeZoneTest{
+	{"gmt hi there", 0, false},
+	{"GMT hi there", 3, true},
+	{"GMT+12 hi there", 6, true},
+	{"GMT+00 hi there", 3, true}, // 0 or 00 is not a legal offset.
+	{"GMT-5 hi there", 5, true},
+	{"GMT-51 hi there", 3, true},
+	{"ChST hi there", 4, true},
+	{"MeST hi there", 4, true},
+	{"MSDx", 3, true},
+	{"MSDY", 0, false}, // four letters must end in T.
+	{"ESAST hi", 5, true},
+	{"ESASTT hi", 0, false}, // run of upper-case letters too long.
+	{"ESATY hi", 0, false},  // five letters must end in T.
+}
+
+func TestParseTimeZone(t *testing.T) {
+	for _, test := range parseTimeZoneTests {
+		length, ok := ParseTimeZone(test.value)
+		if ok != test.ok {
+			t.Errorf("expected %t for %q got %t", test.ok, test.value, ok)
+		} else if length != test.length {
+			t.Errorf("expected %d for %q got %d", test.length, test.value, length)
+		}
+	}
+}
+
+type ParseErrorTest struct {
+	format string
+	value  string
+	expect string // must appear within the error
+}
+
+var parseErrorTests = []ParseErrorTest{
+	{ANSIC, "Feb  4 21:00:60 2010", "cannot parse"}, // cannot parse Feb as Mon
+	{ANSIC, "Thu Feb  4 21:00:57 @2010", "cannot parse"},
+	{ANSIC, "Thu Feb  4 21:00:60 2010", "second out of range"},
+	{ANSIC, "Thu Feb  4 21:61:57 2010", "minute out of range"},
+	{ANSIC, "Thu Feb  4 24:00:60 2010", "hour out of range"},
+	{"Mon Jan _2 15:04:05.000 2006", "Thu Feb  4 23:00:59x01 2010", "cannot parse"},
+	{"Mon Jan _2 15:04:05.000 2006", "Thu Feb  4 23:00:59.xxx 2010", "cannot parse"},
+	{"Mon Jan _2 15:04:05.000 2006", "Thu Feb  4 23:00:59.-123 2010", "fractional second out of range"},
+	// issue 4502. StampNano requires exactly 9 digits of precision.
+	{StampNano, "Dec  7 11:22:01.000000", `cannot parse ".000000" as ".000000000"`},
+	{StampNano, "Dec  7 11:22:01.0000000000", "extra text: 0"},
+	// issue 4493. Helpful errors.
+	{RFC3339, "2006-01-02T15:04:05Z07:00", `parsing time "2006-01-02T15:04:05Z07:00": extra text: 07:00`},
+	{RFC3339, "2006-01-02T15:04_abc", `parsing time "2006-01-02T15:04_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as ":"`},
+	{RFC3339, "2006-01-02T15:04:05_abc", `parsing time "2006-01-02T15:04:05_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as "Z07:00"`},
+	{RFC3339, "2006-01-02T15:04:05Z_abc", `parsing time "2006-01-02T15:04:05Z_abc": extra text: _abc`},
+}
+
+func TestParseErrors(t *testing.T) {
+	for _, test := range parseErrorTests {
+		_, err := Parse(test.format, test.value)
+		if err == nil {
+			t.Errorf("expected error for %q %q", test.format, test.value)
+		} else if strings.Index(err.Error(), test.expect) < 0 {
+			t.Errorf("expected error with %q for %q %q; got %s", test.expect, test.format, test.value, err)
+		}
+	}
+}
+
+func TestNoonIs12PM(t *testing.T) {
+	noon := Date(0, January, 1, 12, 0, 0, 0, UTC)
+	const expect = "12:00PM"
+	got := noon.Format("3:04PM")
+	if got != expect {
+		t.Errorf("got %q; expect %q", got, expect)
+	}
+	got = noon.Format("03:04PM")
+	if got != expect {
+		t.Errorf("got %q; expect %q", got, expect)
+	}
+}
+
+func TestMidnightIs12AM(t *testing.T) {
+	midnight := Date(0, January, 1, 0, 0, 0, 0, UTC)
+	expect := "12:00AM"
+	got := midnight.Format("3:04PM")
+	if got != expect {
+		t.Errorf("got %q; expect %q", got, expect)
+	}
+	got = midnight.Format("03:04PM")
+	if got != expect {
+		t.Errorf("got %q; expect %q", got, expect)
+	}
+}
+
+func Test12PMIsNoon(t *testing.T) {
+	noon, err := Parse("3:04PM", "12:00PM")
+	if err != nil {
+		t.Fatal("error parsing date:", err)
+	}
+	if noon.Hour() != 12 {
+		t.Errorf("got %d; expect 12", noon.Hour())
+	}
+	noon, err = Parse("03:04PM", "12:00PM")
+	if err != nil {
+		t.Fatal("error parsing date:", err)
+	}
+	if noon.Hour() != 12 {
+		t.Errorf("got %d; expect 12", noon.Hour())
+	}
+}
+
+func Test12AMIsMidnight(t *testing.T) {
+	midnight, err := Parse("3:04PM", "12:00AM")
+	if err != nil {
+		t.Fatal("error parsing date:", err)
+	}
+	if midnight.Hour() != 0 {
+		t.Errorf("got %d; expect 0", midnight.Hour())
+	}
+	midnight, err = Parse("03:04PM", "12:00AM")
+	if err != nil {
+		t.Fatal("error parsing date:", err)
+	}
+	if midnight.Hour() != 0 {
+		t.Errorf("got %d; expect 0", midnight.Hour())
+	}
+}
+
+// Check that a time without a Zone still produces a (numeric) time zone
+// when formatted with MST as a requested zone.
+func TestMissingZone(t *testing.T) {
+	time, err := Parse(RubyDate, "Thu Feb 02 16:10:03 -0500 2006")
+	if err != nil {
+		t.Fatal("error parsing date:", err)
+	}
+	expect := "Thu Feb  2 16:10:03 -0500 2006" // -0500 not EST
+	str := time.Format(UnixDate)               // uses MST as its time zone
+	if str != expect {
+		t.Errorf("got %s; expect %s", str, expect)
+	}
+}
+
+func TestMinutesInTimeZone(t *testing.T) {
+	time, err := Parse(RubyDate, "Mon Jan 02 15:04:05 +0123 2006")
+	if err != nil {
+		t.Fatal("error parsing date:", err)
+	}
+	expected := (1*60 + 23) * 60
+	_, offset := time.Zone()
+	if offset != expected {
+		t.Errorf("ZoneOffset = %d, want %d", offset, expected)
+	}
+}
+
+type SecondsTimeZoneOffsetTest struct {
+	format         string
+	value          string
+	expectedoffset int
+}
+
+var secondsTimeZoneOffsetTests = []SecondsTimeZoneOffsetTest{
+	{"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)},
+	{"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02-00:34:08", -(34*60 + 8)},
+	{"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02+003408", 34*60 + 8},
+	{"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
+	{"2006-01-02T15:04:05Z070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)},
+	{"2006-01-02T15:04:05Z07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
+}
+
+func TestParseSecondsInTimeZone(t *testing.T) {
+	// should accept timezone offsets with seconds like: Zone America/New_York   -4:56:02 -      LMT     1883 Nov 18 12:03:58
+	for _, test := range secondsTimeZoneOffsetTests {
+		time, err := Parse(test.format, test.value)
+		if err != nil {
+			t.Fatal("error parsing date:", err)
+		}
+		_, offset := time.Zone()
+		if offset != test.expectedoffset {
+			t.Errorf("ZoneOffset = %d, want %d", offset, test.expectedoffset)
+		}
+	}
+}
+
+func TestFormatSecondsInTimeZone(t *testing.T) {
+	d := Date(1871, 9, 17, 20, 4, 26, 0, FixedZone("LMT", -(34*60+8)))
+	timestr := d.Format("2006-01-02T15:04:05Z070000")
+	expected := "1871-09-17T20:04:26-003408"
+	if timestr != expected {
+		t.Errorf("Got %s, want %s", timestr, expected)
+	}
+}
diff --git a/src/pkg/time/internal_test.go b/src/pkg/time/internal_test.go
index 87fdd32..2243d36 100644
--- a/src/pkg/time/internal_test.go
+++ b/src/pkg/time/internal_test.go
@@ -29,16 +29,20 @@ func CheckRuntimeTimerOverflow() error {
 	// detection logic in NewTimer: we're testing the underlying
 	// runtime.addtimer function.
 	r := &runtimeTimer{
-		when: nano() + (1<<63 - 1),
+		when: runtimeNano() + (1<<63 - 1),
 		f:    empty,
 		arg:  nil,
 	}
 	startTimer(r)
 
 	timeout := 100 * Millisecond
-	if runtime.GOOS == "windows" {
-		// Allow more time for gobuilder to succeed.
+	switch runtime.GOOS {
+	// Allow more time for gobuilder to succeed.
+	case "windows":
 		timeout = Second
+	case "plan9":
+		// TODO(0intro): We don't know why it is needed.
+		timeout = 3 * Second
 	}
 
 	// Start a goroutine that should send on t.C before the timeout.
@@ -74,7 +78,15 @@ func CheckRuntimeTimerOverflow() error {
 			if Now().After(stop) {
 				return errors.New("runtime timer stuck: overflow in addtimer")
 			}
-			runtime.Gosched()
+			// Issue 6874. This test previously called runtime.Gosched to try to yield
+			// to the goroutine servicing t, however the scheduler has a bias towards the
+			// previously running goroutine in an idle system. Combined with high load due
+			// to all CPUs busy running tests t's goroutine could be delayed beyond the
+			// timeout window.
+			//
+			// Calling runtime.GC() reduces the worst case lantency for scheduling t by 20x
+			// under the current Go 1.3 scheduler.
+			runtime.GC()
 		}
 	}
 }
diff --git a/src/pkg/time/sleep.go b/src/pkg/time/sleep.go
index 4f55beb..6a03f41 100644
--- a/src/pkg/time/sleep.go
+++ b/src/pkg/time/sleep.go
@@ -8,10 +8,8 @@ package time
 // A negative or zero duration causes Sleep to return immediately.
 func Sleep(d Duration)
 
-func nano() int64 {
-	sec, nsec := now()
-	return sec*1e9 + int64(nsec)
-}
+// runtimeNano returns the current value of the runtime clock in nanoseconds.
+func runtimeNano() int64
 
 // Interface to timers implemented in package runtime.
 // Must be in sync with ../runtime/runtime.h:/^struct.Timer$
@@ -29,9 +27,9 @@ type runtimeTimer struct {
 // zero because of an overflow, MaxInt64 is returned.
 func when(d Duration) int64 {
 	if d <= 0 {
-		return nano()
+		return runtimeNano()
 	}
-	t := nano() + int64(d)
+	t := runtimeNano() + int64(d)
 	if t < 0 {
 		t = 1<<63 - 1 // math.MaxInt64
 	}
@@ -92,7 +90,7 @@ func sendTime(now int64, c interface{}) {
 	// the desired behavior when the reader gets behind,
 	// because the sends are periodic.
 	select {
-	case c.(chan Time) <- Unix(0, now):
+	case c.(chan Time) <- Now():
 	default:
 	}
 }
diff --git a/src/pkg/time/sleep_test.go b/src/pkg/time/sleep_test.go
index 4687259..03f8e73 100644
--- a/src/pkg/time/sleep_test.go
+++ b/src/pkg/time/sleep_test.go
@@ -74,26 +74,13 @@ func benchmark(b *testing.B, bench func(n int)) {
 	for i := 0; i < len(garbage); i++ {
 		garbage[i] = AfterFunc(Hour, nil)
 	}
-
-	const batch = 1000
-	P := runtime.GOMAXPROCS(-1)
-	N := int32(b.N / batch)
-
 	b.ResetTimer()
 
-	var wg sync.WaitGroup
-	wg.Add(P)
-
-	for p := 0; p < P; p++ {
-		go func() {
-			for atomic.AddInt32(&N, -1) >= 0 {
-				bench(batch)
-			}
-			wg.Done()
-		}()
-	}
-
-	wg.Wait()
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			bench(1000)
+		}
+	})
 
 	b.StopTimer()
 	for i := 0; i < len(garbage); i++ {
@@ -360,19 +347,18 @@ func TestReset(t *testing.T) {
 // Test that sleeping for an interval so large it overflows does not
 // result in a short sleep duration.
 func TestOverflowSleep(t *testing.T) {
-	const timeout = 25 * Millisecond
 	const big = Duration(int64(1<<63 - 1))
 	select {
 	case <-After(big):
 		t.Fatalf("big timeout fired")
-	case <-After(timeout):
+	case <-After(25 * Millisecond):
 		// OK
 	}
 	const neg = Duration(-1 << 63)
 	select {
 	case <-After(neg):
 		// OK
-	case <-After(timeout):
+	case <-After(1 * Second):
 		t.Fatalf("negative timeout didn't fire")
 	}
 }
@@ -398,6 +384,9 @@ func TestIssue5745(t *testing.T) {
 }
 
 func TestOverflowRuntimeTimer(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping in short mode, see issue 6874")
+	}
 	if err := CheckRuntimeTimerOverflow(); err != nil {
 		t.Fatalf(err.Error())
 	}
diff --git a/src/pkg/time/sys_unix.go b/src/pkg/time/sys_unix.go
index 60a3ce0..379e13d 100644
--- a/src/pkg/time/sys_unix.go
+++ b/src/pkg/time/sys_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 time
 
diff --git a/src/pkg/time/tick.go b/src/pkg/time/tick.go
index b92c339..1900784 100644
--- a/src/pkg/time/tick.go
+++ b/src/pkg/time/tick.go
@@ -17,6 +17,7 @@ type Ticker struct {
 // time with a period specified by the duration argument.
 // It adjusts the intervals or drops ticks to make up for slow receivers.
 // The duration d must be greater than zero; if not, NewTicker will panic.
+// Stop the ticker to release associated resources.
 func NewTicker(d Duration) *Ticker {
 	if d <= 0 {
 		panic(errors.New("non-positive interval for NewTicker"))
@@ -28,7 +29,7 @@ func NewTicker(d Duration) *Ticker {
 	t := &Ticker{
 		C: c,
 		r: runtimeTimer{
-			when:   nano() + int64(d),
+			when:   when(d),
 			period: int64(d),
 			f:      sendTime,
 			arg:    c,
diff --git a/src/pkg/time/tick_test.go b/src/pkg/time/tick_test.go
index d8a086c..32f4740 100644
--- a/src/pkg/time/tick_test.go
+++ b/src/pkg/time/tick_test.go
@@ -48,6 +48,24 @@ func TestTeardown(t *testing.T) {
 	}
 }
 
+// Test the Tick convenience wrapper.
+func TestTick(t *testing.T) {
+	// Test that giving a negative duration returns nil.
+	if got := Tick(-1); got != nil {
+		t.Errorf("Tick(-1) = %v; want nil", got)
+	}
+}
+
+// Test that NewTicker panics when given a duration less than zero.
+func TestNewTickerLtZeroDuration(t *testing.T) {
+	defer func() {
+		if err := recover(); err == nil {
+			t.Errorf("NewTicker(-1) should have panicked")
+		}
+	}()
+	NewTicker(-1)
+}
+
 func BenchmarkTicker(b *testing.B) {
 	ticker := NewTicker(1)
 	b.ResetTimer()
diff --git a/src/pkg/time/time.go b/src/pkg/time/time.go
index c504df7..0a2b091 100644
--- a/src/pkg/time/time.go
+++ b/src/pkg/time/time.go
@@ -934,6 +934,8 @@ func (t *Time) GobDecode(data []byte) error {
 // The time is a quoted string in RFC 3339 format, with sub-second precision added if present.
 func (t Time) MarshalJSON() ([]byte, error) {
 	if y := t.Year(); y < 0 || y >= 10000 {
+		// RFC 3339 is clear that years are 4 digits exactly.
+		// See golang.org/issue/4556#c15 for more discussion.
 		return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
 	}
 	return []byte(t.Format(`"` + RFC3339Nano + `"`)), nil
diff --git a/src/pkg/time/time_test.go b/src/pkg/time/time_test.go
index 334c4b0..4ae7da5 100644
--- a/src/pkg/time/time_test.go
+++ b/src/pkg/time/time_test.go
@@ -12,8 +12,6 @@ import (
 	"math/big"
 	"math/rand"
 	"runtime"
-	"strconv"
-	"strings"
 	"testing"
 	"testing/quick"
 	. "time"
@@ -372,502 +370,6 @@ func TestTruncateRound(t *testing.T) {
 	quick.Check(f4, cfg)
 }
 
-type TimeFormatTest struct {
-	time           Time
-	formattedValue string
-}
-
-var rfc3339Formats = []TimeFormatTest{
-	{Date(2008, 9, 17, 20, 4, 26, 0, UTC), "2008-09-17T20:04:26Z"},
-	{Date(1994, 9, 17, 20, 4, 26, 0, FixedZone("EST", -18000)), "1994-09-17T20:04:26-05:00"},
-	{Date(2000, 12, 26, 1, 15, 6, 0, FixedZone("OTO", 15600)), "2000-12-26T01:15:06+04:20"},
-}
-
-func TestRFC3339Conversion(t *testing.T) {
-	for _, f := range rfc3339Formats {
-		if f.time.Format(RFC3339) != f.formattedValue {
-			t.Error("RFC3339:")
-			t.Errorf("  want=%+v", f.formattedValue)
-			t.Errorf("  have=%+v", f.time.Format(RFC3339))
-		}
-	}
-}
-
-type FormatTest struct {
-	name   string
-	format string
-	result string
-}
-
-var formatTests = []FormatTest{
-	{"ANSIC", ANSIC, "Wed Feb  4 21:00:57 2009"},
-	{"UnixDate", UnixDate, "Wed Feb  4 21:00:57 PST 2009"},
-	{"RubyDate", RubyDate, "Wed Feb 04 21:00:57 -0800 2009"},
-	{"RFC822", RFC822, "04 Feb 09 21:00 PST"},
-	{"RFC850", RFC850, "Wednesday, 04-Feb-09 21:00:57 PST"},
-	{"RFC1123", RFC1123, "Wed, 04 Feb 2009 21:00:57 PST"},
-	{"RFC1123Z", RFC1123Z, "Wed, 04 Feb 2009 21:00:57 -0800"},
-	{"RFC3339", RFC3339, "2009-02-04T21:00:57-08:00"},
-	{"RFC3339Nano", RFC3339Nano, "2009-02-04T21:00:57.0123456-08:00"},
-	{"Kitchen", Kitchen, "9:00PM"},
-	{"am/pm", "3pm", "9pm"},
-	{"AM/PM", "3PM", "9PM"},
-	{"two-digit year", "06 01 02", "09 02 04"},
-	// Three-letter months and days must not be followed by lower-case letter.
-	{"Janet", "Hi Janet, the Month is January", "Hi Janet, the Month is February"},
-	// Time stamps, Fractional seconds.
-	{"Stamp", Stamp, "Feb  4 21:00:57"},
-	{"StampMilli", StampMilli, "Feb  4 21:00:57.012"},
-	{"StampMicro", StampMicro, "Feb  4 21:00:57.012345"},
-	{"StampNano", StampNano, "Feb  4 21:00:57.012345600"},
-}
-
-func TestFormat(t *testing.T) {
-	// The numeric time represents Thu Feb  4 21:00:57.012345600 PST 2010
-	time := Unix(0, 1233810057012345600)
-	for _, test := range formatTests {
-		result := time.Format(test.format)
-		if result != test.result {
-			t.Errorf("%s expected %q got %q", test.name, test.result, result)
-		}
-	}
-}
-
-func TestFormatShortYear(t *testing.T) {
-	years := []int{
-		-100001, -100000, -99999,
-		-10001, -10000, -9999,
-		-1001, -1000, -999,
-		-101, -100, -99,
-		-11, -10, -9,
-		-1, 0, 1,
-		9, 10, 11,
-		99, 100, 101,
-		999, 1000, 1001,
-		9999, 10000, 10001,
-		99999, 100000, 100001,
-	}
-
-	for _, y := range years {
-		time := Date(y, January, 1, 0, 0, 0, 0, UTC)
-		result := time.Format("2006.01.02")
-		var want string
-		if y < 0 {
-			// The 4 in %04d counts the - sign, so print -y instead
-			// and introduce our own - sign.
-			want = fmt.Sprintf("-%04d.%02d.%02d", -y, 1, 1)
-		} else {
-			want = fmt.Sprintf("%04d.%02d.%02d", y, 1, 1)
-		}
-		if result != want {
-			t.Errorf("(jan 1 %d).Format(\"2006.01.02\") = %q, want %q", y, result, want)
-		}
-	}
-}
-
-type ParseTest struct {
-	name       string
-	format     string
-	value      string
-	hasTZ      bool // contains a time zone
-	hasWD      bool // contains a weekday
-	yearSign   int  // sign of year, -1 indicates the year is not present in the format
-	fracDigits int  // number of digits of fractional second
-}
-
-var parseTests = []ParseTest{
-	{"ANSIC", ANSIC, "Thu Feb  4 21:00:57 2010", false, true, 1, 0},
-	{"UnixDate", UnixDate, "Thu Feb  4 21:00:57 PST 2010", true, true, 1, 0},
-	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
-	{"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true, 1, 0},
-	{"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true, 1, 0},
-	{"RFC1123", RFC1123, "Thu, 04 Feb 2010 22:00:57 PDT", true, true, 1, 0},
-	{"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57 -0800", true, true, 1, 0},
-	{"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00", true, false, 1, 0},
-	{"custom: \"2006-01-02 15:04:05-07\"", "2006-01-02 15:04:05-07", "2010-02-04 21:00:57-08", true, false, 1, 0},
-	// Optional fractional seconds.
-	{"ANSIC", ANSIC, "Thu Feb  4 21:00:57.0 2010", false, true, 1, 1},
-	{"UnixDate", UnixDate, "Thu Feb  4 21:00:57.01 PST 2010", true, true, 1, 2},
-	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57.012 -0800 2010", true, true, 1, 3},
-	{"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57.0123 PST", true, true, 1, 4},
-	{"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57.01234 PST", true, true, 1, 5},
-	{"RFC1123Z", RFC1123Z, "Thu, 04 Feb 2010 21:00:57.01234 -0800", true, true, 1, 5},
-	{"RFC3339", RFC3339, "2010-02-04T21:00:57.012345678-08:00", true, false, 1, 9},
-	{"custom: \"2006-01-02 15:04:05\"", "2006-01-02 15:04:05", "2010-02-04 21:00:57.0", false, false, 1, 0},
-	// Amount of white space should not matter.
-	{"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
-	{"ANSIC", ANSIC, "Thu      Feb     4     21:00:57     2010", false, true, 1, 0},
-	// Case should not matter
-	{"ANSIC", ANSIC, "THU FEB 4 21:00:57 2010", false, true, 1, 0},
-	{"ANSIC", ANSIC, "thu feb 4 21:00:57 2010", false, true, 1, 0},
-	// Fractional seconds.
-	{"millisecond", "Mon Jan _2 15:04:05.000 2006", "Thu Feb  4 21:00:57.012 2010", false, true, 1, 3},
-	{"microsecond", "Mon Jan _2 15:04:05.000000 2006", "Thu Feb  4 21:00:57.012345 2010", false, true, 1, 6},
-	{"nanosecond", "Mon Jan _2 15:04:05.000000000 2006", "Thu Feb  4 21:00:57.012345678 2010", false, true, 1, 9},
-	// Leading zeros in other places should not be taken as fractional seconds.
-	{"zero1", "2006.01.02.15.04.05.0", "2010.02.04.21.00.57.0", false, false, 1, 1},
-	{"zero2", "2006.01.02.15.04.05.00", "2010.02.04.21.00.57.01", false, false, 1, 2},
-	// Month and day names only match when not followed by a lower-case letter.
-	{"Janet", "Hi Janet, the Month is January: Jan _2 15:04:05 2006", "Hi Janet, the Month is February: Feb  4 21:00:57 2010", false, true, 1, 0},
-
-	// GMT with offset.
-	{"GMT-8", UnixDate, "Fri Feb  5 05:00:57 GMT-8 2010", true, true, 1, 0},
-
-	// Accept any number of fractional second digits (including none) for .999...
-	// In Go 1, .999... was completely ignored in the format, meaning the first two
-	// cases would succeed, but the next four would not. Go 1.1 accepts all six.
-	{"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
-	{"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57 -0800 PST", true, false, 1, 0},
-	{"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
-	{"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.0123 -0800 PST", true, false, 1, 4},
-	{"", "2006-01-02 15:04:05.9999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
-	{"", "2006-01-02 15:04:05.999999999 -0700 MST", "2010-02-04 21:00:57.012345678 -0800 PST", true, false, 1, 9},
-
-	// issue 4502.
-	{"", StampNano, "Feb  4 21:00:57.012345678", false, false, -1, 9},
-	{"", "Jan _2 15:04:05.999", "Feb  4 21:00:57.012300000", false, false, -1, 4},
-	{"", "Jan _2 15:04:05.999", "Feb  4 21:00:57.012345678", false, false, -1, 9},
-	{"", "Jan _2 15:04:05.999999999", "Feb  4 21:00:57.0123", false, false, -1, 4},
-	{"", "Jan _2 15:04:05.999999999", "Feb  4 21:00:57.012345678", false, false, -1, 9},
-}
-
-func TestParse(t *testing.T) {
-	for _, test := range parseTests {
-		time, err := Parse(test.format, test.value)
-		if err != nil {
-			t.Errorf("%s error: %v", test.name, err)
-		} else {
-			checkTime(time, &test, t)
-		}
-	}
-}
-
-func TestParseInSydney(t *testing.T) {
-	loc, err := LoadLocation("Australia/Sydney")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// Check that Parse (and ParseInLocation) understand
-	// that Feb EST and Aug EST are different time zones in Sydney
-	// even though both are called EST.
-	t1, err := ParseInLocation("Jan 02 2006 MST", "Feb 01 2013 EST", loc)
-	if err != nil {
-		t.Fatal(err)
-	}
-	t2 := Date(2013, February, 1, 00, 00, 00, 0, loc)
-	if t1 != t2 {
-		t.Fatalf("ParseInLocation(Feb 01 2013 EST, Sydney) = %v, want %v", t1, t2)
-	}
-	_, offset := t1.Zone()
-	if offset != 11*60*60 {
-		t.Fatalf("ParseInLocation(Feb 01 2013 EST, Sydney).Zone = _, %d, want _, %d", offset, 11*60*60)
-	}
-
-	t1, err = ParseInLocation("Jan 02 2006 MST", "Aug 01 2013 EST", loc)
-	if err != nil {
-		t.Fatal(err)
-	}
-	t2 = Date(2013, August, 1, 00, 00, 00, 0, loc)
-	if t1 != t2 {
-		t.Fatalf("ParseInLocation(Aug 01 2013 EST, Sydney) = %v, want %v", t1, t2)
-	}
-	_, offset = t1.Zone()
-	if offset != 10*60*60 {
-		t.Fatalf("ParseInLocation(Aug 01 2013 EST, Sydney).Zone = _, %d, want _, %d", offset, 10*60*60)
-	}
-}
-
-func TestLoadLocationZipFile(t *testing.T) {
-	ForceZipFileForTesting(true)
-	defer ForceZipFileForTesting(false)
-
-	_, err := LoadLocation("Australia/Sydney")
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
-var rubyTests = []ParseTest{
-	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
-	// Ignore the time zone in the test. If it parses, it'll be OK.
-	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0000 2010", false, true, 1, 0},
-	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +0000 2010", false, true, 1, 0},
-	{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +1130 2010", false, true, 1, 0},
-}
-
-// Problematic time zone format needs special tests.
-func TestRubyParse(t *testing.T) {
-	for _, test := range rubyTests {
-		time, err := Parse(test.format, test.value)
-		if err != nil {
-			t.Errorf("%s error: %v", test.name, err)
-		} else {
-			checkTime(time, &test, t)
-		}
-	}
-}
-
-func checkTime(time Time, test *ParseTest, t *testing.T) {
-	// The time should be Thu Feb  4 21:00:57 PST 2010
-	if test.yearSign >= 0 && test.yearSign*time.Year() != 2010 {
-		t.Errorf("%s: bad year: %d not %d", test.name, time.Year(), 2010)
-	}
-	if time.Month() != February {
-		t.Errorf("%s: bad month: %s not %s", test.name, time.Month(), February)
-	}
-	if time.Day() != 4 {
-		t.Errorf("%s: bad day: %d not %d", test.name, time.Day(), 4)
-	}
-	if time.Hour() != 21 {
-		t.Errorf("%s: bad hour: %d not %d", test.name, time.Hour(), 21)
-	}
-	if time.Minute() != 0 {
-		t.Errorf("%s: bad minute: %d not %d", test.name, time.Minute(), 0)
-	}
-	if time.Second() != 57 {
-		t.Errorf("%s: bad second: %d not %d", test.name, time.Second(), 57)
-	}
-	// Nanoseconds must be checked against the precision of the input.
-	nanosec, err := strconv.ParseUint("012345678"[:test.fracDigits]+"000000000"[:9-test.fracDigits], 10, 0)
-	if err != nil {
-		panic(err)
-	}
-	if time.Nanosecond() != int(nanosec) {
-		t.Errorf("%s: bad nanosecond: %d not %d", test.name, time.Nanosecond(), nanosec)
-	}
-	name, offset := time.Zone()
-	if test.hasTZ && offset != -28800 {
-		t.Errorf("%s: bad tz offset: %s %d not %d", test.name, name, offset, -28800)
-	}
-	if test.hasWD && time.Weekday() != Thursday {
-		t.Errorf("%s: bad weekday: %s not %s", test.name, time.Weekday(), Thursday)
-	}
-}
-
-func TestFormatAndParse(t *testing.T) {
-	const fmt = "Mon MST " + RFC3339 // all fields
-	f := func(sec int64) bool {
-		t1 := Unix(sec, 0)
-		if t1.Year() < 1000 || t1.Year() > 9999 {
-			// not required to work
-			return true
-		}
-		t2, err := Parse(fmt, t1.Format(fmt))
-		if err != nil {
-			t.Errorf("error: %s", err)
-			return false
-		}
-		if t1.Unix() != t2.Unix() || t1.Nanosecond() != t2.Nanosecond() {
-			t.Errorf("FormatAndParse %d: %q(%d) %q(%d)", sec, t1, t1.Unix(), t2, t2.Unix())
-			return false
-		}
-		return true
-	}
-	f32 := func(sec int32) bool { return f(int64(sec)) }
-	cfg := &quick.Config{MaxCount: 10000}
-
-	// Try a reasonable date first, then the huge ones.
-	if err := quick.Check(f32, cfg); err != nil {
-		t.Fatal(err)
-	}
-	if err := quick.Check(f, cfg); err != nil {
-		t.Fatal(err)
-	}
-}
-
-type ParseTimeZoneTest struct {
-	value  string
-	length int
-	ok     bool
-}
-
-var parseTimeZoneTests = []ParseTimeZoneTest{
-	{"gmt hi there", 0, false},
-	{"GMT hi there", 3, true},
-	{"GMT+12 hi there", 6, true},
-	{"GMT+00 hi there", 3, true}, // 0 or 00 is not a legal offset.
-	{"GMT-5 hi there", 5, true},
-	{"GMT-51 hi there", 3, true},
-	{"ChST hi there", 4, true},
-	{"MSDx", 3, true},
-	{"MSDY", 0, false}, // four letters must end in T.
-	{"ESAST hi", 5, true},
-	{"ESASTT hi", 0, false}, // run of upper-case letters too long.
-	{"ESATY hi", 0, false},  // five letters must end in T.
-}
-
-func TestParseTimeZone(t *testing.T) {
-	for _, test := range parseTimeZoneTests {
-		length, ok := ParseTimeZone(test.value)
-		if ok != test.ok {
-			t.Errorf("expected %t for %q got %t", test.ok, test.value, ok)
-		} else if length != test.length {
-			t.Errorf("expected %d for %q got %d", test.length, test.value, length)
-		}
-	}
-}
-
-type ParseErrorTest struct {
-	format string
-	value  string
-	expect string // must appear within the error
-}
-
-var parseErrorTests = []ParseErrorTest{
-	{ANSIC, "Feb  4 21:00:60 2010", "cannot parse"}, // cannot parse Feb as Mon
-	{ANSIC, "Thu Feb  4 21:00:57 @2010", "cannot parse"},
-	{ANSIC, "Thu Feb  4 21:00:60 2010", "second out of range"},
-	{ANSIC, "Thu Feb  4 21:61:57 2010", "minute out of range"},
-	{ANSIC, "Thu Feb  4 24:00:60 2010", "hour out of range"},
-	{"Mon Jan _2 15:04:05.000 2006", "Thu Feb  4 23:00:59x01 2010", "cannot parse"},
-	{"Mon Jan _2 15:04:05.000 2006", "Thu Feb  4 23:00:59.xxx 2010", "cannot parse"},
-	{"Mon Jan _2 15:04:05.000 2006", "Thu Feb  4 23:00:59.-123 2010", "fractional second out of range"},
-	// issue 4502. StampNano requires exactly 9 digits of precision.
-	{StampNano, "Dec  7 11:22:01.000000", `cannot parse ".000000" as ".000000000"`},
-	{StampNano, "Dec  7 11:22:01.0000000000", "extra text: 0"},
-	// issue 4493. Helpful errors.
-	{RFC3339, "2006-01-02T15:04:05Z07:00", `parsing time "2006-01-02T15:04:05Z07:00": extra text: 07:00`},
-	{RFC3339, "2006-01-02T15:04_abc", `parsing time "2006-01-02T15:04_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as ":"`},
-	{RFC3339, "2006-01-02T15:04:05_abc", `parsing time "2006-01-02T15:04:05_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as "Z07:00"`},
-	{RFC3339, "2006-01-02T15:04:05Z_abc", `parsing time "2006-01-02T15:04:05Z_abc": extra text: _abc`},
-}
-
-func TestParseErrors(t *testing.T) {
-	for _, test := range parseErrorTests {
-		_, err := Parse(test.format, test.value)
-		if err == nil {
-			t.Errorf("expected error for %q %q", test.format, test.value)
-		} else if strings.Index(err.Error(), test.expect) < 0 {
-			t.Errorf("expected error with %q for %q %q; got %s", test.expect, test.format, test.value, err)
-		}
-	}
-}
-
-func TestNoonIs12PM(t *testing.T) {
-	noon := Date(0, January, 1, 12, 0, 0, 0, UTC)
-	const expect = "12:00PM"
-	got := noon.Format("3:04PM")
-	if got != expect {
-		t.Errorf("got %q; expect %q", got, expect)
-	}
-	got = noon.Format("03:04PM")
-	if got != expect {
-		t.Errorf("got %q; expect %q", got, expect)
-	}
-}
-
-func TestMidnightIs12AM(t *testing.T) {
-	midnight := Date(0, January, 1, 0, 0, 0, 0, UTC)
-	expect := "12:00AM"
-	got := midnight.Format("3:04PM")
-	if got != expect {
-		t.Errorf("got %q; expect %q", got, expect)
-	}
-	got = midnight.Format("03:04PM")
-	if got != expect {
-		t.Errorf("got %q; expect %q", got, expect)
-	}
-}
-
-func Test12PMIsNoon(t *testing.T) {
-	noon, err := Parse("3:04PM", "12:00PM")
-	if err != nil {
-		t.Fatal("error parsing date:", err)
-	}
-	if noon.Hour() != 12 {
-		t.Errorf("got %d; expect 12", noon.Hour())
-	}
-	noon, err = Parse("03:04PM", "12:00PM")
-	if err != nil {
-		t.Fatal("error parsing date:", err)
-	}
-	if noon.Hour() != 12 {
-		t.Errorf("got %d; expect 12", noon.Hour())
-	}
-}
-
-func Test12AMIsMidnight(t *testing.T) {
-	midnight, err := Parse("3:04PM", "12:00AM")
-	if err != nil {
-		t.Fatal("error parsing date:", err)
-	}
-	if midnight.Hour() != 0 {
-		t.Errorf("got %d; expect 0", midnight.Hour())
-	}
-	midnight, err = Parse("03:04PM", "12:00AM")
-	if err != nil {
-		t.Fatal("error parsing date:", err)
-	}
-	if midnight.Hour() != 0 {
-		t.Errorf("got %d; expect 0", midnight.Hour())
-	}
-}
-
-// Check that a time without a Zone still produces a (numeric) time zone
-// when formatted with MST as a requested zone.
-func TestMissingZone(t *testing.T) {
-	time, err := Parse(RubyDate, "Thu Feb 02 16:10:03 -0500 2006")
-	if err != nil {
-		t.Fatal("error parsing date:", err)
-	}
-	expect := "Thu Feb  2 16:10:03 -0500 2006" // -0500 not EST
-	str := time.Format(UnixDate)               // uses MST as its time zone
-	if str != expect {
-		t.Errorf("got %s; expect %s", str, expect)
-	}
-}
-
-func TestMinutesInTimeZone(t *testing.T) {
-	time, err := Parse(RubyDate, "Mon Jan 02 15:04:05 +0123 2006")
-	if err != nil {
-		t.Fatal("error parsing date:", err)
-	}
-	expected := (1*60 + 23) * 60
-	_, offset := time.Zone()
-	if offset != expected {
-		t.Errorf("ZoneOffset = %d, want %d", offset, expected)
-	}
-}
-
-type SecondsTimeZoneOffsetTest struct {
-	format         string
-	value          string
-	expectedoffset int
-}
-
-var secondsTimeZoneOffsetTests = []SecondsTimeZoneOffsetTest{
-	{"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)},
-	{"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02-00:34:08", -(34*60 + 8)},
-	{"2006-01-02T15:04:05-070000", "1871-01-01T05:33:02+003408", 34*60 + 8},
-	{"2006-01-02T15:04:05-07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
-	{"2006-01-02T15:04:05Z070000", "1871-01-01T05:33:02-003408", -(34*60 + 8)},
-	{"2006-01-02T15:04:05Z07:00:00", "1871-01-01T05:33:02+00:34:08", 34*60 + 8},
-}
-
-func TestParseSecondsInTimeZone(t *testing.T) {
-	// should accept timezone offsets with seconds like: Zone America/New_York   -4:56:02 -      LMT     1883 Nov 18 12:03:58
-	for _, test := range secondsTimeZoneOffsetTests {
-		time, err := Parse(test.format, test.value)
-		if err != nil {
-			t.Fatal("error parsing date:", err)
-		}
-		_, offset := time.Zone()
-		if offset != test.expectedoffset {
-			t.Errorf("ZoneOffset = %d, want %d", offset, test.expectedoffset)
-		}
-	}
-}
-
-func TestFormatSecondsInTimeZone(t *testing.T) {
-	d := Date(1871, 9, 17, 20, 4, 26, 0, FixedZone("LMT", -(34*60+8)))
-	timestr := d.Format("2006-01-02T15:04:05Z070000")
-	expected := "1871-09-17T20:04:26-003408"
-	if timestr != expected {
-		t.Errorf("Got %s, want %s", timestr, expected)
-	}
-}
-
 type ISOWeekTest struct {
 	year       int // year
 	month, day int // month and day
@@ -1340,6 +842,7 @@ var parseDurationTests = []struct {
 	{"-.", false, 0},
 	{".s", false, 0},
 	{"+.s", false, 0},
+	{"3000000h", false, 0}, // overflow
 }
 
 func TestParseDuration(t *testing.T) {
@@ -1461,6 +964,60 @@ func TestSub(t *testing.T) {
 	}
 }
 
+var nsDurationTests = []struct {
+	d    Duration
+	want int64
+}{
+	{Duration(-1000), -1000},
+	{Duration(-1), -1},
+	{Duration(1), 1},
+	{Duration(1000), 1000},
+}
+
+func TestDurationNanoseconds(t *testing.T) {
+	for _, tt := range nsDurationTests {
+		if got := tt.d.Nanoseconds(); got != tt.want {
+			t.Errorf("d.Nanoseconds() = %d; want: %d", got, tt.want)
+		}
+	}
+}
+
+var minDurationTests = []struct {
+	d    Duration
+	want float64
+}{
+	{Duration(-60000000000), -1},
+	{Duration(-1), -1 / 60e9},
+	{Duration(1), 1 / 60e9},
+	{Duration(60000000000), 1},
+}
+
+func TestDurationMinutes(t *testing.T) {
+	for _, tt := range minDurationTests {
+		if got := tt.d.Minutes(); got != tt.want {
+			t.Errorf("d.Minutes() = %g; want: %g", got, tt.want)
+		}
+	}
+}
+
+var hourDurationTests = []struct {
+	d    Duration
+	want float64
+}{
+	{Duration(-3600000000000), -1},
+	{Duration(-1), -1 / 3600e9},
+	{Duration(1), 1 / 3600e9},
+	{Duration(3600000000000), 1},
+}
+
+func TestDurationHours(t *testing.T) {
+	for _, tt := range hourDurationTests {
+		if got := tt.d.Hours(); got != tt.want {
+			t.Errorf("d.Hours() = %g; want: %g", got, tt.want)
+		}
+	}
+}
+
 func BenchmarkNow(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		t = Now()
diff --git a/src/pkg/time/zoneinfo.go b/src/pkg/time/zoneinfo.go
index 1c61862..c8e53a2 100644
--- a/src/pkg/time/zoneinfo.go
+++ b/src/pkg/time/zoneinfo.go
@@ -45,6 +45,13 @@ type zoneTrans struct {
 	isstd, isutc bool  // ignored - no idea what these mean
 }
 
+// alpha and omega are the beginning and end of time for zone
+// transitions.
+const (
+	alpha = -1 << 63  // math.MinInt64
+	omega = 1<<63 - 1 // math.MaxInt64
+)
+
 // UTC represents Universal Coordinated Time (UTC).
 var UTC *Location = &utcLoc
 
@@ -83,9 +90,9 @@ func FixedZone(name string, offset int) *Location {
 	l := &Location{
 		name:       name,
 		zone:       []zone{{name, offset, false}},
-		tx:         []zoneTrans{{-1 << 63, 0, false, false}},
-		cacheStart: -1 << 63,
-		cacheEnd:   1<<63 - 1,
+		tx:         []zoneTrans{{alpha, 0, false, false}},
+		cacheStart: alpha,
+		cacheEnd:   omega,
 	}
 	l.cacheZone = &l.zone[0]
 	return l
@@ -101,12 +108,12 @@ func FixedZone(name string, offset int) *Location {
 func (l *Location) lookup(sec int64) (name string, offset int, isDST bool, start, end int64) {
 	l = l.get()
 
-	if len(l.tx) == 0 {
+	if len(l.zone) == 0 {
 		name = "UTC"
 		offset = 0
 		isDST = false
-		start = -1 << 63
-		end = 1<<63 - 1
+		start = alpha
+		end = omega
 		return
 	}
 
@@ -119,10 +126,24 @@ func (l *Location) lookup(sec int64) (name string, offset int, isDST bool, start
 		return
 	}
 
+	if len(l.tx) == 0 || sec < l.tx[0].when {
+		zone := &l.zone[l.lookupFirstZone()]
+		name = zone.name
+		offset = zone.offset
+		isDST = zone.isDST
+		start = alpha
+		if len(l.tx) > 0 {
+			end = l.tx[0].when
+		} else {
+			end = omega
+		}
+		return
+	}
+
 	// Binary search for entry with largest time <= sec.
 	// Not using sort.Search to avoid dependencies.
 	tx := l.tx
-	end = 1<<63 - 1
+	end = omega
 	lo := 0
 	hi := len(tx)
 	for hi-lo > 1 {
@@ -144,6 +165,58 @@ func (l *Location) lookup(sec int64) (name string, offset int, isDST bool, start
 	return
 }
 
+// lookupFirstZone returns the index of the time zone to use for times
+// before the first transition time, or when there are no transition
+// times.
+//
+// The reference implementation in localtime.c from
+// http://www.iana.org/time-zones/repository/releases/tzcode2013g.tar.gz
+// implements the following algorithm for these cases:
+// 1) If the first zone is unused by the transitions, use it.
+// 2) Otherwise, if there are transition times, and the first
+//    transition is to a zone in daylight time, find the first
+//    non-daylight-time zone before and closest to the first transition
+//    zone.
+// 3) Otherwise, use the first zone that is not daylight time, if
+//    there is one.
+// 4) Otherwise, use the first zone.
+func (l *Location) lookupFirstZone() int {
+	// Case 1.
+	if !l.firstZoneUsed() {
+		return 0
+	}
+
+	// Case 2.
+	if len(l.tx) > 0 && l.zone[l.tx[0].index].isDST {
+		for zi := int(l.tx[0].index) - 1; zi >= 0; zi-- {
+			if !l.zone[zi].isDST {
+				return zi
+			}
+		}
+	}
+
+	// Case 3.
+	for zi := range l.zone {
+		if !l.zone[zi].isDST {
+			return zi
+		}
+	}
+
+	// Case 4.
+	return 0
+}
+
+// firstZoneUsed returns whether the first zone is used by some
+// transition.
+func (l *Location) firstZoneUsed() bool {
+	for _, tx := range l.tx {
+		if tx.index == 0 {
+			return true
+		}
+	}
+	return false
+}
+
 // lookupName returns information about the time zone with
 // the given name (such as "EST") at the given pseudo-Unix time
 // (what the given time of day would be in UTC).
diff --git a/src/pkg/time/zoneinfo_plan9.go b/src/pkg/time/zoneinfo_plan9.go
index 0e8f381..4bb0cb3 100644
--- a/src/pkg/time/zoneinfo_plan9.go
+++ b/src/pkg/time/zoneinfo_plan9.go
@@ -100,7 +100,7 @@ func loadZoneDataPlan9(s string) (l *Location, err error) {
 	for i := range tx {
 		if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
 			l.cacheStart = tx[i].when
-			l.cacheEnd = 1<<63 - 1
+			l.cacheEnd = omega
 			if i+1 < len(tx) {
 				l.cacheEnd = tx[i+1].when
 			}
diff --git a/src/pkg/time/zoneinfo_read.go b/src/pkg/time/zoneinfo_read.go
index 7714aa9..de9ebb4 100644
--- a/src/pkg/time/zoneinfo_read.go
+++ b/src/pkg/time/zoneinfo_read.go
@@ -68,7 +68,7 @@ func loadZoneData(bytes []byte) (l *Location, err error) {
 
 	// 1-byte version, then 15 bytes of padding
 	var p []byte
-	if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' {
+	if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' && p[0] != '3' {
 		return nil, badData
 	}
 
@@ -123,7 +123,7 @@ func loadZoneData(bytes []byte) (l *Location, err error) {
 		return nil, badData
 	}
 
-	// If version == 2, the entire file repeats, this time using
+	// If version == 2 or 3, the entire file repeats, this time using
 	// 8-byte ints for txtimes and leap seconds.
 	// We won't need those until 2106.
 
@@ -173,7 +173,7 @@ func loadZoneData(bytes []byte) (l *Location, err error) {
 	if len(tx) == 0 {
 		// Build fake transition to cover all time.
 		// This happens in fixed locations like "Etc/GMT0".
-		tx = append(tx, zoneTrans{when: -1 << 63, index: 0})
+		tx = append(tx, zoneTrans{when: alpha, index: 0})
 	}
 
 	// Committed to succeed.
@@ -185,7 +185,7 @@ func loadZoneData(bytes []byte) (l *Location, err error) {
 	for i := range tx {
 		if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
 			l.cacheStart = tx[i].when
-			l.cacheEnd = 1<<63 - 1
+			l.cacheEnd = omega
 			if i+1 < len(tx) {
 				l.cacheEnd = tx[i+1].when
 			}
diff --git a/src/pkg/time/zoneinfo_test.go b/src/pkg/time/zoneinfo_test.go
new file mode 100644
index 0000000..4ca7fad
--- /dev/null
+++ b/src/pkg/time/zoneinfo_test.go
@@ -0,0 +1,63 @@
+// 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 time_test
+
+import (
+	"testing"
+	"time"
+)
+
+func TestVersion3(t *testing.T) {
+	time.ForceZipFileForTesting(true)
+	defer time.ForceZipFileForTesting(false)
+	_, err := time.LoadLocation("Asia/Jerusalem")
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+// Test that we get the correct results for times before the first
+// transition time.  To do this we explicitly check early dates in a
+// couple of specific timezones.
+func TestFirstZone(t *testing.T) {
+	time.ForceZipFileForTesting(true)
+	defer time.ForceZipFileForTesting(false)
+
+	const format = "Mon, 02 Jan 2006 15:04:05 -0700 (MST)"
+	var tests = []struct {
+		zone  string
+		unix  int64
+		want1 string
+		want2 string
+	}{
+		{
+			"PST8PDT",
+			-1633269601,
+			"Sun, 31 Mar 1918 01:59:59 -0800 (PST)",
+			"Sun, 31 Mar 1918 03:00:00 -0700 (PDT)",
+		},
+		{
+			"Pacific/Fakaofo",
+			1325242799,
+			"Thu, 29 Dec 2011 23:59:59 -1100 (TKT)",
+			"Sat, 31 Dec 2011 00:00:00 +1300 (TKT)",
+		},
+	}
+
+	for _, test := range tests {
+		z, err := time.LoadLocation(test.zone)
+		if err != nil {
+			t.Fatal(err)
+		}
+		s := time.Unix(test.unix, 0).In(z).Format(format)
+		if s != test.want1 {
+			t.Errorf("for %s %d got %q want %q", test.zone, test.unix, s, test.want1)
+		}
+		s = time.Unix(test.unix+1, 0).In(z).Format(format)
+		if s != test.want2 {
+			t.Errorf("for %s %d got %q want %q", test.zone, test.unix, s, test.want2)
+		}
+	}
+}
diff --git a/src/pkg/time/zoneinfo_unix.go b/src/pkg/time/zoneinfo_unix.go
index fc5ae89..ab7e461 100644
--- a/src/pkg/time/zoneinfo_unix.go
+++ b/src/pkg/time/zoneinfo_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
 
 // Parse "zoneinfo" time zone file.
 // This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
diff --git a/src/pkg/time/zoneinfo_windows.go b/src/pkg/time/zoneinfo_windows.go
index be4e5c1..6046743 100644
--- a/src/pkg/time/zoneinfo_windows.go
+++ b/src/pkg/time/zoneinfo_windows.go
@@ -54,7 +54,7 @@ func matchZoneKey(zones syscall.Handle, kname string, stdname, dstname string) (
 	if err != nil {
 		return false, err
 	}
-	if s != dstname {
+	if s != dstname && dstname != stdname {
 		return false, nil
 	}
 	return true, nil
@@ -90,7 +90,7 @@ func toEnglishName(stdname, dstname string) (string, error) {
 	return "", errors.New(`English name for time zone "` + stdname + `" not found in registry`)
 }
 
-// extractCAPS exracts capital letters from description desc.
+// extractCAPS extracts capital letters from description desc.
 func extractCAPS(desc string) string {
 	var short []rune
 	for _, c := range desc {
@@ -165,8 +165,8 @@ func initLocalFromTZI(i *syscall.Timezoneinformation) {
 	if nzone == 1 {
 		// No daylight savings.
 		std.offset = -int(i.Bias) * 60
-		l.cacheStart = -1 << 63
-		l.cacheEnd = 1<<63 - 1
+		l.cacheStart = alpha
+		l.cacheEnd = omega
 		l.cacheZone = std
 		l.tx = make([]zoneTrans, 1)
 		l.tx[0].when = l.cacheStart
diff --git a/src/pkg/unicode/letter.go b/src/pkg/unicode/letter.go
index fadaa57..977bd2b 100644
--- a/src/pkg/unicode/letter.go
+++ b/src/pkg/unicode/letter.go
@@ -74,7 +74,7 @@ const (
 
 type d [MaxCase]rune // to make the CaseRanges text shorter
 
-// If the Delta field of a CaseRange is UpperLower or LowerUpper, it means
+// If the Delta field of a CaseRange is UpperLower, it means
 // this CaseRange represents a sequence of the form (say)
 // Upper Lower Upper Lower.
 const (
@@ -316,7 +316,7 @@ type foldPair struct {
 // SimpleFold iterates over Unicode code points equivalent under
 // the Unicode-defined simple case folding.  Among the code points
 // equivalent to rune (including rune itself), SimpleFold returns the
-// smallest rune >= r if one exists, or else the smallest rune >= 0.
+// smallest rune > r if one exists, or else the smallest rune >= 0.
 //
 // For example:
 //	SimpleFold('A') = 'a'
diff --git a/src/pkg/unicode/letter_test.go b/src/pkg/unicode/letter_test.go
index e4d5572..4ee11fb 100644
--- a/src/pkg/unicode/letter_test.go
+++ b/src/pkg/unicode/letter_test.go
@@ -387,32 +387,20 @@ func TestTurkishCase(t *testing.T) {
 }
 
 var simpleFoldTests = []string{
-	// SimpleFold could order its returned slices in any order it wants,
-	// but we know it orders them in increasing order starting at in
-	// and looping around from MaxRune to 0.
+	// SimpleFold(x) returns the next equivalent rune > x or wraps
+	// around to smaller values.
 
 	// Easy cases.
 	"Aa",
-	"aA",
 	"δΔ",
-	"Δδ",
 
 	// ASCII special cases.
 	"KkK",
-	"kKK",
-	"KKk",
 	"Ssſ",
-	"sſS",
-	"ſSs",
 
 	// Non-ASCII special cases.
 	"ρϱΡ",
-	"ϱΡρ",
-	"Ρρϱ",
 	"ͅΙιι",
-	"Ιιιͅ",
-	"ιιͅΙ",
-	"ιͅΙι",
 
 	// Extra special cases: has lower/upper but no case fold.
 	"İ",
diff --git a/src/pkg/unicode/maketables.go b/src/pkg/unicode/maketables.go
index e5ed08b..8116ab8 100644
--- a/src/pkg/unicode/maketables.go
+++ b/src/pkg/unicode/maketables.go
@@ -40,7 +40,7 @@ func main() {
 var dataURL = flag.String("data", "", "full URL for UnicodeData.txt; defaults to --url/UnicodeData.txt")
 var casefoldingURL = flag.String("casefolding", "", "full URL for CaseFolding.txt; defaults to --url/CaseFolding.txt")
 var url = flag.String("url",
-	"http://www.unicode.org/Public/6.2.0/ucd/",
+	"http://www.unicode.org/Public/6.3.0/ucd/",
 	"URL of Unicode database directory")
 var tablelist = flag.String("tables",
 	"all",
@@ -386,7 +386,11 @@ func loadCasefold() {
 	}
 }
 
-const progHeader = `// Generated by running
+const progHeader = `// 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.
+
+// Generated by running
 //	maketables --tables=%s --data=%s --casefolding=%s
 // DO NOT EDIT
 
diff --git a/src/pkg/unicode/script_test.go b/src/pkg/unicode/script_test.go
index 395cc71..e2ba001 100644
--- a/src/pkg/unicode/script_test.go
+++ b/src/pkg/unicode/script_test.go
@@ -182,7 +182,7 @@ var inPropTest = []T{
 	{0x0EC4, "Logical_Order_Exception"},
 	{0x2FFFF, "Noncharacter_Code_Point"},
 	{0x065E, "Other_Alphabetic"},
-	{0x2069, "Other_Default_Ignorable_Code_Point"},
+	{0x2065, "Other_Default_Ignorable_Code_Point"},
 	{0x0BD7, "Other_Grapheme_Extend"},
 	{0x0387, "Other_ID_Continue"},
 	{0x212E, "Other_ID_Start"},
diff --git a/src/pkg/unicode/tables.go b/src/pkg/unicode/tables.go
index 939c41d..5670d1c 100644
--- a/src/pkg/unicode/tables.go
+++ b/src/pkg/unicode/tables.go
@@ -1,11 +1,15 @@
+// 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.
+
 // Generated by running
-//	maketables --tables=all --data=http://www.unicode.org/Public/6.2.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/6.2.0/ucd/CaseFolding.txt
+//	maketables --tables=all --data=http://www.unicode.org/Public/6.3.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/6.3.0/ucd/CaseFolding.txt
 // DO NOT EDIT
 
 package unicode
 
 // Version is the Unicode edition from which the tables are derived.
-const Version = "6.2.0"
+const Version = "6.3.0"
 
 // Categories is the set of Unicode category tables.
 var Categories = map[string]*RangeTable{
@@ -53,11 +57,12 @@ var _C = &RangeTable{
 		{0x007f, 0x009f, 1},
 		{0x00ad, 0x0600, 1363},
 		{0x0601, 0x0604, 1},
-		{0x06dd, 0x070f, 50},
+		{0x061c, 0x06dd, 193},
+		{0x070f, 0x180e, 4351},
 		{0x200b, 0x200f, 1},
 		{0x202a, 0x202e, 1},
 		{0x2060, 0x2064, 1},
-		{0x206a, 0x206f, 1},
+		{0x2066, 0x206f, 1},
 		{0xd800, 0xf8ff, 1},
 		{0xfeff, 0xfff9, 250},
 		{0xfffa, 0xfffb, 1},
@@ -85,11 +90,12 @@ var _Cf = &RangeTable{
 	R16: []Range16{
 		{0x00ad, 0x0600, 1363},
 		{0x0601, 0x0604, 1},
-		{0x06dd, 0x070f, 50},
+		{0x061c, 0x06dd, 193},
+		{0x070f, 0x180e, 4351},
 		{0x200b, 0x200f, 1},
 		{0x202a, 0x202e, 1},
 		{0x2060, 0x2064, 1},
-		{0x206a, 0x206f, 1},
+		{0x2066, 0x206f, 1},
 		{0xfeff, 0xfff9, 250},
 		{0xfffa, 0xfffb, 1},
 	},
@@ -1545,7 +1551,7 @@ var _Mc = &RangeTable{
 		{0x1933, 0x1938, 1},
 		{0x19b0, 0x19c0, 1},
 		{0x19c8, 0x19c9, 1},
-		{0x1a19, 0x1a1b, 1},
+		{0x1a19, 0x1a1a, 1},
 		{0x1a55, 0x1a57, 2},
 		{0x1a61, 0x1a63, 2},
 		{0x1a64, 0x1a6d, 9},
@@ -1717,8 +1723,8 @@ var _Mn = &RangeTable{
 		{0x1932, 0x1939, 7},
 		{0x193a, 0x193b, 1},
 		{0x1a17, 0x1a18, 1},
-		{0x1a56, 0x1a58, 2},
-		{0x1a59, 0x1a5e, 1},
+		{0x1a1b, 0x1a56, 59},
+		{0x1a58, 0x1a5e, 1},
 		{0x1a60, 0x1a62, 2},
 		{0x1a65, 0x1a6c, 1},
 		{0x1a73, 0x1a7c, 1},
@@ -2086,6 +2092,7 @@ var _P = &RangeTable{
 		{0x2053, 0x205e, 1},
 		{0x207d, 0x207e, 1},
 		{0x208d, 0x208e, 1},
+		{0x2308, 0x230b, 1},
 		{0x2329, 0x232a, 1},
 		{0x2768, 0x2775, 1},
 		{0x27c5, 0x27c6, 1},
@@ -2183,7 +2190,8 @@ var _Pe = &RangeTable{
 		{0x007d, 0x0f3b, 3774},
 		{0x0f3d, 0x169c, 1887},
 		{0x2046, 0x207e, 56},
-		{0x208e, 0x232a, 668},
+		{0x208e, 0x2309, 635},
+		{0x230b, 0x232a, 31},
 		{0x2769, 0x2775, 2},
 		{0x27c6, 0x27e7, 33},
 		{0x27e9, 0x27ef, 2},
@@ -2360,7 +2368,8 @@ var _Ps = &RangeTable{
 		{0x0f3c, 0x169b, 1887},
 		{0x201a, 0x201e, 4},
 		{0x2045, 0x207d, 56},
-		{0x208d, 0x2329, 668},
+		{0x208d, 0x2308, 635},
+		{0x230a, 0x2329, 31},
 		{0x2768, 0x2774, 2},
 		{0x27c5, 0x27e6, 33},
 		{0x27e8, 0x27ee, 2},
@@ -2450,7 +2459,8 @@ var _S = &RangeTable{
 		{0x2141, 0x2144, 1},
 		{0x214a, 0x214d, 1},
 		{0x214f, 0x2190, 65},
-		{0x2191, 0x2328, 1},
+		{0x2191, 0x2307, 1},
+		{0x230c, 0x2328, 1},
 		{0x232b, 0x23f3, 1},
 		{0x2400, 0x2426, 1},
 		{0x2440, 0x244a, 1},
@@ -2630,7 +2640,6 @@ var _Sm = &RangeTable{
 		{0x21cf, 0x21d2, 3},
 		{0x21d4, 0x21f4, 32},
 		{0x21f5, 0x22ff, 1},
-		{0x2308, 0x230b, 1},
 		{0x2320, 0x2321, 1},
 		{0x237c, 0x239b, 31},
 		{0x239c, 0x23b3, 1},
@@ -2818,8 +2827,8 @@ var _So = &RangeTable{
 var _Z = &RangeTable{
 	R16: []Range16{
 		{0x0020, 0x00a0, 128},
-		{0x1680, 0x180e, 398},
-		{0x2000, 0x200a, 1},
+		{0x1680, 0x2000, 2432},
+		{0x2001, 0x200a, 1},
 		{0x2028, 0x2029, 1},
 		{0x202f, 0x205f, 48},
 		{0x3000, 0x3000, 1},
@@ -2842,8 +2851,8 @@ var _Zp = &RangeTable{
 var _Zs = &RangeTable{
 	R16: []Range16{
 		{0x0020, 0x00a0, 128},
-		{0x1680, 0x180e, 398},
-		{0x2000, 0x200a, 1},
+		{0x1680, 0x2000, 2432},
+		{0x2001, 0x200a, 1},
 		{0x202f, 0x205f, 48},
 		{0x3000, 0x3000, 1},
 	},
@@ -2902,7 +2911,7 @@ var (
 )
 
 // Generated by running
-//	maketables --scripts=all --url=http://www.unicode.org/Public/6.2.0/ucd/
+//	maketables --scripts=all --url=http://www.unicode.org/Public/6.3.0/ucd/
 // DO NOT EDIT
 
 // Scripts is the set of Unicode script tables.
@@ -3016,6 +3025,7 @@ var _Arabic = &RangeTable{
 		{0x0600, 0x0604, 1},
 		{0x0606, 0x060b, 1},
 		{0x060d, 0x061a, 1},
+		{0x061c, 0x061c, 1},
 		{0x061e, 0x061e, 1},
 		{0x0620, 0x063f, 1},
 		{0x0641, 0x064a, 1},
@@ -3245,7 +3255,7 @@ var _Common = &RangeTable{
 		{0x1cf5, 0x1cf6, 1},
 		{0x2000, 0x200b, 1},
 		{0x200e, 0x2064, 1},
-		{0x206a, 0x2070, 1},
+		{0x2066, 0x2070, 1},
 		{0x2074, 0x207e, 1},
 		{0x2080, 0x208e, 1},
 		{0x20a0, 0x20ba, 1},
@@ -3281,6 +3291,7 @@ var _Common = &RangeTable{
 		{0xa700, 0xa721, 1},
 		{0xa788, 0xa78a, 1},
 		{0xa830, 0xa839, 1},
+		{0xa9cf, 0xa9cf, 1},
 		{0xfd3e, 0xfd3f, 1},
 		{0xfdfd, 0xfdfd, 1},
 		{0xfe10, 0xfe19, 1},
@@ -3710,7 +3721,7 @@ var _Inscriptional_Parthian = &RangeTable{
 var _Javanese = &RangeTable{
 	R16: []Range16{
 		{0xa980, 0xa9cd, 1},
-		{0xa9cf, 0xa9d9, 1},
+		{0xa9d0, 0xa9d9, 1},
 		{0xa9de, 0xa9df, 1},
 	},
 }
@@ -4403,7 +4414,7 @@ var (
 )
 
 // Generated by running
-//	maketables --props=all --url=http://www.unicode.org/Public/6.2.0/ucd/
+//	maketables --props=all --url=http://www.unicode.org/Public/6.3.0/ucd/
 // DO NOT EDIT
 
 // Properties is the set of Unicode property tables.
@@ -4453,8 +4464,10 @@ var _ASCII_Hex_Digit = &RangeTable{
 
 var _Bidi_Control = &RangeTable{
 	R16: []Range16{
+		{0x061c, 0x061c, 1},
 		{0x200e, 0x200f, 1},
 		{0x202a, 0x202e, 1},
+		{0x2066, 0x2069, 1},
 	},
 }
 
@@ -4931,7 +4944,7 @@ var _Other_Default_Ignorable_Code_Point = &RangeTable{
 		{0x034f, 0x034f, 1},
 		{0x115f, 0x1160, 1},
 		{0x17b4, 0x17b5, 1},
-		{0x2065, 0x2069, 1},
+		{0x2065, 0x2065, 1},
 		{0x3164, 0x3164, 1},
 		{0xffa0, 0xffa0, 1},
 		{0xfff0, 0xfff8, 1},
@@ -5053,6 +5066,7 @@ var _Other_Math = &RangeTable{
 		{0x21d5, 0x21db, 1},
 		{0x21dd, 0x21dd, 1},
 		{0x21e4, 0x21e5, 1},
+		{0x2308, 0x230b, 1},
 		{0x23b4, 0x23b5, 1},
 		{0x23b7, 0x23b7, 1},
 		{0x23d0, 0x23d0, 1},
@@ -5440,7 +5454,6 @@ var _White_Space = &RangeTable{
 		{0x0085, 0x0085, 1},
 		{0x00a0, 0x00a0, 1},
 		{0x1680, 0x1680, 1},
-		{0x180e, 0x180e, 1},
 		{0x2000, 0x200a, 1},
 		{0x2028, 0x2029, 1},
 		{0x202f, 0x202f, 1},
@@ -5487,7 +5500,7 @@ var (
 )
 
 // Generated by running
-//	maketables --data=http://www.unicode.org/Public/6.2.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/6.2.0/ucd/CaseFolding.txt
+//	maketables --data=http://www.unicode.org/Public/6.3.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/6.3.0/ucd/CaseFolding.txt
 // DO NOT EDIT
 
 // CaseRanges is the table describing case mappings for all letters with
@@ -6372,7 +6385,7 @@ var foldMn = &RangeTable{
 // If there is no entry for a script name, there are no such points.
 var FoldScript = map[string]*RangeTable{}
 
-// Range entries: 3462 16-bit, 832 32-bit, 4294 total.
-// Range bytes: 20772 16-bit, 9984 32-bit, 30756 total.
+// Range entries: 3471 16-bit, 832 32-bit, 4303 total.
+// Range bytes: 20826 16-bit, 9984 32-bit, 30810 total.
 
 // Fold orbit bytes: 63 pairs, 252 bytes
diff --git a/src/pkg/unicode/utf16/utf16.go b/src/pkg/unicode/utf16/utf16.go
index 903e401..c0e47c5 100644
--- a/src/pkg/unicode/utf16/utf16.go
+++ b/src/pkg/unicode/utf16/utf16.go
@@ -36,7 +36,7 @@ func IsSurrogate(r rune) bool {
 // the Unicode replacement code point U+FFFD.
 func DecodeRune(r1, r2 rune) rune {
 	if surr1 <= r1 && r1 < surr2 && surr2 <= r2 && r2 < surr3 {
-		return (rune(r1)-surr1)<<10 | (rune(r2) - surr2) + 0x10000
+		return (r1-surr1)<<10 | (r2 - surr2) + 0x10000
 	}
 	return replacementChar
 }
diff --git a/src/pkg/unicode/utf16/utf16_test.go b/src/pkg/unicode/utf16/utf16_test.go
index ee16a30..3dca472 100644
--- a/src/pkg/unicode/utf16/utf16_test.go
+++ b/src/pkg/unicode/utf16/utf16_test.go
@@ -99,3 +99,51 @@ func TestDecode(t *testing.T) {
 		}
 	}
 }
+
+var decodeRuneTests = []struct {
+	r1, r2 rune
+	want   rune
+}{
+	{0xd800, 0xdc00, 0x10000},
+	{0xd800, 0xdc01, 0x10001},
+	{0xd808, 0xdf45, 0x12345},
+	{0xdbff, 0xdfff, 0x10ffff},
+	{0xd800, 'a', 0xfffd}, // illegal, replacement rune substituted
+}
+
+func TestDecodeRune(t *testing.T) {
+	for i, tt := range decodeRuneTests {
+		got := DecodeRune(tt.r1, tt.r2)
+		if got != tt.want {
+			t.Errorf("%d: DecodeRune(%q, %q) = %v; want %v", i, tt.r1, tt.r2, got, tt.want)
+		}
+	}
+}
+
+var surrogateTests = []struct {
+	r    rune
+	want bool
+}{
+	// from http://en.wikipedia.org/wiki/UTF-16
+	{'\u007A', false},     // LATIN SMALL LETTER Z
+	{'\u6C34', false},     // CJK UNIFIED IDEOGRAPH-6C34 (water)
+	{'\uFEFF', false},     // Byte Order Mark
+	{'\U00010000', false}, // LINEAR B SYLLABLE B008 A (first non-BMP code point)
+	{'\U0001D11E', false}, // MUSICAL SYMBOL G CLEF
+	{'\U0010FFFD', false}, // PRIVATE USE CHARACTER-10FFFD (last Unicode code point)
+
+	{rune(0xd7ff), false}, // surr1-1
+	{rune(0xd800), true},  // surr1
+	{rune(0xdc00), true},  // surr2
+	{rune(0xe000), false}, // surr3
+	{rune(0xdfff), true},  // surr3-1
+}
+
+func TestIsSurrogate(t *testing.T) {
+	for i, tt := range surrogateTests {
+		got := IsSurrogate(tt.r)
+		if got != tt.want {
+			t.Errorf("%d: IsSurrogate(%q) = %v; want %v", i, tt.r, got, tt.want)
+		}
+	}
+}
diff --git a/src/pkg/unicode/utf8/example_test.go b/src/pkg/unicode/utf8/example_test.go
index fe20373..7b3e7ac 100644
--- a/src/pkg/unicode/utf8/example_test.go
+++ b/src/pkg/unicode/utf8/example_test.go
@@ -1,3 +1,7 @@
+// 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 utf8_test
 
 import (
diff --git a/src/pkg/unicode/utf8/utf8.go b/src/pkg/unicode/utf8/utf8.go
index 93d0be5..0dc859a 100644
--- a/src/pkg/unicode/utf8/utf8.go
+++ b/src/pkg/unicode/utf8/utf8.go
@@ -329,37 +329,29 @@ func RuneLen(r rune) int {
 // It returns the number of bytes written.
 func EncodeRune(p []byte, r rune) int {
 	// Negative values are erroneous.  Making it unsigned addresses the problem.
-	if uint32(r) <= rune1Max {
+	switch i := uint32(r); {
+	case i <= rune1Max:
 		p[0] = byte(r)
 		return 1
-	}
-
-	if uint32(r) <= rune2Max {
+	case i <= rune2Max:
 		p[0] = t2 | byte(r>>6)
 		p[1] = tx | byte(r)&maskx
 		return 2
-	}
-
-	if uint32(r) > MaxRune {
+	case i > MaxRune, surrogateMin <= i && i <= surrogateMax:
 		r = RuneError
-	}
-
-	if surrogateMin <= r && r <= surrogateMax {
-		r = RuneError
-	}
-
-	if uint32(r) <= rune3Max {
+		fallthrough
+	case i <= rune3Max:
 		p[0] = t3 | byte(r>>12)
 		p[1] = tx | byte(r>>6)&maskx
 		p[2] = tx | byte(r)&maskx
 		return 3
+	default:
+		p[0] = t4 | byte(r>>18)
+		p[1] = tx | byte(r>>12)&maskx
+		p[2] = tx | byte(r>>6)&maskx
+		p[3] = tx | byte(r)&maskx
+		return 4
 	}
-
-	p[0] = t4 | byte(r>>18)
-	p[1] = tx | byte(r>>12)&maskx
-	p[2] = tx | byte(r>>6)&maskx
-	p[3] = tx | byte(r)&maskx
-	return 4
 }
 
 // RuneCount returns the number of runes in p.  Erroneous and short
diff --git a/src/race.bash b/src/race.bash
index 18201f9..1680c09 100755
--- a/src/race.bash
+++ b/src/race.bash
@@ -38,5 +38,11 @@ fi
 # golang.org/issue/5537 - we must build a race enabled cmd/cgo before trying to use it.
 go install -race cmd/cgo
 go install -race std
+
+# we must unset GOROOT_FINAL before tests, because runtime/debug requires
+# correct access to source code, so if we have GOROOT_FINAL in effect,
+# at least runtime/debug test will fail.
+unset GOROOT_FINAL
+
 go test -race -short std
 go test -race -run=nothingplease -bench=.* -benchtime=.1s -cpu=4 std
diff --git a/src/race.bat b/src/race.bat
index 0a6aee9..8858c57 100644
--- a/src/race.bat
+++ b/src/race.bat
@@ -15,6 +15,7 @@ echo race.bat must be run from go\src
 goto end
 :ok
 
+set GOROOT=%CD%\..
 call make.bat --dist-tool >NUL
 if errorlevel 1 goto fail
 .\cmd\dist\dist env -wp >env.bat
@@ -35,7 +36,13 @@ go install -race cmd/cgo
 echo # go install -race std
 go install -race std
 if errorlevel 1 goto fail
-echo # go test -race -short -std
+
+:: we must unset GOROOT_FINAL before tests, because runtime/debug requires
+:: correct access to source code, so if we have GOROOT_FINAL in effect,
+:: at least runtime/debug test will fail.
+set GOROOT_FINAL=
+
+echo # go test -race -short std
 go test -race -short std
 if errorlevel 1 goto fail
 echo # go test -race -run=nothingplease -bench=.* -benchtime=.1s -cpu=4 std
@@ -52,4 +59,5 @@ goto end
 echo All tests passed.
 
 :end
+if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%
 
diff --git a/src/run.bash b/src/run.bash
index 6adb7f6..6eec7ca 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -6,6 +6,7 @@
 set -e
 
 eval $(go env)
+export GOROOT   # the api test requires GOROOT to be set.
 
 unset CDPATH	# in case user has it set
 unset GOPATH    # we disallow local import for non-local packages, if $GOROOT happens
@@ -17,6 +18,12 @@ ulimit -c 0
 # Raise soft limits to hard limits for NetBSD/OpenBSD.
 # We need at least 256 files and ~300 MB of bss.
 # On OS X ulimit -S -n rejects 'unlimited'.
+#
+# Note that ulimit -S -n may fail if ulimit -H -n is set higher than a
+# non-root process is allowed to set the high limit.
+# This is a system misconfiguration and should be fixed on the
+# broken system, not "fixed" by ignoring the failure here.
+# See longer discussion on golang.org/issue/7381. 
 [ "$(ulimit -H -n)" == "unlimited" ] || ulimit -S -n $(ulimit -H -n)
 [ "$(ulimit -H -d)" == "unlimited" ] || ulimit -S -d $(ulimit -H -d)
 
@@ -27,7 +34,7 @@ fi
 
 # allow all.bash to avoid double-build of everything
 rebuild=true
-if [ "$1" = "--no-rebuild" ]; then
+if [ "$1" == "--no-rebuild" ]; then
 	shift
 else
 	echo '# Building packages and commands.'
@@ -48,6 +55,8 @@ echo '# Testing packages.'
 time go test std -short -timeout=$(expr 120 \* $timeout_scale)s
 echo
 
+# We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
+# creation of first goroutines and first garbage collections in the parallel setting.
 echo '# GOMAXPROCS=2 runtime -cpu=1,2,4'
 GOMAXPROCS=2 go test runtime -short -timeout=$(expr 300 \* $timeout_scale)s -cpu=1,2,4
 echo
@@ -119,10 +128,30 @@ darwin-386 | darwin-amd64)
 	*) go test -ldflags '-linkmode=external'  || exit 1;;
 	esac
 	;;
-dragonfly-386 | dragonfly-amd64 | freebsd-386 | freebsd-amd64 | linux-386 | linux-amd64 | linux-arm | netbsd-386 | netbsd-amd64)
+dragonfly-386 | dragonfly-amd64 | freebsd-386 | freebsd-amd64 | freebsd-arm | linux-386 | linux-amd64 | linux-arm | netbsd-386 | netbsd-amd64)
 	go test -ldflags '-linkmode=external' || exit 1
 	go test -ldflags '-linkmode=auto' ../testtls || exit 1
 	go test -ldflags '-linkmode=external' ../testtls || exit 1
+	
+	case "$GOHOSTOS-$GOARCH" in
+	netbsd-386 | netbsd-amd64) ;; # no static linking
+	freebsd-arm) ;; # -fPIC compiled tls code will use __tls_get_addr instead
+	                # of __aeabi_read_tp, however, on FreeBSD/ARM, __tls_get_addr
+	                # is implemented in rtld-elf, so -fPIC isn't compatible with
+	                # static linking on FreeBSD/ARM with clang. (cgo depends on
+			# -fPIC fundamentally.)
+	*)
+		if ! $CC -xc -o /dev/null -static - 2>/dev/null <<<'int main() {}' ; then
+			echo "No support for static linking found (lacks libc.a?), skip cgo static linking test."
+		else
+			go test -ldflags '-linkmode=external -extldflags "-static -pthread"' ../testtls || exit 1
+			go test ../nocgo || exit 1
+			go test -ldflags '-linkmode=external' ../nocgo || exit 1
+			go test -ldflags '-linkmode=external -extldflags "-static -pthread"' ../nocgo || exit 1
+		fi
+		;;
+	esac
+	;;
 esac
 ) || exit $?
 
@@ -152,28 +181,26 @@ go run main.go || exit 1
 ./test.bash || exit 1
 ) || exit $?
 
+[ "$GOOS" == nacl ] ||
 (xcd ../doc/progs
 time ./run || exit 1
 ) || exit $?
 
+[ "$GOOS" == nacl ] ||
 [ "$GOARCH" == arm ] ||  # uses network, fails under QEMU
 (xcd ../doc/articles/wiki
-make clean || exit 1
 ./test.bash || exit 1
 ) || exit $?
 
+[ "$GOOS" == nacl ] ||
 (xcd ../doc/codewalk
 time ./run || exit 1
 ) || exit $?
 
-echo
-echo '#' ../misc/goplay
-go build ../misc/goplay
-rm -f goplay
-
+[ "$GOOS" == nacl ] ||
 [ "$GOARCH" == arm ] ||
 (xcd ../test/bench/shootout
-./timing.sh -test || exit 1
+time ./timing.sh -test || exit 1
 ) || exit $?
 
 [ "$GOOS" == openbsd ] || # golang.org/issue/5057
@@ -185,12 +212,17 @@ go test ../test/bench/go1 || exit 1
 
 (xcd ../test
 unset GOMAXPROCS
-time go run run.go || exit 1
+GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go build -o runtest run.go || exit 1
+time ./runtest || exit 1
+rm -f runtest
 ) || exit $?
 
+[ "$GOOS" == nacl ] ||
+(
 echo
 echo '# Checking API compatibility.'
-time go run $GOROOT/src/cmd/api/run.go
+time go run $GOROOT/src/cmd/api/run.go || exit 1
+) || exit $?
 
 echo
 echo ALL TESTS PASSED
diff --git a/src/run.bat b/src/run.bat
index 48f6711..62692ac 100644
--- a/src/run.bat
+++ b/src/run.bat
@@ -42,16 +42,26 @@ go test std -short -timeout=120s
 if errorlevel 1 goto fail
 echo.
 
-echo # runtime -cpu=1,2,4
+set OLDGOMAXPROCS=%GOMAXPROCS%
+
+:: We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
+:: creation of first goroutines and first garbage collections in the parallel setting.
+echo # GOMAXPROCS=2 runtime -cpu=1,2,4
+set GOMAXPROCS=2
 go test runtime -short -timeout=300s -cpu=1,2,4
 if errorlevel 1 goto fail
 echo.
 
+set GOMAXPROCS=%OLDGOMAXPROCS%
+set OLDGOMAXPROCS=
+
 echo # sync -cpu=10
 go test sync -short -timeout=120s -cpu=10
 if errorlevel 1 goto fail
 echo.
 
+:: Race detector only supported on Linux and OS X,
+:: and only on amd64, and only when cgo is enabled.
 if not "%GOHOSTOS%-%GOOS%-%GOARCH%-%CGO_ENABLED%" == "windows-windows-amd64-1" goto norace
 echo # Testing race detector.
 go test -race -i runtime/race flag
@@ -63,11 +73,6 @@ if errorlevel 1 goto fail
 echo.
 :norace
 
-echo # ..\misc\goplay
-go build ..\misc\goplay
-if errorlevel 1 goto fail
-echo.
-
 echo # ..\test\bench\go1
 go test ..\test\bench\go1
 if errorlevel 1 goto fail
diff --git a/src/run.rc b/src/run.rc
index 765b331..65e2c07 100755
--- a/src/run.rc
+++ b/src/run.rc
@@ -7,7 +7,7 @@ rfork e
 
 eval `{go env}
 
-GOPATH = () # we disallow local import for non-local packges, if $GOROOT happens
+GOPATH = () # we disallow local import for non-local packages, if $GOROOT happens
             # to be under $GOPATH, then some tests below will fail
 
 # allow all.rc to avoid double-build of everything
@@ -32,6 +32,8 @@ echo '# Testing packages.'
 time go test std -short -timeout 120s
 echo
 
+# We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
+# creation of first goroutines and first garbage collections in the parallel setting.
 echo '# GOMAXPROCS=2 runtime -cpu=1,2,4'
 GOMAXPROCS=2 go test runtime -short -timeout 240s -cpu 1,2,4
 echo
@@ -47,10 +49,6 @@ fn xcd {
 }
 
 echo
-echo '#' ../misc/goplay
-go build ../misc/gplay
-
-echo
 echo '#' ../test/bench/go1
 go test ../test/bench/go1
 
diff --git a/test/bench/shootout/threadring.c b/test/bench/shootout/threadring.c
index a518134..606db71 100644
--- a/test/bench/shootout/threadring.c
+++ b/test/bench/shootout/threadring.c
@@ -41,8 +41,12 @@ POSSIBILITY OF SUCH DAMAGE.
 #include <string.h>
 #include <limits.h>
 
-#define THREADS (503)
+// PTHREAD_STACK_MIN undeclared on mingw
+#ifndef PTHREAD_STACK_MIN
+#define PTHREAD_STACK_MIN 65535
+#endif
 
+#define THREADS (503)
 
 struct stack {
    char x[PTHREAD_STACK_MIN];
@@ -94,7 +98,13 @@ int main(int argc, char **argv)
       pthread_mutex_init(mutex + i, NULL);
       pthread_mutex_lock(mutex + i);
 
+#if defined(__MINGW32__) || defined(__MINGW64__)
+      pthread_attr_setstackaddr(&stack_attr, &stacks[i]);
+      pthread_attr_setstacksize(&stack_attr, sizeof(struct stack));
+#else
       pthread_attr_setstack(&stack_attr, &stacks[i], sizeof(struct stack));
+#endif
+
       pthread_create(&cthread, &stack_attr, thread, (void*)(uintptr_t)i);
    }
 
diff --git a/test/bench/shootout/timing.sh b/test/bench/shootout/timing.sh
index 2db895c..a06c326 100755
--- a/test/bench/shootout/timing.sh
+++ b/test/bench/shootout/timing.sh
@@ -18,6 +18,33 @@ case "$O" in
 	gccm=-m64;;
 esac
 
+EXE="out"
+havepcre=true
+haveglib=true
+havegmp=true
+case "$(uname)" in
+*MINGW* | *WIN32* | *CYGWIN*)
+	havepcre=false
+	haveglib=false
+	havegmp=false
+	if which pkg-config >/dev/null 2>&1; then
+		if pkg-config --cflags libpcre >/dev/null 2>&1
+		then
+			echo "havepcre"
+			havepcre=true
+		fi
+		if pkg-config --cflags glib-2.0 >/dev/null 2>&1
+		then
+			haveglib=true
+		fi
+		if pkg-config --cflags gmp >/dev/null 2>&1
+		then
+			havegmp=true
+		fi
+	fi
+	EXE=exe;;
+esac
+
 PATH=.:$PATH
 
 havegccgo=false
@@ -34,11 +61,11 @@ X-test)
 esac
 
 gc() {
-	$GC $1.go; $LD $1.$O
+	$GC $1.go; $LD -o $O.$EXE $1.$O
 }
 
 gc_B() {
-	$GC -B $1.go; $LD $1.$O
+	$GC -B $1.go; $LD -o $O.$EXE $1.$O
 }
 
 runonly() {
@@ -86,122 +113,126 @@ run() {
 
 fasta() {
 	runonly echo 'fasta -n 25000000'
-	run "gcc $gccm -O2 fasta.c" a.out 25000000
-	run 'gccgo -O2 fasta.go' a.out -n 25000000	#commented out until WriteString is in bufio
-	run 'gc fasta' $O.out -n 25000000
-	run 'gc_B fasta' $O.out -n 25000000
+	run "gcc $gccm -O2 fasta.c" a.$EXE 25000000
+	run 'gccgo -O2 fasta.go' a.$EXE -n 25000000	#commented out until WriteString is in bufio
+	run 'gc fasta' $O.$EXE -n 25000000
+	run 'gc_B fasta' $O.$EXE -n 25000000
 }
 
 revcomp() {
 	runonly gcc -O2 fasta.c
-	runonly a.out 25000000 > x
+	runonly a.$EXE 25000000 > x
 	runonly echo 'reverse-complement < output-of-fasta-25000000'
-	run "gcc $gccm -O2 reverse-complement.c" a.out < x
-	run 'gccgo -O2 reverse-complement.go' a.out < x
-	run 'gc reverse-complement' $O.out < x
-	run 'gc_B reverse-complement' $O.out < x
+	run "gcc $gccm -O2 reverse-complement.c" a.$EXE < x
+	run 'gccgo -O2 reverse-complement.go' a.$EXE < x
+	run 'gc reverse-complement' $O.$EXE < x
+	run 'gc_B reverse-complement' $O.$EXE < x
 	rm x
 }
 
 nbody() {
 	runonly echo 'nbody -n 50000000'
-	run "gcc $gccm -O2 nbody.c -lm" a.out 50000000
-	run 'gccgo -O2 nbody.go' a.out -n 50000000
-	run 'gc nbody' $O.out -n 50000000
-	run 'gc_B nbody' $O.out -n 50000000
+	run "gcc $gccm -O2 nbody.c -lm" a.$EXE 50000000
+	run 'gccgo -O2 nbody.go' a.$EXE -n 50000000
+	run 'gc nbody' $O.$EXE -n 50000000
+	run 'gc_B nbody' $O.$EXE -n 50000000
 }
 
 binarytree() {
 	runonly echo 'binary-tree 15 # too slow to use 20'
-	run "gcc $gccm -O2 binary-tree.c -lm" a.out 15
-	run 'gccgo -O2 binary-tree.go' a.out -n 15
-	run 'gccgo -O2 binary-tree-freelist.go' a.out -n 15
-	run 'gc binary-tree' $O.out -n 15
-	run 'gc binary-tree-freelist' $O.out -n 15
+	run "gcc $gccm -O2 binary-tree.c -lm" a.$EXE 15
+	run 'gccgo -O2 binary-tree.go' a.$EXE -n 15
+	run 'gccgo -O2 binary-tree-freelist.go' a.$EXE -n 15
+	run 'gc binary-tree' $O.$EXE -n 15
+	run 'gc binary-tree-freelist' $O.$EXE -n 15
 }
 
 fannkuch() {
 	runonly echo 'fannkuch 12'
-	run "gcc $gccm -O2 fannkuch.c" a.out 12
-	run 'gccgo -O2 fannkuch.go' a.out -n 12
-	run 'gccgo -O2 fannkuch-parallel.go' a.out -n 12
-	run 'gc fannkuch' $O.out -n 12
-	run 'gc fannkuch-parallel' $O.out -n 12
-	run 'gc_B fannkuch' $O.out -n 12
+	run "gcc $gccm -O2 fannkuch.c" a.$EXE 12
+	run 'gccgo -O2 fannkuch.go' a.$EXE -n 12
+	run 'gccgo -O2 fannkuch-parallel.go' a.$EXE -n 12
+	run 'gc fannkuch' $O.$EXE -n 12
+	run 'gc fannkuch-parallel' $O.$EXE -n 12
+	run 'gc_B fannkuch' $O.$EXE -n 12
 }
 
 regexdna() {
 	runonly gcc -O2 fasta.c
-	runonly a.out 100000 > x
+	runonly a.$EXE 100000 > x
 	runonly echo 'regex-dna 100000'
-	run "gcc $gccm -O2 regex-dna.c -lpcre" a.out <x
-	run 'gccgo -O2 regex-dna.go' a.out <x
-	run 'gccgo -O2 regex-dna-parallel.go' a.out <x
-	run 'gc regex-dna' $O.out <x
-	run 'gc regex-dna-parallel' $O.out <x
-	run 'gc_B regex-dna' $O.out <x
+	if  $havepcre; then
+		run "gcc $gccm -O2 regex-dna.c $(pkg-config libpcre --cflags --libs)" a.$EXE <x
+	fi
+	run 'gccgo -O2 regex-dna.go' a.$EXE <x
+	run 'gccgo -O2 regex-dna-parallel.go' a.$EXE <x
+	run 'gc regex-dna' $O.$EXE <x
+	run 'gc regex-dna-parallel' $O.$EXE <x
+	run 'gc_B regex-dna' $O.$EXE <x
 	rm x
 }
 
 spectralnorm() {
 	runonly echo 'spectral-norm 5500'
-	run "gcc $gccm -O2 spectral-norm.c -lm" a.out 5500
-	run 'gccgo -O2 spectral-norm.go' a.out -n 5500
-	run 'gc spectral-norm' $O.out -n 5500
-	run 'gc_B spectral-norm' $O.out -n 5500
+	run "gcc $gccm -O2 spectral-norm.c -lm" a.$EXE 5500
+	run 'gccgo -O2 spectral-norm.go' a.$EXE -n 5500
+	run 'gc spectral-norm' $O.$EXE -n 5500
+	run 'gc_B spectral-norm' $O.$EXE -n 5500
 }
 
 knucleotide() {
 	runonly gcc -O2 fasta.c
-	runonly a.out 1000000 > x  # should be using 25000000
+	runonly a.$EXE 1000000 > x  # should be using 25000000
 	runonly echo 'k-nucleotide 1000000'
-	if [ $mode = run ]; then
-		run "gcc -O2 k-nucleotide.c $(pkg-config glib-2.0 --cflags --libs)" a.out <x
+	if [ $mode = run ] && $haveglib; then
+		run "gcc -O2 k-nucleotide.c $(pkg-config glib-2.0 --cflags --libs)" a.$EXE <x
 	fi
-	run 'gccgo -O2 k-nucleotide.go' a.out <x
-	run 'gccgo -O2 k-nucleotide-parallel.go' a.out <x
-	run 'gc k-nucleotide' $O.out <x
-	run 'gc k-nucleotide-parallel' $O.out <x
-	run 'gc_B k-nucleotide' $O.out <x
+	run 'gccgo -O2 k-nucleotide.go' a.$EXE <x
+	run 'gccgo -O2 k-nucleotide-parallel.go' a.$EXE <x
+	run 'gc k-nucleotide' $O.$EXE <x
+	run 'gc k-nucleotide-parallel' $O.$EXE <x
+	run 'gc_B k-nucleotide' $O.$EXE <x
 	rm x
 }
 
 mandelbrot() {
 	runonly echo 'mandelbrot 16000'
-	run "gcc $gccm -O2 mandelbrot.c" a.out 16000
-	run 'gccgo -O2 mandelbrot.go' a.out -n 16000
-	run 'gc mandelbrot' $O.out -n 16000
-	run 'gc_B mandelbrot' $O.out -n 16000
+	run "gcc $gccm -O2 mandelbrot.c" a.$EXE 16000
+	run 'gccgo -O2 mandelbrot.go' a.$EXE -n 16000
+	run 'gc mandelbrot' $O.$EXE -n 16000
+	run 'gc_B mandelbrot' $O.$EXE -n 16000
 }
 
 meteor() {
 	runonly echo 'meteor 2098'
-	run "gcc $gccm -O2 meteor-contest.c" a.out 2098
-	run 'gccgo -O2 meteor-contest.go' a.out -n 2098
-	run 'gc meteor-contest' $O.out -n 2098
-	run 'gc_B  meteor-contest' $O.out -n 2098
+	run "gcc $gccm -O2 meteor-contest.c" a.$EXE 2098
+	run 'gccgo -O2 meteor-contest.go' a.$EXE -n 2098
+	run 'gc meteor-contest' $O.$EXE -n 2098
+	run 'gc_B  meteor-contest' $O.$EXE -n 2098
 }
 
 pidigits() {
 	runonly echo 'pidigits 10000'
-	run "gcc $gccm -O2 pidigits.c -lgmp" a.out 10000
-	run 'gccgo -O2 pidigits.go' a.out -n 10000
-	run 'gc pidigits' $O.out -n 10000
-	run 'gc_B  pidigits' $O.out -n 10000
+	if  $havegmp; then
+		run "gcc $gccm -O2 pidigits.c -lgmp" a.$EXE 10000
+	fi
+	run 'gccgo -O2 pidigits.go' a.$EXE -n 10000
+	run 'gc pidigits' $O.$EXE -n 10000
+	run 'gc_B  pidigits' $O.$EXE -n 10000
 }
 
 threadring() {
 	runonly echo 'threadring 50000000'
-	run "gcc $gccm -O2 threadring.c -lpthread" a.out 50000000
-	run 'gccgo -O2 threadring.go' a.out -n 50000000
-	run 'gc threadring' $O.out -n 50000000
+	run "gcc $gccm -O2 threadring.c -lpthread" a.$EXE 50000000
+	run 'gccgo -O2 threadring.go' a.$EXE -n 50000000
+	run 'gc threadring' $O.$EXE -n 50000000
 }
 
 chameneos() {
 	runonly echo 'chameneos 6000000'
-	run "gcc $gccm -O2 chameneosredux.c -lpthread" a.out 6000000
-	run 'gccgo -O2 chameneosredux.go' a.out 6000000
-	run 'gc chameneosredux' $O.out 6000000
+	run "gcc $gccm -O2 chameneosredux.c -lpthread" a.$EXE 6000000
+	run 'gccgo -O2 chameneosredux.go' a.$EXE 6000000
+	run 'gc chameneosredux' $O.$EXE 6000000
 }
 
 case $# in
diff --git a/test/cmp.go b/test/cmp.go
index 73de502..80d1bf6 100644
--- a/test/cmp.go
+++ b/test/cmp.go
@@ -35,6 +35,10 @@ func istrue(b bool) {
 
 type T *int
 
+type X int
+
+func (X) x() {}
+
 func main() {
 	var a []int
 	var b map[string]int
@@ -129,6 +133,44 @@ func main() {
 		panic("bad m[c]")
 	}
 
+	// interface comparisons (issue 7207)
+	{
+		type I1 interface {
+			x()
+		}
+		type I2 interface {
+			x()
+		}
+		a1 := I1(X(0))
+		b1 := I1(X(1))
+		a2 := I2(X(0))
+		b2 := I2(X(1))
+		a3 := I1(a2)
+		a4 := I2(a1)
+		var e interface{} = X(0)
+		a5 := e.(I1)
+		a6 := e.(I2)
+		isfalse(a1 == b1)
+		isfalse(a1 == b2)
+		isfalse(a2 == b1)
+		isfalse(a2 == b2)
+		istrue(a1 == a2)
+		istrue(a1 == a3)
+		istrue(a1 == a4)
+		istrue(a1 == a5)
+		istrue(a1 == a6)
+		istrue(a2 == a3)
+		istrue(a2 == a4)
+		istrue(a2 == a5)
+		istrue(a2 == a6)
+		istrue(a3 == a4)
+		istrue(a3 == a5)
+		istrue(a3 == a6)
+		istrue(a4 == a5)
+		istrue(a4 == a6)
+		istrue(a5 == a6)
+	}
+
 	// non-interface comparisons
 	{
 		c := make(chan int)
@@ -387,6 +429,23 @@ func main() {
 		isfalse(iz != x)
 	}
 
+	// named booleans
+	{
+		type mybool bool
+		var b mybool
+
+		type T struct{ data [20]byte }
+		var x, y T
+		b = x == y
+		istrue(x == y)
+		istrue(bool(b))
+
+		m := make(map[string][10]interface{})
+		b = m["x"] == m["y"]
+		istrue(m["x"] == m["y"])
+		istrue(bool(b))
+	}
+
 	shouldPanic(p1)
 	shouldPanic(p2)
 	shouldPanic(p3)
diff --git a/test/cmp6.go b/test/cmp6.go
index 839c274..7cf7604 100644
--- a/test/cmp6.go
+++ b/test/cmp6.go
@@ -18,7 +18,10 @@ type T3 struct{ z []int }
 
 var t3 T3
 
-type T4 struct { _ []int; a float64 }
+type T4 struct {
+	_ []int
+	a float64
+}
 
 var t4 T4
 
@@ -51,6 +54,14 @@ func main() {
 	use(p3 == p1)
 	use(p3 == p2)
 
+	// Arrays are comparable if and only if their element type is comparable.
+	var a1 [1]int
+	var a2 [1]func()
+	var a3 [0]func()
+	use(a1 == a1)
+	use(a2 == a2) // ERROR "invalid operation|invalid comparison"
+	use(a3 == a3) // ERROR "invalid operation|invalid comparison"
+
 	// Comparison of structs should have a good message
 	use(t3 == t3) // ERROR "struct|expected"
 	use(t4 == t4) // ERROR "cannot be compared|non-comparable"
diff --git a/test/const1.go b/test/const1.go
index a170ce9..58bddee 100644
--- a/test/const1.go
+++ b/test/const1.go
@@ -88,7 +88,7 @@ func main() {
 }
 
 const ptr = nil // ERROR "const.*nil"
-const _ = string([]byte(nil)) // ERROR "is not a constant"
-const _ = uintptr(unsafe.Pointer((*int)(nil))) // ERROR "is not a constant"
-const _ = unsafe.Pointer((*int)(nil)) // ERROR "cannot be nil"
-const _ = (*int)(nil) // ERROR "cannot be nil"
+const _ = string([]byte(nil)) // ERROR "is not a? ?constant"
+const _ = uintptr(unsafe.Pointer((*int)(nil))) // ERROR "is not a? ?constant"
+const _ = unsafe.Pointer((*int)(nil)) // ERROR "cannot be nil|invalid constant type"
+const _ = (*int)(nil) // ERROR "cannot be nil|invalid constant type"
diff --git a/test/const5.go b/test/const5.go
index 87fe33a..60b4d0d 100644
--- a/test/const5.go
+++ b/test/const5.go
@@ -18,6 +18,7 @@ var s [][30]int
 
 func f() *[40]int
 var c chan *[50]int
+var z complex128
 
 const (
 	n1 = len(b.a)
@@ -29,5 +30,8 @@ const (
 
 	n6 = cap(f())  // ERROR "is not a constant|is not constant"
 	n7 = cap(<-c) // ERROR "is not a constant|is not constant"
+	n8 = real(z) // ERROR "is not a constant|is not constant"
+	n9 = len([4]float64{real(z)}) // ERROR "is not a constant|is not constant"
+
 )
 
diff --git a/test/deferfin.go b/test/deferfin.go
index f9a74eb..8037291 100644
--- a/test/deferfin.go
+++ b/test/deferfin.go
@@ -23,6 +23,10 @@ func main() {
 	if runtime.GOARCH != "amd64" {
 		return
 	}
+	// Likewise for gccgo.
+	if runtime.Compiler == "gccgo" {
+		return
+	}
 	N := 10
 	count := int32(N)
 	var wg sync.WaitGroup
@@ -30,17 +34,17 @@ func main() {
 	for i := 0; i < N; i++ {
 		go func() {
 			defer wg.Done()
-			v := new(int)
+			v := new(string)
 			f := func() {
-				if *v != 0 {
+				if *v != "" {
 					panic("oops")
 				}
 			}
-			if *v != 0 {
+			if *v != "" {
 				// let the compiler think f escapes
 				sink = f
 			}
-			runtime.SetFinalizer(v, func(p *int) {
+			runtime.SetFinalizer(v, func(p *string) {
 				atomic.AddInt32(&count, -1)
 			})
 			defer f()
diff --git a/test/divmod.go b/test/divmod.go
index 49fed02..ad632bc 100644
--- a/test/divmod.go
+++ b/test/divmod.go
@@ -6,7 +6,7 @@
 
 // Test division of variables. Generate many test cases,
 // compute correct answer using shift and subtract,
-// and then compare against results from divison and
+// and then compare against results from division and
 // modulus operators.
 //
 // Primarily useful for testing software div/mod.
diff --git a/test/escape2.go b/test/escape2.go
index be89c2d..28251aa 100644
--- a/test/escape2.go
+++ b/test/escape2.go
@@ -80,7 +80,7 @@ func foo12(yyy **int) { // ERROR "leaking param: yyy"
 	xxx = yyy
 }
 
-// Must treat yyy as leaking because *yyy leaks, and the escape analysis 
+// Must treat yyy as leaking because *yyy leaks, and the escape analysis
 // summaries in exported metadata do not distinguish these two cases.
 func foo13(yyy **int) { // ERROR "leaking param: yyy"
 	*xxx = *yyy
@@ -135,7 +135,7 @@ func (b *Bar) Leak() *int { // ERROR "leaking param: b"
 	return &b.i // ERROR "&b.i escapes to heap"
 }
 
-func (b *Bar) AlsoNoLeak() *int { // ERROR "b does not escape"
+func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param b content to result ~r0"
 	return b.ii
 }
 
@@ -149,7 +149,7 @@ func (b Bar) LeaksToo() *int { // ERROR "leaking param: b"
 	return b.ii
 }
 
-func (b *Bar) LeaksABit() *int { // ERROR "b does not escape"
+func (b *Bar) LeaksABit() *int { // ERROR "leaking param b content to result ~r0"
 	v := 0    // ERROR "moved to heap: v"
 	b.ii = &v // ERROR "&v escapes"
 	return b.ii
@@ -182,7 +182,7 @@ func (b *Bar2) Leak() []int { // ERROR "leaking param: b"
 	return b.i[:] // ERROR "b.i escapes to heap"
 }
 
-func (b *Bar2) AlsoNoLeak() []int { // ERROR "b does not escape"
+func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param b content to result ~r0"
 	return b.ii[0:1]
 }
 
@@ -1294,15 +1294,15 @@ func F4(x []byte)
 func G() {
 	var buf1 [10]byte
 	F1(buf1[:]) // ERROR "buf1 does not escape"
-	
+
 	var buf2 [10]byte // ERROR "moved to heap: buf2"
-	F2(buf2[:]) // ERROR "buf2 escapes to heap"
+	F2(buf2[:])       // ERROR "buf2 escapes to heap"
 
 	var buf3 [10]byte
 	F3(buf3[:]) // ERROR "buf3 does not escape"
-	
+
 	var buf4 [10]byte // ERROR "moved to heap: buf4"
-	F4(buf4[:]) // ERROR "buf4 escapes to heap"
+	F4(buf4[:])       // ERROR "buf4 escapes to heap"
 }
 
 type Tm struct {
@@ -1314,9 +1314,9 @@ func (t *Tm) M() { // ERROR "t does not escape"
 
 func foo141() {
 	var f func()
-	
+
 	t := new(Tm) // ERROR "escapes to heap"
-	f = t.M // ERROR "t.M does not escape"
+	f = t.M      // ERROR "t.M does not escape"
 	_ = f
 }
 
@@ -1324,7 +1324,7 @@ var gf func()
 
 func foo142() {
 	t := new(Tm) // ERROR "escapes to heap"
-	gf = t.M // ERROR "t.M escapes to heap"
+	gf = t.M     // ERROR "t.M escapes to heap"
 }
 
 // issue 3888.
@@ -1357,3 +1357,136 @@ func foo144() {
 //go:noescape
 
 func foo144b(*int)
+
+// issue 7313: for loop init should not be treated as "in loop"
+
+type List struct {
+	Next *List
+}
+
+func foo145(l List) { // ERROR "l does not escape"
+	var p *List
+	for p = &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
+	}
+}
+
+func foo146(l List) { // ERROR "l does not escape"
+	var p *List
+	p = &l // ERROR "&l does not escape"
+	for ; p.Next != nil; p = p.Next {
+	}
+}
+
+func foo147(l List) { // ERROR "l does not escape"
+	var p *List
+	p = &l // ERROR "&l does not escape"
+	for p.Next != nil {
+		p = p.Next
+	}
+}
+
+func foo148(l List) { // ERROR " l does not escape"
+	for p := &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
+	}
+}
+
+// related: address of variable should have depth of variable, not of loop
+
+func foo149(l List) { // ERROR " l does not escape"
+	var p *List
+	for {
+		for p = &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
+		}
+	}
+}
+
+// issue 7934: missed ... if element type had no pointers
+
+var save150 []byte
+
+func foo150(x ...byte) { // ERROR "leaking param: x"
+	save150 = x
+}
+
+func bar150() {
+	foo150(1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
+}
+
+// issue 7931: bad handling of slice of array
+
+var save151 *int
+
+func foo151(x *int) { // ERROR "leaking param: x"
+	save151 = x
+}
+
+func bar151() {
+	var a [64]int // ERROR "moved to heap: a"
+	a[4] = 101
+	foo151(&(&a)[4:8][0]) // ERROR "&\(&a\)\[4:8\]\[0\] escapes to heap" "&a escapes to heap"
+}
+
+func bar151b() {
+	var a [10]int      // ERROR "moved to heap: a"
+	b := a[:]          // ERROR "a escapes to heap"
+	foo151(&b[4:8][0]) // ERROR "&b\[4:8\]\[0\] escapes to heap"
+}
+
+func bar151c() {
+	var a [64]int // ERROR "moved to heap: a"
+	a[4] = 101
+	foo151(&(&a)[4:8:8][0]) // ERROR "&\(&a\)\[4:8:8\]\[0\] escapes to heap" "&a escapes to heap"
+}
+
+func bar151d() {
+	var a [10]int        // ERROR "moved to heap: a"
+	b := a[:]            // ERROR "a escapes to heap"
+	foo151(&b[4:8:8][0]) // ERROR "&b\[4:8:8\]\[0\] escapes to heap"
+}
+
+// issue 8120
+
+type U struct {
+	s *string
+}
+
+func (u *U) String() *string { // ERROR "leaking param u content to result ~r0"
+	return u.s
+}
+
+type V struct {
+	s *string
+}
+
+func NewV(u U) *V { // ERROR "leaking param: u"
+	return &V{u.String()} // ERROR "&V literal escapes to heap" "u does not escape"
+}
+
+func foo152() {
+	a := "a"   // ERROR "moved to heap: a"
+	u := U{&a} // ERROR "&a escapes to heap"
+	v := NewV(u)
+	println(v)
+}
+
+// issue 8176 - &x in type switch body not marked as escaping
+
+func foo153(v interface{}) *int { // ERROR "leaking param: v"
+	switch x := v.(type) {
+	case int: // ERROR "moved to heap: x"
+		return &x // ERROR "&x escapes to heap"
+	}
+	panic(0)
+}
+
+// issue 8185 - &result escaping into result
+
+func f() (x int, y *int) { // ERROR "moved to heap: x"
+	y = &x // ERROR "&x escapes to heap"
+	return
+}
+
+func g() (x interface{}) { // ERROR "moved to heap: x"
+	x = &x // ERROR "&x escapes to heap"
+	return
+}
diff --git a/test/escape5.go b/test/escape5.go
index c964687..a33daee 100644
--- a/test/escape5.go
+++ b/test/escape5.go
@@ -17,19 +17,19 @@ func leaktoret(p *int) *int { // ERROR "leaking param: p to result"
 	return p
 }
 
-func leaktoret2(p *int) (*int, *int) { // ERROR "leaking param: p to result .anon1" "leaking param: p to result .anon2"
+func leaktoret2(p *int) (*int, *int) { // ERROR "leaking param: p to result ~r1" "leaking param: p to result ~r2"
 	return p, p
 }
 
-func leaktoret22(p, q *int) (*int, *int) { // ERROR "leaking param: p to result .anon2" "leaking param: q to result .anon3"
+func leaktoret22(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r2" "leaking param: q to result ~r3"
 	return p, q
 }
 
-func leaktoret22b(p, q *int) (*int, *int) { // ERROR "leaking param: p to result .anon3" "leaking param: q to result .anon2"
+func leaktoret22b(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2"
 	return leaktoret22(q, p)
 }
 
-func leaktoret22c(p, q *int) (*int, *int) { // ERROR "leaking param: p to result .anon3" "leaking param: q to result .anon2"
+func leaktoret22c(p, q *int) (*int, *int) { // ERROR "leaking param: p to result ~r3" "leaking param: q to result ~r2"
 	r, s := leaktoret22(q, p)
 	return r, s
 }
diff --git a/test/fixedbugs/bug176.go b/test/fixedbugs/bug176.go
index 82f8dba..ea3a909 100644
--- a/test/fixedbugs/bug176.go
+++ b/test/fixedbugs/bug176.go
@@ -9,6 +9,6 @@ package main
 var x int
 
 var a = []int{ x: 1}	// ERROR "constant"
-var b = [...]int{ x : 1}	// ERROR "constant"
+var b = [...]int{x: 1}
 var c = map[int]int{ x: 1}
 
diff --git a/test/fixedbugs/bug191.dir/a.go b/test/fixedbugs/bug191.dir/a.go
index b87ad6f..139a8a3 100644
--- a/test/fixedbugs/bug191.dir/a.go
+++ b/test/fixedbugs/bug191.dir/a.go
@@ -4,8 +4,10 @@
 
 package a
 
+var A int
+
 func init() {
-	println("a");
+	A = 1
 }
 
 type T int;
diff --git a/test/fixedbugs/bug191.dir/b.go b/test/fixedbugs/bug191.dir/b.go
index 3e780ac..36770f6 100644
--- a/test/fixedbugs/bug191.dir/b.go
+++ b/test/fixedbugs/bug191.dir/b.go
@@ -4,8 +4,10 @@
 
 package b
 
+var B int
+
 func init() {
-	println("b");
+	B = 2
 }
 
 type V int;
diff --git a/test/fixedbugs/bug191.dir/main.go b/test/fixedbugs/bug191.dir/main.go
index 995134c..2d24dd1 100644
--- a/test/fixedbugs/bug191.dir/main.go
+++ b/test/fixedbugs/bug191.dir/main.go
@@ -11,4 +11,7 @@ var _ T
 var _ V
 
 func main() {
+	if A != 1 || B != 2 {
+		panic("wrong vars")
+	}
 }
diff --git a/test/fixedbugs/bug191.go b/test/fixedbugs/bug191.go
index acb4796..248e23e 100644
--- a/test/fixedbugs/bug191.go
+++ b/test/fixedbugs/bug191.go
@@ -1,4 +1,4 @@
-// rundircmpout
+// rundir
 
 // Copyright 2009 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
diff --git a/test/fixedbugs/bug191.out b/test/fixedbugs/bug191.out
deleted file mode 100644
index 0e1677a..0000000
--- a/test/fixedbugs/bug191.out
+++ /dev/null
@@ -1,2 +0,0 @@
-b
-a
diff --git a/test/fixedbugs/bug385_32.go b/test/fixedbugs/bug385_32.go
index 724ed93..daf2a08 100644
--- a/test/fixedbugs/bug385_32.go
+++ b/test/fixedbugs/bug385_32.go
@@ -1,4 +1,4 @@
-// +build 386 arm
+// +build 386 amd64p32 arm
 // errorcheck
 
 // Copyright 2011 The Go Authors.  All rights reserved.
@@ -9,7 +9,7 @@
 
 package main
 func main() {
-	var arr [1000200030]int   // ERROR "type .* too large"
+	var arr [1000200030]int   // GC_ERROR "type .* too large"
 	arr_bkup := arr
 	_ = arr_bkup
 }
diff --git a/test/fixedbugs/bug385_64.go b/test/fixedbugs/bug385_64.go
index aef03c3..6789c0a 100644
--- a/test/fixedbugs/bug385_64.go
+++ b/test/fixedbugs/bug385_64.go
@@ -12,7 +12,7 @@ package main
 
 var z [10<<20]byte
 
-func main() { // ERROR "stack frame too large"
+func main() { // GC_ERROR "stack frame too large"
 	// seq 1 206 | sed 's/.*/	var x& [10<<20]byte; z = x&/'
 	var x1 [10<<20]byte; z = x1
 	var x2 [10<<20]byte; z = x2
diff --git a/test/fixedbugs/bug462.go b/test/fixedbugs/bug462.go
index 6434255..1a23ad0 100644
--- a/test/fixedbugs/bug462.go
+++ b/test/fixedbugs/bug462.go
@@ -14,6 +14,6 @@ type T struct {
 
 func main() {
 	_ = T {
-		os.File: 1, // ERROR "unknown T field"
+		os.File: 1, // ERROR "unknown T? ?field"
 	}
 }
diff --git a/test/fixedbugs/bug476.go b/test/fixedbugs/bug476.go
index 4ea2174..563fd91 100644
--- a/test/fixedbugs/bug476.go
+++ b/test/fixedbugs/bug476.go
@@ -5,7 +5,7 @@
 // license that can be found in the LICENSE file.
 
 // Logical operation on named boolean type returns the same type,
-// supporting an implicit convertion to an interface type.  This used
+// supporting an implicit conversion to an interface type.  This used
 // to crash gccgo.
 
 package p
diff --git a/test/fixedbugs/bug480.dir/a.go b/test/fixedbugs/bug480.dir/a.go
new file mode 100644
index 0000000..6dff515
--- /dev/null
+++ b/test/fixedbugs/bug480.dir/a.go
@@ -0,0 +1,17 @@
+// 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 a
+
+type S interface{
+	F() T
+}
+
+type T struct {
+	S
+}
+
+type U struct {
+	error
+}
diff --git a/test/fixedbugs/bug480.dir/b.go b/test/fixedbugs/bug480.dir/b.go
new file mode 100644
index 0000000..6207365
--- /dev/null
+++ b/test/fixedbugs/bug480.dir/b.go
@@ -0,0 +1,13 @@
+// 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 b
+
+import "./a"
+
+var t a.T
+
+func F() error {
+	return a.U{}
+}
diff --git a/test/fixedbugs/bug480.go b/test/fixedbugs/bug480.go
new file mode 100644
index 0000000..5b44af4
--- /dev/null
+++ b/test/fixedbugs/bug480.go
@@ -0,0 +1,9 @@
+// compiledir
+
+// 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.
+
+// Gccgo mishandled an import of a forward declared type.
+
+package ignored
diff --git a/test/fixedbugs/bug481.go b/test/fixedbugs/bug481.go
new file mode 100644
index 0000000..d0922a5
--- /dev/null
+++ b/test/fixedbugs/bug481.go
@@ -0,0 +1,18 @@
+// compile
+
+// 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.
+
+// Returning an index into a conversion from string to slice caused a
+// compilation error when using gccgo.
+
+package p
+
+func F1(s string) byte {
+	return []byte(s)[0]
+}
+
+func F2(s string) rune {
+	return []rune(s)[0]
+}
diff --git a/test/fixedbugs/bug482.go b/test/fixedbugs/bug482.go
new file mode 100644
index 0000000..10c4828
--- /dev/null
+++ b/test/fixedbugs/bug482.go
@@ -0,0 +1,20 @@
+// compile
+
+// 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.
+
+// Using the same name for a field in a composite literal and for a
+// global variable that depends on the variable being initialized
+// caused gccgo to erroneously report "variable initializer refers to
+// itself".
+
+package p
+
+type S struct {
+	F int
+}
+
+var V = S{F: 1}
+
+var F = V.F
diff --git a/test/fixedbugs/bug483.go b/test/fixedbugs/bug483.go
new file mode 100644
index 0000000..2372e89
--- /dev/null
+++ b/test/fixedbugs/bug483.go
@@ -0,0 +1,36 @@
+// run
+
+// 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 for a garbage collection bug involving not
+// marking x as having its address taken by &x[0]
+// when x is an array value.
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"runtime"
+)
+
+func main() {
+	var x = [4]struct{ x, y interface{} }{
+		{"a", "b"},
+		{"c", "d"},
+		{"e", "f"},
+		{"g", "h"},
+	}
+
+	var buf bytes.Buffer
+	for _, z := range x {
+		runtime.GC()
+		fmt.Fprintf(&buf, "%s %s ", z.x.(string), z.y.(string))
+	}
+
+	if buf.String() != "a b c d e f g h " {
+		println("BUG wrong output\n", buf.String())
+	}
+}
diff --git a/test/fixedbugs/bug484.go b/test/fixedbugs/bug484.go
new file mode 100644
index 0000000..c664b83
--- /dev/null
+++ b/test/fixedbugs/bug484.go
@@ -0,0 +1,90 @@
+// run
+
+// 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.
+
+// The liveness code used to say that, in func g, s was live
+// starting at its declaration, because it appears to have its
+// address taken by the closure (different s, but the parser
+// gets slightly confused, a separate bug). The liveness analysis
+// saw s as having its address taken but the register optimizer
+// did not. This mismatch meant that s would be marked live
+// (and therefore initialized) at the call to f, but the register optimizer
+// would optimize away the initialization of s before f, causing the
+// garbage collector to use unused data.
+// The register optimizer has been changed to respect the
+// same "address taken" flag that the liveness analysis uses,
+// even if it cannot see any address being taken in the actual
+// machine code. This is conservative but keeps the two consistent,
+// which is the most important thing.
+
+package main
+
+import "runtime"
+
+var c bool
+
+func f() interface{} {
+	if c { // disable inlining
+		f()
+	}
+	runtime.GC()
+	return nil
+}
+
+func g() {
+	if c { // disable inlining
+		g()
+	}
+	var s interface{}
+	_ = func() {
+		s := f()
+		_ = s
+	}
+	s = f()
+	useiface(s)
+	useiface(s)
+}
+
+func useiface(x interface{}) {
+	if c {	// disable inlining
+		useiface(x)
+	}
+}
+
+func h() {
+	if c { // disable inlining
+		h()
+	}
+	var x [16]uintptr
+	for i := range x {
+		x[i] = 1
+	}
+	
+	useint(x[0])
+	useint(x[1])
+	useint(x[2])
+	useint(x[3])
+}
+
+func useint(x uintptr) {
+	if c {	// disable inlining
+		useint(x)
+	}
+}
+
+func main() {
+	// scribble non-zero values on stack
+	h()
+	// call function that used to let the garbage collector
+	// see uninitialized stack values; it will see the
+	// nonzero values.
+	g()
+}
+
+func big(x int) {
+	if x >= 0 {
+		big(x-1)
+	}
+}
diff --git a/test/fixedbugs/bug485.go b/test/fixedbugs/bug485.go
new file mode 100644
index 0000000..1544753
--- /dev/null
+++ b/test/fixedbugs/bug485.go
@@ -0,0 +1,39 @@
+// run
+
+// 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.
+
+// Gccgo chose the wrong embedded method when the same type appeared
+// at different levels and the correct choice was not the first
+// appearance of the type in a depth-first search.
+
+package main
+
+type embedded string
+
+func (s embedded) val() string {
+	return string(s)
+}
+
+type A struct {
+	embedded
+}
+
+type B struct {
+	A
+	embedded
+}
+
+func main() {
+	b := &B{
+		A: A{
+			embedded: "a",
+		},
+		embedded: "b",
+	}
+	s := b.val()
+	if s != "b" {
+		panic(s)
+	}
+}
diff --git a/test/fixedbugs/issue1304.go b/test/fixedbugs/issue1304.go
new file mode 100644
index 0000000..1206e18
--- /dev/null
+++ b/test/fixedbugs/issue1304.go
@@ -0,0 +1,23 @@
+// run
+
+// 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
+
+var a = 1
+
+func main() {
+	defer func() {
+		recover()
+		if a != 2 {
+			println("BUG a =", a)
+		}
+	}()
+	a = 2
+	b := a - a
+	c := 4
+	a = c / b
+	a = 3
+}
diff --git a/test/fixedbugs/issue3705.go b/test/fixedbugs/issue3705.go
index c19bcea..64ef38b 100644
--- a/test/fixedbugs/issue3705.go
+++ b/test/fixedbugs/issue3705.go
@@ -6,4 +6,4 @@
 
 package p
 
-func init() // ERROR "missing function body"
+func init() // ERROR "missing function body|cannot declare init"
diff --git a/test/fixedbugs/issue4251.go b/test/fixedbugs/issue4251.go
index 4adec2b..3668d4c 100644
--- a/test/fixedbugs/issue4251.go
+++ b/test/fixedbugs/issue4251.go
@@ -9,13 +9,13 @@
 package p
 
 func F1(s []byte) []byte {
-	return s[2:1]		// ERROR "invalid slice index"
+	return s[2:1]		// ERROR "invalid slice index|inverted slice range"
 }
 
 func F2(a [10]byte) []byte {
-	return a[2:1]		// ERROR "invalid slice index"
+	return a[2:1]		// ERROR "invalid slice index|inverted slice range"
 }
 
 func F3(s string) string {
-	return s[2:1]		// ERROR "invalid slice index"
+	return s[2:1]		// ERROR "invalid slice index|inverted slice range"
 }
diff --git a/test/fixedbugs/issue4388.go b/test/fixedbugs/issue4388.go
new file mode 100644
index 0000000..2e052e1
--- /dev/null
+++ b/test/fixedbugs/issue4388.go
@@ -0,0 +1,56 @@
+// run
+
+// 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 (
+	"fmt"
+	"io"
+	"runtime"
+)
+
+type T struct {
+	io.Closer
+}
+
+func f1() {
+	// The 4 here and below depends on the number of internal runtime frames
+	// that sit between a deferred function called during panic and
+	// the original frame. If that changes, this test will start failing and
+	// the number here will need to be updated.
+	defer checkLine(4)
+	var t *T
+	var c io.Closer = t
+	c.Close()
+}
+
+func f2() {
+	defer checkLine(4)
+	var t T
+	var c io.Closer = t
+	c.Close()
+}
+
+func main() {
+	f1()
+	f2()
+}
+
+func checkLine(n int) {
+	if err := recover(); err == nil {
+		panic("did not panic")
+	}
+	var file string
+	var line int
+	for i := 1; i <= n; i++ {
+		_, file, line, _ = runtime.Caller(i)
+		if file != "<autogenerated>" || line != 1 {
+			continue
+		}
+		return
+	}
+	panic(fmt.Sprintf("expected <autogenerated>:1 have %s:%d", file, line))
+}
diff --git a/test/fixedbugs/issue4405.go b/test/fixedbugs/issue4405.go
index c0d8085..b8458d7 100644
--- a/test/fixedbugs/issue4405.go
+++ b/test/fixedbugs/issue4405.go
@@ -8,8 +8,8 @@ package p
 
 const (
 	_ = iota
-	_ // ERROR "illegal character"
-	_  // ERROR "illegal character"
-	_
  // ERROR "illegal character"
-	_
  // ERROR "illegal character"
+	_ // ERROR "illegal character|invalid character"
+	_  // ERROR "illegal character|invalid character"
+	_
  // ERROR "illegal character|invalid character"
+	_
  // ERROR "illegal character|invalid character"
 )
diff --git a/test/fixedbugs/issue4429.go b/test/fixedbugs/issue4429.go
index 8a93b02..6822760 100644
--- a/test/fixedbugs/issue4429.go
+++ b/test/fixedbugs/issue4429.go
@@ -12,5 +12,5 @@ type a struct {
 
 func main() {
   av := a{};
-  *a(av); // ERROR "invalid indirect"
+  _ = *a(av); // ERROR "invalid indirect|expected pointer"
 }
diff --git a/test/fixedbugs/issue4510.dir/f1.go b/test/fixedbugs/issue4510.dir/f1.go
index 1e642e4..7e2cffa 100644
--- a/test/fixedbugs/issue4510.dir/f1.go
+++ b/test/fixedbugs/issue4510.dir/f1.go
@@ -4,6 +4,6 @@
 
 package p
 
-import "fmt" // ERROR "fmt redeclared"
+import "fmt" // ERROR "fmt redeclared|imported"
 
 var _ = fmt.Printf
diff --git a/test/fixedbugs/issue4517d.go b/test/fixedbugs/issue4517d.go
index f601db6..3d727d4 100644
--- a/test/fixedbugs/issue4517d.go
+++ b/test/fixedbugs/issue4517d.go
@@ -6,4 +6,4 @@
 
 package p
 
-import init "fmt" // ERROR "cannot import package as init - init must be a func"
+import init "fmt" // ERROR "cannot import package as init"
diff --git a/test/fixedbugs/issue4545.go b/test/fixedbugs/issue4545.go
index 501caad..c37ccef 100644
--- a/test/fixedbugs/issue4545.go
+++ b/test/fixedbugs/issue4545.go
@@ -13,7 +13,7 @@ import "fmt"
 
 func main() {
 	var s uint
-	fmt.Println(1.0 + 1<<s) // ERROR "invalid operation|non-integer type"
+	fmt.Println(1.0 + 1<<s) // ERROR "invalid operation|non-integer type|incompatible type"
 	x := 1.0 + 1<<s         // ERROR "invalid operation|non-integer type"
 	_ = x
 }
diff --git a/test/fixedbugs/issue4610.go b/test/fixedbugs/issue4610.go
index bc6bfe7..d56c6d3 100644
--- a/test/fixedbugs/issue4610.go
+++ b/test/fixedbugs/issue4610.go
@@ -12,6 +12,6 @@ type bar struct {
 
 func main() {
 	var foo bar
-	_ = &foo{} // ERROR "is not a type"
-}
+	_ = &foo{} // ERROR "is not a type|expected .;."
+} // GCCGO_ERROR "expected declaration"
 
diff --git a/test/fixedbugs/issue4618.go b/test/fixedbugs/issue4618.go
index 335feaa..fe875b3 100644
--- a/test/fixedbugs/issue4618.go
+++ b/test/fixedbugs/issue4618.go
@@ -9,6 +9,7 @@ package main
 import (
 	"fmt"
 	"os"
+	"runtime"
 	"testing"
 )
 
@@ -29,11 +30,11 @@ func G() {
 func main() {
 	nf := testing.AllocsPerRun(100, F)
 	ng := testing.AllocsPerRun(100, G)
-	if int(nf) != 1 {
+	if int(nf) > 1 {
 		fmt.Printf("AllocsPerRun(100, F) = %v, want 1\n", nf)
 		os.Exit(1)
 	}
-	if int(ng) != 0 {
+	if int(ng) != 0 && (runtime.Compiler != "gccgo" || int(ng) != 1) {
 		fmt.Printf("AllocsPerRun(100, G) = %v, want 0\n", ng)
 		os.Exit(1)
 	}
diff --git a/test/fixedbugs/issue4654.go b/test/fixedbugs/issue4654.go
index 170594e..d3f582b 100644
--- a/test/fixedbugs/issue4654.go
+++ b/test/fixedbugs/issue4654.go
@@ -12,32 +12,32 @@ package p
 import "unsafe"
 
 func f() {
-	defer int(0) // ERROR "defer requires function call, not conversion"
-	go string([]byte("abc")) // ERROR "go requires function call, not conversion"
+	defer int(0) // ERROR "defer requires function call, not conversion|is not used"
+	go string([]byte("abc")) // ERROR "go requires function call, not conversion|is not used"
 	
 	var c complex128
 	var f float64
 	var t struct {X int}
 
 	var x []int
-	defer append(x, 1) // ERROR "defer discards result of append"
-	defer cap(x) // ERROR "defer discards result of cap"
-	defer complex(1, 2) // ERROR "defer discards result of complex"
-	defer complex(f, 1) // ERROR "defer discards result of complex"
-	defer imag(1i) // ERROR "defer discards result of imag"
-	defer imag(c) // ERROR "defer discards result of imag"
-	defer len(x) // ERROR "defer discards result of len"
-	defer make([]int, 1) // ERROR "defer discards result of make"
-	defer make(chan bool) // ERROR "defer discards result of make"
-	defer make(map[string]int) // ERROR "defer discards result of make"
-	defer new(int) // ERROR "defer discards result of new"
-	defer real(1i) // ERROR "defer discards result of real"
-	defer real(c) // ERROR "defer discards result of real"
-	defer append(x, 1) // ERROR "defer discards result of append"
-	defer append(x, 1) // ERROR "defer discards result of append"
-	defer unsafe.Alignof(t.X) // ERROR "defer discards result of unsafe.Alignof"
-	defer unsafe.Offsetof(t.X) // ERROR "defer discards result of unsafe.Offsetof"
-	defer unsafe.Sizeof(t) // ERROR "defer discards result of unsafe.Sizeof"
+	defer append(x, 1) // ERROR "defer discards result of append|is not used"
+	defer cap(x) // ERROR "defer discards result of cap|is not used"
+	defer complex(1, 2) // ERROR "defer discards result of complex|is not used"
+	defer complex(f, 1) // ERROR "defer discards result of complex|is not used"
+	defer imag(1i) // ERROR "defer discards result of imag|is not used"
+	defer imag(c) // ERROR "defer discards result of imag|is not used"
+	defer len(x) // ERROR "defer discards result of len|is not used"
+	defer make([]int, 1) // ERROR "defer discards result of make|is not used"
+	defer make(chan bool) // ERROR "defer discards result of make|is not used"
+	defer make(map[string]int) // ERROR "defer discards result of make|is not used"
+	defer new(int) // ERROR "defer discards result of new|is not used"
+	defer real(1i) // ERROR "defer discards result of real|is not used"
+	defer real(c) // ERROR "defer discards result of real|is not used"
+	defer append(x, 1) // ERROR "defer discards result of append|is not used"
+	defer append(x, 1) // ERROR "defer discards result of append|is not used"
+	defer unsafe.Alignof(t.X) // ERROR "defer discards result of unsafe.Alignof|is not used"
+	defer unsafe.Offsetof(t.X) // ERROR "defer discards result of unsafe.Offsetof|is not used"
+	defer unsafe.Sizeof(t) // ERROR "defer discards result of unsafe.Sizeof|is not used"
 	
 	defer copy(x, x) // ok
 	m := make(map[int]int)
@@ -47,8 +47,8 @@ func f() {
 	defer println(1) // ok
 	defer recover() // ok
 
-	int(0) // ERROR "int\(0\) evaluated but not used"
-	string([]byte("abc")) // ERROR "string\(.*\) evaluated but not used"
+	int(0) // ERROR "int\(0\) evaluated but not used|is not used"
+	string([]byte("abc")) // ERROR "string\(.*\) evaluated but not used|is not used"
 
 	append(x, 1) // ERROR "not used"
 	cap(x) // ERROR "not used"
diff --git a/test/fixedbugs/issue4667.go b/test/fixedbugs/issue4667.go
index 3a00a31..18d773c 100644
--- a/test/fixedbugs/issue4667.go
+++ b/test/fixedbugs/issue4667.go
@@ -26,11 +26,11 @@ func F() {
 func main() {
 	nf := testing.AllocsPerRun(100, F)
 	ng := testing.AllocsPerRun(100, G)
-	if int(nf) != 1 {
+	if int(nf) > 1 {
 		fmt.Printf("AllocsPerRun(100, F) = %v, want 1\n", nf)
 		os.Exit(1)
 	}
-	if int(ng) != 1 {
+	if int(ng) > 1 {
 		fmt.Printf("AllocsPerRun(100, G) = %v, want 1\n", ng)
 		os.Exit(1)
 	}
diff --git a/test/fixedbugs/issue4776.go b/test/fixedbugs/issue4776.go
index c38dc09..13781af 100644
--- a/test/fixedbugs/issue4776.go
+++ b/test/fixedbugs/issue4776.go
@@ -6,5 +6,5 @@
 
 // Issue 4776: missing package declaration error should be fatal.
 
-type MyInt int32 // ERROR "package statement must be first"
+type MyInt int32 // ERROR "package statement must be first|package clause"
 
diff --git a/test/fixedbugs/issue4813.go b/test/fixedbugs/issue4813.go
index 20dc587..f560b2f 100644
--- a/test/fixedbugs/issue4813.go
+++ b/test/fixedbugs/issue4813.go
@@ -28,25 +28,25 @@ var (
 var (
 	a1 = A[i]
 	a2 = A[f]
-	a3 = A[f2] // ERROR "truncated"
+	a3 = A[f2] // ERROR "truncated|must be integer"
 	a4 = A[c]
-	a5 = A[c2] // ERROR "truncated"
+	a5 = A[c2] // ERROR "truncated|must be integer"
 	a6 = A[vf] // ERROR "non-integer|must be integer"
 	a7 = A[vc] // ERROR "non-integer|must be integer"
 
 	s1 = S[i]
 	s2 = S[f]
-	s3 = S[f2] // ERROR "truncated"
+	s3 = S[f2] // ERROR "truncated|must be integer"
 	s4 = S[c]
-	s5 = S[c2] // ERROR "truncated"
+	s5 = S[c2] // ERROR "truncated|must be integer"
 	s6 = S[vf] // ERROR "non-integer|must be integer"
 	s7 = S[vc] // ERROR "non-integer|must be integer"
 
 	t1 = T[i]
 	t2 = T[f]
-	t3 = T[f2] // ERROR "truncated"
+	t3 = T[f2] // ERROR "truncated|must be integer"
 	t4 = T[c]
-	t5 = T[c2] // ERROR "truncated"
+	t5 = T[c2] // ERROR "truncated|must be integer"
 	t6 = T[vf] // ERROR "non-integer|must be integer"
 	t7 = T[vc] // ERROR "non-integer|must be integer"
 )
diff --git a/test/fixedbugs/issue4847.go b/test/fixedbugs/issue4847.go
index a99e801..91a6568 100644
--- a/test/fixedbugs/issue4847.go
+++ b/test/fixedbugs/issue4847.go
@@ -19,6 +19,6 @@ func matchList(s *S) E { return matcher(matchAnyFn)(s) }
 
 var foo = matcher(matchList)
 
-var matchAny = matcher(matchList) // ERROR "initialization loop"
+var matchAny = matcher(matchList) // ERROR "initialization loop|depends upon itself"
 
 func matchAnyFn(s *S) (err E) { return matchAny(s) }
diff --git a/test/fixedbugs/issue5089.go b/test/fixedbugs/issue5089.go
index 14d6bde..81b9f05 100644
--- a/test/fixedbugs/issue5089.go
+++ b/test/fixedbugs/issue5089.go
@@ -8,8 +8,8 @@
 
 package p
 
-import "bufio"
+import "bufio"	// GCCGO_ERROR "previous"
 
-func (b *bufio.Reader) Buffered() int { // ERROR "non-local"
+func (b *bufio.Reader) Buffered() int { // ERROR "non-local|redefinition"
 	return -1
 }
diff --git a/test/fixedbugs/issue5172.go b/test/fixedbugs/issue5172.go
index 2dd542a..a6acbd3 100644
--- a/test/fixedbugs/issue5172.go
+++ b/test/fixedbugs/issue5172.go
@@ -14,6 +14,6 @@ type foo struct {
 
 func main() {
 	var f foo
-	go f.bar()
-	defer f.bar()
+	go f.bar()	// GCCGO_ERROR "undefined"
+	defer f.bar()	// GCCGO_ERROR "undefined"
 }
diff --git a/test/fixedbugs/issue5358.go b/test/fixedbugs/issue5358.go
index 75aa953..c2b1da9 100644
--- a/test/fixedbugs/issue5358.go
+++ b/test/fixedbugs/issue5358.go
@@ -13,5 +13,5 @@ func f(x int, y ...int) {}
 func g() (int, []int)
 
 func main() {
-	f(g()) // ERROR "as type int in"
+	f(g()) // ERROR "as type int in|incompatible type"
 }
diff --git a/test/fixedbugs/issue5493.go b/test/fixedbugs/issue5493.go
index affc07b..2ee0398 100644
--- a/test/fixedbugs/issue5493.go
+++ b/test/fixedbugs/issue5493.go
@@ -31,9 +31,10 @@ func run() error {
 }
 
 func main() {
-	// Does not work on 32-bits due to partially conservative GC.
+	// Does not work on 32-bits, or with gccgo, due to partially
+	// conservative GC.
 	// Try to enable when we have fully precise GC.
-	if runtime.GOARCH != "amd64" {
+	if runtime.GOARCH != "amd64" || runtime.Compiler == "gccgo" {
 		return
 	}
 	count = N
diff --git a/test/fixedbugs/issue5581.go b/test/fixedbugs/issue5581.go
index 8c2d597..36a4ad6 100644
--- a/test/fixedbugs/issue5581.go
+++ b/test/fixedbugs/issue5581.go
@@ -26,7 +26,7 @@ type Foo struct {
 
 type Bar struct {
 	A *Foo
-	B chan Blah // ERROR "undefined: Blah"
+	B chan Blah // ERROR "undefined.*Blah"
 }
 
 func main() {
diff --git a/test/fixedbugs/issue5793.go b/test/fixedbugs/issue5793.go
new file mode 100644
index 0000000..f5a9965
--- /dev/null
+++ b/test/fixedbugs/issue5793.go
@@ -0,0 +1,36 @@
+// run
+
+// 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 5793: calling 2-arg builtin with multiple-result f() call expression gives
+// spurious error.
+
+package main
+
+func complexArgs() (float64, float64) {
+	return 5, 7
+}
+
+func appendArgs() ([]string, string) {
+	return []string{"foo"}, "bar"
+}
+
+func appendMultiArgs() ([]byte, byte, byte) {
+	return []byte{'a', 'b'}, '1', '2'
+}
+
+func main() {
+	if c := complex(complexArgs()); c != 5+7i {
+		panic(c)
+	}
+
+	if s := append(appendArgs()); len(s) != 2 || s[0] != "foo" || s[1] != "bar" {
+		panic(s)
+	}
+
+	if b := append(appendMultiArgs()); len(b) != 4 || b[0] != 'a' || b[1] != 'b' || b[2] != '1' || b[3] != '2' {
+		panic(b)
+	}
+}
diff --git a/test/fixedbugs/issue5957.dir/c.go b/test/fixedbugs/issue5957.dir/c.go
index 42c8817..a1781d4 100644
--- a/test/fixedbugs/issue5957.dir/c.go
+++ b/test/fixedbugs/issue5957.dir/c.go
@@ -1,12 +1,12 @@
 package p
 
 import (
-	"./a" // ERROR "imported and not used: \x22a\x22 as surprise"
-	"./b" // ERROR "imported and not used: \x22b\x22 as surprise2"
-	b "./b" // ERROR "imported and not used: \x22b\x22$"
-	foo "math" // ERROR "imported and not used: \x22math\x22 as foo"
+	"./a" // ERROR "imported and not used: \x22a\x22 as surprise|imported and not used: surprise"
+	"./b" // GC_ERROR "imported and not used: \x22b\x22 as surprise2|imported and not used: surprise2"
+	b "./b" // ERROR "imported and not used: \x22b\x22$|imported and not used: surprise2"
+	foo "math" // ERROR "imported and not used: \x22math\x22 as foo|imported and not used: math"
 	"fmt" // actually used
-	"strings" // ERROR "imported and not used: \x22strings\x22"
+	"strings" // ERROR "imported and not used: \x22strings\x22|imported and not used: strings"
 )
 
 var _ = fmt.Printf
diff --git a/test/fixedbugs/issue6295.dir/p0.go b/test/fixedbugs/issue6295.dir/p0.go
new file mode 100644
index 0000000..cf86fbc
--- /dev/null
+++ b/test/fixedbugs/issue6295.dir/p0.go
@@ -0,0 +1,13 @@
+// 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 p0
+
+type T0 interface {
+	m0()
+}
+
+type S0 struct{}
+
+func (S0) m0() {}
diff --git a/test/fixedbugs/issue6295.dir/p1.go b/test/fixedbugs/issue6295.dir/p1.go
new file mode 100644
index 0000000..974d02f
--- /dev/null
+++ b/test/fixedbugs/issue6295.dir/p1.go
@@ -0,0 +1,26 @@
+// 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 p1
+
+import "./p0"
+
+type T1 interface {
+	p0.T0
+	m1()
+}
+
+type S1 struct {
+	p0.S0
+}
+
+func (S1) m1() {}
+
+func NewT0() p0.T0 {
+	return S1{}
+}
+
+func NewT1() T1 {
+	return S1{}
+}
diff --git a/test/fixedbugs/issue6295.dir/p2.go b/test/fixedbugs/issue6295.dir/p2.go
new file mode 100644
index 0000000..4703ec0
--- /dev/null
+++ b/test/fixedbugs/issue6295.dir/p2.go
@@ -0,0 +1,19 @@
+// 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 (
+	"./p0"
+	"./p1"
+)
+
+var (
+	_ p0.T0 = p0.S0{}
+	_ p0.T0 = p1.S1{}
+	_ p0.T0 = p1.NewT0()
+	_ p0.T0 = p1.NewT1() // same as p1.S1{}
+)
+
+func main() {}
diff --git a/test/fixedbugs/issue6295.go b/test/fixedbugs/issue6295.go
new file mode 100644
index 0000000..b8da212
--- /dev/null
+++ b/test/fixedbugs/issue6295.go
@@ -0,0 +1,10 @@
+// compiledir
+
+// 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 6295: qualified name of unexported methods
+// is corrupted during import.
+
+package ignored
diff --git a/test/fixedbugs/issue6402.go b/test/fixedbugs/issue6402.go
new file mode 100644
index 0000000..da5980c
--- /dev/null
+++ b/test/fixedbugs/issue6402.go
@@ -0,0 +1,13 @@
+// errorcheck
+
+// 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 6402: spurious 'use of untyped nil' error
+
+package p
+
+func f() uintptr {
+	return nil // ERROR "cannot use nil as type uintptr in return argument"
+}
diff --git a/test/fixedbugs/issue6403.go b/test/fixedbugs/issue6403.go
new file mode 100644
index 0000000..b61e2e2
--- /dev/null
+++ b/test/fixedbugs/issue6403.go
@@ -0,0 +1,14 @@
+// errorcheck
+
+// 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 6403: fix spurious 'const initializer is not a constant' error
+
+package p
+
+import "syscall"
+
+const A int = syscall.X // ERROR "undefined: syscall.X"
+const B int = voidpkg.X // ERROR "undefined: voidpkg"
diff --git a/test/fixedbugs/issue6405.go b/test/fixedbugs/issue6405.go
new file mode 100644
index 0000000..b4551cc
--- /dev/null
+++ b/test/fixedbugs/issue6405.go
@@ -0,0 +1,13 @@
+// errorcheck
+
+// 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 6405: spurious 'not enough arguments to return' error
+
+package p
+
+func Open() (int, error) {
+	return OpenFile() // ERROR "undefined: OpenFile"
+}
diff --git a/test/fixedbugs/issue6406.go b/test/fixedbugs/issue6406.go
new file mode 100644
index 0000000..5491193
--- /dev/null
+++ b/test/fixedbugs/issue6406.go
@@ -0,0 +1,12 @@
+// errorcheck
+
+// 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
+
+func main() {
+	s = "bob" // ERROR "undefined.*s"
+	_ = s // ERROR "undefined.*s"
+}
diff --git a/test/fixedbugs/issue6500.go b/test/fixedbugs/issue6500.go
new file mode 100644
index 0000000..b265f9a
--- /dev/null
+++ b/test/fixedbugs/issue6500.go
@@ -0,0 +1,29 @@
+// errorcheck
+
+// 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 6500: missing error when fallthrough appears in a block.
+
+package main
+
+func main() {
+	var x int
+	switch x {
+	case 0:
+		{
+			fallthrough // ERROR "fallthrough"
+		}
+	case 1:
+		{
+			switch x {
+			case 2:
+				fallthrough
+			case 3:
+			}
+		}
+		fallthrough
+	default:
+	}
+}
diff --git a/test/fixedbugs/issue6572.go b/test/fixedbugs/issue6572.go
new file mode 100644
index 0000000..e75da54
--- /dev/null
+++ b/test/fixedbugs/issue6572.go
@@ -0,0 +1,21 @@
+// errorcheck
+
+// 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
+
+func foo() (T, T) { // ERROR "undefined"
+	return 0, 0
+}
+
+func bar() (T, string, T) { // ERROR "undefined"
+	return 0, "", 0
+}
+
+func main() {
+	var x, y, z int
+	x, y = foo()
+	x, y, z = bar() // ERROR "cannot (use type|assign) string"
+}
diff --git a/test/fixedbugs/issue6789.dir/a.go b/test/fixedbugs/issue6789.dir/a.go
new file mode 100644
index 0000000..9c90e07
--- /dev/null
+++ b/test/fixedbugs/issue6789.dir/a.go
@@ -0,0 +1,14 @@
+// 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 a
+
+type unexported struct {
+        a int
+        b bool
+}
+
+type Struct struct {
+        unexported
+}
diff --git a/test/fixedbugs/issue6789.dir/b.go b/test/fixedbugs/issue6789.dir/b.go
new file mode 100644
index 0000000..b6a6fc3
--- /dev/null
+++ b/test/fixedbugs/issue6789.dir/b.go
@@ -0,0 +1,12 @@
+// 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 "./a"
+
+type s a.Struct
+
+func main() {
+}
diff --git a/test/fixedbugs/issue6789.go b/test/fixedbugs/issue6789.go
new file mode 100644
index 0000000..e3a2c33
--- /dev/null
+++ b/test/fixedbugs/issue6789.go
@@ -0,0 +1,10 @@
+// rundir
+
+// 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 6789: gccgo failed to find the hash function for an
+// unexported struct embedded in an exported struct.
+
+package ignored
diff --git a/test/fixedbugs/issue6847.go b/test/fixedbugs/issue6847.go
new file mode 100644
index 0000000..e6427e1
--- /dev/null
+++ b/test/fixedbugs/issue6847.go
@@ -0,0 +1,85 @@
+// compile
+
+// 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 6847: select clauses involving implicit conversion
+// of channels trigger a spurious typechecking error during walk.
+
+package p
+
+type I1 interface {
+	String()
+}
+type I2 interface {
+	String()
+}
+
+func F() {
+	var (
+		cr <-chan int
+		cs chan<- int
+		c  chan int
+
+		ccr chan (<-chan int)
+		ccs chan chan<- int
+		cc  chan chan int
+
+		ok bool
+	)
+	// Send cases.
+	select {
+	case ccr <- cr:
+	case ccr <- c:
+	}
+	select {
+	case ccs <- cs:
+	case ccs <- c:
+	}
+	select {
+	case ccr <- c:
+	default:
+	}
+	// Receive cases.
+	select {
+	case cr = <-cc:
+	case cs = <-cc:
+	case c = <-cc:
+	}
+	select {
+	case cr = <-cc:
+	default:
+	}
+	select {
+	case cr, ok = <-cc:
+	case cs, ok = <-cc:
+	case c = <-cc:
+	}
+      // Interfaces.
+	var (
+		c1 chan I1
+		c2 chan I2
+		x1 I1
+		x2 I2
+	)
+	select {
+	case c1 <- x1:
+	case c1 <- x2:
+	case c2 <- x1:
+	case c2 <- x2:
+	}
+	select {
+	case x1 = <-c1:
+	case x1 = <-c2:
+	case x2 = <-c1:
+	case x2 = <-c2:
+	}
+	select {
+	case x1, ok = <-c1:
+	case x1, ok = <-c2:
+	case x2, ok = <-c1:
+	case x2, ok = <-c2:
+	}
+	_ = ok
+}
diff --git a/test/fixedbugs/issue6889.go b/test/fixedbugs/issue6889.go
new file mode 100644
index 0000000..46bb5da
--- /dev/null
+++ b/test/fixedbugs/issue6889.go
@@ -0,0 +1,103 @@
+// errorcheck
+
+// 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 6889: confusing error message: ovf in mpaddxx
+
+package main
+
+const (
+	f1  = 1
+	f2  = f1 * 2
+	f3  = f2 * 3
+	f4  = f3 * 4
+	f5  = f4 * 5
+	f6  = f5 * 6
+	f7  = f6 * 7
+	f8  = f7 * 8
+	f9  = f8 * 9
+	f10 = f9 * 10
+	f11 = f10 * 11
+	f12 = f11 * 12
+	f13 = f12 * 13
+	f14 = f13 * 14
+	f15 = f14 * 15
+	f16 = f15 * 16
+	f17 = f16 * 17
+	f18 = f17 * 18
+	f19 = f18 * 19
+	f20 = f19 * 20
+	f21 = f20 * 21
+	f22 = f21 * 22
+	f23 = f22 * 23
+	f24 = f23 * 24
+	f25 = f24 * 25
+	f26 = f25 * 26
+	f27 = f26 * 27
+	f28 = f27 * 28
+	f29 = f28 * 29
+	f30 = f29 * 30
+	f31 = f30 * 31
+	f32 = f31 * 32
+	f33 = f32 * 33
+	f34 = f33 * 34
+	f35 = f34 * 35
+	f36 = f35 * 36
+	f37 = f36 * 37
+	f38 = f37 * 38
+	f39 = f38 * 39
+	f40 = f39 * 40
+	f41 = f40 * 41
+	f42 = f41 * 42
+	f43 = f42 * 43
+	f44 = f43 * 44
+	f45 = f44 * 45
+	f46 = f45 * 46
+	f47 = f46 * 47
+	f48 = f47 * 48
+	f49 = f48 * 49
+	f50 = f49 * 50
+	f51 = f50 * 51
+	f52 = f51 * 52
+	f53 = f52 * 53
+	f54 = f53 * 54
+	f55 = f54 * 55
+	f56 = f55 * 56
+	f57 = f56 * 57
+	f58 = f57 * 58
+	f59 = f58 * 59
+	f60 = f59 * 60
+	f61 = f60 * 61
+	f62 = f61 * 62
+	f63 = f62 * 63
+	f64 = f63 * 64
+	f65 = f64 * 65
+	f66 = f65 * 66
+	f67 = f66 * 67
+	f68 = f67 * 68
+	f69 = f68 * 69
+	f70 = f69 * 70
+	f71 = f70 * 71
+	f72 = f71 * 72
+	f73 = f72 * 73
+	f74 = f73 * 74
+	f75 = f74 * 75
+	f76 = f75 * 76
+	f77 = f76 * 77
+	f78 = f77 * 78
+	f79 = f78 * 79
+	f80 = f79 * 80
+	f81 = f80 * 81
+	f82 = f81 * 82
+	f83 = f82 * 83
+	f84 = f83 * 84
+	f85 = f84 * 85
+	f86 = f85 * 86
+	f87 = f86 * 87
+	f88 = f87 * 88
+	f89 = f88 * 89
+	f90 = f89 * 90
+	f91 = f90 * 91 // ERROR "overflow"
+)
diff --git a/test/fixedbugs/issue6899.go b/test/fixedbugs/issue6899.go
new file mode 100644
index 0000000..a693bf2
--- /dev/null
+++ b/test/fixedbugs/issue6899.go
@@ -0,0 +1,13 @@
+// cmpout
+
+// 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 "math"
+
+func main() {
+	println(math.Copysign(0, -1))
+}
diff --git a/test/fixedbugs/issue6899.out b/test/fixedbugs/issue6899.out
new file mode 100644
index 0000000..e2375f0
--- /dev/null
+++ b/test/fixedbugs/issue6899.out
@@ -0,0 +1 @@
+-0.000000e+000
diff --git a/test/fixedbugs/issue6902.go b/test/fixedbugs/issue6902.go
new file mode 100644
index 0000000..5c2c545
--- /dev/null
+++ b/test/fixedbugs/issue6902.go
@@ -0,0 +1,21 @@
+// run
+
+// 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 6902: confusing printing of large floating point constants
+
+package main
+
+import (
+	"os"
+)
+
+var x = -1e-10000
+
+func main() {
+	if x != 0 {
+		os.Exit(1)
+	}
+}
diff --git a/test/fixedbugs/issue6964.go b/test/fixedbugs/issue6964.go
new file mode 100644
index 0000000..821735c
--- /dev/null
+++ b/test/fixedbugs/issue6964.go
@@ -0,0 +1,11 @@
+// errorcheck
+
+// 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
+
+func main() {
+	_ = string(-4 + 2i + 2) // ERROR "-4\+2i"
+}
diff --git a/test/fixedbugs/issue7023.dir/a.go b/test/fixedbugs/issue7023.dir/a.go
new file mode 100644
index 0000000..cdb5432
--- /dev/null
+++ b/test/fixedbugs/issue7023.dir/a.go
@@ -0,0 +1,10 @@
+// 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 a
+
+func Foo() {
+	goto bar
+bar:
+}
diff --git a/test/fixedbugs/issue7023.dir/b.go b/test/fixedbugs/issue7023.dir/b.go
new file mode 100644
index 0000000..c6fe40d
--- /dev/null
+++ b/test/fixedbugs/issue7023.dir/b.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.
+
+package b
+
+import (
+	"./a"
+)
+
+var f = a.Foo
diff --git a/test/fixedbugs/issue7023.go b/test/fixedbugs/issue7023.go
new file mode 100644
index 0000000..f18c611
--- /dev/null
+++ b/test/fixedbugs/issue7023.go
@@ -0,0 +1,10 @@
+// compiledir
+
+// 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 7023: corrupted export data when an inlined function
+// contains a goto.
+
+package ignored
diff --git a/test/fixedbugs/issue7044.go b/test/fixedbugs/issue7044.go
new file mode 100644
index 0000000..cac6a76
--- /dev/null
+++ b/test/fixedbugs/issue7044.go
@@ -0,0 +1,43 @@
+// run
+
+// 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 7044: bad AMOVFD and AMOVDF assembly generation on
+// arm for registers above 7.
+
+package main
+
+import (
+	"fmt"
+	"reflect"
+)
+
+func f() [16]float32 {
+	f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15 :=
+		float32(1), float32(1), float32(1), float32(1), float32(1), float32(1), float32(1), float32(1), float32(1), float32(1), float32(1), float32(1), float32(1), float32(1), float32(1), float32(1)
+	// Use all 16 registers to do float32 --> float64 conversion.
+	d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15 :=
+		float64(f0), float64(f1), float64(f2), float64(f3), float64(f4), float64(f5), float64(f6), float64(f7), float64(f8), float64(f9), float64(f10), float64(f11), float64(f12), float64(f13), float64(f14), float64(f15)
+	// Use all 16 registers to do float64 --> float32 conversion.
+	g0, g1, g2, g3, g4, g5, g6, g7, g8, g9, g10, g11, g12, g13, g14, g15 :=
+		float32(d0), float32(d1), float32(d2), float32(d3), float32(d4), float32(d5), float32(d6), float32(d7), float32(d8), float32(d9), float32(d10), float32(d11), float32(d12), float32(d13), float32(d14), float32(d15)
+	// Force another conversion, so that the previous conversion doesn't
+	// get optimized away into constructing the returned array. With current
+	// optimizations, constructing the returned array uses only
+	// a single register.
+	e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15 :=
+		float64(g0), float64(g1), float64(g2), float64(g3), float64(g4), float64(g5), float64(g6), float64(g7), float64(g8), float64(g9), float64(g10), float64(g11), float64(g12), float64(g13), float64(g14), float64(g15)
+	return [16]float32{
+		float32(e0), float32(e1), float32(e2), float32(e3), float32(e4), float32(e5), float32(e6), float32(e7), float32(e8), float32(e9), float32(e10), float32(e11), float32(e12), float32(e13), float32(e14), float32(e15),
+	}
+}
+
+func main() {
+	want := [16]float32{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
+	got := f()
+	if !reflect.DeepEqual(got, want) {
+		fmt.Printf("f() = %#v; want %#v\n", got, want)
+	}
+}
diff --git a/test/fixedbugs/issue7050.go b/test/fixedbugs/issue7050.go
new file mode 100644
index 0000000..e58b684
--- /dev/null
+++ b/test/fixedbugs/issue7050.go
@@ -0,0 +1,19 @@
+// run
+
+// 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 (
+	"fmt"
+	"os"
+)
+
+func main() {
+	_, err := os.Stdout.Write(nil)
+	if err != nil {
+		fmt.Printf("BUG: os.Stdout.Write(nil) = %v\n", err)
+	}
+}
diff --git a/test/fixedbugs/issue7083.go b/test/fixedbugs/issue7083.go
new file mode 100644
index 0000000..79bfd3b
--- /dev/null
+++ b/test/fixedbugs/issue7083.go
@@ -0,0 +1,22 @@
+// run
+
+package main
+
+import "runtime/debug"
+
+func f(m map[int]*string, i int) {
+	s := ""
+	m[i] = &s
+}
+
+func main() {
+	debug.SetGCPercent(0)
+	m := map[int]*string{}
+	for i := 0; i < 40; i++ {
+		f(m, i)
+		if len(*m[i]) != 0 {
+			println("bad length", i, m[i], len(*m[i]))
+			panic("bad length")
+		}
+	}
+}
diff --git a/test/fixedbugs/issue7129.go b/test/fixedbugs/issue7129.go
new file mode 100644
index 0000000..2425cbd
--- /dev/null
+++ b/test/fixedbugs/issue7129.go
@@ -0,0 +1,21 @@
+// errorcheck
+
+// 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 7129: inconsistent "wrong arg type" error for multivalued g in f(g())
+
+package main
+
+func f(int) {}
+
+func g() bool { return true }
+
+func h(int, int) {}
+
+func main() {
+	f(g())        // ERROR "in argument to f"
+	f(true)       // ERROR "in argument to f"
+	h(true, true) // ERROR "in argument to h"
+}
diff --git a/test/fixedbugs/issue7150.go b/test/fixedbugs/issue7150.go
new file mode 100644
index 0000000..264958a
--- /dev/null
+++ b/test/fixedbugs/issue7150.go
@@ -0,0 +1,17 @@
+// errorcheck
+
+// 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 7150: array index out of bounds error off by one
+
+package main
+
+func main() {
+	_ = [0]int{-1: 50}              // ERROR "array index must be non-negative integer constant"
+	_ = [0]int{0: 0}                // ERROR "array index 0 out of bounds \[0:0\]"
+	_ = [0]int{5: 25}               // ERROR "array index 5 out of bounds \[0:0\]"
+	_ = [10]int{2: 10, 15: 30}      // ERROR "array index 15 out of bounds \[0:10\]"
+	_ = [10]int{5: 5, 1: 1, 12: 12} // ERROR "array index 12 out of bounds \[0:10\]"
+}
diff --git a/test/fixedbugs/issue7153.go b/test/fixedbugs/issue7153.go
new file mode 100644
index 0000000..d70d858
--- /dev/null
+++ b/test/fixedbugs/issue7153.go
@@ -0,0 +1,11 @@
+// errorcheck
+
+// 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 7153: array invalid index error duplicated on successive bad values
+
+package p
+
+var _ = []int{a: true, true} // ERROR "undefined: a" "cannot use true \(type bool\) as type int in array element"
diff --git a/test/fixedbugs/issue7214.go b/test/fixedbugs/issue7214.go
new file mode 100644
index 0000000..82ddf74
--- /dev/null
+++ b/test/fixedbugs/issue7214.go
@@ -0,0 +1,30 @@
+// errorcheck
+
+// 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 7214: No duplicate key error for maps with interface{} key type
+
+package p
+
+var _ = map[interface{}]int{2: 1, 2: 1} // ERROR "duplicate key"
+var _ = map[interface{}]int{int(2): 1, int16(2): 1}
+var _ = map[interface{}]int{int16(2): 1, int16(2): 1} // ERROR "duplicate key"
+
+type S string
+
+var _ = map[interface{}]int{"a": 1, "a": 1} // ERROR "duplicate key"
+var _ = map[interface{}]int{"a": 1, S("a"): 1}
+var _ = map[interface{}]int{S("a"): 1, S("a"): 1} // ERROR "duplicate key"
+
+type I interface {
+	f()
+}
+
+type N int
+
+func (N) f() {}
+
+var _ = map[I]int{N(0): 1, N(2): 1}
+var _ = map[I]int{N(2): 1, N(2): 1} // ERROR "duplicate key"
diff --git a/test/fixedbugs/issue7223.go b/test/fixedbugs/issue7223.go
new file mode 100644
index 0000000..c5955d5
--- /dev/null
+++ b/test/fixedbugs/issue7223.go
@@ -0,0 +1,20 @@
+// errorcheck
+
+// 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
+
+var bits1 uint = 10
+const bits2 uint = 10
+
+func main() {
+	_ = make([]byte, 1<<bits1)
+	_ = make([]byte, 1<<bits2)
+	_ = make([]byte, nil) // ERROR "non-integer.*len"
+	_ = make([]byte, nil, 2) // ERROR "non-integer.*len"
+	_ = make([]byte, 1, nil) // ERROR "non-integer.*cap"
+	_ = make([]byte, true) // ERROR "non-integer.*len"
+	_ = make([]byte, "abc") // ERROR "non-integer.*len"
+}
diff --git a/test/fixedbugs/issue7272.go b/test/fixedbugs/issue7272.go
new file mode 100644
index 0000000..97a08da
--- /dev/null
+++ b/test/fixedbugs/issue7272.go
@@ -0,0 +1,48 @@
+// compile
+
+// 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.
+
+// Issue 7272: test builtin functions in statement context and in
+// go/defer functions.
+
+package p
+
+func F() {
+	var a []int
+	var c chan int
+	var m map[int]int
+
+	close(c)
+	copy(a, a)
+	delete(m, 0)
+	panic(0)
+	print("foo")
+	println("bar")
+	recover()
+
+	(close(c))
+	(copy(a, a))
+	(delete(m, 0))
+	(panic(0))
+	(print("foo"))
+	(println("bar"))
+	(recover())
+
+	go close(c)
+	go copy(a, a)
+	go delete(m, 0)
+	go panic(0)
+	go print("foo")
+	go println("bar")
+	go recover()
+
+	defer close(c)
+	defer copy(a, a)
+	defer delete(m, 0)
+	defer panic(0)
+	defer print("foo")
+	defer println("bar")
+	defer recover()
+}
diff --git a/test/fixedbugs/issue7310.go b/test/fixedbugs/issue7310.go
new file mode 100644
index 0000000..4a535a1
--- /dev/null
+++ b/test/fixedbugs/issue7310.go
@@ -0,0 +1,15 @@
+// errorcheck
+
+// 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.
+
+// Internal compiler crash used to stop errors during second copy.
+
+package main
+
+func main() {
+	_ = copy(nil, []int{}) // ERROR "use of untyped nil"
+	_ = copy([]int{}, nil) // ERROR "use of untyped nil"
+	_ = 1+true // ERROR "cannot convert true" "mismatched types int and bool"
+}
diff --git a/test/fixedbugs/issue7316.go b/test/fixedbugs/issue7316.go
new file mode 100644
index 0000000..4b32261
--- /dev/null
+++ b/test/fixedbugs/issue7316.go
@@ -0,0 +1,37 @@
+// runoutput
+
+// 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 7316
+// This test exercises all types of numeric conversions, which was one
+// of the sources of etype mismatch during register allocation in 8g.
+
+package main
+
+import "fmt"
+
+const tpl = `
+func init() {
+	var i %s
+	j := %s(i)
+	_ = %s(j)
+}
+`
+
+func main() {
+	fmt.Println("package main")
+	ntypes := []string{
+		"byte", "rune", "uintptr",
+		"float32", "float64",
+		"int", "int8", "int16", "int32", "int64",
+		"uint", "uint8", "uint16", "uint32", "uint64",
+	}
+	for i, from := range ntypes {
+		for _, to := range ntypes[i:] {
+			fmt.Printf(tpl, from, to, from)
+		}
+	}
+	fmt.Println("func main() {}")
+}
diff --git a/test/fixedbugs/issue7346.go b/test/fixedbugs/issue7346.go
new file mode 100644
index 0000000..dd5ea22
--- /dev/null
+++ b/test/fixedbugs/issue7346.go
@@ -0,0 +1,14 @@
+// compile
+
+// 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 7346 : internal error "doasm" error due to checknil
+// of a nil literal.
+
+package main
+
+func main() {
+	_ = *(*int)(nil)
+}
diff --git a/test/fixedbugs/issue7366.go b/test/fixedbugs/issue7366.go
new file mode 100644
index 0000000..754da6f
--- /dev/null
+++ b/test/fixedbugs/issue7366.go
@@ -0,0 +1,21 @@
+// compile
+
+// 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 7366: generates a temporary with ideal type
+// during comparison of small structs.
+
+package main
+
+type T struct {
+	data [10]byte
+}
+
+func main() {
+	var a T
+	var b T
+	if a == b {
+	}
+}
diff --git a/test/fixedbugs/issue7405.go b/test/fixedbugs/issue7405.go
new file mode 100644
index 0000000..52e1176
--- /dev/null
+++ b/test/fixedbugs/issue7405.go
@@ -0,0 +1,51 @@
+// compile
+
+// 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 7405: the equality function for struct with many
+// embedded fields became more complex after fixing issue 7366,
+// leading to out of registers on 386.
+
+package p
+
+type T1 struct {
+	T2
+	T3
+	T4
+}
+
+type T2 struct {
+	Conn
+}
+
+type T3 struct {
+	PacketConn
+}
+
+type T4 struct {
+	PacketConn
+	T5
+}
+
+type T5 struct {
+	x int
+	T6
+}
+
+type T6 struct {
+	y, z int
+}
+
+type Conn interface {
+	A()
+}
+
+type PacketConn interface {
+	B()
+}
+
+func F(a, b T1) bool {
+	return a == b
+}
diff --git a/test/fixedbugs/issue7419.go b/test/fixedbugs/issue7419.go
new file mode 100644
index 0000000..39b454c
--- /dev/null
+++ b/test/fixedbugs/issue7419.go
@@ -0,0 +1,25 @@
+// run
+
+// 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 7419: odd behavior for float constants underflowing to 0
+
+package main
+
+import (
+	"os"
+)
+
+var x = 1e-779137
+var y = 1e-779138
+
+func main() {
+	if x != 0 {
+		os.Exit(1)
+	}
+	if y != 0 {
+		os.Exit(2)
+	}
+}
diff --git a/test/fixedbugs/issue7525.go b/test/fixedbugs/issue7525.go
new file mode 100644
index 0000000..4e1d88a
--- /dev/null
+++ b/test/fixedbugs/issue7525.go
@@ -0,0 +1,19 @@
+// errorcheck
+
+// 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 7525: self-referential array types.
+
+package main
+
+import "unsafe"
+
+var x struct {
+	a [unsafe.Sizeof(x.a)]int // ERROR "array bound|typechecking loop|invalid expression"
+	b [unsafe.Offsetof(x.b)]int // ERROR "array bound"
+	c [unsafe.Alignof(x.c)]int // ERROR "array bound|invalid expression"
+	d [len(x.d)]int // ERROR "array bound|invalid array"
+	e [cap(x.e)]int // ERROR "array bound|invalid array"
+}
diff --git a/test/fixedbugs/issue7538a.go b/test/fixedbugs/issue7538a.go
new file mode 100644
index 0000000..283d9eb
--- /dev/null
+++ b/test/fixedbugs/issue7538a.go
@@ -0,0 +1,15 @@
+// errorcheck
+
+// 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 7538: blank (_) labels handled incorrectly
+
+package p
+
+func f() {
+_:
+_:
+	goto _ // ERROR "not defined"
+}
diff --git a/test/fixedbugs/issue7538b.go b/test/fixedbugs/issue7538b.go
new file mode 100644
index 0000000..28cef5d
--- /dev/null
+++ b/test/fixedbugs/issue7538b.go
@@ -0,0 +1,13 @@
+// compile
+
+// 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 7538: blank (_) labels handled incorrectly
+
+package p
+
+func f() {
+_:
+}
diff --git a/test/fixedbugs/issue7547.go b/test/fixedbugs/issue7547.go
new file mode 100644
index 0000000..f75a330
--- /dev/null
+++ b/test/fixedbugs/issue7547.go
@@ -0,0 +1,17 @@
+// compile
+
+// 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
+
+func f() map[string]interface{} {
+	var p *map[string]map[string]interface{}
+	_ = p
+	return nil
+}
+
+func main() {
+	f()
+}
diff --git a/test/fixedbugs/issue7550.go b/test/fixedbugs/issue7550.go
new file mode 100644
index 0000000..0c4cf93
--- /dev/null
+++ b/test/fixedbugs/issue7550.go
@@ -0,0 +1,27 @@
+// run
+
+// 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
+
+func shouldPanic(f func()) {
+        defer func() {
+                if recover() == nil {
+                        panic("not panicking")
+                }
+        }()
+        f()
+}
+
+func f() {
+        length := int(^uint(0) >> 1)
+        a := make([]struct{}, length)
+        b := make([]struct{}, length)
+        _ = append(a, b...)
+}
+
+func main() {
+	shouldPanic(f)
+}
diff --git a/test/fixedbugs/issue7590.go b/test/fixedbugs/issue7590.go
new file mode 100644
index 0000000..e283832
--- /dev/null
+++ b/test/fixedbugs/issue7590.go
@@ -0,0 +1,21 @@
+// compile
+
+// 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 7590: gccgo incorrectly traverses nested composite literals.
+
+package p
+
+type S struct {
+	F int
+}
+
+var M = map[string]S{
+	"a": { F: 1 },
+}
+
+var P = M["a"]
+
+var F = P.F
diff --git a/test/fixedbugs/issue7648.dir/a.go b/test/fixedbugs/issue7648.dir/a.go
new file mode 100644
index 0000000..c76aaa6
--- /dev/null
+++ b/test/fixedbugs/issue7648.dir/a.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.
+
+package a
+
+const (
+	sinPi4 = 0.70710678118654752440084436210484903928483593768847
+	A = complex(sinPi4, -sinPi4)
+)
+
diff --git a/test/fixedbugs/issue7648.dir/b.go b/test/fixedbugs/issue7648.dir/b.go
new file mode 100644
index 0000000..b9223ed
--- /dev/null
+++ b/test/fixedbugs/issue7648.dir/b.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.
+
+package b
+
+import "a"
+
+func f() {
+	println(a.A)
+}
diff --git a/test/fixedbugs/issue7648.go b/test/fixedbugs/issue7648.go
new file mode 100644
index 0000000..b391c4a
--- /dev/null
+++ b/test/fixedbugs/issue7648.go
@@ -0,0 +1,9 @@
+// compiledir
+
+// 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 7648: spurious "bad negated constant" for complex constants.
+
+package ignored
diff --git a/test/fixedbugs/issue7675.go b/test/fixedbugs/issue7675.go
new file mode 100644
index 0000000..d97ee35
--- /dev/null
+++ b/test/fixedbugs/issue7675.go
@@ -0,0 +1,24 @@
+// errorcheck
+
+// 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 7675: fewer errors for wrong argument count
+
+package p
+
+func f(string, int, float64, string)
+
+func g(string, int, float64, ...string)
+
+func main() {
+	f(1, 0.5, "hello") // ERROR "not enough arguments"
+	f("1", 2, 3.1, "4")
+	f(1, 0.5, "hello", 4, 5) // ERROR "too many arguments"
+	g(1, 0.5)                // ERROR "not enough arguments"
+	g("1", 2, 3.1)
+	g(1, 0.5, []int{3, 4}...) // ERROR "not enough arguments"
+	g("1", 2, 3.1, "4", "5")
+	g(1, 0.5, "hello", 4, []int{5, 6}...) // ERROR "too many arguments"
+}
diff --git a/test/fixedbugs/issue7742.go b/test/fixedbugs/issue7742.go
new file mode 100644
index 0000000..dc167c2
--- /dev/null
+++ b/test/fixedbugs/issue7742.go
@@ -0,0 +1,18 @@
+// compile
+
+// 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 7742: cannot use &autotmp_0001 (type *map[string]string) as type *string in function argument
+
+package main
+
+var (
+	m map[string]string
+	v string
+)
+
+func main() {
+	m[v], _ = v, v
+}
diff --git a/test/fixedbugs/issue7794.go b/test/fixedbugs/issue7794.go
new file mode 100644
index 0000000..1e303bd
--- /dev/null
+++ b/test/fixedbugs/issue7794.go
@@ -0,0 +1,12 @@
+// compile
+
+// 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
+
+func main() {
+	var a [10]int
+	const ca = len(a)
+}
diff --git a/test/fixedbugs/issue7863.go b/test/fixedbugs/issue7863.go
new file mode 100644
index 0000000..97f2255
--- /dev/null
+++ b/test/fixedbugs/issue7863.go
@@ -0,0 +1,60 @@
+// run
+
+// 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 (
+	"fmt"
+)
+
+type Foo int64
+
+func (f *Foo) F() int64 {
+	return int64(*f)
+}
+
+type Bar int64
+
+func (b Bar) F() int64 {
+	return int64(b)
+}
+
+type Baz int32
+
+func (b Baz) F() int64 {
+	return int64(b)
+}
+
+func main() {
+	foo := Foo(123)
+	f := foo.F
+	if foo.F() != f() {
+		bug()
+		fmt.Println("foo.F", foo.F(), f())
+	}
+	bar := Bar(123)
+	f = bar.F
+	if bar.F() != f() {
+		bug()
+		fmt.Println("bar.F", bar.F(), f()) // duh!
+	}
+
+	baz := Baz(123)
+	f = baz.F
+	if baz.F() != f() {
+		bug()
+		fmt.Println("baz.F", baz.F(), f())
+	}
+}
+
+var bugged bool
+
+func bug() {
+	if !bugged {
+		bugged = true
+		fmt.Println("BUG")
+	}
+}
diff --git a/test/fixedbugs/issue7867.go b/test/fixedbugs/issue7867.go
new file mode 100644
index 0000000..9f28a71
--- /dev/null
+++ b/test/fixedbugs/issue7867.go
@@ -0,0 +1,43 @@
+// runoutput
+
+// 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 7867.
+
+package main
+
+import "fmt"
+
+const tpl = `
+func Test%d(t %s) {
+	_ = t
+	_ = t
+}
+`
+
+func main() {
+	fmt.Println("package main")
+	types := []string{
+		// These types always passed
+		"bool", "int", "rune",
+		"*int", "uintptr",
+		"float32", "float64",
+		"chan struct{}",
+		"map[string]struct{}",
+		"func()", "func(string)error",
+
+		// These types caused compilation failures
+		"complex64", "complex128",
+		"struct{}", "struct{n int}", "struct{e error}", "struct{m map[string]string}",
+		"string",
+		"[4]byte",
+		"[]byte",
+		"interface{}", "error",
+	}
+	for i, typ := range types {
+		fmt.Printf(tpl, i, typ)
+	}
+	fmt.Println("func main() {}")
+}
diff --git a/test/fixedbugs/issue7884.go b/test/fixedbugs/issue7884.go
new file mode 100644
index 0000000..497e261
--- /dev/null
+++ b/test/fixedbugs/issue7884.go
@@ -0,0 +1,15 @@
+// compile
+
+// 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 "fmt"
+
+func main() {
+	var ii interface{} = 5
+	zz, err := ii.(interface{})
+	fmt.Println(zz, err)
+}
diff --git a/test/fixedbugs/issue7944.go b/test/fixedbugs/issue7944.go
new file mode 100644
index 0000000..9e5bed1
--- /dev/null
+++ b/test/fixedbugs/issue7944.go
@@ -0,0 +1,40 @@
+// run
+
+// 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 7944:
+// Liveness bitmaps said b was live at call to g,
+// but no one told the register optimizer.
+
+package main
+
+import "runtime"
+
+func f(b []byte) {
+	for len(b) > 0 {
+		n := len(b)
+		n = f1(n)
+		f2(b[n:])
+		b = b[n:]
+	}
+	g()
+}
+
+func f1(n int) int {
+	runtime.GC()
+	return n
+}
+
+func f2(b []byte) {
+	runtime.GC()
+}
+
+func g() {
+	runtime.GC()
+}
+
+func main() {
+	f(make([]byte, 100))
+}
diff --git a/test/fixedbugs/issue7995.go b/test/fixedbugs/issue7995.go
new file mode 100644
index 0000000..05f1168
--- /dev/null
+++ b/test/fixedbugs/issue7995.go
@@ -0,0 +1,25 @@
+// run
+
+// 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 7995: globals not flushed quickly enough.
+
+package main
+
+import "fmt"
+
+var (
+	p = 1
+	q = &p
+)
+
+func main() {
+	p = 50
+	*q = 100
+	s := fmt.Sprintln(p, *q)
+	if s != "100 100\n" {
+		println("BUG:", s)
+	}
+}
diff --git a/test/fixedbugs/issue7995b.dir/x1.go b/test/fixedbugs/issue7995b.dir/x1.go
new file mode 100644
index 0000000..075911b
--- /dev/null
+++ b/test/fixedbugs/issue7995b.dir/x1.go
@@ -0,0 +1,16 @@
+package x1
+
+import "fmt"
+
+var P int
+
+var b bool
+
+func F(x *int) string {
+	if b { // avoid inlining
+		F(x)
+	}
+	P = 50
+	*x = 100
+	return fmt.Sprintln(P, *x)
+}
diff --git a/test/fixedbugs/issue7995b.dir/x2.go b/test/fixedbugs/issue7995b.dir/x2.go
new file mode 100644
index 0000000..eea23ea
--- /dev/null
+++ b/test/fixedbugs/issue7995b.dir/x2.go
@@ -0,0 +1,10 @@
+package main
+
+import "./x1"
+
+func main() {
+	s := x1.F(&x1.P)
+	if s != "100 100\n" {
+		println("BUG:", s)
+	}
+}
diff --git a/test/fixedbugs/issue7995b.go b/test/fixedbugs/issue7995b.go
new file mode 100644
index 0000000..2f57371
--- /dev/null
+++ b/test/fixedbugs/issue7995b.go
@@ -0,0 +1,9 @@
+// rundir
+
+// 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 7995: globals not flushed quickly enough.
+
+package ignored
diff --git a/test/fixedbugs/issue7996.go b/test/fixedbugs/issue7996.go
new file mode 100644
index 0000000..98289eb
--- /dev/null
+++ b/test/fixedbugs/issue7996.go
@@ -0,0 +1,14 @@
+// compile
+
+// 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.
+
+// /tmp/x.go:5: illegal constant expression: bool == interface {}
+
+package p
+
+var m = map[interface{}]struct{}{
+	nil:  {},
+	true: {},
+}
diff --git a/test/fixedbugs/issue7997.go b/test/fixedbugs/issue7997.go
new file mode 100644
index 0000000..10c5262
--- /dev/null
+++ b/test/fixedbugs/issue7997.go
@@ -0,0 +1,53 @@
+// compile
+
+// 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.
+
+// /tmp/x.go:3: internal error: f &p (type *int) recorded as live on entry
+
+package p
+
+func f(ch chan int) *int {
+	select {
+	case p1x := <-ch:
+		return &p1x
+	default:
+		// ok
+	}
+	select {
+	case p1 := <-ch:
+		return &p1
+	default:
+		// ok
+	}
+	select {
+	case p2 := <-ch:
+		return &p2
+	case p3 := <-ch:
+		return &p3
+	default:
+		// ok
+	}
+	select {
+	case p4, ok := <-ch:
+		if ok {
+			return &p4
+		}
+	default:
+		// ok
+	}
+	select {
+	case p5, ok := <-ch:
+		if ok {
+			return &p5
+		}
+	case p6, ok := <-ch:
+		if !ok {
+			return &p6
+		}
+	default:
+		// ok
+	}
+	return nil
+}
diff --git a/test/fixedbugs/issue7998.go b/test/fixedbugs/issue7998.go
new file mode 100644
index 0000000..245035e
--- /dev/null
+++ b/test/fixedbugs/issue7998.go
@@ -0,0 +1,23 @@
+// compile
+
+// 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.
+
+// /tmp/x.go:5: cannot use _ as value
+
+package p
+
+func f(ch chan int) bool {
+	select {
+	case _, ok := <-ch:
+		return ok
+	}
+	_, ok := <-ch
+	_ = ok
+	select {
+	case _, _ = <-ch:
+		return true
+	}
+	return false
+}
diff --git a/test/fixedbugs/issue8004.go b/test/fixedbugs/issue8004.go
new file mode 100644
index 0000000..37e2fe0
--- /dev/null
+++ b/test/fixedbugs/issue8004.go
@@ -0,0 +1,59 @@
+// run
+
+// 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"
+	"runtime"
+	"unsafe"
+)
+
+func main() {
+	test1()
+	test2()
+}
+
+func test1() {
+	var all []interface{}
+	for i := 0; i < 100; i++ {
+		p := new([]int)
+		*p = append(*p, 1, 2, 3, 4)
+		h := (*reflect.SliceHeader)(unsafe.Pointer(p))
+		all = append(all, h, p)
+	}
+	runtime.GC()
+	for i := 0; i < 100; i++ {
+		p := *all[2*i+1].(*[]int)
+		if p[0] != 1 || p[1] != 2 || p[2] != 3 || p[3] != 4 {
+			println("BUG test1: bad slice at index", i, p[0], p[1], p[2], p[3])
+			return
+		}
+	}
+}
+
+type T struct {
+	H *reflect.SliceHeader
+	P *[]int
+}
+
+func test2() {
+	var all []T
+	for i := 0; i < 100; i++ {
+		p := new([]int)
+		*p = append(*p, 1, 2, 3, 4)
+		h := (*reflect.SliceHeader)(unsafe.Pointer(p))
+		all = append(all, T{H: h}, T{P: p})
+	}
+	runtime.GC()
+	for i := 0; i < 100; i++ {
+		p := *all[2*i+1].P
+		if p[0] != 1 || p[1] != 2 || p[2] != 3 || p[3] != 4 {
+			println("BUG test2: bad slice at index", i, p[0], p[1], p[2], p[3])
+			return
+		}
+	}
+}
diff --git a/test/fixedbugs/issue8011.go b/test/fixedbugs/issue8011.go
new file mode 100644
index 0000000..b966174
--- /dev/null
+++ b/test/fixedbugs/issue8011.go
@@ -0,0 +1,18 @@
+// run
+
+// 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
+
+func main() {
+	c := make(chan chan int, 1)
+	c1 := make(chan int, 1)
+	c1 <- 42
+	c <- c1
+	x := <-<-c
+	if x != 42 {
+		println("BUG:", x, "!= 42")
+	}
+}
diff --git a/test/fixedbugs/issue8028.go b/test/fixedbugs/issue8028.go
new file mode 100644
index 0000000..7ceb902
--- /dev/null
+++ b/test/fixedbugs/issue8028.go
@@ -0,0 +1,27 @@
+// compile
+
+// 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 8028. Used to fail in -race mode with "non-orig name" error.
+
+package p
+
+var (
+	t2 = T{F, "s1"}
+	t1 = T{F, "s2"}
+
+	tt = [...]T{t1, t2}
+)
+
+type I interface{}
+
+type T struct {
+	F func() I
+	S string
+}
+
+type E struct{}
+
+func F() I { return new(E) }
diff --git a/test/fixedbugs/issue8036.go b/test/fixedbugs/issue8036.go
new file mode 100644
index 0000000..f32fde8
--- /dev/null
+++ b/test/fixedbugs/issue8036.go
@@ -0,0 +1,45 @@
+// run
+
+// 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 8036. Stores necessary for stack scan being eliminated as redundant by optimizer.
+
+package main
+
+import "runtime"
+
+type T struct {
+	X *int
+	Y *int
+	Z *int
+}
+
+type TI [3]uintptr
+
+func G() (t TI) {
+	t[0] = 1
+	t[1] = 2
+	t[2] = 3
+	runtime.GC() // prevent inlining
+	return
+}
+
+func F() (t T) {
+	t.X = newint()
+	t.Y = t.X
+	t.Z = t.Y
+	runtime.GC() // prevent inlining
+	return
+}
+
+func newint() *int {
+	runtime.GC()
+	return nil
+}
+
+func main() {
+	G() // leave non-pointers where F's return values go
+	F()
+}
diff --git a/test/fixedbugs/issue8039.go b/test/fixedbugs/issue8039.go
new file mode 100644
index 0000000..b13e474
--- /dev/null
+++ b/test/fixedbugs/issue8039.go
@@ -0,0 +1,23 @@
+// run
+
+// 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 8039. defer copy(x, <-c) did not rewrite <-c properly.
+
+package main
+
+func f(s []int) {
+	c := make(chan []int, 1)
+	c <- []int{1}
+	defer copy(s, <-c)
+}
+
+func main() {
+	x := make([]int, 1)
+	f(x)
+	if x[0] != 1 {
+		println("BUG", x[0])
+	}
+}
diff --git a/test/fixedbugs/issue8047.go b/test/fixedbugs/issue8047.go
new file mode 100644
index 0000000..fe7ada5
--- /dev/null
+++ b/test/fixedbugs/issue8047.go
@@ -0,0 +1,29 @@
+// run
+
+// 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 8047.  Stack copier shouldn't crash if there
+// is a nil defer.
+
+package main
+
+func stackit(n int) {
+	if n == 0 {
+		return
+	}
+	stackit(n - 1)
+}
+
+func main() {
+	defer func() {
+		// catch & ignore panic from nil defer below
+		err := recover()
+		if err == nil {
+			panic("defer of nil func didn't panic")
+		}
+	}()
+	defer ((func())(nil))()
+	stackit(1000)
+}
diff --git a/test/fixedbugs/issue8047b.go b/test/fixedbugs/issue8047b.go
new file mode 100644
index 0000000..de6acaa
--- /dev/null
+++ b/test/fixedbugs/issue8047b.go
@@ -0,0 +1,22 @@
+// run
+
+// 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 8047. Defer setup during panic shouldn't crash for nil defer.
+
+package main
+
+func main() {
+	defer func() {
+		recover()
+	}()
+	f()
+}
+
+func f() {
+	var g func()
+	defer g()
+	panic(1)
+}
diff --git a/test/fixedbugs/issue8048.go b/test/fixedbugs/issue8048.go
new file mode 100644
index 0000000..a7984c4
--- /dev/null
+++ b/test/fixedbugs/issue8048.go
@@ -0,0 +1,107 @@
+// run
+
+// 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 8048. Incorrect handling of liveness when walking stack
+// containing faulting frame.
+
+package main
+
+import "runtime"
+
+func main() {
+	test1()
+	test2()
+	test3()
+}
+
+func test1() {
+	// test1f will panic without its own defer.
+	// The runtime.GC checks that we can walk the stack
+	// at that point and not get confused.
+	// The recover lets test1 exit normally.
+	defer func() {
+		runtime.GC()
+		recover()
+	}()
+	test1f()
+}
+
+func test1f() {
+	// Because b == false, the if does not execute,
+	// so x == nil, so the println(*x) faults reading
+	// from nil. The compiler will lay out the code
+	// so that the if body occurs above the *x,
+	// so if the liveness info at the *x is used, it will
+	// find the liveness at the call to runtime.GC.
+	// It will think y is live, but y is uninitialized,
+	// and the runtime will crash detecting a bad slice.
+	// The runtime should see that there are no defers
+	// corresponding to this panicked frame and ignore
+	// the frame entirely.
+	var x *int
+	var b bool
+	if b {
+		y := make([]int, 1)
+		runtime.GC()
+		x = &y[0]
+	}
+	println(*x)
+}
+
+func test2() {
+	// Same as test1, but the fault happens in the function with the defer.
+	// The runtime should see the defer and garbage collect the frame
+	// as if the PC were immediately after the defer statement.
+	defer func() {
+		runtime.GC()
+		recover()
+	}()
+	var x *int
+	var b bool
+	if b {
+		y := make([]int, 1)
+		runtime.GC()
+		x = &y[0]
+	}
+	println(*x)
+}
+
+func test3() {
+	// Like test1 but avoid array index, which does not
+	// move to end of function on ARM.
+	defer func() {
+		runtime.GC()
+		recover()
+	}()
+	test3setup()
+	test3f()
+}
+
+func test3setup() {
+	var x uintptr
+	var b bool
+	b = true
+	if b {
+		y := uintptr(123)
+		runtime.GC()
+		x = y
+	}
+	runtime.GC()
+	globl = x
+}
+
+var globl uintptr
+
+func test3f() {
+	var x *int
+	var b bool
+	if b {
+		y := new(int)
+		runtime.GC()
+		x = y
+	}
+	println(*x)
+}
diff --git a/test/fixedbugs/issue8073.go b/test/fixedbugs/issue8073.go
new file mode 100644
index 0000000..6601221
--- /dev/null
+++ b/test/fixedbugs/issue8073.go
@@ -0,0 +1,15 @@
+// compile
+
+// 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 8073.
+// was "internal compiler error: overflow: float64 integer constant"
+
+package main
+
+func main() {
+	var x int
+	_ = float64(x * 0)
+}
diff --git a/test/fixedbugs/issue8076.go b/test/fixedbugs/issue8076.go
new file mode 100644
index 0000000..ad89067
--- /dev/null
+++ b/test/fixedbugs/issue8076.go
@@ -0,0 +1,17 @@
+// compile
+
+// 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 8076. nilwalkfwd walked forward forever
+// on the instruction loop following the dereference.
+
+package main
+
+func main() {
+	_ = *(*int)(nil)
+L:
+	_ = 0
+	goto L
+}
diff --git a/test/fixedbugs/issue8132.go b/test/fixedbugs/issue8132.go
new file mode 100644
index 0000000..52f5d39
--- /dev/null
+++ b/test/fixedbugs/issue8132.go
@@ -0,0 +1,32 @@
+// run
+
+// 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 8132. stack walk handling of panic stack was confused
+// about what was legal.
+
+package main
+
+import "runtime"
+
+var p *int
+
+func main() {
+	func() {
+		defer func() {
+			runtime.GC()
+			recover()
+		}()
+		var x [8192]byte
+		func(x [8192]byte) {
+			defer func() {
+				if err := recover(); err != nil {
+					println(*p)
+				}
+			}()
+			println(*p)
+		}(x)
+	}()
+}
diff --git a/test/fixedbugs/issue8139.go b/test/fixedbugs/issue8139.go
new file mode 100644
index 0000000..821c9ff
--- /dev/null
+++ b/test/fixedbugs/issue8139.go
@@ -0,0 +1,50 @@
+// run
+
+// 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 8139. The x.(T) assertions used to write 1 (unexpected)
+// return byte for the 0-byte return value T.
+
+package main
+
+import "fmt"
+
+type T struct{}
+
+func (T) M() {}
+
+type M interface {
+	M()
+}
+
+var e interface{} = T{}
+var i M = T{}
+var b bool
+
+func f1() int {
+	if b {
+		return f1() // convince inliner not to inline
+	}
+	z := 0x11223344
+	_ = e.(T)
+	return z
+}
+
+func f2() int {
+	if b {
+		return f1() // convince inliner not to inline
+	}
+	z := 0x11223344
+	_ = i.(T)
+	return z
+}
+
+func main() {
+	x := f1()
+	y := f2()
+	if x != 0x11223344 || y != 0x11223344 {
+		fmt.Printf("BUG: x=%#x y=%#x, want 0x11223344 for both\n", x, y)
+	}
+}
diff --git a/test/fixedbugs/issue8155.go b/test/fixedbugs/issue8155.go
new file mode 100644
index 0000000..c611f6c
--- /dev/null
+++ b/test/fixedbugs/issue8155.go
@@ -0,0 +1,48 @@
+// run
+
+// 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 8155.
+// Alignment of stack prologue zeroing was wrong on 64-bit Native Client
+// (because of 32-bit pointers).
+
+package main
+
+import "runtime"
+
+func bad(b bool) uintptr {
+	var p **int
+	var x1 uintptr
+	x1 = 1
+	if b {
+		var x [11]*int
+		p = &x[0]
+	}
+	if b {
+		var x [1]*int
+		p = &x[0]
+	}
+	runtime.GC()
+	if p != nil {
+		x1 = uintptr(**p)
+	}
+	return x1
+}
+
+func poison() uintptr {
+	runtime.GC()
+	var x [20]uintptr
+	var s uintptr
+	for i := range x {
+		x[i] = uintptr(i+1)
+		s += x[i]
+	}
+	return s
+}
+
+func main() {
+	poison()
+	bad(false)
+}
diff --git a/test/fixedbugs/issue8158.go b/test/fixedbugs/issue8158.go
new file mode 100644
index 0000000..b110de1
--- /dev/null
+++ b/test/fixedbugs/issue8158.go
@@ -0,0 +1,41 @@
+// run
+
+// 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 (
+	"runtime"
+	"time"
+)
+
+func main() {
+	c := make(chan bool, 1)
+	go f1(c)
+	<-c
+	time.Sleep(10 * time.Millisecond)
+	go f2(c)
+	<-c
+}
+
+func f1(done chan bool) {
+	defer func() {
+		recover()
+		done <- true
+		runtime.Goexit() // left stack-allocated Panic struct on gp->panic stack
+	}()
+	panic("p")
+}
+
+func f2(done chan bool) {
+	defer func() {
+		recover()
+		done <- true
+		runtime.Goexit()
+	}()
+	time.Sleep(10 * time.Millisecond) // overwrote Panic struct with Timer struct
+	runtime.GC()                      // walked gp->panic list, found mangled Panic struct, crashed
+	panic("p")
+}
diff --git a/test/float_lit2.go b/test/float_lit2.go
new file mode 100644
index 0000000..96d23f3
--- /dev/null
+++ b/test/float_lit2.go
@@ -0,0 +1,164 @@
+// run
+
+// Check conversion of constant to float32/float64 near min/max boundaries.
+
+// 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 (
+	"fmt"
+	"math"
+)
+
+// The largest exact float32 is f₁ = (1+(1-2²³))×2¹²⁷ = (1-2²⁴)×2¹²⁸ = 2¹²⁸ - 2¹⁰⁴.
+// The next float32 would be f₂ = (1+1)×2¹²⁷ = 1×2¹²⁸, except that exponent is out of range.
+// Float32 conversion rounds to the nearest float32, rounding to even mantissa:
+// between f₁ and f₂, values closer to f₁ round to f₁ and values closer to f₂ are rejected as out of range.
+// f₁ is an odd mantissa, so the halfway point (f₁+f₂)/2 rounds to f₂ and is rejected.
+// The halfway point is (f₁+f₂)/2 = 2¹²⁸ - 2¹⁰⁵.
+//
+// The same is true of float64, with different constants: s/24/53/ and s/128/1024/.
+
+const (
+	two24   = 1.0 * (1 << 24)
+	two53   = 1.0 * (1 << 53)
+	two64   = 1.0 * (1 << 64)
+	two128  = two64 * two64
+	two256  = two128 * two128
+	two512  = two256 * two256
+	two768  = two512 * two256
+	two1024 = two512 * two512
+
+	ulp32 = two128 / two24
+	max32 = two128 - ulp32
+
+	ulp64 = two1024 / two53
+	max64 = two1024 - ulp64
+)
+
+var cvt = []struct {
+	bits   uint64 // keep us honest
+	exact  interface{}
+	approx interface{}
+	text   string
+}{
+	// 0
+	{0x7f7ffffe, float32(max32 - ulp32), float32(max32 - ulp32 - ulp32/2), "max32 - ulp32 - ulp32/2"},
+	{0x7f7ffffe, float32(max32 - ulp32), float32(max32 - ulp32), "max32 - ulp32"},
+	{0x7f7ffffe, float32(max32 - ulp32), float32(max32 - ulp32/2), "max32 - ulp32/2"},
+	{0x7f7ffffe, float32(max32 - ulp32), float32(max32 - ulp32 + ulp32/2), "max32 - ulp32 + ulp32/2"},
+	{0x7f7fffff, float32(max32), float32(max32 - ulp32 + ulp32/2 + ulp32/two64), "max32 - ulp32 + ulp32/2 + ulp32/two64"},
+	{0x7f7fffff, float32(max32), float32(max32 - ulp32/2 + ulp32/two64), "max32 - ulp32/2 + ulp32/two64"},
+	{0x7f7fffff, float32(max32), float32(max32), "max32"},
+	{0x7f7fffff, float32(max32), float32(max32 + ulp32/2 - ulp32/two64), "max32 + ulp32/2 - ulp32/two64"},
+
+	{0xff7ffffe, float32(-(max32 - ulp32)), float32(-(max32 - ulp32 - ulp32/2)), "-(max32 - ulp32 - ulp32/2)"},
+	{0xff7ffffe, float32(-(max32 - ulp32)), float32(-(max32 - ulp32)), "-(max32 - ulp32)"},
+	{0xff7ffffe, float32(-(max32 - ulp32)), float32(-(max32 - ulp32/2)), "-(max32 - ulp32/2)"},
+	{0xff7ffffe, float32(-(max32 - ulp32)), float32(-(max32 - ulp32 + ulp32/2)), "-(max32 - ulp32 + ulp32/2)"},
+	{0xff7fffff, float32(-(max32)), float32(-(max32 - ulp32 + ulp32/2 + ulp32/two64)), "-(max32 - ulp32 + ulp32/2 + ulp32/two64)"},
+	{0xff7fffff, float32(-(max32)), float32(-(max32 - ulp32/2 + ulp32/two64)), "-(max32 - ulp32/2 + ulp32/two64)"},
+	{0xff7fffff, float32(-(max32)), float32(-(max32)), "-(max32)"},
+	{0xff7fffff, float32(-(max32)), float32(-(max32 + ulp32/2 - ulp32/two64)), "-(max32 + ulp32/2 - ulp32/two64)"},
+
+	// These are required to work: according to the Go spec, the internal float mantissa must be at least 256 bits,
+	// and these expressions can be represented exactly with a 256-bit mantissa.
+	{0x7f7fffff, float32(max32), float32(max32 - ulp32 + ulp32/2 + 1), "max32 - ulp32 + ulp32/2 + 1"},
+	{0x7f7fffff, float32(max32), float32(max32 - ulp32/2 + 1), "max32 - ulp32/2 + 1"},
+	{0x7f7fffff, float32(max32), float32(max32 + ulp32/2 - 1), "max32 + ulp32/2 - 1"},
+	{0xff7fffff, float32(-(max32)), float32(-(max32 - ulp32 + ulp32/2 + 1)), "-(max32 - ulp32 + ulp32/2 + 1)"},
+	{0xff7fffff, float32(-(max32)), float32(-(max32 - ulp32/2 + 1)), "-(max32 - ulp32/2 + 1)"},
+	{0xff7fffff, float32(-(max32)), float32(-(max32 + ulp32/2 - 1)), "-(max32 + ulp32/2 - 1)"},
+
+	{0x7f7fffff, float32(max32), float32(max32 - ulp32 + ulp32/2 + 1/two128), "max32 - ulp32 + ulp32/2 + 1/two128"},
+	{0x7f7fffff, float32(max32), float32(max32 - ulp32/2 + 1/two128), "max32 - ulp32/2 + 1/two128"},
+	{0x7f7fffff, float32(max32), float32(max32 + ulp32/2 - 1/two128), "max32 + ulp32/2 - 1/two128"},
+	{0xff7fffff, float32(-(max32)), float32(-(max32 - ulp32 + ulp32/2 + 1/two128)), "-(max32 - ulp32 + ulp32/2 + 1/two128)"},
+	{0xff7fffff, float32(-(max32)), float32(-(max32 - ulp32/2 + 1/two128)), "-(max32 - ulp32/2 + 1/two128)"},
+	{0xff7fffff, float32(-(max32)), float32(-(max32 + ulp32/2 - 1/two128)), "-(max32 + ulp32/2 - 1/two128)"},
+
+	{0x7feffffffffffffe, float64(max64 - ulp64), float64(max64 - ulp64 - ulp64/2), "max64 - ulp64 - ulp64/2"},
+	{0x7feffffffffffffe, float64(max64 - ulp64), float64(max64 - ulp64), "max64 - ulp64"},
+	{0x7feffffffffffffe, float64(max64 - ulp64), float64(max64 - ulp64/2), "max64 - ulp64/2"},
+	{0x7feffffffffffffe, float64(max64 - ulp64), float64(max64 - ulp64 + ulp64/2), "max64 - ulp64 + ulp64/2"},
+	{0x7fefffffffffffff, float64(max64), float64(max64 - ulp64 + ulp64/2 + ulp64/two64), "max64 - ulp64 + ulp64/2 + ulp64/two64"},
+	{0x7fefffffffffffff, float64(max64), float64(max64 - ulp64/2 + ulp64/two64), "max64 - ulp64/2 + ulp64/two64"},
+	{0x7fefffffffffffff, float64(max64), float64(max64), "max64"},
+	{0x7fefffffffffffff, float64(max64), float64(max64 + ulp64/2 - ulp64/two64), "max64 + ulp64/2 - ulp64/two64"},
+
+	{0xffeffffffffffffe, float64(-(max64 - ulp64)), float64(-(max64 - ulp64 - ulp64/2)), "-(max64 - ulp64 - ulp64/2)"},
+	{0xffeffffffffffffe, float64(-(max64 - ulp64)), float64(-(max64 - ulp64)), "-(max64 - ulp64)"},
+	{0xffeffffffffffffe, float64(-(max64 - ulp64)), float64(-(max64 - ulp64/2)), "-(max64 - ulp64/2)"},
+	{0xffeffffffffffffe, float64(-(max64 - ulp64)), float64(-(max64 - ulp64 + ulp64/2)), "-(max64 - ulp64 + ulp64/2)"},
+	{0xffefffffffffffff, float64(-(max64)), float64(-(max64 - ulp64 + ulp64/2 + ulp64/two64)), "-(max64 - ulp64 + ulp64/2 + ulp64/two64)"},
+	{0xffefffffffffffff, float64(-(max64)), float64(-(max64 - ulp64/2 + ulp64/two64)), "-(max64 - ulp64/2 + ulp64/two64)"},
+	{0xffefffffffffffff, float64(-(max64)), float64(-(max64)), "-(max64)"},
+	{0xffefffffffffffff, float64(-(max64)), float64(-(max64 + ulp64/2 - ulp64/two64)), "-(max64 + ulp64/2 - ulp64/two64)"},
+
+	// These are required to work.
+	// The mantissas are exactly 256 bits.
+	// max64 is just below 2¹⁰²⁴ so the bottom bit we can use is 2⁷⁶⁸.
+	{0x7fefffffffffffff, float64(max64), float64(max64 - ulp64 + ulp64/2 + two768), "max64 - ulp64 + ulp64/2 + two768"},
+	{0x7fefffffffffffff, float64(max64), float64(max64 - ulp64/2 + two768), "max64 - ulp64/2 + two768"},
+	{0x7fefffffffffffff, float64(max64), float64(max64 + ulp64/2 - two768), "max64 + ulp64/2 - two768"},
+	{0xffefffffffffffff, float64(-(max64)), float64(-(max64 - ulp64 + ulp64/2 + two768)), "-(max64 - ulp64 + ulp64/2 + two768)"},
+	{0xffefffffffffffff, float64(-(max64)), float64(-(max64 - ulp64/2 + two768)), "-(max64 - ulp64/2 + two768)"},
+	{0xffefffffffffffff, float64(-(max64)), float64(-(max64 + ulp64/2 - two768)), "-(max64 + ulp64/2 - two768)"},
+}
+
+var bugged = false
+
+func bug() {
+	if !bugged {
+		bugged = true
+		fmt.Println("BUG")
+	}
+}
+
+func main() {
+	u64 := math.Float64frombits(0x7fefffffffffffff) - math.Float64frombits(0x7feffffffffffffe)
+	if ulp64 != u64 {
+		bug()
+		fmt.Printf("ulp64=%g, want %g", ulp64, u64)
+	}
+
+	u32 := math.Float32frombits(0x7f7fffff) - math.Float32frombits(0x7f7ffffe)
+	if ulp32 != u32 {
+		bug()
+		fmt.Printf("ulp32=%g, want %g", ulp32, u32)
+	}
+
+	for _, c := range cvt {
+		if bits(c.exact) != c.bits {
+			bug()
+			fmt.Printf("%s: inconsistent table: bits=%#x (%g) but exact=%g (%#x)\n", c.text, c.bits, fromBits(c.bits, c.exact), c.exact, bits(c.exact))
+		}
+		if c.approx != c.exact || bits(c.approx) != c.bits {
+			bug()
+			fmt.Printf("%s: have %g (%#x) want %g (%#x)\n", c.text, c.approx, bits(c.approx), c.exact, c.bits)
+		}
+	}
+}
+
+func bits(x interface{}) interface{} {
+	switch x := x.(type) {
+	case float32:
+		return uint64(math.Float32bits(x))
+	case float64:
+		return math.Float64bits(x)
+	}
+	return 0
+}
+
+func fromBits(b uint64, x interface{}) interface{} {
+	switch x.(type) {
+	case float32:
+		return math.Float32frombits(uint32(b))
+	case float64:
+		return math.Float64frombits(b)
+	}
+	return "?"
+}
diff --git a/test/float_lit3.go b/test/float_lit3.go
new file mode 100644
index 0000000..43dca9c
--- /dev/null
+++ b/test/float_lit3.go
@@ -0,0 +1,48 @@
+// errorcheck
+
+// Check flagging of invalid conversion of constant to float32/float64 near min/max boundaries.
+
+// 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
+
+// See float_lit2.go for motivation for these values.
+const (
+	two24   = 1.0 * (1 << 24)
+	two53   = 1.0 * (1 << 53)
+	two64   = 1.0 * (1 << 64)
+	two128  = two64 * two64
+	two256  = two128 * two128
+	two512  = two256 * two256
+	two768  = two512 * two256
+	two1024 = two512 * two512
+
+	ulp32 = two128 / two24
+	max32 = two128 - ulp32
+
+	ulp64 = two1024 / two53
+	max64 = two1024 - ulp64
+)
+
+var x = []interface{}{
+	float32(max32 + ulp32/2 - 1),             // ok
+	float32(max32 + ulp32/2 - two128/two256), // ok
+	float32(max32 + ulp32/2),                 // ERROR "constant 3\.40282e\+38 overflows float32"
+
+	float32(-max32 - ulp32/2 + 1),             // ok
+	float32(-max32 - ulp32/2 + two128/two256), // ok
+	float32(-max32 - ulp32/2),                 // ERROR "constant -3\.40282e\+38 overflows float32"
+
+	// If the compiler's internal floating point representation
+	// is shorter than 1024 bits, it cannot distinguish max64+ulp64/2-1 and max64+ulp64/2.
+	// gc uses fewer than 1024 bits, so allow it to print the overflow error for the -1 case.
+	float64(max64 + ulp64/2 - two1024/two256), // ok
+	float64(max64 + ulp64/2 - 1),              // GC_ERROR "constant 1\.79769e\+308 overflows float64"
+	float64(max64 + ulp64/2),                  // ERROR "constant 1\.79769e\+308 overflows float64"
+
+	float64(-max64 - ulp64/2 + two1024/two256), // ok
+	float64(-max64 - ulp64/2 + 1),              // GC_ERROR "constant -1\.79769e\+308 overflows float64"
+	float64(-max64 - ulp64/2),                  // ERROR "constant -1\.79769e\+308 overflows float64"
+}
diff --git a/test/funcdup.go b/test/funcdup.go
index 706dd63..d15d685 100644
--- a/test/funcdup.go
+++ b/test/funcdup.go
@@ -7,21 +7,21 @@
 package p
 
 type T interface {
-	F1(i int) (i int) // ERROR "duplicate argument i"
-	F2(i, i int) // ERROR "duplicate argument i"
-	F3() (i, i int) // ERROR "duplicate argument i"
+	F1(i int) (i int) // ERROR "duplicate argument i|redefinition|previous"
+	F2(i, i int) // ERROR "duplicate argument i|redefinition|previous"
+	F3() (i, i int) // ERROR "duplicate argument i|redefinition|previous"
 }
 
-type T1 func(i, i int) // ERROR "duplicate argument i"
-type T2 func(i int) (i int) // ERROR "duplicate argument i"
-type T3 func() (i, i int) // ERROR "duplicate argument i"
+type T1 func(i, i int) // ERROR "duplicate argument i|redefinition|previous"
+type T2 func(i int) (i int) // ERROR "duplicate argument i|redefinition|previous"
+type T3 func() (i, i int) // ERROR "duplicate argument i|redefinition|previous"
 
 type R struct{}
 
-func (i *R) F1(i int)         {} // ERROR "duplicate argument i"
-func (i *R) F2() (i int)      {return 0} // ERROR "duplicate argument i"
-func (i *R) F3(j int) (j int) {return 0} // ERROR "duplicate argument j"
+func (i *R) F1(i int)         {} // ERROR "duplicate argument i|redefinition|previous"
+func (i *R) F2() (i int)      {return 0} // ERROR "duplicate argument i|redefinition|previous"
+func (i *R) F3(j int) (j int) {return 0} // ERROR "duplicate argument j|redefinition|previous"
 
-func F1(i, i int)      {} // ERROR "duplicate argument i"
-func F2(i int) (i int) {return 0} // ERROR "duplicate argument i"
-func F3() (i, i int)   {return 0, 0} // ERROR "duplicate argument i"
+func F1(i, i int)      {} // ERROR "duplicate argument i|redefinition|previous"
+func F2(i int) (i int) {return 0} // ERROR "duplicate argument i|redefinition|previous"
+func F3() (i, i int)   {return 0, 0} // ERROR "duplicate argument i|redefinition|previous"
diff --git a/test/funcdup2.go b/test/funcdup2.go
index aeb5f7e..1db1a39 100644
--- a/test/funcdup2.go
+++ b/test/funcdup2.go
@@ -7,11 +7,11 @@
 package p
 
 var T interface {
-	F1(i int) (i int) // ERROR "duplicate argument i"
-	F2(i, i int) // ERROR "duplicate argument i"
-	F3() (i, i int) // ERROR "duplicate argument i"
+	F1(i int) (i int) // ERROR "duplicate argument i|redefinition|previous"
+	F2(i, i int) // ERROR "duplicate argument i|redefinition|previous"
+	F3() (i, i int) // ERROR "duplicate argument i|redefinition|previous"
 }
 
-var T1 func(i, i int) // ERROR "duplicate argument i"
-var T2 func(i int) (i int) // ERROR "duplicate argument i"
-var T3 func() (i, i int) // ERROR "duplicate argument i"
+var T1 func(i, i int) // ERROR "duplicate argument i|redefinition|previous"
+var T2 func(i int) (i int) // ERROR "duplicate argument i|redefinition|previous"
+var T3 func() (i, i int) // ERROR "duplicate argument i|redefinition|previous"
diff --git a/test/gc2.go b/test/gc2.go
index de52a4f..561516b 100644
--- a/test/gc2.go
+++ b/test/gc2.go
@@ -1,5 +1,7 @@
 // run
 
+// +build !nacl
+
 // 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.
@@ -36,7 +38,7 @@ func main() {
 	}
 
 	runtime.ReadMemStats(memstats)
-	obj := memstats.HeapObjects - st.HeapObjects
+	obj := int64(memstats.HeapObjects - st.HeapObjects)
 	if obj > N/5 {
 		fmt.Println("too many objects left:", obj)
 		os.Exit(1)
diff --git a/test/gcstring.go b/test/gcstring.go
new file mode 100644
index 0000000..627a426
--- /dev/null
+++ b/test/gcstring.go
@@ -0,0 +1,48 @@
+// run
+
+// 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 s[len(s):] - which can point past the end of the allocated block -
+// does not confuse the garbage collector.
+
+package main
+
+import (
+	"runtime"
+	"time"
+)
+
+type T struct {
+	ptr **int
+	pad [120]byte
+}
+
+var things []interface{}
+
+func main() {
+	setup()
+	runtime.GC()
+	runtime.GC()
+	time.Sleep(10*time.Millisecond)
+	runtime.GC()
+	runtime.GC()
+	time.Sleep(10*time.Millisecond)
+}
+
+func setup() {
+	var Ts []interface{}
+	buf := make([]byte, 128)
+	
+	for i := 0; i < 10000; i++ {
+		s := string(buf)
+		t := &T{ptr: new(*int)}
+		runtime.SetFinalizer(t.ptr, func(**int) { panic("*int freed too early") })
+		Ts = append(Ts, t)
+		things = append(things, s[len(s):])
+	}
+	
+	things = append(things, Ts...)
+}
+
diff --git a/test/import1.go b/test/import1.go
index d2bb55c..2433b5f 100644
--- a/test/import1.go
+++ b/test/import1.go
@@ -15,5 +15,5 @@ import bufio "os"	// ERROR "redeclared|redefinition|incompatible" "imported and
 import (
 	"fmt"	// GCCGO_ERROR "previous|not used"
 	fmt "math"	// ERROR "redeclared|redefinition|incompatible" "imported and not used: \x22math\x22 as fmt"
-	. "math"	// ERROR "imported and not used: \x22math\x22$"
+	. "math"	// GC_ERROR "imported and not used: \x22math\x22$"
 )
diff --git a/test/import4.dir/empty.go b/test/import4.dir/empty.go
index c8214f3..1dffa17 100644
--- a/test/import4.dir/empty.go
+++ b/test/import4.dir/empty.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.
 
-package P
+package empty
 
 import ( )
 const ( )
diff --git a/test/import4.dir/import4.go b/test/import4.dir/import4.go
index b9f973f..f92c663 100644
--- a/test/import4.dir/import4.go
+++ b/test/import4.dir/import4.go
@@ -18,7 +18,7 @@ import X "math"	// ERROR "imported and not used.*math"
 import . "bufio"	// ERROR "imported and not used.*bufio"
 
 // again, package without anything in it
-import "./empty"	// ERROR "imported and not used.*empty"
-import Z "./empty"	// ERROR "imported and not used.*empty"
+import "./empty"	// GC_ERROR "imported and not used.*empty"
+import Z "./empty"	// GC_ERROR "imported and not used.*empty"
 import . "./empty"	// ERROR "imported and not used.*empty"
 
diff --git a/test/live.go b/test/live.go
new file mode 100644
index 0000000..b4cced4
--- /dev/null
+++ b/test/live.go
@@ -0,0 +1,624 @@
+// errorcheck -0 -l -live
+
+// 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.
+
+// liveness tests with inlining disabled.
+// see also live2.go.
+
+package main
+
+func f1() {
+	var x *int
+	print(&x) // ERROR "live at call to printpointer: x$"
+	print(&x) // ERROR "live at call to printpointer: x$"
+}
+
+func f2(b bool) {
+	if b {
+		print(0) // nothing live here
+		return
+	}
+	var x *int
+	print(&x) // ERROR "live at call to printpointer: x$"
+	print(&x) // ERROR "live at call to printpointer: x$"
+}
+
+func f3(b bool) {
+	// Because x and y are ambiguously live, they appear
+	// live throughout the function, to avoid being poisoned
+	// in GODEBUG=gcdead=1 mode.
+
+	print(0) // ERROR "live at call to printint: x y$"
+	if b == false {
+		print(0) // ERROR "live at call to printint: x y$"
+		return
+	}
+
+	if b {
+		var x *int
+		print(&x) // ERROR "live at call to printpointer: x y$"
+		print(&x) // ERROR "live at call to printpointer: x y$"
+	} else {
+		var y *int
+		print(&y) // ERROR "live at call to printpointer: x y$"
+		print(&y) // ERROR "live at call to printpointer: x y$"
+	}
+	print(0) // ERROR "live at call to printint: x y$" "x \(type \*int\) is ambiguously live" "y \(type \*int\) is ambiguously live"
+}
+
+// The old algorithm treated x as live on all code that
+// could flow to a return statement, so it included the
+// function entry and code above the declaration of x
+// but would not include an indirect use of x in an infinite loop.
+// Check that these cases are handled correctly.
+
+func f4(b1, b2 bool) { // x not live here
+	if b2 {
+		print(0) // x not live here
+		return
+	}
+	var z **int
+	x := new(int)
+	*x = 42
+	z = &x
+	print(**z) // ERROR "live at call to printint: x z$"
+	if b2 {
+		print(1) // ERROR "live at call to printint: x$"
+		return
+	}
+	for {
+		print(**z) // ERROR "live at call to printint: x z$"
+	}
+}
+
+func f5(b1 bool) {
+	var z **int
+	if b1 {
+		x := new(int)
+		*x = 42
+		z = &x
+	} else {
+		y := new(int)
+		*y = 54
+		z = &y
+	}
+	print(**z) // ERROR "live at call to printint: x y$" "x \(type \*int\) is ambiguously live" "y \(type \*int\) is ambiguously live"
+}
+
+// confusion about the _ result used to cause spurious "live at entry to f6: _".
+
+func f6() (_, y string) {
+	y = "hello"
+	return
+}
+
+// confusion about addressed results used to cause "live at entry to f7: x".
+
+func f7() (x string) {
+	_ = &x
+	x = "hello"
+	return
+}
+
+// ignoring block returns used to cause "live at entry to f8: x, y".
+
+func f8() (x, y string) {
+	return g8()
+}
+
+func g8() (string, string)
+
+// ignoring block assignments used to cause "live at entry to f9: x"
+// issue 7205
+
+var i9 interface{}
+
+func f9() bool {
+	g8()
+	x := i9
+	return x != 99
+}
+
+// liveness formerly confused by UNDEF followed by RET,
+// leading to "live at entry to f10: ~r1" (unnamed result).
+
+func f10() string {
+	panic(1)
+}
+
+// liveness formerly confused by select, thinking runtime.selectgo
+// can return to next instruction; it always jumps elsewhere.
+// note that you have to use at least two cases in the select
+// to get a true select; smaller selects compile to optimized helper functions.
+
+var c chan *int
+var b bool
+
+// this used to have a spurious "live at entry to f11a: ~r0"
+func f11a() *int {
+	select { // ERROR "live at call to selectgo: autotmp"
+	case <-c: // ERROR "live at call to selectrecv: autotmp"
+		return nil
+	case <-c: // ERROR "live at call to selectrecv: autotmp"
+		return nil
+	}
+}
+
+func f11b() *int {
+	p := new(int)
+	if b {
+		// At this point p is dead: the code here cannot
+		// get to the bottom of the function.
+		// This used to have a spurious "live at call to printint: p".
+		print(1) // nothing live here!
+		select { // ERROR "live at call to selectgo: autotmp"
+		case <-c: // ERROR "live at call to selectrecv: autotmp"
+			return nil
+		case <-c: // ERROR "live at call to selectrecv: autotmp"
+			return nil
+		}
+	}
+	println(*p)
+	return nil
+}
+
+func f11c() *int {
+	p := new(int)
+	if b {
+		// Unlike previous, the cases in this select fall through,
+		// so we can get to the println, so p is not dead.
+		print(1) // ERROR "live at call to printint: p"
+		select { // ERROR "live at call to newselect: p" "live at call to selectgo: autotmp.* p"
+		case <-c: // ERROR "live at call to selectrecv: autotmp.* p"
+		case <-c: // ERROR "live at call to selectrecv: autotmp.* p"
+		}
+	}
+	println(*p)
+	return nil
+}
+
+// similarly, select{} does not fall through.
+// this used to have a spurious "live at entry to f12: ~r0".
+
+func f12() *int {
+	if b {
+		select{}
+	} else {
+		return nil
+	}
+}
+
+// incorrectly placed VARDEF annotations can cause missing liveness annotations.
+// this used to be missing the fact that s is live during the call to g13 (because it is
+// needed for the call to h13).
+
+func f13() {
+	s := "hello"
+	s = h13(s, g13(s)) // ERROR "live at call to g13: s"
+}
+
+func g13(string) string
+func h13(string, string) string
+
+// more incorrectly placed VARDEF.
+
+func f14() {
+	x := g14()
+	print(&x) // ERROR "live at call to printpointer: x"
+}
+
+func g14() string
+
+func f15() {
+	var x string
+	_ = &x
+	x = g15() // ERROR "live at call to g15: x"
+	print(x) // ERROR "live at call to printstring: x"
+}
+
+func g15() string
+
+// Checking that various temporaries do not persist or cause
+// ambiguously live values that must be zeroed.
+// The exact temporary names are inconsequential but we are
+// trying to check that there is only one at any given site,
+// and also that none show up in "ambiguously live" messages.
+
+var m map[string]int
+
+func f16() {
+	if b {
+		delete(m, "hi") // ERROR "live at call to mapdelete: autotmp_[0-9]+$"
+	}
+	delete(m, "hi") // ERROR "live at call to mapdelete: autotmp_[0-9]+$"
+	delete(m, "hi") // ERROR "live at call to mapdelete: autotmp_[0-9]+$"
+}
+
+var m2s map[string]*byte
+var m2 map[[2]string]*byte
+var x2 [2]string
+var bp *byte
+
+func f17a() {
+	// value temporary only
+	if b {
+		m2[x2] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+	}
+	m2[x2] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+	m2[x2] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+}
+
+func f17b() {
+	// key temporary only
+	if b {
+		m2s["x"] = bp // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+	}
+	m2s["x"] = bp // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+	m2s["x"] = bp // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+}
+
+func f17c() {
+	// key and value temporaries
+	if b {
+		m2s["x"] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+	}
+	m2s["x"] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+	m2s["x"] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+}
+
+func g18() [2]string
+
+func f18() {
+	// key temporary for mapaccess.
+	// temporary introduced by orderexpr.
+	var z *byte
+	if b {
+		z = m2[g18()] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+	}
+	z = m2[g18()] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+	z = m2[g18()] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+	print(z)
+}
+
+var ch chan *byte
+
+func f19() {
+	// dest temporary for channel receive.
+	var z *byte
+	
+	if b {
+		z = <-ch // ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
+	}
+	z = <-ch // ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
+	z = <-ch // ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
+	print(z)
+}
+
+func f20() {
+	// src temporary for channel send
+	if b {
+		ch <- nil // ERROR "live at call to chansend1: autotmp_[0-9]+$"
+	}
+	ch <- nil // ERROR "live at call to chansend1: autotmp_[0-9]+$"
+	ch <- nil // ERROR "live at call to chansend1: autotmp_[0-9]+$"
+}
+
+func f21() {
+	// key temporary for mapaccess using array literal key.
+	var z *byte
+	if b {
+		z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+	}
+	z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+	z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+	print(z)
+}
+
+func f23() {
+	// key temporary for two-result map access using array literal key.
+	var z *byte
+	var ok bool
+	if b {
+		z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: autotmp_[0-9]+$"
+	}
+	z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: autotmp_[0-9]+$"
+	z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: autotmp_[0-9]+$"
+	print(z, ok)
+}
+
+func f24() {
+	// key temporary for map access using array literal key.
+	// value temporary too.
+	if b {
+		m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+	}
+	m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+	m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+}
+
+// defer should not cause spurious ambiguously live variables
+
+func f25(b bool) {
+	defer g25()
+	if b {
+		return
+	}
+	var x string
+	_ = &x
+	x = g15() // ERROR "live at call to g15: x"
+	print(x) // ERROR "live at call to printstring: x"
+} // ERROR "live at call to deferreturn: x"
+
+func g25()
+	
+// non-escaping ... slices passed to function call should die on return,
+// so that the temporaries do not stack and do not cause ambiguously
+// live variables.
+
+func f26(b bool) {
+	if b {
+		print26(1,2,3) // ERROR "live at call to print26: autotmp_[0-9]+$"
+	}
+	print26(4,5,6) // ERROR "live at call to print26: autotmp_[0-9]+$"
+	print26(7,8,9) // ERROR "live at call to print26: autotmp_[0-9]+$"
+	println()
+}
+
+//go:noescape
+func print26(...interface{})
+
+// non-escaping closures passed to function call should die on return
+
+func f27(b bool) {
+	x := 0
+	if b {
+		call27(func() {x++}) // ERROR "live at call to call27: autotmp_[0-9]+$"
+	}
+	call27(func() {x++}) // ERROR "live at call to call27: autotmp_[0-9]+$"
+	call27(func() {x++}) // ERROR "live at call to call27: autotmp_[0-9]+$"
+	println()
+}
+
+// but defer does escape to later execution in the function
+
+func f27defer(b bool) {
+	x := 0
+	if b {
+		defer call27(func() {x++}) // ERROR "live at call to deferproc: autotmp_[0-9]+$" "live at call to deferreturn: autotmp_[0-9]+$"
+	}
+	defer call27(func() {x++}) // ERROR "live at call to deferproc: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to deferreturn: autotmp_[0-9]+ autotmp_[0-9]+$" "ambiguously live"
+	println() // ERROR "live at call to printnl: autotmp_[0-9]+ autotmp_[0-9]+$"
+} // ERROR "live at call to deferreturn: autotmp_[0-9]+ autotmp_[0-9]+$"
+
+// and newproc (go) escapes to the heap
+
+func f27go(b bool) {
+	x := 0
+	if b {
+		go call27(func() {x++}) // ERROR "live at call to new: &x" "live at call to newproc: &x$"
+	}
+	go call27(func() {x++}) // ERROR "live at call to new: &x"
+	println()
+}
+
+//go:noescape
+func call27(func())
+
+// concatstring slice should die on return
+
+var s1, s2, s3, s4, s5, s6, s7, s8, s9, s10 string
+
+func f28(b bool) {
+	if b {
+		print(s1+s2+s3+s4+s5+s6+s7+s8+s9+s10) // ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
+	}
+	print(s1+s2+s3+s4+s5+s6+s7+s8+s9+s10) // ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
+	print(s1+s2+s3+s4+s5+s6+s7+s8+s9+s10) // ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
+}	
+
+// map iterator should die on end of range loop
+
+func f29(b bool) {
+	if b {
+		for k := range m { // ERROR "live at call to mapiterinit: autotmp_[0-9]+$" "live at call to mapiternext: autotmp_[0-9]+$"
+			print(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
+		}
+	}
+	for k := range m { // ERROR "live at call to mapiterinit: autotmp_[0-9]+$" "live at call to mapiternext: autotmp_[0-9]+$"
+		print(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
+	}
+	for k := range m { // ERROR "live at call to mapiterinit: autotmp_[0-9]+$" "live at call to mapiternext: autotmp_[0-9]+$"
+		print(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
+	}
+}
+
+// copy of array of pointers should die at end of range loop
+
+var ptrarr [10]*int
+
+func f30(b bool) {
+	// two live temps during print(p):
+	// the copy of ptrarr and the internal iterator pointer.
+	if b {
+		for _, p := range ptrarr {
+			print(p) // ERROR "live at call to printpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
+		}
+	}
+	for _, p := range ptrarr {
+		print(p) // ERROR "live at call to printpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
+	}
+	for _, p := range ptrarr {
+		print(p) // ERROR "live at call to printpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
+	}
+}
+
+// conversion to interface should not leave temporary behind
+
+func f31(b1, b2, b3 bool) {
+	if b1 {
+		g31("a") // ERROR "live at call to convT2E: autotmp_[0-9]+$" "live at call to g31: autotmp_[0-9]+$"
+	}
+	if b2 {
+		h31("b") // ERROR "live at call to new: autotmp_[0-9]+$" "live at call to convT2E: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to h31: autotmp_[0-9]+$"
+	}
+	if b3 {
+		panic("asdf") // ERROR "live at call to convT2E: autotmp_[0-9]+$" "live at call to panic: autotmp_[0-9]+$"
+	}
+	print(b3)
+}
+
+func g31(interface{})
+func h31(...interface{})
+
+// non-escaping partial functions passed to function call should die on return
+
+type T32 int
+
+func (t *T32) Inc() { // ERROR "live at entry"
+	*t++
+}
+
+var t32 T32
+
+func f32(b bool) {
+	if b {
+		call32(t32.Inc) // ERROR "live at call to call32: autotmp_[0-9]+$"
+	}
+	call32(t32.Inc) // ERROR "live at call to call32: autotmp_[0-9]+$"
+	call32(t32.Inc) // ERROR "live at call to call32: autotmp_[0-9]+$"
+}
+
+//go:noescape
+func call32(func())
+
+// temporaries introduced during if conditions and && || expressions
+// should die once the condition has been acted upon.
+
+var m33 map[interface{}]int
+
+func f33() {
+	if m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+		println()
+		return
+	} else {
+		println()
+	}
+	println()
+}
+
+func f34() {
+	if m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+		println()
+		return
+	}
+	println()
+}
+
+func f35() {
+	if m33[nil] == 0 && m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+		println()
+		return
+	}
+	println()
+}
+
+func f36() {
+	if m33[nil] == 0 || m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+		println()
+		return
+	}
+	println()
+}
+
+func f37() {
+	if (m33[nil] == 0 || m33[nil] == 0) && m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+		println()
+		return
+	}
+	println()
+}
+
+// select temps should disappear in the case bodies
+
+var c38 chan string
+
+func fc38() chan string
+func fi38(int) *string
+func fb38() *bool
+
+func f38(b bool) {
+	// we don't care what temps are printed on the lines with output.
+	// we care that the println lines have no live variables
+	// and therefore no output.
+	if b {
+		select { // ERROR "live at call"
+		case <-fc38(): // ERROR "live at call"
+			println()
+		case fc38() <- *fi38(1): // ERROR "live at call"
+			println()
+		case *fi38(2) = <-fc38(): // ERROR "live at call"
+			println()
+		case *fi38(3), *fb38() = <-fc38(): // ERROR "live at call"
+			println()
+		}
+		println()
+	}
+	println()
+}
+
+// issue 8097: mishandling of x = x during return.
+
+func f39() (x []int) {
+	x = []int{1}
+	println() // ERROR "live at call to printnl: x"
+	return x
+}
+
+func f39a() (x []int) {
+	x = []int{1}
+	println() // ERROR "live at call to printnl: x"
+	return
+}
+
+func f39b() (x [10]*int) {
+	x = [10]*int{new(int)} // ERROR "live at call to new: x"
+	println() // ERROR "live at call to printnl: x"
+	return x
+}
+
+func f39c() (x [10]*int) {
+	x = [10]*int{new(int)} // ERROR "live at call to new: x"
+	println() // ERROR "live at call to printnl: x"
+	return
+}
+
+// issue 8142: lost 'addrtaken' bit on inlined variables.
+// no inlining in this test, so just checking that non-inlined works.
+
+type T40 struct {
+	m map[int]int
+}
+
+func newT40() *T40 {
+	ret := T40{ // ERROR "live at call to makemap: &ret"
+		make(map[int]int), 
+	}
+	return &ret
+}
+
+func bad40() {
+	t := newT40()
+	println()
+	_ = t
+}
+
+func good40() {
+	ret := T40{ // ERROR "live at call to makemap: ret"
+		make(map[int]int),
+	}
+	t := &ret
+	println() // ERROR "live at call to printnl: ret"
+	_ = t
+}
diff --git a/test/live1.go b/test/live1.go
new file mode 100644
index 0000000..b05ec1f
--- /dev/null
+++ b/test/live1.go
@@ -0,0 +1,46 @@
+// compile
+
+// 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 code compiles without
+// "internal error: ... recorded as live on entry" errors
+// from the liveness code.
+//
+// This code contains methods or other construct that
+// trigger the generation of wrapper functions with no
+// clear line number (they end up using line 1), and those
+// would have annotations printed if we used -live=1,
+// like the live.go test does.
+// Instead, this test relies on the fact that the liveness
+// analysis turns any non-live parameter on entry into
+// a compile error. Compiling successfully means that bug
+// has been avoided.
+
+package main
+
+// The liveness analysis used to get confused by the tail return
+// instruction in the wrapper methods generated for T1.M and (*T1).M,
+// causing a spurious "live at entry: ~r1" for the return result.
+
+type T struct {
+}
+
+func (t *T) M() *int
+
+type T1 struct {
+	*T
+}
+
+// Liveness analysis used to have the VARDEFs in the wrong place,
+// causing a temporary to appear live on entry.
+
+func f1(pkg, typ, meth string) {
+	panic("value method " + pkg + "." + typ + "." + meth + " called using nil *" + typ + " pointer")
+}
+
+func f2() interface{} {
+	return new(int)
+}
+
diff --git a/test/live2.go b/test/live2.go
new file mode 100644
index 0000000..1e32794
--- /dev/null
+++ b/test/live2.go
@@ -0,0 +1,39 @@
+// errorcheck -0 -live
+
+// 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.
+
+// liveness tests with inlining ENABLED
+// see also live.go.
+
+package main
+
+// issue 8142: lost 'addrtaken' bit on inlined variables.
+// no inlining in this test, so just checking that non-inlined works.
+
+type T40 struct {
+	m map[int]int
+}
+
+func newT40() *T40 {
+	ret := T40{ // ERROR "live at call to makemap: &ret"
+		make(map[int]int),
+	}
+	return &ret
+}
+
+func bad40() {
+	t := newT40() // ERROR "live at call to makemap: ret"
+	println()     // ERROR "live at call to printnl: ret"
+	_ = t
+}
+
+func good40() {
+	ret := T40{ // ERROR "live at call to makemap: ret"
+		make(map[int]int),
+	}
+	t := &ret
+	println() // ERROR "live at call to printnl: ret"
+	_ = t
+}
diff --git a/test/method4.dir/prog.go b/test/method4.dir/prog.go
index 77d580c..cb5cf65 100644
--- a/test/method4.dir/prog.go
+++ b/test/method4.dir/prog.go
@@ -73,7 +73,14 @@ func main() {
 	f4 := I2.Sum
 	eq(f4(t1, a, 17), 27)
 	eq(f4(t2, a, 18), 28)
-	
+
+	// issue 6723
+	f5 := (interface {
+		I2
+	}).Sum
+	eq(f5(t1, a, 19), 29)
+	eq(f5(t2, a, 20), 30)
+
 	mt1 := method4a.T1(4)
 	mt2 := &method4a.T2{4}
 
diff --git a/test/nilptr3.go b/test/nilptr3.go
index 08597a0..2757dae 100644
--- a/test/nilptr3.go
+++ b/test/nilptr3.go
@@ -17,7 +17,7 @@ type Struct struct {
 type BigStruct struct {
 	X int
 	Y float64
-	A [1<<20]int
+	A [1 << 20]int
 	Z string
 }
 
@@ -29,93 +29,94 @@ type Empty1 struct {
 }
 
 var (
-	intp *int
-	arrayp *[10]int
-	array0p *[0]int
-	bigarrayp *[1<<26]int
-	structp *Struct
+	intp       *int
+	arrayp     *[10]int
+	array0p    *[0]int
+	bigarrayp  *[1 << 26]int
+	structp    *Struct
 	bigstructp *BigStruct
-	emptyp *Empty
-	empty1p *Empty1
+	emptyp     *Empty
+	empty1p    *Empty1
 )
 
 func f1() {
 	_ = *intp // ERROR "generated nil check"
-	
+
 	// This one should be removed but the block copy needs
 	// to be turned into its own pseudo-op in order to see
 	// the indirect.
 	_ = *arrayp // ERROR "generated nil check"
-	
-	// 0-byte indirect doesn't suffice
+
+	// 0-byte indirect doesn't suffice.
+	// we don't registerize globals, so there are no removed repeated nil checks.
+	_ = *array0p // ERROR "generated nil check"
 	_ = *array0p // ERROR "generated nil check"
-	_ = *array0p // ERROR "removed repeated nil check" 386
 
-	_ = *intp // ERROR "removed repeated nil check"
-	_ = *arrayp // ERROR "removed repeated nil check"
+	_ = *intp    // ERROR "generated nil check"
+	_ = *arrayp  // ERROR "generated nil check"
 	_ = *structp // ERROR "generated nil check"
-	_ = *emptyp // ERROR "generated nil check"
-	_ = *arrayp // ERROR "removed repeated nil check"
+	_ = *emptyp  // ERROR "generated nil check"
+	_ = *arrayp  // ERROR "generated nil check"
 }
 
 func f2() {
 	var (
-		intp *int
-		arrayp *[10]int
-		array0p *[0]int
-		bigarrayp *[1<<20]int
-		structp *Struct
+		intp       *int
+		arrayp     *[10]int
+		array0p    *[0]int
+		bigarrayp  *[1 << 20]int
+		structp    *Struct
 		bigstructp *BigStruct
-		emptyp *Empty
-		empty1p *Empty1
+		emptyp     *Empty
+		empty1p    *Empty1
 	)
 
-	_ = *intp // ERROR "generated nil check"
-	_ = *arrayp // ERROR "generated nil check"
-	_ = *array0p // ERROR "generated nil check"
-	_ = *array0p // ERROR "removed repeated nil check"
-	_ = *intp // ERROR "removed repeated nil check"
-	_ = *arrayp // ERROR "removed repeated nil check"
-	_ = *structp // ERROR "generated nil check"
-	_ = *emptyp // ERROR "generated nil check"
-	_ = *arrayp // ERROR "removed repeated nil check"
-	_ = *bigarrayp // ERROR "generated nil check" ARM removed nil check before indirect!!
+	_ = *intp       // ERROR "generated nil check"
+	_ = *arrayp     // ERROR "generated nil check"
+	_ = *array0p    // ERROR "generated nil check"
+	_ = *array0p    // ERROR "removed repeated nil check"
+	_ = *intp       // ERROR "removed repeated nil check"
+	_ = *arrayp     // ERROR "removed repeated nil check"
+	_ = *structp    // ERROR "generated nil check"
+	_ = *emptyp     // ERROR "generated nil check"
+	_ = *arrayp     // ERROR "removed repeated nil check"
+	_ = *bigarrayp  // ERROR "generated nil check" ARM removed nil check before indirect!!
 	_ = *bigstructp // ERROR "generated nil check"
-	_ = *empty1p // ERROR "generated nil check"
+	_ = *empty1p    // ERROR "generated nil check"
 }
 
 func fx10k() *[10000]int
-var b bool
 
+var b bool
 
 func f3(x *[10000]int) {
 	// Using a huge type and huge offsets so the compiler
 	// does not expect the memory hardware to fault.
 	_ = x[9999] // ERROR "generated nil check"
-	
+
 	for {
 		if x[9999] != 0 { // ERROR "generated nil check"
 			break
 		}
 	}
-	
-	x = fx10k() 
+
+	x = fx10k()
 	_ = x[9999] // ERROR "generated nil check"
 	if b {
 		_ = x[9999] // ERROR "removed repeated nil check"
 	} else {
 		_ = x[9999] // ERROR "removed repeated nil check"
-	}	
+	}
 	_ = x[9999] // ERROR "generated nil check"
 
-	x = fx10k() 
+	x = fx10k()
 	if b {
 		_ = x[9999] // ERROR "generated nil check"
 	} else {
 		_ = x[9999] // ERROR "generated nil check"
-	}	
+	}
 	_ = x[9999] // ERROR "generated nil check"
-	
+
 	fx10k()
 	// This one is a bit redundant, if we figured out that
 	// x wasn't going to change across the function call.
@@ -145,7 +146,7 @@ func f3b() {
 	_ = &x[9] // ERROR "removed repeated nil check"
 }
 
-func fx10() *[10]int 
+func fx10() *[10]int
 
 func f4(x *[10]int) {
 	// Most of these have no checks because a real memory reference follows,
@@ -153,14 +154,14 @@ func f4(x *[10]int) {
 	// in the first unmapped page of memory.
 
 	_ = x[9] // ERROR "removed nil check before indirect"
-	
+
 	for {
 		if x[9] != 0 { // ERROR "removed nil check before indirect"
 			break
 		}
 	}
-	
-	x = fx10() 
+
+	x = fx10()
 	_ = x[9] // ERROR "removed nil check before indirect"
 	if b {
 		_ = x[9] // ERROR "removed nil check before indirect"
@@ -169,17 +170,17 @@ func f4(x *[10]int) {
 	}
 	_ = x[9] // ERROR "removed nil check before indirect"
 
-	x = fx10() 
+	x = fx10()
 	if b {
 		_ = x[9] // ERROR "removed nil check before indirect"
 	} else {
 		_ = &x[9] // ERROR "generated nil check"
-	}	
+	}
 	_ = x[9] // ERROR "removed nil check before indirect"
-	
+
 	fx10()
 	_ = x[9] // ERROR "removed nil check before indirect"
-	
+
 	x = fx10()
 	y := fx10()
 	_ = &x[9] // ERROR "generated nil check"
@@ -188,4 +189,3 @@ func f4(x *[10]int) {
 	x = y
 	_ = &x[9] // ERROR "removed repeated nil check"
 }
-
diff --git a/test/nilptr4.go b/test/nilptr4.go
new file mode 100644
index 0000000..3dd7d4e
--- /dev/null
+++ b/test/nilptr4.go
@@ -0,0 +1,24 @@
+// build
+
+// 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 the compiler does not crash during compilation.
+
+package main
+
+import "unsafe"
+
+// Issue 7413
+func f1() {
+	type t struct {
+		i int
+	}
+
+	var v *t
+	_ = int(uintptr(unsafe.Pointer(&v.i)))
+	_ = int32(uintptr(unsafe.Pointer(&v.i)))
+}
+
+func main() {}
diff --git a/test/nosplit.go b/test/nosplit.go
new file mode 100644
index 0000000..35aa510
--- /dev/null
+++ b/test/nosplit.go
@@ -0,0 +1,314 @@
+// run
+
+// +build !nacl
+
+// 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"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"runtime"
+	"strconv"
+	"strings"
+)
+
+var tests = `
+# These are test cases for the linker analysis that detects chains of
+# nosplit functions that would cause a stack overflow.
+#
+# Lines beginning with # are comments.
+#
+# Each test case describes a sequence of functions, one per line.
+# Each function definition is the function name, then the frame size,
+# then optionally the keyword 'nosplit', then the body of the function.
+# The body is assembly code, with some shorthands.
+# The shorthand 'call x' stands for CALL x(SB).
+# The shorthand 'callind' stands for 'CALL R0', where R0 is a register.
+# Each test case must define a function named main, and it must be first.
+# That is, a line beginning "main " indicates the start of a new test case.
+# Within a stanza, ; can be used instead of \n to separate lines.
+#
+# After the function definition, the test case ends with an optional
+# REJECT line, specifying the architectures on which the case should
+# be rejected. "REJECT" without any architectures means reject on all architectures.
+# The linker should accept the test case on systems not explicitly rejected.
+#
+# 64-bit systems do not attempt to execute test cases with frame sizes
+# that are only 32-bit aligned.
+
+# Ordinary function should work
+main 0
+
+# Large frame marked nosplit is always wrong.
+main 10000 nosplit
+REJECT
+
+# Calling a large frame is okay.
+main 0 call big
+big 10000
+
+# But not if the frame is nosplit.
+main 0 call big
+big 10000 nosplit
+REJECT
+
+# Recursion is okay.
+main 0 call main
+
+# Recursive nosplit runs out of space.
+main 0 nosplit call main
+REJECT
+
+# Chains of ordinary functions okay.
+main 0 call f1
+f1 80 call f2
+f2 80
+
+# Chains of nosplit must fit in the stack limit, 128 bytes.
+main 0 call f1
+f1 80 nosplit call f2
+f2 80 nosplit
+REJECT
+
+# Larger chains.
+main 0 call f1
+f1 16 call f2
+f2 16 call f3
+f3 16 call f4
+f4 16 call f5
+f5 16 call f6
+f6 16 call f7
+f7 16 call f8
+f8 16 call end
+end 1000
+
+main 0 call f1
+f1 16 nosplit call f2
+f2 16 nosplit call f3
+f3 16 nosplit call f4
+f4 16 nosplit call f5
+f5 16 nosplit call f6
+f6 16 nosplit call f7
+f7 16 nosplit call f8
+f8 16 nosplit call end
+end 1000
+REJECT
+
+# Test cases near the 128-byte limit.
+
+# Ordinary stack split frame is always okay.
+main 112
+main 116
+main 120
+main 124
+main 128
+main 132
+main 136
+
+# A nosplit leaf can use the whole 128-CallSize bytes available on entry.
+main 112 nosplit
+main 116 nosplit
+main 120 nosplit
+main 124 nosplit
+main 128 nosplit; REJECT
+main 132 nosplit; REJECT
+main 136 nosplit; REJECT
+
+# Calling a nosplit function from a nosplit function requires
+# having room for the saved caller PC and the called frame.
+# Because ARM doesn't save LR in the leaf, it gets an extra 4 bytes.
+main 112 nosplit call f; f 0 nosplit
+main 116 nosplit call f; f 0 nosplit; REJECT amd64
+main 120 nosplit call f; f 0 nosplit; REJECT amd64
+main 124 nosplit call f; f 0 nosplit; REJECT amd64 386
+main 128 nosplit call f; f 0 nosplit; REJECT
+main 132 nosplit call f; f 0 nosplit; REJECT
+main 136 nosplit call f; f 0 nosplit; REJECT
+
+# Calling a splitting function from a nosplit function requires
+# having room for the saved caller PC of the call but also the
+# saved caller PC for the call to morestack. Again the ARM works
+# in less space.
+main 104 nosplit call f; f 0 call f
+main 108 nosplit call f; f 0 call f
+main 112 nosplit call f; f 0 call f; REJECT amd64
+main 116 nosplit call f; f 0 call f; REJECT amd64
+main 120 nosplit call f; f 0 call f; REJECT amd64 386
+main 124 nosplit call f; f 0 call f; REJECT amd64 386
+main 128 nosplit call f; f 0 call f; REJECT
+main 132 nosplit call f; f 0 call f; REJECT
+main 136 nosplit call f; f 0 call f; REJECT
+
+# Indirect calls are assumed to be splitting functions.
+main 104 nosplit callind
+main 108 nosplit callind
+main 112 nosplit callind; REJECT amd64
+main 116 nosplit callind; REJECT amd64
+main 120 nosplit callind; REJECT amd64 386
+main 124 nosplit callind; REJECT amd64 386
+main 128 nosplit callind; REJECT
+main 132 nosplit callind; REJECT
+main 136 nosplit callind; REJECT
+
+# Issue 7623
+main 0 call f; f 112
+main 0 call f; f 116
+main 0 call f; f 120
+main 0 call f; f 124
+main 0 call f; f 128
+main 0 call f; f 132
+main 0 call f; f 136
+`
+
+var (
+	commentRE = regexp.MustCompile(`(?m)^#.*`)
+	rejectRE  = regexp.MustCompile(`(?s)\A(.+?)((\n|; *)REJECT(.*))?\z`)
+	lineRE    = regexp.MustCompile(`(\w+) (\d+)( nosplit)?(.*)`)
+	callRE    = regexp.MustCompile(`\bcall (\w+)\b`)
+	callindRE = regexp.MustCompile(`\bcallind\b`)
+)
+
+func main() {
+	goarch := os.Getenv("GOARCH")
+	if goarch == "" {
+		goarch = runtime.GOARCH
+	}
+
+	dir, err := ioutil.TempDir("", "go-test-nosplit")
+	if err != nil {
+		bug()
+		fmt.Printf("creating temp dir: %v\n", err)
+		return
+	}
+	defer os.RemoveAll(dir)
+	ioutil.WriteFile(filepath.Join(dir, "main.go"), []byte("package main\nfunc main()\n"), 0666)
+
+	tests = strings.Replace(tests, "\t", " ", -1)
+	tests = commentRE.ReplaceAllString(tests, "")
+
+	nok := 0
+	nfail := 0
+TestCases:
+	for len(tests) > 0 {
+		var stanza string
+		i := strings.Index(tests, "\nmain ")
+		if i < 0 {
+			stanza, tests = tests, ""
+		} else {
+			stanza, tests = tests[:i], tests[i+1:]
+		}
+
+		m := rejectRE.FindStringSubmatch(stanza)
+		if m == nil {
+			bug()
+			fmt.Printf("invalid stanza:\n\t%s\n", indent(stanza))
+			continue
+		}
+		lines := strings.TrimSpace(m[1])
+		reject := false
+		if m[2] != "" {
+			if strings.TrimSpace(m[4]) == "" {
+				reject = true
+			} else {
+				for _, rej := range strings.Fields(m[4]) {
+					if rej == goarch {
+						reject = true
+					}
+				}
+			}
+		}
+		if lines == "" && !reject {
+			continue
+		}
+
+		var buf bytes.Buffer
+		if goarch == "arm" {
+			fmt.Fprintf(&buf, "#define CALL BL\n#define REGISTER (R0)\n")
+		} else {
+			fmt.Fprintf(&buf, "#define REGISTER AX\n")
+		}
+
+		for _, line := range strings.Split(lines, "\n") {
+			line = strings.TrimSpace(line)
+			if line == "" {
+				continue
+			}
+			for _, subline := range strings.Split(line, ";") {
+				subline = strings.TrimSpace(subline)
+				if subline == "" {
+					continue
+				}
+				m := lineRE.FindStringSubmatch(subline)
+				if m == nil {
+					bug()
+					fmt.Printf("invalid function line: %s\n", subline)
+					continue TestCases
+				}
+				name := m[1]
+				size, _ := strconv.Atoi(m[2])
+				if goarch == "amd64" && size%8 == 4 {
+					continue TestCases
+				}
+				nosplit := m[3]
+				body := m[4]
+
+				if nosplit != "" {
+					nosplit = ",7"
+				} else {
+					nosplit = ",0"
+				}
+				body = callRE.ReplaceAllString(body, "CALL ·$1(SB);")
+				body = callindRE.ReplaceAllString(body, "CALL REGISTER;")
+
+				fmt.Fprintf(&buf, "TEXT ·%s(SB)%s,$%d-0\n\t%s\n\tRET\n\n", name, nosplit, size, body)
+			}
+		}
+
+		ioutil.WriteFile(filepath.Join(dir, "asm.s"), buf.Bytes(), 0666)
+
+		cmd := exec.Command("go", "build")
+		cmd.Dir = dir
+		output, err := cmd.CombinedOutput()
+		if err == nil {
+			nok++
+			if reject {
+				bug()
+				fmt.Printf("accepted incorrectly:\n\t%s\n", indent(strings.TrimSpace(stanza)))
+			}
+		} else {
+			nfail++
+			if !reject {
+				bug()
+				fmt.Printf("rejected incorrectly:\n\t%s\n", indent(strings.TrimSpace(stanza)))
+				fmt.Printf("\n\tlinker output:\n\t%s\n", indent(string(output)))
+			}
+		}
+	}
+
+	if !bugged && (nok == 0 || nfail == 0) {
+		bug()
+		fmt.Printf("not enough test cases run\n")
+	}
+}
+
+func indent(s string) string {
+	return strings.Replace(s, "\n", "\n\t", -1)
+}
+
+var bugged = false
+
+func bug() {
+	if !bugged {
+		bugged = true
+		fmt.Printf("BUG\n")
+	}
+}
diff --git a/test/reorder2.go b/test/reorder2.go
index d91f1d8..e56be2b 100644
--- a/test/reorder2.go
+++ b/test/reorder2.go
@@ -167,6 +167,175 @@ func main() {
 		err++
 	}
 	log = ""
+	
+	x := 0
+	switch x {
+	case 0:
+		if a("1")("2")("3"); log != "a(1)a(2)a(3)" {
+			println("in switch, expecting a(1)a(2)a(3) , got ", log)
+			err++
+		}
+		log = ""
+	
+		if t.a("1").a(t.b("2")); log != "a(1)b(2)a(2)" {
+			println("in switch, expecting a(1)b(2)a(2), got ", log)
+			err++
+		}
+		log = ""
+		if a("3")(b("4"))(b("5")); log != "a(3)b(4)a(4)b(5)a(5)" {
+			println("in switch, expecting a(3)b(4)a(4)b(5)a(5), got ", log)
+			err++
+		}
+		log = ""
+		var i I = T1(0)
+		if i.a("6").a(i.b("7")).a(i.b("8")).a(i.b("9")); log != "a(6)b(7)a(7)b(8)a(8)b(9)a(9)" {
+			println("in switch, expecting a(6)ba(7)ba(8)ba(9), got", log)
+			err++
+		}
+		log = ""
+	}
+	
+	c := make(chan int, 1)
+	c <- 1
+	select {
+	case c <- 0:
+	case c <- 1:
+	case <-c:
+		if a("1")("2")("3"); log != "a(1)a(2)a(3)" {
+			println("in select1, expecting a(1)a(2)a(3) , got ", log)
+			err++
+		}
+		log = ""
+	
+		if t.a("1").a(t.b("2")); log != "a(1)b(2)a(2)" {
+			println("in select1, expecting a(1)b(2)a(2), got ", log)
+			err++
+		}
+		log = ""
+		if a("3")(b("4"))(b("5")); log != "a(3)b(4)a(4)b(5)a(5)" {
+			println("in select1, expecting a(3)b(4)a(4)b(5)a(5), got ", log)
+			err++
+		}
+		log = ""
+		var i I = T1(0)
+		if i.a("6").a(i.b("7")).a(i.b("8")).a(i.b("9")); log != "a(6)b(7)a(7)b(8)a(8)b(9)a(9)" {
+			println("in select1, expecting a(6)ba(7)ba(8)ba(9), got", log)
+			err++
+		}
+		log = ""
+	}
+
+	c <- 1
+	select {
+	case <-c:
+		if a("1")("2")("3"); log != "a(1)a(2)a(3)" {
+			println("in select2, expecting a(1)a(2)a(3) , got ", log)
+			err++
+		}
+		log = ""
+	
+		if t.a("1").a(t.b("2")); log != "a(1)b(2)a(2)" {
+			println("in select2, expecting a(1)b(2)a(2), got ", log)
+			err++
+		}
+		log = ""
+		if a("3")(b("4"))(b("5")); log != "a(3)b(4)a(4)b(5)a(5)" {
+			println("in select2, expecting a(3)b(4)a(4)b(5)a(5), got ", log)
+			err++
+		}
+		log = ""
+		var i I = T1(0)
+		if i.a("6").a(i.b("7")).a(i.b("8")).a(i.b("9")); log != "a(6)b(7)a(7)b(8)a(8)b(9)a(9)" {
+			println("in select2, expecting a(6)ba(7)ba(8)ba(9), got", log)
+			err++
+		}
+		log = ""
+	}
+
+	c <- 1
+	select {
+	default:
+	case c<-1:
+	case <-c:
+		if a("1")("2")("3"); log != "a(1)a(2)a(3)" {
+			println("in select3, expecting a(1)a(2)a(3) , got ", log)
+			err++
+		}
+		log = ""
+	
+		if t.a("1").a(t.b("2")); log != "a(1)b(2)a(2)" {
+			println("in select3, expecting a(1)b(2)a(2), got ", log)
+			err++
+		}
+		log = ""
+		if a("3")(b("4"))(b("5")); log != "a(3)b(4)a(4)b(5)a(5)" {
+			println("in select3, expecting a(3)b(4)a(4)b(5)a(5), got ", log)
+			err++
+		}
+		log = ""
+		var i I = T1(0)
+		if i.a("6").a(i.b("7")).a(i.b("8")).a(i.b("9")); log != "a(6)b(7)a(7)b(8)a(8)b(9)a(9)" {
+			println("in select3, expecting a(6)ba(7)ba(8)ba(9), got", log)
+			err++
+		}
+		log = ""
+	}
+
+	c <- 1
+	select {
+	default:
+	case <-c:
+		if a("1")("2")("3"); log != "a(1)a(2)a(3)" {
+			println("in select4, expecting a(1)a(2)a(3) , got ", log)
+			err++
+		}
+		log = ""
+	
+		if t.a("1").a(t.b("2")); log != "a(1)b(2)a(2)" {
+			println("in select4, expecting a(1)b(2)a(2), got ", log)
+			err++
+		}
+		log = ""
+		if a("3")(b("4"))(b("5")); log != "a(3)b(4)a(4)b(5)a(5)" {
+			println("in select4, expecting a(3)b(4)a(4)b(5)a(5), got ", log)
+			err++
+		}
+		log = ""
+		var i I = T1(0)
+		if i.a("6").a(i.b("7")).a(i.b("8")).a(i.b("9")); log != "a(6)b(7)a(7)b(8)a(8)b(9)a(9)" {
+			println("in select4, expecting a(6)ba(7)ba(8)ba(9), got", log)
+			err++
+		}
+		log = ""
+	}
+
+	select {
+	case <-c:
+	case <-c:
+	default:
+		if a("1")("2")("3"); log != "a(1)a(2)a(3)" {
+			println("in select5, expecting a(1)a(2)a(3) , got ", log)
+			err++
+		}
+		log = ""
+	
+		if t.a("1").a(t.b("2")); log != "a(1)b(2)a(2)" {
+			println("in select5, expecting a(1)b(2)a(2), got ", log)
+			err++
+		}
+		log = ""
+		if a("3")(b("4"))(b("5")); log != "a(3)b(4)a(4)b(5)a(5)" {
+			println("in select5, expecting a(3)b(4)a(4)b(5)a(5), got ", log)
+			err++
+		}
+		log = ""
+		var i I = T1(0)
+		if i.a("6").a(i.b("7")).a(i.b("8")).a(i.b("9")); log != "a(6)b(7)a(7)b(8)a(8)b(9)a(9)" {
+			println("in select5, expecting a(6)ba(7)ba(8)ba(9), got", log)
+			err++
+		}
+		log = ""
+	}
 
 	if err > 0 {
 		panic("fail")
diff --git a/test/run b/test/run
index d206312..729fc1e 100755
--- a/test/run
+++ b/test/run
@@ -33,7 +33,7 @@ unset GOROOT_FINAL  # breaks ./ imports
 
 failed=0
 
-PATH=${GOBIN:-$GOROOT/bin}:`pwd`:/bin:/usr/bin:/usr/local/bin
+PATH=${GOBIN:-$GOROOT/bin}:`pwd`:/bin:/usr/bin:/usr/local/bin:/usr/pkg/bin
 
 # TODO: We add the tool directory to the PATH to avoid thinking about a better way.
 PATH="$GOTOOLDIR:$PATH"
diff --git a/test/run.go b/test/run.go
index f1f1ec0..a8d4baa 100644
--- a/test/run.go
+++ b/test/run.go
@@ -27,6 +27,7 @@ import (
 	"sort"
 	"strconv"
 	"strings"
+	"time"
 	"unicode"
 )
 
@@ -44,6 +45,8 @@ var (
 
 	// letter is the build.ArchChar
 	letter string
+	
+	goos, goarch string
 
 	// dirs are the directories to look for *.go files in.
 	// TODO(bradfitz): just use all directories?
@@ -68,8 +71,12 @@ const maxTests = 5000
 func main() {
 	flag.Parse()
 
-	// Disable parallelism if printing
-	if *verbose {
+	goos = os.Getenv("GOOS")
+	goarch = os.Getenv("GOARCH")
+	findExecCmd()
+
+	// Disable parallelism if printing or if using a simulator.
+	if *verbose || len(findExecCmd()) > 0 {
 		*numParallel = 1
 	}
 
@@ -114,28 +121,39 @@ func main() {
 	failed := false
 	resCount := map[string]int{}
 	for _, test := range tests {
-		<-test.donec
-		_, isSkip := test.err.(skipError)
-		errStr := "pass"
+		<-test.donec		
+		status := "ok  "
+		errStr := ""
+		if _, isSkip := test.err.(skipError); isSkip {
+			status = "skip"
+			test.err = nil
+			if !skipOkay[path.Join(test.dir, test.gofile)] {
+				errStr = "unexpected skip for " + path.Join(test.dir, test.gofile) + ": " + errStr
+				status = "FAIL"
+			}
+		}
 		if test.err != nil {
+			status = "FAIL"
 			errStr = test.err.Error()
-			if !isSkip {
-				failed = true
-			}
 		}
-		if isSkip && !skipOkay[path.Join(test.dir, test.gofile)] {
-			errStr = "unexpected skip for " + path.Join(test.dir, test.gofile) + ": " + errStr
-			isSkip = false
+		if status == "FAIL" {
 			failed = true
 		}
-		resCount[errStr]++
-		if isSkip && !*verbose && !*showSkips {
+		resCount[status]++
+		if status == "skip" && !*verbose && !*showSkips {
 			continue
 		}
-		if !*verbose && test.err == nil {
+		dt := fmt.Sprintf("%.3fs", test.dt.Seconds())
+		if status == "FAIL" {
+			fmt.Printf("# go run run.go -- %s\n%s\nFAIL\t%s\t%s\n",
+				path.Join(test.dir, test.gofile),
+				errStr, test.goFileName(), dt)
 			continue
 		}
-		fmt.Printf("# go run run.go -- %s\n%-20s %-20s: %s\n", path.Join(test.dir, test.gofile), test.action, test.goFileName(), errStr)
+		if !*verbose {
+			continue
+		}
+		fmt.Printf("%s\t%s\t%s\n", status, test.goFileName(), dt)
 	}
 
 	if *summary {
@@ -188,7 +206,7 @@ func compileInDir(runcmd runCmd, dir string, names ...string) (out []byte, err e
 
 func linkFile(runcmd runCmd, goname string) (err error) {
 	pfile := strings.Replace(goname, ".go", "."+letter, -1)
-	_, err = runcmd("go", "tool", ld, "-o", "a.exe", "-L", ".", pfile)
+	_, err = runcmd("go", "tool", ld, "-w", "-o", "a.exe", "-L", ".", pfile)
 	return
 }
 
@@ -207,7 +225,8 @@ func check(err error) {
 type test struct {
 	dir, gofile string
 	donec       chan bool // closed when done
-
+	dt time.Duration
+	
 	src    string
 	action string // "compile", "build", etc.
 
@@ -379,7 +398,11 @@ func init() { checkShouldTest() }
 
 // run runs a test.
 func (t *test) run() {
-	defer close(t.donec)
+	start := time.Now()
+	defer func() {
+		t.dt = time.Since(start)
+		close(t.donec)
+	}()
 
 	srcBytes, err := ioutil.ReadFile(t.goFileName())
 	if err != nil {
@@ -396,7 +419,7 @@ func (t *test) run() {
 		t.err = errors.New("double newline not found")
 		return
 	}
-	if ok, why := shouldTest(t.src, runtime.GOOS, runtime.GOARCH); !ok {
+	if ok, why := shouldTest(t.src, goos, goarch); !ok {
 		t.action = "skip"
 		if *showSkips {
 			fmt.Printf("%-20s %-20s: %s\n", t.action, t.goFileName(), why)
@@ -456,8 +479,12 @@ func (t *test) run() {
 	check(err)
 
 	// A few tests (of things like the environment) require these to be set.
-	os.Setenv("GOOS", runtime.GOOS)
-	os.Setenv("GOARCH", runtime.GOARCH)
+	if os.Getenv("GOOS") == "" {
+		os.Setenv("GOOS", runtime.GOOS)
+	}
+	if os.Getenv("GOARCH") == "" {
+		os.Setenv("GOARCH", runtime.GOARCH)
+	}
 
 	useTmp := true
 	runcmd := func(args ...string) ([]byte, error) {
@@ -572,7 +599,11 @@ func (t *test) run() {
 					t.err = err
 					return
 				}
-				out, err := runcmd(append([]string{filepath.Join(t.tempDir, "a.exe")}, args...)...)
+				var cmd []string
+				cmd = append(cmd, findExecCmd()...)
+				cmd = append(cmd, filepath.Join(t.tempDir, "a.exe"))
+				cmd = append(cmd, args...)
+				out, err := runcmd(cmd...)
 				if err != nil {
 					t.err = err
 					return
@@ -654,6 +685,23 @@ func (t *test) run() {
 	}
 }
 
+var execCmd []string
+
+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
+}	
+
 func (t *test) String() string {
 	return filepath.Join(t.dir, t.gofile)
 }
@@ -712,7 +760,7 @@ func (t *test) errorCheck(outStr string, fullshort ...string) (err error) {
 
 	for _, we := range want {
 		var errmsgs []string
-		errmsgs, out = partitionStrings(we.filterRe, out)
+		errmsgs, out = partitionStrings(we.prefix, out)
 		if len(errmsgs) == 0 {
 			errs = append(errs, fmt.Errorf("%s:%d: missing error %q", we.file, we.lineNum, we.reStr))
 			continue
@@ -754,9 +802,29 @@ func (t *test) errorCheck(outStr string, fullshort ...string) (err error) {
 
 }
 
-func partitionStrings(rx *regexp.Regexp, strs []string) (matched, unmatched []string) {
+// matchPrefix reports whether s is of the form ^(.*/)?prefix(:|[),
+// That is, it needs the file name prefix followed by a : or a [,
+// and possibly preceded by a directory name.
+func matchPrefix(s, prefix string) bool {
+	i := strings.Index(s, ":")
+	if i < 0 {
+		return false
+	}
+	j := strings.LastIndex(s[:i], "/")
+	s = s[j+1:]
+	if len(s) <= len(prefix) || s[:len(prefix)] != prefix {
+		return false
+	}
+	switch s[len(prefix)] {
+	case '[', ':':
+		return true
+	}
+	return false
+}
+
+func partitionStrings(prefix string, strs []string) (matched, unmatched []string) {
 	for _, s := range strs {
-		if rx.MatchString(s) {
+		if matchPrefix(s, prefix) {
 			matched = append(matched, s)
 		} else {
 			unmatched = append(unmatched, s)
@@ -770,7 +838,7 @@ type wantedError struct {
 	re       *regexp.Regexp
 	lineNum  int
 	file     string
-	filterRe *regexp.Regexp // /^file:linenum\b/m
+	prefix string
 }
 
 var (
@@ -780,6 +848,8 @@ var (
 )
 
 func (t *test) wantedErrors(file, short string) (errs []wantedError) {
+	cache := make(map[string]*regexp.Regexp)
+
 	src, _ := ioutil.ReadFile(file)
 	for i, line := range strings.Split(string(src), "\n") {
 		lineNum := i + 1
@@ -808,15 +878,20 @@ func (t *test) wantedErrors(file, short string) (errs []wantedError) {
 				}
 				return fmt.Sprintf("%s:%d", short, n)
 			})
-			re, err := regexp.Compile(rx)
-			if err != nil {
-				log.Fatalf("%s:%d: invalid regexp in ERROR line: %v", t.goFileName(), lineNum, err)
+			re := cache[rx]
+			if re == nil {
+				var err error
+				re, err = regexp.Compile(rx)
+				if err != nil {
+					log.Fatalf("%s:%d: invalid regexp in ERROR line: %v", t.goFileName(), lineNum, err)
+				}
+				cache[rx] = re
 			}
-			filterPattern := fmt.Sprintf(`^(\w+/)?%s:%d[:[]`, regexp.QuoteMeta(short), lineNum)
+			prefix := fmt.Sprintf("%s:%d", short, lineNum)
 			errs = append(errs, wantedError{
 				reStr:    rx,
 				re:       re,
-				filterRe: regexp.MustCompile(filterPattern),
+				prefix: prefix,
 				lineNum:  lineNum,
 				file:     short,
 			})
@@ -869,7 +944,7 @@ func checkShouldTest() {
 	// Build tags separated by a space are OR-ed together.
 	assertNot(shouldTest("// +build arm 386", "linux", "amd64"))
 
-	// Build tags seperated by a comma are AND-ed together.
+	// Build tags separated by a comma are AND-ed together.
 	assertNot(shouldTest("// +build !windows,!plan9", "windows", "amd64"))
 	assertNot(shouldTest("// +build !windows,!plan9", "plan9", "386"))
 
diff --git a/test/sigchld.go b/test/sigchld.go
index a60d28d..38437e5 100644
--- a/test/sigchld.go
+++ b/test/sigchld.go
@@ -1,4 +1,4 @@
-// +build !windows
+// +build !plan9,!windows
 // cmpout
 
 // Copyright 2009 The Go Authors. All rights reserved.
diff --git a/test/slice3err.go b/test/slice3err.go
index 906b007..83fb39b 100644
--- a/test/slice3err.go
+++ b/test/slice3err.go
@@ -54,58 +54,58 @@ func f() {
 
 	// check invalid indices
 	_ = array[1:2]
-	_ = array[2:1] // ERROR "invalid slice index"
+	_ = array[2:1] // ERROR "invalid slice index|inverted slice"
 	_ = array[2:2]
 	_ = array[i:1]
 	_ = array[1:j]
 	_ = array[1:2:3]
-	_ = array[1:3:2] // ERROR "invalid slice index"
-	_ = array[2:1:3] // ERROR "invalid slice index"
-	_ = array[2:3:1] // ERROR "invalid slice index"
-	_ = array[3:1:2] // ERROR "invalid slice index"
-	_ = array[3:2:1] // ERROR "invalid slice index"
+	_ = array[1:3:2] // ERROR "invalid slice index|inverted slice"
+	_ = array[2:1:3] // ERROR "invalid slice index|inverted slice"
+	_ = array[2:3:1] // ERROR "invalid slice index|inverted slice"
+	_ = array[3:1:2] // ERROR "invalid slice index|inverted slice"
+	_ = array[3:2:1] // ERROR "invalid slice index|inverted slice"
 	_ = array[i:1:2]
-	_ = array[i:2:1] // ERROR "invalid slice index"
+	_ = array[i:2:1] // ERROR "invalid slice index|inverted slice"
 	_ = array[1:j:2]
 	_ = array[2:j:1] // ERROR "invalid slice index"
 	_ = array[1:2:k]
-	_ = array[2:1:k] // ERROR "invalid slice index"
+	_ = array[2:1:k] // ERROR "invalid slice index|inverted slice"
 	
 	_ = slice[1:2]
-	_ = slice[2:1] // ERROR "invalid slice index"
+	_ = slice[2:1] // ERROR "invalid slice index|inverted slice"
 	_ = slice[2:2]
 	_ = slice[i:1]
 	_ = slice[1:j]
 	_ = slice[1:2:3]
-	_ = slice[1:3:2] // ERROR "invalid slice index"
-	_ = slice[2:1:3] // ERROR "invalid slice index"
-	_ = slice[2:3:1] // ERROR "invalid slice index"
-	_ = slice[3:1:2] // ERROR "invalid slice index"
-	_ = slice[3:2:1] // ERROR "invalid slice index"
+	_ = slice[1:3:2] // ERROR "invalid slice index|inverted slice"
+	_ = slice[2:1:3] // ERROR "invalid slice index|inverted slice"
+	_ = slice[2:3:1] // ERROR "invalid slice index|inverted slice"
+	_ = slice[3:1:2] // ERROR "invalid slice index|inverted slice"
+	_ = slice[3:2:1] // ERROR "invalid slice index|inverted slice"
 	_ = slice[i:1:2]
-	_ = slice[i:2:1] // ERROR "invalid slice index"
+	_ = slice[i:2:1] // ERROR "invalid slice index|inverted slice"
 	_ = slice[1:j:2]
 	_ = slice[2:j:1] // ERROR "invalid slice index"
 	_ = slice[1:2:k]
-	_ = slice[2:1:k] // ERROR "invalid slice index"
+	_ = slice[2:1:k] // ERROR "invalid slice index|inverted slice"
 	
 	_ = str[1:2]
-	_ = str[2:1] // ERROR "invalid slice index"
+	_ = str[2:1] // ERROR "invalid slice index|inverted slice"
 	_ = str[2:2]
 	_ = str[i:1]
 	_ = str[1:j]
 
 	// check out of bounds indices on array
-	_ = array[11:11] // ERROR "out of bounds for 10-element array"
-	_ = array[11:12] // ERROR "out of bounds for 10-element array"
-	_ = array[11:] // ERROR "out of bounds for 10-element array"
-	_ = array[:11] // ERROR "out of bounds for 10-element array"
-	_ = array[1:11] // ERROR "out of bounds for 10-element array"
-	_ = array[1:11:12] // ERROR "out of bounds for 10-element array"
-	_ = array[1:2:11] // ERROR "out of bounds for 10-element array"
-	_ = array[1:11:3] // ERROR "out of bounds for 10-element array"
-	_ = array[11:2:3] // ERROR "out of bounds for 10-element array"
-	_ = array[11:12:13] // ERROR "out of bounds for 10-element array"
+	_ = array[11:11] // ERROR "out of bounds"
+	_ = array[11:12] // ERROR "out of bounds"
+	_ = array[11:] // ERROR "out of bounds"
+	_ = array[:11] // ERROR "out of bounds"
+	_ = array[1:11] // ERROR "out of bounds"
+	_ = array[1:11:12] // ERROR "out of bounds"
+	_ = array[1:2:11] // ERROR "out of bounds"
+	_ = array[1:11:3] // ERROR "out of bounds|invalid slice index"
+	_ = array[11:2:3] // ERROR "out of bounds|inverted slice|invalid slice index"
+	_ = array[11:12:13] // ERROR "out of bounds"
 
 	// slice bounds not checked
 	_ = slice[11:11]
@@ -116,6 +116,6 @@ func f() {
 	_ = slice[1:11:12]
 	_ = slice[1:2:11]
 	_ = slice[1:11:3] // ERROR "invalid slice index"
-	_ = slice[11:2:3] // ERROR "invalid slice index"
+	_ = slice[11:2:3] // ERROR "invalid slice index|inverted slice"
 	_ = slice[11:12:13]
 }
diff --git a/test/string_lit.go b/test/string_lit.go
index fea6f55..4751b82 100644
--- a/test/string_lit.go
+++ b/test/string_lit.go
@@ -125,6 +125,11 @@ func main() {
 	s = string(-1)
 	assert(s, "\xef\xbf\xbd", "negative rune")
 
+	// the large rune tests yet again, with a slice.
+	rs := []rune{0x10ffff, 0x10ffff + 1, 0xD800, 0xDFFF, -1}
+	s = string(rs)
+	assert(s, "\xf4\x8f\xbf\xbf\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd", "large rune slice")
+
 	assert(string(gr1), gx1, "global ->[]rune")
 	assert(string(gr2), gx2fix, "global invalid ->[]rune")
 	assert(string(gb1), gx1, "->[]byte")
diff --git a/test/syntax/semi1.go b/test/syntax/semi1.go
index cc30f26..6e04281 100644
--- a/test/syntax/semi1.go
+++ b/test/syntax/semi1.go
@@ -7,7 +7,7 @@
 package main
 
 func main() {
-	if x; y		// ERROR "missing { after if clause|undefined"
+	if x; y		// ERROR "missing .*{.* after if clause|undefined"
 	{
 		z	// GCCGO_ERROR "undefined"
 
diff --git a/test/syntax/semi2.go b/test/syntax/semi2.go
index 61b8bf6..23d7bd0 100644
--- a/test/syntax/semi2.go
+++ b/test/syntax/semi2.go
@@ -7,7 +7,7 @@
 package main
 
 func main() {
-	switch x; y	// ERROR "missing { after switch clause|undefined"
+	switch x; y	// ERROR "missing .*{.* after switch clause|undefined"
 	{
 		z
 
diff --git a/test/syntax/semi3.go b/test/syntax/semi3.go
index bb87520..ca070d8 100644
--- a/test/syntax/semi3.go
+++ b/test/syntax/semi3.go
@@ -7,7 +7,7 @@
 package main
 
 func main() {
-	for x; y; z	// ERROR "missing { after for clause|undefined"
+	for x; y; z	// ERROR "missing .*{.* after for clause|undefined"
 	{
 		z	// GCCGO_ERROR "undefined"
 
diff --git a/test/syntax/semi4.go b/test/syntax/semi4.go
index 00fa3f5..99c2d22 100644
--- a/test/syntax/semi4.go
+++ b/test/syntax/semi4.go
@@ -8,7 +8,7 @@ package main
 
 func main() {
 	for x		// GCCGO_ERROR "undefined"
-	{		// ERROR "missing { after for clause"
+	{		// ERROR "missing .*{.* after for clause"
 		z	// GCCGO_ERROR "undefined"
 
 
diff --git a/test/tinyfin.go b/test/tinyfin.go
new file mode 100644
index 0000000..8fb109f
--- /dev/null
+++ b/test/tinyfin.go
@@ -0,0 +1,62 @@
+// run
+
+// 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 finalizers work for tiny (combined) allocations.
+
+package main
+
+import (
+	"runtime"
+	"sync/atomic"
+	"time"
+)
+
+func main() {
+	// Does not work on 32-bits due to partially conservative GC.
+	// Try to enable when we have fully precise GC.
+	if runtime.GOARCH != "amd64" {
+		return
+	}
+	// Likewise for gccgo.
+	if runtime.Compiler == "gccgo" {
+		return
+	}
+	N := int32(100)
+	count := N
+	done := make([]bool, N)
+	for i := int32(0); i < N; i++ {
+		x := i // subject to tiny alloc
+		// the closure must be big enough to be combined
+		runtime.SetFinalizer(&x, func(p *int32) {
+			// Check that p points to the correct subobject of the tiny allocation.
+			// It's a bit tricky, because we can't capture another variable
+			// with the expected value (it would be combined as well).
+			if *p < 0 || *p >= N {
+				println("got", *p)
+				panic("corrupted")
+			}
+			if done[*p] {
+				println("got", *p)
+				panic("already finalized")
+			}
+			done[*p] = true
+			atomic.AddInt32(&count, -1)
+		})
+	}
+	for i := 0; i < 4; i++ {
+		runtime.GC()
+		time.Sleep(10 * time.Millisecond)
+	}
+	// Some of the finalizers may not be executed,
+	// if the outermost allocations are combined with something persistent.
+	// Currently 4 int32's are combined into a 16-byte block,
+	// ensure that most of them are finalized.
+	if count >= N/4 {
+		println(count, "out of", N, "finalizer are not called")
+		panic("not all finalizers are called")
+	}
+}
+
diff --git a/test/typecheck.go b/test/typecheck.go
index 239ceac..6f12042 100644
--- a/test/typecheck.go
+++ b/test/typecheck.go
@@ -13,6 +13,6 @@ func mine(int b) int {	// ERROR "undefined.*b"
 }
 
 func main() {
-	mine()
-	c = mine()	// ERROR "undefined.*c" "cannot assign to c"
+	mine()		// GCCGO_ERROR "not enough arguments"
+	c = mine()	// ERROR "undefined.*c|not enough arguments"
 }

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-golang/golang.git



More information about the pkg-golang-commits mailing list